Looking for llvm Answers? Try Ask4KnowledgeBase
Looking for llvm Keywords? Try Ask4Keywords

llvmErste Schritte mit llvm


Bemerkungen

Dieser Abschnitt bietet einen Überblick über das, was llvm ist und warum ein Entwickler es möglicherweise verwenden möchte.

Es sollte auch alle großen Themen in llvm erwähnen und auf die verwandten Themen verweisen. Da die Dokumentation für llvm neu ist, müssen Sie möglicherweise erste Versionen dieser verwandten Themen erstellen.

Erstellung einer einfachen Funktion in llvm 4.0

Wir werden also versuchen, eine nachfolgende Funktion zu kompilieren

int sum(int a, int b) {
    return a + b + 2;
}
 

on the fly Und hier ist das gesamte .cpp Beispiel:

#include <iostream>

#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Verifier.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
#include "llvm/Support/TargetSelect.h"

// Optimizations
#include "llvm/Transforms/Scalar.h"
#include "llvm/Analysis/BasicAliasAnalysis.h"

using namespace llvm;


llvm::Function* createSumFunction(Module* module) {
    /* Builds the following function:
    
    int sum(int a, int b) {
        int sum1 = 1 + 1;
        int sum2 = sum1 + a;
        int result = sum2 + b;
        return result;
    }
    */

    LLVMContext &context = module->getContext();
    IRBuilder<> builder(context);

    // Define function's signature
    std::vector<Type*> Integers(2, builder.getInt32Ty());
    auto *funcType = FunctionType::get(builder.getInt32Ty(), Integers, false);

    // create the function "sum" and bind it to the module with ExternalLinkage,
    // so we can retrieve it later
    auto *fooFunc = Function::Create(
        funcType, Function::ExternalLinkage, "sum", module
    );

    // Define the entry block and fill it with an appropriate code
    auto *entry = BasicBlock::Create(context, "entry", fooFunc);
    builder.SetInsertPoint(entry);

    // Add constant to itself, to visualize constant folding
    Value *constant = ConstantInt::get(builder.getInt32Ty(), 0x1);
    auto *sum1 = builder.CreateAdd(constant, constant, "sum1");

    // Retrieve arguments and proceed with further adding...
    auto args = fooFunc->arg_begin();
    Value *arg1 = &(*args);
    args = std::next(args);
    Value *arg2 = &(*args);
    auto *sum2 = builder.CreateAdd(sum1, arg1, "sum2");
    auto *result = builder.CreateAdd(sum2, arg2, "result");  
    
    // ...and return
    builder.CreateRet(result);

    // Verify at the end
    verifyFunction(*fooFunc);
    return fooFunc;
};

int main(int argc, char* argv[]) {
    // Initilaze native target
    llvm::TargetOptions Opts;
    InitializeNativeTarget();
    InitializeNativeTargetAsmPrinter();

    LLVMContext context;
    auto myModule = make_unique<Module>("My First JIT", context);
    auto* module = myModule.get();

    std::unique_ptr<llvm::RTDyldMemoryManager> MemMgr(new llvm::SectionMemoryManager());

    // Create JIT engine
    llvm::EngineBuilder factory(std::move(myModule));
    factory.setEngineKind(llvm::EngineKind::JIT);
    factory.setTargetOptions(Opts);
    factory.setMCJITMemoryManager(std::move(MemMgr));
    auto executionEngine = std::unique_ptr<llvm::ExecutionEngine>(factory.create());
    module->setDataLayout(executionEngine->getDataLayout());

    // Create optimizations, not necessary, whole block can be ommited.
    // auto fpm = llvm::make_unique<legacy::FunctionPassManager>(module);
    // fpm->add(llvm::createBasicAAWrapperPass());
    // fpm->add(llvm::createPromoteMemoryToRegisterPass());
    // fpm->add(llvm::createInstructionCombiningPass());
    // fpm->add(llvm::createReassociatePass());
    // fpm->add(llvm::createNewGVNPass());
    // fpm->add(llvm::createCFGSimplificationPass());
    // fpm->doInitialization();

    auto* func = createSumFunction(module);  // create function
    executionEngine->finalizeObject();       // compile the module
    module->dump();                          // print the compiled code

    // Get raw pointer
    auto* raw_ptr = executionEngine->getPointerToFunction(func);
    auto* func_ptr = (int(*)(int, int))raw_ptr;

    // Execute
    int arg1 = 5;
    int arg2 = 7;
    int result = func_ptr(arg1, arg2);
    std::cout << arg1 << " + " << arg2 << " + 1 + 1 = " << result << std::endl;

    return 0;
}
 

