可以转载,请注明出处!
预期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