IR API(四)——操作IR的字符串、全局变量、全局常量及数组

可以转载,请注明出处!

一、操作字符串

llvm ir中的字符串是以全局常量GlobalVariable的形式存放的。

	//创建字符串常量
	llvm::Constant *strConst1 = llvm::ConstantDataArray::getString(context,
			"exception_name");
	llvm::Value *globalVar1 = new llvm::GlobalVariable(*module,
			strConst1->getType(), true, llvm::GlobalValue::PrivateLinkage,
			strConst1, "globalVar1");
	
	//ir长这样
	@globalVar1 = private constant [15 x i8] c"exception_name\00"

完整代码:

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

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,
			"_Exception");
	std::vector<llvm::Type*> elements;
	elements.push_back(llvm::Type::getInt8PtrTy(context));
	elements.push_back(llvm::Type::getInt32Ty(context));
	elements.push_back(llvm::Type::getInt8PtrTy(context));
	structType->setBody(elements);

	//定义一个函数 double(*func)(struct Number, struct Number),以结构体做函数的参数的时候,
	//需要一个指针指向结构体,然后以指针作为参数
	llvm::SmallVector<llvm::Type*, 0> functionArgs;
	llvm::Type *returnType = llvm::Type::getInt32Ty(context);
	llvm::FunctionType *functionType = llvm::FunctionType::get(returnType,
			functionArgs, false);
	llvm::Function *func = llvm::cast<llvm::Function>(
			module->getOrInsertFunction("func", functionType));

	//创建字符串常量
	llvm::Constant *strConst1 = llvm::ConstantDataArray::getString(context,
			"exception_name");
	llvm::Value *globalVar1 = new llvm::GlobalVariable(*module,
			strConst1->getType(), true, llvm::GlobalValue::PrivateLinkage,
			strConst1, "globalVar1");
	llvm::Constant *strConst2 = llvm::ConstantDataArray::getString(context,
			"uuid");
	llvm::Value *globalVar2 = new llvm::GlobalVariable(*module,
			strConst2->getType(), true, llvm::GlobalValue::PrivateLinkage,
			strConst2, "globalVar2");

	//创建函数的入口基本块
	llvm::BasicBlock *entry = llvm::BasicBlock::Create(context);
	entry->insertInto(func);
	llvm::IRBuilder<> builder(context);
	builder.SetInsertPoint(entry);

	llvm::AllocaInst *alloca_Struct = builder.CreateAlloca(structType);
	llvm::SmallVector<llvm::Value*, 2> indexVector;

	llvm::Value *const_0 = llvm::ConstantInt::get(
			llvm::IntegerType::getInt32Ty(context), 0);
	llvm::Value *const_1 = llvm::ConstantInt::get(
			llvm::IntegerType::getInt32Ty(context), 1);
	llvm::Value *const_2 = llvm::ConstantInt::get(
			llvm::IntegerType::getInt32Ty(context), 2);

	indexVector.push_back(const_0);
	indexVector.push_back(const_0);
	llvm::Value *number_ptr_1 = builder.CreateGEP(alloca_Struct, indexVector);

	indexVector.clear();
	indexVector.push_back(const_0);
	indexVector.push_back(const_1);
	llvm::Value *number_ptr_2 = builder.CreateGEP(alloca_Struct, indexVector);

	indexVector.clear();
	indexVector.push_back(const_0);
	indexVector.push_back(const_2);
	llvm::Value *number_ptr_3 = builder.CreateGEP(alloca_Struct, indexVector);

	builder.CreateStore(
			builder.CreatePointerCast(globalVar1, builder.getInt8PtrTy()),
			number_ptr_1);
	builder.CreateStore(const_2, number_ptr_2);
	builder.CreateStore(
			builder.CreatePointerCast(globalVar2, builder.getInt8PtrTy()),
			number_ptr_3);

	builder.CreateRet(
			builder.CreateLoad(llvm::Type::getInt32Ty(context), number_ptr_2));

	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 int (*FuncType)();
	FuncType add_fun = (FuncType) ee->getPointerToFunction(func);//(FuncType)ee->getFunctionAddress("func");使用这种方式也可以
	ee->finalizeObject();

	//将结构体参数参入到add_fun方法中,也就是上面定义的func方法
	std::cout << "Result: " << add_fun() << std::endl;

	delete module;
	return 0;
}

API生成的IR:

; ModuleID = 'test'
source_filename = "test"

%_Exception = type { i8*, i32, i8* }

@globalVar1 = private constant [15 x i8] c"exception_name\00"
@globalVar2 = private constant [5 x i8] c"uuid\00"

