自己使用 LLVM Interpreter API 的方法。
首先先產生 LLVM 的 function,如下:
#define NDEBUG, dbgs() == errs()
#include <stdio.h>
#include<vector>
#include "llvm/LLVMContext.h"
#include "llvm/Support/Threading.h"
#include "llvm/Module.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
#include "llvm/BasicBlock.h"
#include "llvm/CallingConv.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/ExecutionEngine/Interpreter.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include <stdlib.h>
#include <pthread.h>
#include "llvm/GlobalVariable.h"
#include "llvm/Support/ThreadLocal.h"
#include<iostream>
#include"llvm/Constants.h"
#include "llvm/CodeGen/MachineCodeInfo.h"
#include "llvm/ADT/SmallVector.h"
using namespace std;
using namespace llvm;
llvm::GlobalVariable* gvar,*gvar2;
ExecutionEngine* EE;
MachineCodeInfo info[5];
struct myType
{
int a,b,c[32],d;
};
int main()
{
struct myType my;
my.b = 10;
my.a = 50;
my.c[1] = 100; my.c[8] = 128;
// llvm_start_multithreaded();
// InitializeNativeTarget();
IRBuilder<> irbuilder(llvm::getGlobalContext());
llvm::Module* mod = new llvm::Module("",llvm::getGlobalContext());
mod->setTargetTriple("x86-unknown-linux-gnu");
/* SET DATA LAYOUT, THIS IS IMPORTANT */
mod->setDataLayout("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128");
//mod->getDataLayout();
// LLVMLinkInInterpreter();
//Interpreter inp(mod) ;//llvm::Interpreter(mod);
/* CREATE AN INTERPRETER */
EngineBuilder builder(mod);
builder.setEngineKind(EngineKind::Interpreter);
// builder.setOptLevel(CodeGenOpt::Default);
EE = builder.create();
StructType *sty = StructType::create(mod->getContext(),"Struct.MyType");
vector<Type*> field;
Type* tp = IntegerType::get(mod->getContext(),32);
field.push_back(IntegerType::get(mod->getContext(),32));
field.push_back(IntegerType::get(mod->getContext(),32));
field.push_back(ArrayType::get(tp,32));
field.push_back(tp);
sty->setBody(field,false);
PointerType* pty = PointerType::get(sty,0);
vector<Type*> par;
par.push_back(pty);
FunctionType* fty = FunctionType::get(IntegerType::get(mod->getContext(),32),par,false);
Function* f = Function::Create(fty,GlobalValue::InternalLinkage,"styF",mod);
Function::arg_iterator it1 = f->arg_begin();
Value* fv = it1++;
fv->setName("p");
fv->getType();
BasicBlock* fbb = BasicBlock::Create(mod->getContext(),"",
f,0);
irbuilder.SetInsertPoint(fbb);
LoadInst* ld1 = irbuilder.CreateLoad(fv);
Value*v1 = irbuilder.CreateExtractValue(ld1,2);
v1 = irbuilder.CreateExtractValue(v1,8);
ConstantInt* const_int = llvm::ConstantInt::get(mod->getContext(),
APInt(32,StringRef("522"),10));
irbuilder.CreateRet(v1);
// function : setValue
vector<Type*>FuncTy1_args;
FuncTy1_args.push_back(pty);
FuncTy1_args.push_back(IntegerType::get(mod->getContext(),32));
FunctionType* setfty = FunctionType::get(irbuilder.getVoidTy(),FuncTy1_args,false);
Function* sf = Function::Create(setfty,GlobalValue::InternalLinkage,"setValueF",mod);
BasicBlock* bb1 = BasicBlock::Create(mod->getContext(),"",sf,0);
irbuilder.SetInsertPoint(bb1);
it1 = sf->arg_begin();
Value* arg1 = it1++; arg1->setName("sty");
Value* arg2 = it1++; arg2->setName("value");
AllocaInst* ptr1_23=irbuilder.CreateAlloca(pty); ptr1_23->setAlignment(4);
StoreInst* s_24 = irbuilder.CreateStore(arg1, ptr1_23); s_24->setAlignment(4);
LoadInst* ptr1_25 = irbuilder.CreateLoad(ptr1_23); ptr1_25->setAlignment(4);
Value* ptr1_26 = irbuilder.CreateStructGEP(ptr1_25,2);
ptr1_26 = irbuilder.CreateStructGEP(ptr1_26,1);
StoreInst* va = irbuilder.CreateStore(arg2, ptr1_26); va->setAlignment(4);
irbuilder.CreateRetVoid();
gvar = new llvm::GlobalVariable(*mod,
llvm::IntegerType::get(mod->getContext(),32),
false,
llvm::GlobalValue::InternalLinkage,
const_int,
"",
0,
0,
0);
gvar->setAlignment(4);
// gvar->setThreadLocal(true);
Value* hi = irbuilder.CreateGlobalStringPtr("1234567hi\n");
// printf
PointerType* PointerTy_71 = PointerType::get(IntegerType::get(mod->getContext(), 8), 0);
std::vector<Type*> FuncTy_12_args;
FuncTy_12_args.push_back(PointerTy_71);
FunctionType* FuncTy_12 = FunctionType::get(IntegerType::get(mod->getContext(),32),
FuncTy_12_args,true);
Function* func_printf = Function::Create(FuncTy_12,GlobalValue::ExternalLinkage,
"printf",mod);
func_printf->setCallingConv(CallingConv::C);
PointerType* PointerTy_1 = PointerType::get(IntegerType::get(mod->getContext(),64),0);
StructType* StructTy_union_pthread_attr_t = mod->getTypeByName("union.pthread_attr_t");
if (!StructTy_union_pthread_attr_t) {
StructTy_union_pthread_attr_t = StructType::create(mod->getContext(), "union.pthread_attr_t");
}
PointerType* PointerTy_7 = PointerType::get(IntegerType::get(mod->getContext(),8),0);
vector<Type*>FuncTy8_args;
FunctionType* FuncTy_8 = FunctionType::get(PointerTy_7,
FuncTy8_args,
false);
if(StructTy_union_pthread_attr_t==NULL)cout<<"FUCK NULL"<<endl;
PointerType* PointerTy_2 = PointerType::get(StructTy_union_pthread_attr_t,0);
PointerType* PointerTy_3 = PointerType::get(FuncTy_8,0);
PointerType* PointerTy_4 = PointerType::get(IntegerType::get(mod->getContext(),8),0);
vector<Type*> FuncTy_args;
FuncTy_args.push_back(PointerTy_1);
FuncTy_args.push_back(PointerTy_2);
FuncTy_args.push_back(PointerTy_3);
FuncTy_args.push_back(PointerTy_4);
FunctionType* FuncTy = FunctionType::get(
IntegerType::get(mod->getContext(),32),
FuncTy_args,
false);
// function : set value
ConstantInt* const_int32_4 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("1321"), 10));
Function* setV;
std::vector<Type*> sv_args;
sv_args.push_back( PointerType::get(IntegerType::get(mod->getContext(),32),0));
FunctionType* svTy = FunctionType::get(
Type::getVoidTy(mod->getContext()),
sv_args,
false);
setV = Function::Create(svTy,GlobalValue::ExternalLinkage,"setValue",mod);
Function::arg_iterator it = setV->arg_begin();
Value* int32_v = it++;
int32_v->setName("v");
BasicBlock* svbb = BasicBlock::Create(mod->getContext(),"",
setV,0);
/*AllocaInst* ptr_6 = new AllocaInst(
PointerType::get(IntegerType::get(mod->getContext(),32),0),
"",
svbb);
ptr_6->setAlignment(4);
StoreInst* void_7 = new StoreInst(int32_v,ptr_6,false,svbb);
void_7->setAlignment(4);
LoadInst* int32_8 = new LoadInst(ptr_6,"",false,svbb);
int32_8->setAlignment(4);*/
StoreInst* void_9 = new StoreInst(const_int32_4,int32_v,false,svbb);
void_9->setAlignment(4);
ReturnInst::Create(mod->getContext(),svbb);
// function: getvalue
std::vector<Type*> gv_args;
FunctionType* gvTy = FunctionType::get(IntegerType::get(mod->getContext(),32),
gv_args,
false);
Function* gv = Function::Create(gvTy,
GlobalValue::ExternalLinkage,
"getValue",mod);
gv->setCallingConv(CallingConv::C);
BasicBlock* gvbb = BasicBlock::Create(
mod->getContext(),
"",
gv,
0);
irbuilder.SetInsertPoint(gvbb);
irbuilder.CreateCall(func_printf,hi);
//LoadInst* ld = irbuilder.CreateLoad(gvar);
// irbuilder.CreateRet(ld);
irbuilder.CreateRet(const_int32_4);
vector<GenericValue> arg;
GenericValue rv;
APInt ap;
unsigned long long uv;
/* 確保 INTERPRETER 有被 create */
if(!EE)cout<<"EE null"<<endl;
/* 呼叫 LLVM::FUNCTION gv , 這個 function 沒有參數 */
rv = EE->runFunction(gv,arg);
cout<<rv.IntVal.toString(10,1)<<endl;
// rv.IntVal.dump();
mod->dump();
int p = 128;;
// printf("Pointer : %x\n",(p));
/* 呼叫另一個 LLVM::FUNCTION setV, 參數一個 , 這個function 的 prototype : void setV(int* ) , 因此傳參數使用 PTOGV function, 其實也可以寫成
GenericValue gg ; gg.PointerVal = &p;
*/
arg.push_back(PTOGV(&p));
EE->runFunction(setV,arg);
printf("value: %d\n",p);
// EE->runJITOnFunction(setV,info);
// EE->runJITOnFunction(gv,info+1);
// EE->runJITOnFunction(f,info+2);
// EE->runJITOnFunction(sf,info+3);
return 0;
}
以下為產生的 LLVM IR
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
target triple = "x86-unknown-linux-gnu"
%Struct.MyType = type { i32, i32, [32 x i32], i32 }
@0 = internal global i32 522, align 4
@1 = private unnamed_addr constant [11 x i8] c"1234567hi\0A\00"
define internal i32 @styF(%Struct.MyType* %p) {
%1 = load %Struct.MyType* %p
%2 = extractvalue %Struct.MyType %1, 2
%3 = extractvalue [32 x i32] %2, 8
ret i32 %3
}
define internal void @setValueF(%Struct.MyType* %sty, i32 %value) {
%1 = alloca %Struct.MyType*, align 4
store %Struct.MyType* %sty, %Struct.MyType** %1, align 4
%2 = load %Struct.MyType** %1, align 4
%3 = getelementptr inbounds %Struct.MyType* %2, i32 0, i32 2
%4 = getelementptr inbounds [32 x i32]* %3, i32 0, i32 1
store i32 %value, i32* %4, align 4
ret void
}
declare i32 @printf(i8*, ...)
define void @setValue(i32* %v) {
store i32 1321, i32* %v, align 4
ret void
}
define i32 @getValue() {
%1 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([11 x i8]* @1, i32 0, i32 0))
ret i32 1321
}
執行結果印出
value: 1321
原本值是 128
%注意%
LLVM 沒有辦法讓 user 直接開一個 interpreter 的 instance ,而需要用 ExecutionEngine 去創造。
傳參數需要用 GenericValue,裡頭有一個 Union structure ,依造你所需要的 type 給值, 但 int 似乎要另外放, 放在 一個 APInt IntVal 的參數。
將 c int 轉成APint ,APInt(32,c) 及可。
因為Interpreter store, load 時,會查user 所設定的 data layout ,所以一定要設定。
留言列表