LLVM Discussion Forums

LLVM IR: Convert array store to memcpy call

(This is a copy of my query to the Stack Overflow forum…)

LLVM IR includes arrays as a base type, so a “store” instruction in IR will take an array object and store it to a pointer to memory.

I’m compiling to a C environment, so I need to convert “store” instructions to calls to memcpy. I’ve tried to use IRBuilder to make the job easier, but I’m stuck on how to take the address of an object.

The function I’ve written is as follows:

bool convert_array_store_to_memcpy(llvm::StoreInst *instruction)
{
llvm::Type *value_type = instruction->getValueOperand()->getType();
if (!value_type->isArrayTy())
return false;

/* set up IRBuilder and get the pieces of the store */
llvm::IRBuilder<> Builder(llvm::getGlobalContext());
Builder.SetInsertPoint(instruction);
llvm::Value *destination = instruction->getPointerOperand();
llvm::Value *source = instruction->getValueOperand();

/* get the number of bytes by getting the size of the array (elements*element-size) */
llvm::ArrayType *array_type = cast<ArrayType>(value_type);
uint64_t element_count = array_type->getNumElements();
llvm::Type *element_type = array_type->getElementType();
DataLayout *targetData = new DataLayout(mod);
uint64_t element_size = targetData->getTypeAllocSize(element_type);
uint64_t size = element_count*element_size;

/* FIRST PROBLEM: I am trying to take the address of the start of the array */
llvm::Type *i32_type = llvm::IntegerType::getInt32Ty(llvm::getGlobalContext());
llvm::Constant *constant_int = llvm::ConstantInt::get(i32_type, 0, true);
Value *indexList[1] = {constant_int};
/* NEW PROBLEM:indexList seems to be the wrong type or contain the wrong type of thing */
llvm::Value *pointer_to_source = Builder.CreateGEP(source,  ArrayRef<Value*>(indexList, 1));
unsigned alignment = instruction->getAlignment();

/* insert the memcpy */
llvm::CallInst *memcpy_call = Builder.CreateMemCpy(destination,
                       pointer_to_source,
                       size,
                       alignment,
                       instruction->isVolatile());

/* erase the store */
instruction->eraseFromParent();
return true;

} /* convert_array_store_to_memcpy */

This compiles, but I get the following runtime error from the call to IRBuilder::CreateGEP:

…/llvm/install/include/llvm/IR/Instructions.h:782: llvm::Type *llvm::checkGEPType(llvm::Type *): Assertion `Ty && “Invalid GetElementPtrInst indices for type!”’ failed.

Note that I’m using LLVM 3.6 under Linux.

This is failing inside of getIndexedType, which returns a NULL pointer, but I don’t understand why it does that – clearly, I’ve incorrectly created the index array, but it matches the example here: https://stackoverflow.com/questions/26787341/inserting-getelementpointer-instruction-in-llvm-ir .