AlgebraMaster

Modern C++ 创造非凡 . 改变世界

导航

Master LLVM GEP

主要参考<< LLVM Essentials>> 结果发现这书内容太老了,无法编译。

然后某种情况下写对了,各种崩溃。

丝滑解决:

 

1. 先从C来看起来

 如果一个函数参数是指针意味着下面:

#include <iostream>
struct Foo{
    int f{0};
};

void access_pointer(Foo *foo){
    std::cout << &(foo->f) << std::endl;
    std::cout << &(foo[0].f) << std::endl; // 这个魔幻的0,很关键,也就是你的array就是一个单独的平整的一个维度,这个永远是0.
}

int main() {
    Foo *foo = new Foo;
    foo->f = 100;
    access_pointer(foo);
    return 0;
}
00000188B8096AA0
00000188B8096AA0

函数参数意味着:

*foo 代表有可能是个数组(LLVM就要用这个方法来调用,也就是作为数组 &(foo[0].f)这个方法来操作。 
*foo 也可能就是一个单纯的Foo类型值指针

 

2. 需要2个参数的原因

这是一段c代码,来自官方:

struct munger_struct {
  int f1;
  int f2;
};
void munge(struct munger_struct *P) {    // 注意这里传进来的p是个数组,所以比如先要解开数组!!!!即P[idx] 
  P[0].f1 = P[1].f1 + P[2].f2;
}
...
struct munger_struct Array[3];
...
munge(Array);

翻译成LLVM:

define void @munge(ptr %P) {
entry:
  %tmp = getelementptr %struct.munger_struct, ptr %P, i32 1, i32 0  ; 访问数组P的: P[1]的0,也就是P[1].f1 的地址
  %tmp1 = load i32, ptr %tmp                                        ; int tmp1 = P[1].f1;
  %tmp2 = getelementptr %struct.munger_struct, ptr %P, i32 2, i32 1 ; 访问数组P的: P[2]的1,也就是P[2].f2 的地址
  %tmp3 = load i32, ptr %tmp2                                       ; int tmp3 = P[2].f2;
  %tmp4 = add i32 %tmp3, %tmp1                                      ; int tmp4 = tmp3 + tmp1;
  %tmp5 = getelementptr %struct.munger_struct, ptr %P, i32 0, i32 0 ; 访问数组P的: P[0]的0,也就是P[0].f1 的地址
  store i32 %tmp4, ptr %tmp5                                        ; P[0].f1 = tmp4;
  ret void
}

所以2个参数第一个用来确定一块内存的ID,第二个参数用来偏移其中的位置,精确到一个元素上。

 

3. LLVM 获取一个函数array参数的 "index=2" 的元素

实现C代码类似:

int test(int *array){
    return arry[2];  
}

对应的LLVM:

define i32 @foo(<3 x i32>* %array) {
entry:
  %a_0 = getelementptr <3 x i32>, <3 x i32>* %array, i32 0, i32 2  ; 这里是关键,第一个参数是解第一层数组,然后出来才是真正的array,然后接着第二个参数就是2,也就是访问数组参数array[2](即数组第三个元素)
  %ret = load i32, i32* %a_0, align 4
  ret i32 %ret
}

Source:

#include <iostream>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"



llvm::Value *getArg(llvm::Function *function, int idx){
    return function->getArg(idx);
}
void setArgName(llvm::Function *func, const std::string &name, int idx){
    auto *arg = func->getArg(idx);
    arg->setName(name);
}

llvm::BasicBlock *createBlock(llvm::Function *func, const std::string &blockName){
    return llvm::BasicBlock::Create(   func->getContext(),blockName, func);
}

auto *createFunction(llvm::IRBuilder<> &builder, const std::string &funcName, llvm::Module &m){
    llvm::Function *ret{nullptr};
    auto *array_type= builder.getInt32Ty();
    auto *vec_type = llvm::VectorType::get(array_type, 3,false);
    auto *ptr = vec_type->getPointerTo(0);

    auto *funcType = llvm::FunctionType::get(builder.getInt32Ty(), ptr, false);
    ret = llvm::Function::Create(funcType, llvm::Function::ExternalLinkage, funcName, m);
    setArgName(ret, "array", 0 );
    return ret;
}



int main(int argc, char **argv) {
    llvm::ExitOnError ExitOnErr;
    llvm::InitLLVM give_me_a_name(argc,argv);
    llvm::InitializeNativeTarget();
    llvm::InitializeNativeTargetAsmPrinter();


    auto context = std::make_unique<llvm::LLVMContext>();
    auto mod = std::make_unique<llvm::Module>("test foo module", *context);
    auto &contextRef = *context;
    auto &modRef = *mod;

    llvm::IRBuilder<> builder(contextRef);
    auto func = createFunction(builder, "foo", modRef);
    auto *entry_block = createBlock(func, "entry");
    builder.SetInsertPoint(entry_block);

    llvm::Value *base = getArg(func, 0);
    base->getType()->dump();
    base->getType()->getScalarType()->dump();
    base->getType()->getScalarType()->getNonOpaquePointerElementType()->dump();

    std::vector<llvm::Value*> indices(2);
    indices[0] = builder.getInt32(0);
    indices[1] = builder.getInt32(0);

    llvm::Value* indexList[2] = {builder.getInt32(0), builder.getInt32(2)};

    //builder.CreateAlloca(builder.getInt32Ty(), builder.getInt32(5), "test_array");


    auto *gep_0 = builder.CreateGEP(base->getType()->getScalarType()->getNonOpaquePointerElementType(), base,  indexList, "a_0" );
    auto *ret = builder.CreateLoad(builder.getInt32Ty(), gep_0, "ret");
    builder.CreateRet(ret);

    mod->dump();


    // create execution engine
    auto J = ExitOnErr(llvm::orc::LLJITBuilder().create());
    auto threadSafeMod = llvm::orc::ThreadSafeModule(std::move(mod), std::move(context));
    J->addIRModule(std::move(threadSafeMod));


    int arr[] = {24, 12, 32};
    // Look up the JIT'd function, cast it to a function pointer, then call it.
    auto addSymbol = ExitOnErr(J->lookup("foo"));
    auto fooFunc= (int (*)(int*))addSymbol.getAddress();
    int Result1 = fooFunc(arr);

    std::cout << Result1 << std::endl;



    return 0;
}
View Code

 

int arr[] = {24, 12, 32};
    // Look up the JIT'd function, cast it to a function pointer, then call it.
auto addSymbol = ExitOnErr(J->lookup("foo"));
auto fooFunc= (int (*)(int*))addSymbol.getAddress();
int Result1 = fooFunc(arr);
std::cout << Result1 << std::endl;

可以看到console输出了32;

 

关键就是这一句:

auto *gep_0 = builder.CreateGEP(base->getType()->getScalarType()->getNonOpaquePointerElementType(), base,  indexList, "a_0" );
llvm::Value *base = getArg(func, 0);
base->getType()->dump();                  // 输出<3 x i32>*
base->getType()->getScalarType()->dump(); // 输出 <3 x i32>*
base->getType()->getScalarType()->getNonOpaquePointerElementType()->dump(); // 只有这个是输出<3 x i32>

LLVM getelementptr:看第一个参数类型必须是array里的确定类型才可以。

%a_0 = getelementptr <3 x i32>, <3 x i32>* %array, i32 0, i32 2  ;

 

 

4. 数组求和:

对应的C代码:

int foo(int *array){
    int ret=0;
    for(int i=0;i < 3;i++){
        ret = ret + array[i];
    }
    return ret;
}

对应的LLVM:

; ModuleID = 'test foo module'
source_filename = "test foo module"

define i32 @foo(<3 x i32>* %array) {
entry:
  %ret_alloc = alloca i32, align 4
  store i32 0, i32* %ret_alloc, align 4 ; 相当于int ret = 0;
  br label %loop

loop:                                             ; preds = %loop_body, %entry
  %phi_i = phi i32 [ 0, %entry ], [ %next_val, %loop_body ]
  %cmp = icmp slt i32 %phi_i, 3
  br i1 %cmp, label %loop_body, label %after_loop

loop_body:                                        ; preds = %loop
  %next_val = add i32 %phi_i, 1
  %gep_addr = getelementptr <3 x i32>, <3 x i32>* %array, i32 0, i32 %phi_i
  %gep_load = load i32, i32* %gep_addr, align 4
  %ret_temp_load_value = load i32, i32* %ret_alloc, align 4
  %added = add i32 %ret_temp_load_value, %gep_load
  store i32 %added, i32* %ret_alloc, align 4
  br label %loop

after_loop:                                       ; preds = %loop
  %ret = load i32, i32* %ret_alloc, align 4
  ret i32 %ret
}

source:

#include <iostream>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"



constexpr int array_size  = 3;

llvm::Value *getArg(llvm::Function *function, int idx){
    return function->getArg(idx);
}
void setArgName(llvm::Function *func, const std::string &name, int idx){
    auto *arg = func->getArg(idx);
    arg->setName(name);
}

llvm::BasicBlock *createBlock(llvm::Function *func, const std::string &blockName){
    return llvm::BasicBlock::Create(   func->getContext(),blockName, func);
}

auto *createFunction(llvm::IRBuilder<> &builder, const std::string &funcName, llvm::Module &m){
    llvm::Function *ret{nullptr};
    auto *array_type= builder.getInt32Ty();
    auto *vec_type = llvm::VectorType::get(array_type, array_size,false);
    auto *ptr = vec_type->getPointerTo(0);

    auto *funcType = llvm::FunctionType::get(builder.getInt32Ty(), ptr, false);
    ret = llvm::Function::Create(funcType, llvm::Function::ExternalLinkage, funcName, m);
    setArgName(ret, "array", 0 );
    return ret;
}

int main(int argc, char **argv) {
    llvm::ExitOnError ExitOnErr;
    llvm::InitLLVM give_me_a_name(argc,argv);
    llvm::InitializeNativeTarget();
    llvm::InitializeNativeTargetAsmPrinter();


    auto context = std::make_unique<llvm::LLVMContext>();
    auto mod = std::make_unique<llvm::Module>("test foo module", *context);
    auto &contextRef = *context;
    auto &modRef = *mod;

    llvm::IRBuilder<> builder(contextRef);
    auto func = createFunction(builder, "foo", modRef);
    auto *entry_block = createBlock(func, "entry");
    auto *loop_block = createBlock(func, "loop");
    auto *loop_body_block = createBlock(func, "loop_body");
    auto *after_loop_block = createBlock(func, "after_loop");
    builder.SetInsertPoint(entry_block);

    llvm::Value *base = getArg(func, 0);
    base->getType()->dump();
    base->getType()->getScalarType()->dump();
    base->getType()->getScalarType()->getNonOpaquePointerElementType()->dump();


    auto *ret_alloc = builder.CreateAlloca(builder.getInt32Ty(),nullptr, "ret_alloc");
    builder.CreateStore(builder.getInt32(0), ret_alloc);
    builder.CreateBr(loop_block);

    // loop block
    builder.SetInsertPoint(loop_block);
    auto *phi_i = builder.CreatePHI(builder.getInt32Ty(), 2, "phi_i");
    phi_i->addIncoming(builder.getInt32(0), entry_block);
    auto *cmp = builder.CreateICmpSLT(phi_i, builder.getInt32(array_size ) , "cmp"); // i < 3
    builder.CreateCondBr(cmp, loop_body_block, after_loop_block);

    // loop_body
    builder.SetInsertPoint(loop_body_block);
    auto *next_value = builder.CreateAdd(phi_i, builder.getInt32(1), "next_val");
    phi_i->addIncoming(next_value, loop_body_block);
    llvm::Value* indices[] = {builder.getInt32(0), phi_i};
    auto *gep = builder.CreateGEP(base->getType()->getScalarType()->getNonOpaquePointerElementType(), base, indices, "gep_addr" );
    auto *gep_value = builder.CreateLoad(builder.getInt32Ty(), gep, "gep_load");
    auto *ret_temp_load_value = builder.CreateLoad(builder.getInt32Ty(),ret_alloc, "ret_temp_load_value");
    auto *added = builder.CreateAdd(ret_temp_load_value, gep_value, "added");
    builder.CreateStore(added,ret_alloc);
    builder.CreateBr(loop_block);


    // after loop body
    builder.SetInsertPoint(after_loop_block);
    builder.CreateRet(builder.CreateLoad(builder.getInt32Ty(),ret_alloc, "ret"));
    mod->dump();



    // create execution engine
    auto J = ExitOnErr(llvm::orc::LLJITBuilder().create());
    auto threadSafeMod = llvm::orc::ThreadSafeModule(std::move(mod), std::move(context));
    J->addIRModule(std::move(threadSafeMod));


    int arr[] = {1, 2, 3};
    // Look up the JIT'd function, cast it to a function pointer, then call it.
    auto addSymbol = ExitOnErr(J->lookup("foo"));
    auto fooFunc= (int (*)(int*))addSymbol.getAddress();
    int Result1 = fooFunc(arr);

    std::cout << Result1 << std::endl;



    return 0;
}
View Code

关键就看这一句:

%gep_addr = getelementptr <3 x i32>, <3 x i32>* %array, i32 0, i32 %phi_i

第一个参数一定是<3 x i32>。 

5. 数组求和2 CreateGEP使用一个参数+extractelement指令

有必要看下CreateGEP中使用一个值的偏移(off)情况,顺便配合extractelement实现一样的求和

注意这里我使用LLVM git 版本是12,有个函数是改了,上面的都是LLVM14

base->getType()->getScalarType()->getNonOpaquePointerElementType()

改成了:

base->getType()->getPointerElementType()->dump();

 

看看两个参数和一个参数 区别:

llvm::Value *gep = builder.CreateGEP( base, {builder.getInt32(0), builder.getInt32(0)}, "gep_addr" );
gep->getType()->dump(); // i32*
auto *load1 = builder.CreateLoad(gep, "load_grep");
load1->getType()->dump(); // i32

llvm::Value *gep2 = builder.CreateGEP( base, builder.getInt32(0), "gep_addr" );    // 注意这里,只有一个参数。
gep2->getType()->dump(); // <3 x i32> *                                            // 指向数组。
auto *load2 = builder.CreateLoad(gep2, "load_grep");                              
load2->getType()->dump(); // <3 x i32>                                             // 注意,这个时候load2是数组。

非常符合预期。相当于指向数组。

接着对load2 来一次extract element 指令就可以得到<3 x i32>元素的值

auto *element = builder.CreateExtractElement(load2, phi_i, "extract");

源码:

#include <iostream>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"



constexpr int array_size  = 3;

llvm::Value *getArg(llvm::Function *function, int idx){
    return function->getArg(idx);
}
void setArgName(llvm::Function *func, const std::string &name, int idx){
    auto *arg = func->getArg(idx);
    arg->setName(name);
}

llvm::BasicBlock *createBlock(llvm::Function *func, const std::string &blockName){
    return llvm::BasicBlock::Create(   func->getContext(),blockName, func);
}

auto *createFunction(llvm::IRBuilder<> &builder, const std::string &funcName, llvm::Module &m){
    llvm::Function *ret{nullptr};
    auto *array_type= builder.getInt32Ty();
    auto *vec_type = llvm::VectorType::get(array_type, array_size, false);
    auto *ptr = vec_type->getPointerTo(0);

    auto *funcType = llvm::FunctionType::get(builder.getInt32Ty(), ptr, false);
    ret = llvm::Function::Create(funcType, llvm::Function::ExternalLinkage, funcName, m);
    setArgName(ret, "array", 0 );
    return ret;
}

int main(int argc, char **argv) {
    llvm::ExitOnError ExitOnErr;
    llvm::InitLLVM give_me_a_name(argc,argv);
    llvm::InitializeNativeTarget();
    llvm::InitializeNativeTargetAsmPrinter();


    auto context = std::make_unique<llvm::LLVMContext>();
    auto mod = std::make_unique<llvm::Module>("test foo module", *context);
    auto &contextRef = *context;
    auto &modRef = *mod;

    llvm::IRBuilder<> builder(contextRef);
    auto func = createFunction(builder, "foo", modRef);
    auto *entry_block = createBlock(func, "entry");
    auto *loop_block = createBlock(func, "loop");
    auto *loop_body_block = createBlock(func, "loop_body");
    auto *after_loop_block = createBlock(func, "after_loop");
    builder.SetInsertPoint(entry_block);

    llvm::Value *base = getArg(func, 0);
    base->getType()->dump();
    base->getType()->getScalarType()->dump();
    base->getType()->getPointerElementType()->dump();


    auto *ret_alloc = builder.CreateAlloca(builder.getInt32Ty(),nullptr, "ret_alloc");
    builder.CreateStore(builder.getInt32(0), ret_alloc);
    builder.CreateBr(loop_block);

    // loop block
    builder.SetInsertPoint(loop_block);
    auto *phi_i = builder.CreatePHI(builder.getInt32Ty(), 2, "phi_i");
    phi_i->addIncoming(builder.getInt32(0), entry_block);
    auto *cmp = builder.CreateICmpSLT(phi_i, builder.getInt32(array_size ) , "cmp"); // i < 3
    builder.CreateCondBr(cmp, loop_body_block, after_loop_block);

    // loop_body
    builder.SetInsertPoint(loop_body_block);
    auto *next_value = builder.CreateAdd(phi_i, builder.getInt32(1), "next_val");
    phi_i->addIncoming(next_value, loop_body_block);
    llvm::Value* indices[] = {builder.getInt32(0), phi_i};

    //  base->getType()->getPointerElementType()->dump();
    /*
    llvm::Value *gep = builder.CreateGEP( base, {builder.getInt32(0), builder.getInt32(0)}, "gep_addr" );
    gep->getType()->dump(); // i32*
    auto *load1 = builder.CreateLoad(gep, "load_grep");
    load1->getType()->dump(); // i32
     */
    llvm::Value *gep2 = builder.CreateGEP( base, builder.getInt32(0), "gep_addr" );
    gep2->getType()->dump(); // <3 x i32> *
    auto *load2 = builder.CreateLoad(gep2, "load_grep");
    load2->getType()->dump(); // <3 x i32>
    auto *element = builder.CreateExtractElement(load2, phi_i, "extract");

    auto *ret_temp_load_value = builder.CreateLoad(builder.getInt32Ty(), ret_alloc, "ret_temp_load_value");
    auto *added = builder.CreateAdd(ret_temp_load_value, element, "added");
    builder.CreateStore(added,ret_alloc);
    builder.CreateBr(loop_block);
    // after loop body
    builder.SetInsertPoint(after_loop_block);
    builder.CreateRet(builder.CreateLoad(builder.getInt32Ty(),ret_alloc, "ret"));



    
    /* USE GEP WITH indices ARG{}
    auto *gep = builder.CreateGEP(base->getType()->getPointerElementType(), base, indices, "gep_addr" );
    auto *gep_value = builder.CreateLoad(builder.getInt32Ty(), gep, "gep_load");
    auto *ret_temp_load_value = builder.CreateLoad(builder.getInt32Ty(),ret_alloc, "ret_temp_load_value");
    auto *added = builder.CreateAdd(ret_temp_load_value, gep_value, "added");
    builder.CreateStore(added,ret_alloc);
    builder.CreateBr(loop_block);
    // after loop body
    builder.SetInsertPoint(after_loop_block);
    builder.CreateRet(builder.CreateLoad(builder.getInt32Ty(),ret_alloc, "ret"));*/
    mod->dump();
    // create execution engine
    auto J = ExitOnErr(llvm::orc::LLJITBuilder().create());
    auto threadSafeMod = llvm::orc::ThreadSafeModule(std::move(mod), std::move(context));
    J->addIRModule(std::move(threadSafeMod));


    int arr[] = {1, 2, 3};
    // Look up the JIT'd function, cast it to a function pointer, then call it.
    auto addSymbol = ExitOnErr(J->lookup("foo"));


    auto fooFunc= (int (*)(int*))addSymbol.getAddress();
    int Result1 = fooFunc(arr);
    std::cout << Result1 << std::endl;


    std::cin.get();

    return 0;
}
View Code

 

6:数组求和3 LLVM15 API 又尼玛的改了

 下面是用LLVM15, LLVM15 的API我感觉是正常人可用了。

注意看LLVM 14 IR函数参数是

define i32 @foo(<3 x i32>* %array) {
}

然后我手动把c->LLVM IR 试了试

extern "C" int foo(int array[]){  // 参数也可以是int *
    return array[2];
}

int main(){
    int a[3] = {100,200,300};
    foo(a);
    return 0;
}

clang -emit-llvm -c -S const_array.cpp

@__const.main.a = private unnamed_addr constant [3 x i32] [i32 100, i32 200, i32 300], align 4

; Function Attrs: mustprogress noinline nounwind optnone uwtable
define dso_local i32 @foo(ptr noundef %0) #0 {          // 注意这个参数。是ptr %var,以前是<3 x i32>* %array
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8
  %3 = load ptr, ptr %2, align 8
  %4 = getelementptr inbounds i32, ptr %3, i64 2        // 注意这里,直接就是getelementptr, indices其实就是一个了,也就是符合C语言这个风格。
  %5 = load i32, ptr %4, align 4
  ret i32 %5
}

