c++ - 如何在 LLVM 中获取结构成员的值?

标签 c++ llvm llvm-ir

所以我用这个创建了一个结构类型:

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 的类型)。

IR 在调用 irbuilder.CreateInBoundsGEP(...) 之前生成,并将值复制到堆栈上的变量:

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 等表达式)。

最佳答案

掌握这个概念需要一些时间,但值得花时间在上面。查看 getelementpointer 的文档来自 llvm 语言引用。它解释了成员访问的工作原理。

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* vector 来存储索引以访问特定的 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)

关于c++ - 如何在 LLVM 中获取结构成员的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40771022/

相关文章:

javascript - 当我在 C++ 附加组件中创建 ArrayBuffer 时,node-webkit 崩溃

c++ - 如何使 llvm jit 在 MSVC++ 中工作

loops - Clang: 怎么看loop flattening pass的效果?

assembly - LLVM 解释器在哪里寻找外部函数(库?)

只有一个可能的前任的 LLVM IR phi 节点

c++ - boost 异步读/写失败, "Insufficient system resources exist to complete the requested service"

c++ - GNU make - $(MAKEFILES) 中的 makefile 中的规则未被读取/确认

c++ - 我有一个存储在内存中的表。如何根据列对其进行排序?

clang - 你如何为自己组装一个交叉编译器?