Urist McDev
Urist McDev

Reputation: 508

generate machine code directly via LLVM API

With the following code, I can generate an LLVM bitcode file from a module:

llvm::Module * module;

// fill module with code
module = ...;

std::error_code ec;
llvm::raw_fd_ostream out("anonymous.bc", ec, llvm::sys::fs::F_None);

llvm::WriteBitcodeToFile(module, out);

I can then use that bitcode file to generate an executable machine code file, e.g.:

clang -o anonymous anonymous.bc

Alternatively:

llc anonymous.bc
gcc -o anonymous anonymous.s

My question now is: Can I generate the machine code directly in C++ with the LLVM API without first needing to write the bitcode file?

I am looking for either a code example or at least some starting points in the LLVM API, e.g. which classes to use, nudging me in the right direction might even be enough.

Upvotes: 4

Views: 1501

Answers (2)

youneverknow
youneverknow

Reputation: 147

I was also looking for the code for this, and @arrowd's suggestion worked.

To save the trouble for the next person, this is what I came up with.

Given a Module, it generates assembly code on stdout for your native target:

void printASM(Module *M) {
    InitializeNativeTarget();
    InitializeNativeTargetAsmPrinter();

    auto TargetTriple = sys::getDefaultTargetTriple();
    M->setTargetTriple(TargetTriple);

    std::string Error;
    const Target *target = TargetRegistry::lookupTarget(TargetTriple, Error);
    auto cpu = sys::getHostCPUName();
    SubtargetFeatures Features;
    StringMap<bool> HostFeatures;
    if (sys::getHostCPUFeatures(HostFeatures))
        for (auto &F : HostFeatures)
            Features.AddFeature(F.first(), F.second);
    auto features = Features.getString();

    TargetOptions Options;
    std::unique_ptr<TargetMachine> TM{
            target->createTargetMachine(
                    TargetTriple, cpu, features, Options,
                    Reloc::PIC_, None, CodeGenOpt::None)
    };

    legacy::PassManager PM;
    M->setDataLayout(TM->createDataLayout());
    TM->addPassesToEmitFile(PM, (raw_pwrite_stream &) outs(), (raw_pwrite_stream *) (&outs()),
                            TargetMachine::CodeGenFileType::CGFT_AssemblyFile, true, nullptr);
    PM.run(*M);
}

If anyone knows a shorter way to write this code, feel free to correct me!

Upvotes: 6

arrowd
arrowd

Reputation: 34421

Take a look at llc tool source, spcifically compileModule() function. In short, it creates Target, sets some options for it via TargetOptions, then uses it to addPassesToEmitFile() and finally asks PassManager to perform all planned tasks.

Upvotes: 3

Related Questions