IR API(三)——将C/C++中定义的结构体作为LLVM IR中函数的实参

可以转载,请注明出处!

预期IR代码,定义一个结构体%Number,用两个结构体类型作为函数@func的形参,在执行时传入C++中与之定义相同的结构体实参:

%Number = type { i32, i32, double }

define double @func(%Number* %num1, %Number* %num2) {
	...
}

C++中定义的结构体和用于实参的结构体变量:

//定义结构体
struct Number{
	int precision;
	int scale;
	double value;
};

//结构体变量
Number number1,number2;
number1.precision = 13;
number1.scale = 2;
number1.value = 15.3;
number2.precision = 18;
number2.scale = 5;
number2.value = 17.3333;

将结构体参数参入到add_fun方法中,也就是上面定义的func方法,看完整代码就知道,add_fun只是一个函数指针,指向func函数

add_fun(&number1, &number2);

完整代码:

#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>

struct Number{
	int precision;
	int scale;
	double value;
};

int main(){
	static llvm::LLVMContext llvmContext;
	llvm::LLVMContext& context = llvmContext;
	llvm::Module* module = new llvm::Module("test", context);
	
	//定义一个结构体,定义结构体的步骤是:
	//创建一个StructType,再创建elements并set到其中
	llvm::StructType* structType = llvm::StructType::create(context, "Number");
	std::vector<llvm::Type*> elements;
	elements.push_back(llvm::Type::getInt32Ty(context));
	elements.push_back(llvm::Type::getInt32Ty(context));
	elements.push_back(llvm::Type::getDoubleTy(context));
	structType->setBody(elements);
	
	//定义一个函数 double(*func)(struct Number, struct Number),以结构体做函数的参数的时候,
	//需要一个指针指向结构体,然后以指针作为参数
	llvm::PointerType *pstructType1 = llvm::PointerType::get(structType, 0);
	llvm::PointerType *pstructType2 = llvm::PointerType::get(structType, 0);
	llvm::SmallVector<llvm::Type*, 2> functionArgs;
	functionArgs.push_back(pstructType1);
	functionArgs.push_back(pstructType2);
	llvm::Type* returnType = llvm::Type::getDoubleTy(context);
	llvm::FunctionType* functionType = llvm::FunctionType::get(returnType, functionArgs, false);
	llvm::Function* func = llvm::cast<llvm::Function>(module->getOrInsertFunction("func", functionType));
	
	//创建函数的入口基本块
	llvm::BasicBlock* entry = llvm::BasicBlock::Create(context);
	entry->insertInto(func);
	llvm::IRBuilder<> builder(context);
	builder.SetInsertPoint(entry);
	
	//arg_begin()方法返回的是一个迭代器,迭代器相当于一个指针,可以对其进行加减操作,
	//arg_iterator迭代器是 Argument *类型,而 Argument是Value的子类,所以这里用Value*接受
	llvm::Function::arg_iterator argsIT = func->arg_begin();
	llvm::Value* arg1 = argsIT++;
	llvm::Value* arg2 = argsIT;
	
	//通过GEP指令获取结构体参数中元素的指针,这里索引是0、2,所以获取的是第三个元素的指针,
	//然后将两个指针对应的值相加
	llvm::Value* const_0 = llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(context), 0);
	llvm::Value* const_2 = llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(context), 2);
	llvm::SmallVector<llvm::Value*, 2> indexVector;
	indexVector.push_back(const_0);
	indexVector.push_back(const_2);
	llvm::Value* number_ptr_1 = builder.CreateGEP(arg1, indexVector);
	llvm::Value* number_ptr_2 = builder.CreateGEP(arg2, indexVector);
	llvm::Value* loaded_number1 = builder.CreateLoad(number_ptr_1);
	llvm::Value* loaded_number2 = builder.CreateLoad(number_ptr_2);
	llvm::Value* add_value = builder.CreateFAdd(loaded_number1, loaded_number2);
	builder.CreateRet(add_value);
	
	module->dump();
	
	llvm::InitializeNativeTarget();
    llvm::InitializeNativeTargetAsmPrinter();
    llvm::InitializeNativeTargetAsmParser();
	
	llvm::ExecutionEngine *ee = llvm::EngineBuilder(std::unique_ptr<llvm::Module>(module)).setEngineKind(llvm::EngineKind::JIT).create();
	
	//C++复杂类型的声明,FuncType是一个函数指针指针类型为double(*)(Number*, Number*)
	typedef double(*FuncType)(Number*, Number*);
	FuncType add_fun = (FuncType)ee->getPointerToFunction(func);//(FuncType)ee->getFunctionAddress("func");使用这种方式也可以
	ee->finalizeObject();
	
	Number number1,number2;
	number1.precision = 13;
	number1.scale = 2;
	number1.value = 15.3;
	number2.precision = 18;
	number2.scale = 5;
	number2.value = 17.3333;
	
	//将结构体参数参入到add_fun方法中,也就是上面定义的func方法
	std::cout<<"Result: "<<add_fun(&number1, &number2)<<std::endl;
	
	delete module;
	return 0;
}

用API生成的IR代码:

; ModuleID = 'test'
source_filename = "test"

%Number = type { i32, i32, double }

define double @func(%Number*, %Number*) {
  %3 = getelementptr %Number, %Number* %0, i32 0, i32 2
  %4 = getelementptr %Number, %Number* %1, i32 0, i32 2
  %5 = load double, double* %3
  %6 = load double, double* %4
  %7 = fadd double %5, %6
  ret double %7
}

//下面是执行结果
Result: 32.6333

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

yelvens

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

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

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

打赏作者

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

抵扣说明:

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

余额充值