; Function Attrs: mustprogress noinline norecurse nounwind optnone uwtable
define dso_local noundef i32 @main() #1 {
  %1 = alloca i32, align 4
  %2 = alloca [3 x i32], align 4
  store i32 0, ptr %1, align 4
  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %2, ptr align 4 @__const.main.a, i64 12, i1 false)
  %3 = getelementptr inbounds [3 x i32], ptr %2, i64 0, i64 0
  %4 = call i32 @foo(ptr noundef %3)
  ret i32 0
}

可以看到参数完全变了,这个时候其实请好。

所以 对于我这边的源码改了:

 全部源码:

#include <iostream>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"



constexpr int array_size  = 3;

llvm::Value *getArg(llvm::Function *function, int idx){
    return function->getArg(idx);
}
void setArgName(llvm::Function *func, const std::string &name, int idx){
    auto *arg = func->getArg(idx);
    arg->setName(name);
}

llvm::BasicBlock *createBlock(llvm::Function *func, const std::string &blockName){
    return llvm::BasicBlock::Create(   func->getContext(),blockName, func);
}

auto *createFunction(llvm::IRBuilder<> &builder, const std::string &funcName, llvm::Module &m){
    llvm::Function *ret{nullptr};
    auto *array_type= builder.getInt32Ty();
    auto *vec_type = llvm::VectorType::get(array_type, array_size, false);
    auto *ptr = vec_type->getPointerTo(0);

    auto *funcType = llvm::FunctionType::get(builder.getInt32Ty(), ptr, false);
    ret = llvm::Function::Create(funcType, llvm::Function::ExternalLinkage, funcName, m);
    setArgName(ret, "array", 0 );
    return ret;
}

