如何在LLVM中获取结构成员的值?
How to get the value of a member of a structure in LLVM?
所以我用这个创建了一个结构类型:
llvm::StructType* llvm_struct = llvm::StructType::create(llvm_context, struct_name);
std::vector<llvm::Type*> members;
for(size_t j = 0; j != struct_data.members.size(); j++){
llvm::Type* member_type = /*get member type*/;
members.push_back(member_type);
}
llvm_struct->setBody(members)
我想知道如何访问结构中的成员。
到目前为止,我已经尝试使用getelementptr,但没有运气:
llvm::Value* member_index = llvm::ConstantInt::get(llvm_context, llvm::APInt(32, /*structure member index*/, true));
llvm::Value* indices[2] = {llvm::ConstantInt::get(member_index->getType(), 0), member_index};
llvm::Value* data = /*expression value*/;
return irbuilder.CreateInBoundsGEP(data, llvm::ArrayRef<llvm::Value*>(indices, 2), "membtmp");
感谢您的任何反馈!
编辑:
好的,所以llvm::Value* data
的类型是从堆栈上的指针加载的%a_struct
。从文档中可以看出,irbuilder.CreateInBoundsGEP(llvm::Value*, llvm::ArrayRef<llvm::Value*>, llvm::Twine)
要求第一个参数是指向结构的指针,而不是结构本身的值。
将结构的值复制到堆栈上的变量中时,会抛出此错误:Expression: getOperand(0)->getType() == cast<PointerType>(getOperand(1)->getType())->getElementType() && "Ptr must be a pointer to Val type!"
.抛出此错误时粘贴到irbuidler.CreateInBoundsGEP(...)
的指针是一个在堆栈上新分配的llvm::AllocaInst*
,其中包含复制到其中的llvm::Value* data
(%a_struct
类型)的值。
在调用irbuilder.CreateInBoundsGEP(...)
之前生成的 IR,并将值复制到堆栈上的变量:
define i32 @main() {
entry:
%calltmp = call %a_struct @new_a_struct()
%a_var = alloca %a_struct
store %a_struct %calltmp, %a_struct* %a_var
%a_var1 = load %a_struct, %a_struct* %a_var
%memballoctmp = alloca %a_struct
store %a_struct %a_var1, %a_struct* %memballoctmp
}
此外,应该有一种更好的方法来访问%a_var
的成员而不复制它(同时仍然支持语言中的a_struct_var1.member + a_struct_var2.member
等表达式)。
掌握这个概念需要一些时间,但值得花时间在上面。查看 llvm 语言参考中的 getelementpointer 文档。它解释了成员访问的工作原理。
struct RT {
char A;
int B[10][20];
char C;
};
struct ST {
int X;
double Y;
struct RT Z;
};
int *foo(struct ST *s) {
return &s[1].Z.B[5][13];
}
读取结构体的成员 B[5][13] 可以直接完成:
%arrayidx = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1, i32 2, i32 1, i64 5, i64 13
或间接:
%t1 = getelementptr %struct.ST, %struct.ST* %s, i32 1
%t2 = getelementptr %struct.ST, %struct.ST* %t1, i32 0, i32 2
%t3 = getelementptr %struct.RT, %struct.RT* %t2, i32 0, i32 1
%t4 = getelementptr [10 x [20 x i32]], [10 x [20 x i32]]* %t3, i32 0, i32 5
%t5 = getelementptr [20 x i32], [20 x i32]* %t4, i32 0, i32 13
我将展示直接的方式。让我们首先创建结构
StructType* createStruct(Module &M)
{
Type* intTy = Type::getInt32Ty(M.getContext());
Type* charTy = Type::getInt8Ty(M.getContext());
Type* doubleTy = Type::getDoubleTy(M.getContext());
auto* _B = ArrayType::get(intTy, 20);
auto* B = ArrayType::get(_B, 10);
auto* RT = StructType::create("struct.RT", charTy, B, charTy);
auto* ST = StructType::create("struct.ST", intTy, doubleTy, RT);
RT->dump();
ST->dump();
return ST;
}
现在我们可以使用 gep 来访问结构,但首先我们需要一个 Values* 向量来存储索引以访问特定的 gep 地址
template <size_t N>
std::vector<Value*> getIndex(Module &M, int (&dims)[N])
{
std::vector<Value*> idx;
for (auto i : dims)
{
idx.push_back(ConstantInt::get(M.getContext(), APInt(32, i, true)));
}
for (auto i : idx)
{
i->dump();
}
return idx;
}
void doGEP(Module &M)
{
auto* structInst = createStruct(M);
auto* structGlobVar = new GlobalVariable(M, structInst, true, GlobalVariable::ExternalLinkage, UndefValue::get(structInst), "_structGV", nullptr, GlobalVariable::ThreadLocalMode::NotThreadLocal, 0, true);
structGlobVar->dump();
int dims[] = {1, 2, 1, 5, 13};
std::vector<Value*> indx = getIndex(M, dims);
auto* gepInst = builder.CreateGEP(structGlobVar, indx);
gepInst->dump();
}
将生成输出:
%struct.RT = type { i8, [10 x [20 x i32]], i8 }
%struct.ST = type { i32, double, %struct.RT }
i32 1
i32 2
i32 1
i32 5
i32 13
@_structGV = externally_initialized constant %struct.ST undef
i32* getelementptr (%struct.ST, %struct.ST* @_structGV, i32 1, i32 2, i32 1, i32 5, i32 13)
我已经找到了解决方案。我想我错误地传递了索引或其他什么。
注意:我还没有用具有不同数据类型的成员对此进行测试,但它似乎可以工作
llvm::Value* member_index = llvm::ConstantInt::get(llvm_context, llvm::APInt(32, index /*The index of the member*/, true));
llvm::Value* data = /*A structure value*/;
llvm::AllocaInst* alloc = irbuilder.CreateAlloca(struct_type, 0, "alloctmp");
irbuilder.CreateStore(data, alloc);
std::vector<llvm::Value*> indices(2);
indices[0] = llvm::ConstantInt::get(llvm_context, llvm::APInt(32, 0, true));
indices[1] = member_index;
llvm::Value* member_ptr = irbuilder.CreateGEP(struct_type, alloc, indices, "memberptr");
llvm::Value* loaded_member = irbuilder.CreateLoad(member_ptr, "loadtmp");
- 如何在C++中定义静态成员结构
- 使用模板化类的成员结构
- 初始化固定的 C 数组成员结构
- 指向成员结构的指针如何工作
- 如何将此“指针从外部类传递到成员结构
- 导致IAR ARM中出现错误的成员结构位字段元素的Initializer列表初始化
- 映射文件中成员结构的地址
- Visual C++ 模板类成员结构初始化语法糖
- C :初始化成员结构的静态字段的正确方法
- 如何在C 类的初始化器列表中使用未命名结构初始化成员结构
- 从成员结构的成员函数中访问类的成员?
- 模板化类的成员函数无法返回指向成员结构的指针?
- 重载非类型模板结构的成员结构的复制赋值运算符
- 灵气属性传播问题与单成员结构.
- 将具有 int* 成员C++结构编接到 C#
- 复杂的班级成员结构
- 将向量成员(结构)传递给函数
- 成员结构的前向声明
- 重载运算符<<用于模板结构中定义的成员结构
- 返回带有模板化类的类成员结构