title: LLVM IR -- how to convert array store to memcpy?
body: <p>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.</p>
  
  <p>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.</p>
  
  <p>The function I've written is as follows:</p>
  
  <pre><code>bool convert_array_store_to_memcpy(llvm::StoreInst *instruction)
  {
      llvm::Type *value_type = instruction-&gt;getValueOperand()-&gt;getType();
      if (!value_type-&gt;isArrayTy())
          return false;
  
      /* set up IRBuilder and get the pieces of the store */
      llvm::IRBuilder&lt;&gt; Builder(llvm::getGlobalContext());
      Builder.SetInsertPoint(instruction);
      llvm::Value *destination = instruction-&gt;getPointerOperand();
      llvm::Value *source = instruction-&gt;getValueOperand();
  
      /* get the number of bytes by getting the size of the array (elements*element-size) */
      llvm::ArrayType *array_type = cast&lt;ArrayType&gt;(value_type);
      uint64_t element_count = array_type-&gt;getNumElements();
      llvm::Type *element_type = array_type-&gt;getElementType();
      DataLayout *targetData = new DataLayout(mod);
      uint64_t element_size = targetData-&gt;getTypeAllocSize(element_type);
      uint64_t size = element_count*element_size;
  
      /* 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&lt;Value*&gt;(indexList, 1));
      unsigned alignment = instruction-&gt;getAlignment();
      if (!array_type)
          fprintf(stderr, "ERROR!\n");
  
      /* insert the memcpy */
      llvm::CallInst *memcpy_call = Builder.CreateMemCpy(destination,
                             pointer_to_source,
                             size,
                             alignment,
                             instruction-&gt;isVolatile());
  
      /* erase the store */
      instruction-&gt;eraseFromParent();
      return true;
  } /* convert_array_store_to_memcpy */
  </code></pre>
  
  <p>This compiles, but I get the following runtime error from the call to IRBuilder::CreateGEP:</p>
  
  <blockquote>
    <p>.../llvm/install/include/llvm/IR/Instructions.h:782: llvm::Type
    *llvm::checkGEPType(llvm::Type *): Assertion `Ty &amp;&amp; "Invalid GetElementPtrInst indices for type!"' failed.</p>
  </blockquote>
  
  <p>Note that I'm using LLVM 3.6 under Linux.</p>
  
  <p>EDIT: clearly, the call to createGEP is sending a null instead of the constant zero -- the intent was to get the address of the zeroth element of the array.  I've edited the above function with my latest effort, which is to try to send a length-1 array of indices into createGEP.  This is also failing inside of getIndexedType, which returns a NULL pointer, which I, again, don't understand.</p>
  
  <p>Note: I am using the example from a previous StackOverflow answer: <a href="https://stackoverflow.com/questions/26787341/inserting-getelementpointer-instruction-in-llvm-ir">Inserting GetElementpointer Instruction in LLVM IR</a></p>