int main(int argc, char **argv) {
    llvm::ExitOnError ExitOnErr;
    llvm::InitLLVM give_me_a_name(argc,argv);
    llvm::InitializeNativeTarget();
    llvm::InitializeNativeTargetAsmPrinter();


    auto context = std::make_unique<llvm::LLVMContext>();
    auto mod = std::make_unique<llvm::Module>("test foo module", *context);
    auto &contextRef = *context;
    auto &modRef = *mod;

    llvm::IRBuilder<> builder(contextRef);
    auto func = createFunction(builder, "foo", modRef);
    auto *entry_block = createBlock(func, "entry");
    auto *loop_block = createBlock(func, "loop");
    auto *loop_body_block = createBlock(func, "loop_body");
    auto *after_loop_block = createBlock(func, "after_loop");
    builder.SetInsertPoint(entry_block);

    llvm::Value *base = getArg(func, 0);
    base->getType()->dump();
    base->getType()->getScalarType()->dump();
    base->dump();

    llvm::PointerType::get(builder.getInt32Ty(), base->getType()->getPointerAddressSpace())->dump();


    auto *ret_alloc = builder.CreateAlloca(builder.getInt32Ty(),nullptr, "ret_alloc");
    builder.CreateStore(builder.getInt32(0), ret_alloc);
    builder.CreateBr(loop_block);

    // loop block
    builder.SetInsertPoint(loop_block);
    auto *phi_i = builder.CreatePHI(builder.getInt32Ty(), 2, "phi_i");
    phi_i->addIncoming(builder.getInt32(0), entry_block);
    auto *cmp = builder.CreateICmpSLT(phi_i, builder.getInt32(array_size ) , "cmp"); // i < 3
    builder.CreateCondBr(cmp, loop_body_block, after_loop_block);

    // loop_body
    builder.SetInsertPoint(loop_body_block);
    auto *next_value = builder.CreateAdd(phi_i, builder.getInt32(1), "next_val");
    phi_i->addIncoming(next_value, loop_body_block);


    // this is works
    //auto *vec_type = llvm::VectorType::get(builder.getInt32Ty(), array_size, false);
    //vec_type->dump();
    //builder.CreateGEP(vec_type, base, {builder.getInt32(0), builder.getInt32(0)}, "gep_addr" );

    auto *gep = builder.CreateGEP(builder.getInt32Ty(), base, phi_i, "gep_addr" );
    gep->getType()->dump();
    auto *load = builder.CreateLoad(builder.getInt32Ty(), gep, "load_grep");
    auto *ret_temp_load_value = builder.CreateLoad(builder.getInt32Ty(), ret_alloc, "ret_temp_load_value");
    auto *added = builder.CreateAdd(ret_temp_load_value, load, "added");
    builder.CreateStore(added,ret_alloc);
    builder.CreateBr(loop_block);
    // after loop body
    builder.SetInsertPoint(after_loop_block);
    builder.CreateRet(builder.CreateLoad(builder.getInt32Ty(),ret_alloc, "ret"));
    mod->dump();

    // create execution engine
    auto J = ExitOnErr(llvm::orc::LLJITBuilder().create());
    auto threadSafeMod = llvm::orc::ThreadSafeModule(std::move(mod), std::move(context));
    J->addIRModule(std::move(threadSafeMod));

    int arr[] = {1, 2, 3};
    // Look up the JIT'd function, cast it to a function pointer, then call it.
    auto addSymbol = ExitOnErr(J->lookup("foo"));
    auto fooFunc = addSymbol.toPtr<int(int*)>();
    //auto fooFunc= (int (*)(int*))addSymbol.getAddress();
    int Result1 = fooFunc(arr);
    std::cout << Result1 << std::endl;

    
    std::cin.get();

    return 0;
}
View Code

 

 

 

 

 

参考:

https://mukulrathi.com/create-your-own-programming-language/llvm-ir-cpp-api-tutorial/

posted on 2023-03-13 00:28  gearslogy  阅读(313)  评论(0编辑  收藏  举报