Es sollte gut funktionieren, wenn es mit clang ++ - 4.0 mit folgenden Flags kompiliert wird:

$ llvm-config-4.0 --cxxflags --libs core
 

Installation oder Setup

Es wird immer empfohlen, die offizielle LLVM-Website zu besuchen und die Installationsanweisungen zu befolgen, die von Ihrem Betriebssystem abhängen.

Wenn Sie an Posix arbeiten, müssen Sie kurz gesagt eines der offiziellen LLVM-Paket-Repositories hinzufügen. Zum Beispiel , wenn Sie arbeiten auf Ubuntu Xenial (16.04) Sie fügen deb und deb-src Eintrag in Ihrer /etc/apt/sources.list Datei:

$ sudo su
$ echo deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-4.0 main \ >> /etc/apt/sources.list
$ echo deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial-4.0 main \ >> /etc/apt/sources.list
 

und wenn Sie das getan haben, ist die Installation so einfach wie das Aufrufen

$ sudo apt update
$ sudo apt install clang-X
 

Dabei ist X die Version, nach der Sie suchen (4.0 ist zum Zeitpunkt der Erstellung dieses Beitrags aktuell).

Beachten Sie, dass clang ein C / C ++ - Compiler ist, der über LLVM geschrieben wurde (und jetzt selbst gehostet wird) und in allen LLVM-Bibliotheken enthalten ist. Sobald Sie das getan haben, können Sie zu jedem Turorial gehen und mit dem Programmieren beginnen.

Wenn Sie möchten, können Sie die LLVM-Bibliotheken manuell installieren. Dafür müssen Sie nur apt install llvm-Y wobei Y eine Bibliothek ist, nach der Sie suchen. Ich empfehle jedoch, LLVM mit Projekten mit Clang zu erstellen.

llvm-config sollten Sie das llvm-config Tool haben. Es ist sehr nützlich, Compiler-Flags für die korrekte Kompilierung von LLVM-Projekten zu erhalten. Der erste Test, den es funktionierte, war der Aufruf

$ llvm-config-4.0 --cxxflags --libs engine
-I/usr/lib/llvm-4.0/include -std=c++0x -gsplit-dwarf -Wl,-fuse-ld=gold -fPIC -fvisibility-inlines-hidden -Wall -W -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wno-missing-field-initializers -pedantic -Wno-long-long -Wno-maybe-uninitialized -Wdelete-non-virtual-dtor -Wno-comment -Werror=date-time -std=c++11 -ffunction-sections -fdata-sections -O2 -g -DNDEBUG  -fno-exceptions -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
-lLLVM-4.0
 

Möglicherweise erhalten Sie einen anderen Satz Flags. Machen Sie sich keine Sorgen. Solange es nicht fehlschlägt command not found wenn der command not found , sollte es Ihnen gut gehen.

Im nächsten Schritt testen Sie die eigentliche LLVM-Bibliothek selbst. Erstellen llvmtest.cpp eine einfache llvmtest.cpp Datei:

#include <iostream>
#include "llvm/IR/LLVMContext.h"

int main() {
    llvm::LLVMContext context;
    std::cout << &context << std::endl;
    return 0;
};
 

Beachten Sie, dass ich std::cout damit wir die context Variable tatsächlich verwenden (damit der Compiler sie nicht während der Kompilierungsphase entfernt). Kompilieren Sie nun die Datei mit

$ clang++-4.0 -o llvmtest `llvm-config-4.0 --cxxflags --libs engine` llvmtest.cpp
 

und testen Sie es

$ ./llvmtest
0x7ffd85500970
 

Herzliche Glückwünsche! Sie können LLVM verwenden.