可以转载,请注明出处!
1、IR调用C的库函数
C中使用math.h
中的库函数 double pow(double a, double b)
#include<stdio.h>
#include<math.h>
int main() {
int a = 10;
int b = 2;
return pow(a, b);
}
我们要期待生成IR是下面这样:
- 有
declare double @pow(double, double)
函数的声明。
; ModuleID = 'test'
source_filename = "test"
declare double @pow(double, double)
define i32 @main() {
entry:
%0 = call double @pow(double 1.000000e+01, double 2.000000e+00)
%1 = fptosi double %0 to i32
ret i32 %1
}
使用C的api时,只需要在IR中声明一个同预期库函数名称一样的函数即可,如下面只需要声明一个pow
函数,不需要给改函数定义,调用的时候只管调用就ok。
FunctionType *pow_type = TypeBuilder<double(double, double), false>::get(context);
Function *fun_pow = cast<Function>(module->getOrInsertFunction("pow", pow_type));
完整代码:
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/IR/TypeBuilder.h"
#include <iostream>
#include <algorithm>
using namespace llvm;
using namespace std;
int main(){
static LLVMContext MyGlobalContext;
LLVMContext &context = MyGlobalContext;
Module *module = new Module("test", context);
IRBuilder<> builder(context);
FunctionType *pow_type = TypeBuilder<double(double, double), false>::get(context);
Function *fun_pow = cast<Function>(module->getOrInsertFunction("pow", pow_type));
// 在IR中声明一个函数bar,我们会用IR定义这个函数
FunctionType *bar_type = TypeBuilder<int(), false>::get(context);
Function *bar = cast<Function>(module->getOrInsertFunction("main", bar_type));
// 创建函数bar的代码块
BasicBlock *entry = BasicBlock::Create(context, "entry", bar);
builder.SetInsertPoint(entry);
//构造实参列表
Constant* a_value = ConstantFP::get(Type::getDoubleTy(context), 10.0);
Constant* b_value = ConstantFP::get(Type::getDoubleTy(context), 2.0);
std::vector<Value*> putsargs;
putsargs.push_back(a_value);
putsargs.push_back(b_value);
ArrayRef<Value*> argsRef(putsargs);
// 调用函数pow
Value* ret_pow = builder.CreateCall(fun_pow, argsRef);
Value* ret = builder.CreateFPToSI(ret_pow, Type::getInt32Ty(context));
builder.CreateRet(ret);
//---------------------------------------------------------------------------------------
module->dump();
InitializeNativeTarget();
InitializeNativeTargetAsmPrinter();
InitializeNativeTargetAsmParser();
ExecutionEngine *ee = EngineBuilder(std::unique_ptr<Module>(module)).setEngineKind(EngineKind::JIT).create();
void *barAddr = ee->getPointerToFunction(bar);
//运行机器指令
typedef int (*FuncType)();
FuncType barFunc = (FuncType)barAddr;
ee->finalizeObject();
std::cout << barFunc() << std::endl;
delete module;
return 0;
}
2、IR调用C中定义的函数和全局变量
C中定义的函数和全局变量:
int var_a = 20;
int var_b = 30;
int foo(int x, int y ) {
return max(x, y);
}
目前我们要期待生成IR是下面这样:
- 有
declare i32 @foo(i32, i32)
函数的声明。 - 有
@a= external global i32
、@b = external global i32
全局变量的声明。
; ModuleID = 'test'
source_filename = "test"
@a = external global i32
@b = external global i32
declare i32 @foo(i32, i32)
define i32 @bar() {
entry:
%0 = load i32, i32* @a
%1 = load i32, i32* @b
%2 = call i32 @foo(i32 %0, i32 %1)
ret i32 %2
}
在IR中不给这两个声明做定义,因为在C中已经定义了,只需要在使用JIT执行时,将C中定义的int foo(int x, int y )
函数和int var_a
全局值的地址分别映射到i32 @foo(i32, i32)
和@a
上面即可:
ExecutionEngine *ee = EngineBuilder(std::unique_ptr<Module>(module)).setEngineKind(EngineKind::JIT).create();
// 将外部的C++代码中的全局变量映射到IR代码中,IR代码中只有声明
ee->addGlobalMapping(v1, &var_a);
ee->addGlobalMapping(v2, &var_b);
// 将外部的C++代码中的全局函数映射到IR代码中,IR代码中只有声明
ee->addGlobalMapping(foo_fun, (void *)foo);
完整代码:
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/IR/TypeBuilder.h"
#include <iostream>
#include <algorithm>
using namespace llvm;
using namespace std;
int var_a = 20;
int var_b = 30;
int foo(int x, int y ) {
return max(x, y);
}
int main(){
static LLVMContext MyGlobalContext;
LLVMContext &context = MyGlobalContext;
Module *module = new Module("test", context);
// 在IR代码中声明一个全局变量
GlobalVariable *v1 = cast<GlobalVariable>(module->getOrInsertGlobal("a", Type::getInt32Ty(context)));
GlobalVariable *v2 = cast<GlobalVariable>(module->getOrInsertGlobal("b", Type::getInt32Ty(context)));
// 在IR中声明一个函数,注意我们并不会在IR中定义foo,我们会将这个IR中声明的函数映射到C++代码中的函数
FunctionType *foo_type = TypeBuilder<int(int, int), false>::get(context);
Function *foo_fun = cast<Function>(module->getOrInsertFunction("foo", foo_type));
// 在IR中声明一个函数bar,我们会用IR定义这个函数
FunctionType *bar_type = TypeBuilder<int(), false>::get(context);
Function *bar = cast<Function>(module->getOrInsertFunction("bar", bar_type));
// 创建函数bar的代码块
BasicBlock *entry = BasicBlock::Create(context, "entry", bar);
IRBuilder<> builder(entry);
// 用一个局部变量获取全局变量v的值
Value *v_IR1 = builder.CreateLoad(v1);
Value *v_IR2 = builder.CreateLoad(v2);
//构建参数
std::vector<Value*> args;
args.push_back(v_IR1);
args.push_back(v_IR2);
ArrayRef<Value*> argRef(args);
// 调用函数foo
Value *ret = builder.CreateCall(foo_fun, argRef);
// 返回值
builder.CreateRet(ret);
module->dump();
InitializeNativeTarget();
InitializeNativeTargetAsmPrinter();
InitializeNativeTargetAsmParser();
ExecutionEngine *ee = EngineBuilder(std::unique_ptr<Module>(module)).setEngineKind(EngineKind::JIT).create();
ee->addGlobalMapping(v1, &var_a);
ee->addGlobalMapping(v2, &var_b);
ee->addGlobalMapping(foo_fun, (void *)foo);
void *barAddr = ee->getPointerToFunction(bar);
//运行机器指令
typedef int (*FuncType)();
FuncType barFunc = (FuncType)barAddr;
ee->finalizeObject();
std::cout << barFunc() << std::endl;
delete module;
return 0;
}
//下面是执行的结果:
30