define i32 @func() {
  %1 = alloca %_Exception
  %2 = getelementptr %_Exception, %_Exception* %1, i32 0, i32 0
  %3 = getelementptr %_Exception, %_Exception* %1, i32 0, i32 1
  %4 = getelementptr %_Exception, %_Exception* %1, i32 0, i32 2
  store i8* getelementptr inbounds ([15 x i8], [15 x i8]* @globalVar1, i32 0, i32 0), i8** %2
  store i32 2, i32* %3
  store i8* getelementptr inbounds ([5 x i8], [5 x i8]* @globalVar2, i32 0, i32 0), i8** %4
  %5 = load i32, i32* %3
  ret i32 %5
}
Result: 2

二、全局变量、全局常量及数组

需要注意的是:sum 是一个全局变量;globa_array是一个全局数组常量,也就是它的值一旦初始化就不会在改变;array是一个局部数组变量。

对应的C代码:


int sum = 0;
int globa_array[4] = {1,2,3,4};

int main(){
	int array[4] = {5,6,7,8};
	for(int i = 0; i < 4; i++)
		sum = sum + array[i] + globa_array[i];
	
	return sum;
}

完整代码:

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

int main(){
	static llvm::LLVMContext llvmContext;
	llvm::LLVMContext& context = llvmContext;
	llvm::Module* module = new llvm::Module( "array_test", context);
	llvm::IRBuilder<> builder(context);
	
	//定义常量
	llvm::Constant* con_0 = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 0);
	llvm::Constant* con_1 = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 1);
	llvm::Constant* con_2 = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 2);
	llvm::Constant* con_3 = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 3);
	llvm::Constant* con_4 = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 4);
	llvm::Constant* con_5 = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 5);
	llvm::Constant* con_6 = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 6);
	llvm::Constant* con_7 = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 7);
	llvm::Constant* con_8 = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 8);
	
	//定义一个int类型的全局变量
	llvm::GlobalVariable* sum_global = new llvm::GlobalVariable(/*Module=*/*module,
		/*Type=*/llvm::Type::getInt32Ty(context),
		/*isConstant=*/false,
		/*Linkage=*/llvm::GlobalValue::PrivateLinkage,
		/*Initializer=*/0, // has initializer, specified below
		/*Name=*/"sum");
	sum_global->setInitializer(con_0);//对全局变量初始化,按照ir的语法是必须要初始化的
	
	//定义一个int类型的全局数组常量
	llvm::ArrayType* array_type = llvm::ArrayType::get(llvm::Type::getInt32Ty(context), 4);
	llvm::GlobalVariable* array_global = new llvm::GlobalVariable(/*Module=*/*module,
		/*Type=*/array_type,
		/*isConstant=*/true,
		/*Linkage=*/llvm::GlobalValue::PrivateLinkage,
		/*Initializer=*/0, // has initializer, specified below
		/*Name=*/"array_global");
	array_global->setAlignment(16);
	std::vector<llvm::Constant*> const_array_elems;
	const_array_elems.push_back(con_1);
	const_array_elems.push_back(con_2);
	const_array_elems.push_back(con_3);
	const_array_elems.push_back(con_4);
	llvm::Constant* const_array = llvm::ConstantArray::get(array_type, const_array_elems);//数组常量
	array_global->setInitializer(const_array);//将数组常量初始化给全局常量
	
	//定义函数
	llvm::FunctionType* main_type = llvm::TypeBuilder<int(), false>::get(context);
	llvm::Function* main_func = llvm::cast<llvm::Function>(module->getOrInsertFunction("main", main_type));
	
	//entry基本块
	llvm::BasicBlock* entry_main = llvm::BasicBlock::Create(context, "entry", main_func);
	builder.SetInsertPoint(entry_main);
	//int array[4] = {5,6,7,8};
	llvm::Type* arrayType = llvm::ArrayType::get(llvm::Type::getInt32Ty(context), 4);
	llvm::Value* array = builder.CreateAlloca(arrayType);
	builder.CreateStore(con_5, builder.CreateConstGEP2_32(arrayType, array, 0, 0));
	builder.CreateStore(con_6, builder.CreateConstGEP2_32(arrayType, array, 0, 1));
	builder.CreateStore(con_7, builder.CreateConstGEP2_32(arrayType, array, 0, 2));
	builder.CreateStore(con_8, builder.CreateConstGEP2_32(arrayType, array, 0, 3));
	llvm::Value* i_allo = builder.CreateAlloca(llvm::Type::getInt32Ty(context));
	builder.CreateStore(con_0, i_allo);
	llvm::BasicBlock* for_cont = llvm::BasicBlock::Create(context, "for.cond", main_func);
	llvm::BasicBlock* for_body = llvm::BasicBlock::Create(context, "for.body", main_func);
	llvm::BasicBlock* for_end = llvm::BasicBlock::Create(context, "for.end", main_func);
	builder.CreateBr(for_cont);
	
	//for_cont基本块
	builder.SetInsertPoint(for_cont);
	llvm::Value* i_load = builder.CreateLoad(i_allo);
	llvm::Value* icmp = builder.CreateICmpSLT(i_load, con_4);
	builder.CreateCondBr(icmp, for_body, for_end);
	
	//for_body基本块
	builder.SetInsertPoint(for_body);
	llvm::Value *Idxs[] = {con_0, i_load};
	llvm::Value* array_i = builder.CreateGEP(array, Idxs);//使用gep指令获取元素地址的指令的方式有好几个,最好都掌握
	llvm::Value* array_i_load = builder.CreateLoad(array_i);
	llvm::Value* array_global_i_gep = builder.CreateGEP(array_global, Idxs);
	llvm::Value* array_global_i_load = builder.CreateLoad(array_global_i_gep);
	llvm::Value* sum = builder.CreateLoad(sum_global);
	llvm::Value* add_sum = builder.CreateAdd(builder.CreateAdd(array_i_load, sum), array_global_i_load);
	builder.CreateStore(add_sum, sum_global);
	llvm::Value* i_add = builder.CreateAdd(i_load, con_1);
	builder.CreateStore(i_add, i_allo);
	builder.CreateBr(for_cont);
	
	//for_end基本块,注意这里的返回值不能直接使用for_body中的sum,而是要用load指令再取一次
	builder.SetInsertPoint(for_end);
	llvm::Value* ret_sum = builder.CreateLoad(llvm::Type::getInt32Ty(context), sum_global);
	builder.CreateRet(ret_sum);
	
	module->dump();
	
	llvm::InitializeNativeTarget();
    llvm::InitializeNativeTargetAsmPrinter();
    llvm::InitializeNativeTargetAsmParser();
	
	llvm::ExecutionEngine *ee = llvm::EngineBuilder(std::unique_ptr<llvm::Module>(module)).setEngineKind(llvm::EngineKind::JIT).create();
	 void *mainAddr = ee->getPointerToFunction(main_func);
	typedef int(*FuncType)();
	FuncType mianFunc = (FuncType)mainAddr;
	ee->finalizeObject();
	std::cout<<"Result: "<<mianFunc()<<std::endl;
	
	delete module;
	return 0;
}

