IR API(二)——使用LLVM IR调用C的函数和全局变量

可以转载,请注明出处!

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
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yelvens

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值