2

I'd like to generate LLVM IR for a C++ code like this:

T *arr = (T*) malloc(sizeof(T) * 100);
arr[0] = somevalue;

Here's my code:

llvm::Type* element_type = /... some T type .../;
llvm::Type* int32type = llvm::Type::getInt32Ty(context);

auto element_size = llvm::ConstantInt::get(int32type, data_layout.getTypeAllocSize(element_type));
auto array_size = llvm::ConstantInt::get(int32type, 100);

// malloc:
auto malloc_inst = llvm::CallInst::CreateMalloc(
    ir_builder.GetInsertBlock(), 
    element_type->getPointerTo(), // T*
    element_type,                 // T
    element_size,                 // sizeof(T)
    array_size,                   // 100
    nullptr, 
    "")
ir_builder.Insert(malloc_inst);

// cast to T*:
auto arr = ir_builder.CreatePointerCast(malloc_inst, element_type->getPointerTo());

// arr[0] = somevalue:
llvm::Value *value = /... some value of type T .../
auto element_ptr = ir_builder.CreateInBoundsGEP(
    arr, { 
        llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 0),
        llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 0)
    });
ir_builder.CreateStore(value, element_ptr)

However, when running generated IR I'm getting:

Assertion failed: (Ty && "Invalid GetElementPtrInst indices for type!"), function checkGEPType, file /usr/local/opt/llvm/include/llvm/IR/Instructions.h, line 847

I tried different combinations of types passed to the GEP instruction, but it's obvious I'm missing something basic. Can someone point me to a working example for this?

1 Answer 1

1

There were two issues:

  • First, to access element array there's no need to pass two indices into GEP instruction.
  • Second, 5th argument of CreateMalloc is casted to a pointer for some reason here. After doing the multiplication of element_size * array_size by myself everything worked.

Also, explicit pointer cast (from i8* to T*) was not needed as it happens automatically.

Here's the final working code:

llvm::Type* element_type = /... some T type .../;
llvm::Type* int32type = llvm::Type::getInt32Ty(context);

auto element_size = llvm::ConstantInt::get(int32type, data_layout.getTypeAllocSize(element_type));
auto array_size = llvm::ConstantInt::get(int32type, 100);
auto alloc_size = llvm::ConstantExpr::getMul(element_size, array_size);

// malloc:
auto arr = llvm::CallInst::CreateMalloc(
    ir_builder.GetInsertBlock(), 
    element_type->getPointerTo(), // T*
    element_type,                 // T
    alloc_size,                   // sizeof(T) * 100
    nullptr,
    nullptr, 
    "")
ir_builder.Insert(arr);

// arr[0] = somevalue:
llvm::Value *value = /... some value of type T .../
auto element_ptr = ir_builder.CreateInBoundsGEP(
    arr, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 0));
ir_builder.CreateStore(value, element_ptr)
Sign up to request clarification or add additional context in comments.

1 Comment

I tried to use the information from this answer for my own array allocation/access code. I thought about posting my own question but will try it here first: I get two issues: - verifyFunction complains about "Call parameter type does not match function signature! i32 48" at the malloc call. - verifyFunction complains about "Stored value type does not match pointer operand type! store double 5.000000e+00, double** %acc_tmp, align 8", which is correct (one "*" to much), but i don't know how to fix it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.