Since some days already I’m attempting to write C++ code for creating IR of a function returning a struct containing an array of real values.
I looked at the kaleidoscope examples until including chapter 3.
I’m far away from trying to run the JIT-compiler or optimize.
The point is that I’m either
- getting an assertion below llvm::IRBuilderBase::CreateGEP() inside llvm::checkGEPType() because of the type-ptr being null (in debug mode only)
- The IR code created in Release mode cannot be compiled using clang telling me
tmp.ll:14:27: error: invalid getelementptr indices
%8 = getelementptr ptr, ptr %7, i32 0, i32 0
From what I’m seeing there is more or less no documentation. Or am I missing The-Well-Known-Book everybody needs to read before even attempting this?
I’ve chatted with chatgpt are let him create code for me many times. Usually the code created by chatgpt is missing arguments to IRBuilder::CreateGEP() and I’ve asked it many questions about this function. Today chatgpt started using another function for the same problem (IRBuilder::CreateStructGEP()).
Below is shown what chatGPT created (I inserted the first rgument to CreateGEP(). I tried also passing a pointer using structType->getPointerTo()
instead of just structType
.
Sometimes I’m only getting an assertion firing, if the index for the array passed to IRBuilder::CreateGEP() is non-zero.
I’ve tried multiple versions on both, LINUX (various systems) and windows:
- llvm-8 on centos 7.9
- LLVM-15 on unbuntu 20 running on WSL
- LLVM-16 on Windows.
#include <iostream>
#include "llvm/ADT/ArrayRef.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
using namespace llvm;
int main(int, char**)
{
LLVMContext context;
Module* module = new Module("my_module", context);
// Create a struct type that contains an array of 2 double values
std::vector<Type*> structElements;
structElements.push_back(ArrayType::get(Type::getDoubleTy(context), 2));
StructType* structType = StructType::create(context, structElements, "myStruct");
// Create a function type that returns the struct
FunctionType* funcType = FunctionType::get(structType, {}, false);
// Create the function
Function* func = Function::Create(funcType, Function::ExternalLinkage, "myFunction", module);
// Create a basic block and an IRBuilder
BasicBlock* entryBlock = BasicBlock::Create(context, "entry", func);
IRBuilder<> builder(entryBlock);
// Create an instance of the struct on the stack
AllocaInst* structInstance = builder.CreateAlloca(structType);
// Get a pointer to the array in the struct
Value* zero = ConstantInt::get(Type::getInt32Ty(context), 0);
Value* arrayPtr = builder.CreateStructGEP(structType, structInstance, 0);
// Store values into the array
for (unsigned i = 0; i < 2; ++i)
{ // Compute the value to store (i^2)
Value* index = ConstantInt::get(Type::getInt32Ty(context), i);
Value* value = builder.CreateMul(index, index);
// Convert the value to double
Value* doubleValue = builder.CreateSIToFP(value, Type::getDoubleTy(context));
// Get a pointer to the i-th element of the array
Value* elementPtr = builder.CreateGEP(structType, arrayPtr, {zero, index});
// Store the value into the i-th element of the array
builder.CreateStore(doubleValue, elementPtr);
}
// Return the struct
LoadInst* retVal = builder.CreateLoad(structType->getPointerTo(), structInstance);
builder.CreateRet(retVal);
}