用API生成的IR代码:

; ModuleID = 'array_test'
source_filename = "array_test"

@sum = private global i32 0
@array_global = private constant [4 x i32] [i32 1, i32 2, i32 3, i32 4], align 16

define i32 @main() {
entry:
  %0 = alloca [4 x i32]
  %1 = getelementptr [4 x i32], [4 x i32]* %0, i32 0, i32 0
  store i32 5, i32* %1
  %2 = getelementptr [4 x i32], [4 x i32]* %0, i32 0, i32 1
  store i32 6, i32* %2
  %3 = getelementptr [4 x i32], [4 x i32]* %0, i32 0, i32 2
  store i32 7, i32* %3
  %4 = getelementptr [4 x i32], [4 x i32]* %0, i32 0, i32 3
  store i32 8, i32* %4
  %5 = alloca i32
  store i32 0, i32* %5
  br label %for.cond

for.cond:                                         ; preds = %for.body, %entry
  %6 = load i32, i32* %5
  %7 = icmp slt i32 %6, 4
  br i1 %7, label %for.body, label %for.end

for.body:                                         ; preds = %for.cond
  %8 = getelementptr [4 x i32], [4 x i32]* %0, i32 0, i32 %6
  %9 = load i32, i32* %8
  %10 = getelementptr [4 x i32], [4 x i32]* @array_global, i32 0, i32 %6
  %11 = load i32, i32* %10
  %12 = load i32, i32* @sum
  %13 = add i32 %9, %12
  %14 = add i32 %13, %11
  store i32 %14, i32* @sum
  %15 = add i32 %6, 1
  store i32 %15, i32* %5
  br label %for.cond

for.end:                                          ; preds = %for.cond
  %16 = load i32, i32* @sum
  ret i32 %16
}

//下面是执行结果
Result: 36
  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

yelvens

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

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

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

打赏作者

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

抵扣说明:

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

余额充值