c++llvmllvm-ir

How to get the value of a member of a structure in LLVM?


So I've created a structure type with this:

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)

and I'm wondering how to access the members within the struct.

I've tried using getelementptr with no luck so far:

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");

Thanks for any feedback!

EDIT:

Okay so the type of llvm::Value* data is a %a_struct which was loaded from a pointer on the stack. It seems from the documentation that irbuilder.CreateInBoundsGEP(llvm::Value*, llvm::ArrayRef<llvm::Value*>, llvm::Twine) requires the first argument to be a pointer to the structure and not the value of the structure itself.

When copying the value of the structure into a variable on the stack, this error is thrown: Expression: getOperand(0)->getType() == cast<PointerType>(getOperand(1)->getType())->getElementType(‌​‌​) && "Ptr must be a pointer to Val type!". The pointer pasted to irbuidler.CreateInBoundsGEP(...) when this error was thrown was an llvm::AllocaInst* which was newly allocated on the stack and contained the value of llvm::Value* data (type of %a_struct) copied into it.

The IR generated right before the call to irbuilder.CreateInBoundsGEP(...) with the value copied to a variable on the stack:

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
}

Besides there should be a better way to access the members of %a_var without duplicating it (while still supporting expressions like a_struct_var1.member + a_struct_var2.member in the language).


Solution

  • I have found the solution. I think I was passing the indices incorrectly or something.

    NOTE: I have not tested this with members that have different data types yet but it seems to work

    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");