'Allocation and access of heap arrays with LLVM

Starting with the caleidoscope tutorial and a stack exchange question (question) I tried to output some array-creation and access code with LLVM. The idea is to have an "alloca" stack variable "a" which holds a double* pointing to an array allocated with malloc. The generated code fails, and I believe that the main problem is my Call to "CreateInBoundsGEP" in C++.

So my main question in one sentence is "How to Call CreateInBoundsGEP so that it outputs the right IR code?"

What i tried is the following:

My allocation code is created as output of the llvm c++ interface's "CreateMalloc" call from the question referenced above.

%a = alloca double*, align 8
%malloccall = tail call i8* @malloc(i32 48)
%0 = bitcast i8* %malloccall to double*
store double* %0, double** %a, align 8

This code looks good to me, but it already leads to an error/warning when checked with verifyFunction().

Call parameter type does not match function signature!
i32 48

Sadly it does not tell me, what the right parameter type would be (i64?). The IR reference does not refer to the "malloc"-function call at all but mentions a "malloc" IR-operation instead (reference)!

My main problem (also leading to memory errors if not caught before) occurs with write access to the array.

My first try was copying (more or less) directly from the referenced stack exchange question 1:

//ret is the base adress of the pointer, ie "a"
//rhs is the Value* to the right hand side that is assigned
//index is the Value* to the array index 
auto element_ptr = Builder->CreateInBoundsGEP(ret, index, "acc_tmp");
Builder->CreateStore(rhs, element_ptr);

Which outputs (for a[1]=5 as input code)

%acc_tmp = getelementptr inbounds double*, double** %a, i32 1
store double 5.000000e+00, double** %acc_tmp, align 8

This creates a "verifyFunction" error and I can see that "double**" should probably be "double*". Since I also got a deprecation warning, I decided to try the CreateInBoundsGEP with a type parameter. Since the documentation does not tell me whether "Type" should be the element or pointer type, I tried both

auto element_ptr = Builder->CreateInBoundsGEP(rhs->getType()->getPointerTo(), ret, index, "acc_tmp");

Or

auto element_ptr = Builder->CreateInBoundsGEP(rhs->getType(), ret, index, "acc_tmp");

Both do not work, the first version outputs the same code as without passing a type, the second version leads to

static llvm::GetElementPtrInst *llvm::GetElementPtrInst::Create(llvm::Type *, llvm::Value *, ArrayRef<llvm::Value *>, const llvm::Twine &, llvm::Instruction *): Assertion `cast<PointerType>(Ptr->getType()->getScalarType()) ->isOpaqueOrPointeeTypeMatches(PointeeType)' failed.


Solution 1:[1]

As I noticed in my original question, there is one pointer* too much in my instruction. Initially I did not understand why this is the case, but then I found the answer to my problem in a seemingly unrelated question 1:

If you directly use the return value of "CreateMalloc" as argument for a "CreateInBoundsGEP", the Code that I originally copied from 2 will work.

However in my case there is one more step involved: I store the "CreateMalloc" return value in a local variable, which in turn is referenced by a pointer allocated with "alloca". Because of this, I need one additional dereferencing step compared to the original Code Snippet to access my array elements.

As mentioned in 1 a dereference in LLVM-IR is just a "load". So a correct array access code looks like

//ret is the pointer to(!) the base adress of the array, ie "a"
//rhs is the Value* to the right hand side that is assigned
//index is the Value* holding the array index 
llvm::Value* index = visit(ctx->index).as<llvm::Value*>();
llvm::Value* ret_deref =   Builder->CreateLoad(llvm::Type::getDoubleTy(*TheContext)->getPointerTo(),ret,"deref_tmp");
auto element_ptr = Builder->CreateInBoundsGEP(rhs->getType(), ret_deref, index, "acc_tmp");
Builder->CreateStore(rhs, element_ptr);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Wave and Matter