user1479392
user1479392

Reputation: 91

Segfault when using GetElementPtrInst with an ArrayRef containing more than one Value

I'm trying to write a toy compiler with LLVM and C++. But whenever I try to create a GetElementPtrInst with more than one Index there is a Segfault. The documentation about this instruction didn't help me (API-Documentation Language-Documentation)

My llvm version is 3.1 and this is on Arch Linux. Just tested it on another Arch machine and got the same error.

Am I doing something wrong?

Here is small working program to illustrate my problem. It can be compiled with:

g++ -o segfault_example segfault_example.cpp -Wall -Wextra -pedantic \
    `llvm-config --libs core jit native --cxxflags --ldflags`
#include <llvm/Module.h>
#include <llvm/Constants.h>
#include <llvm/DerivedTypes.h>
#include <llvm/LLVMContext.h>
#include <llvm/Instructions.h>
#include <llvm/Analysis/Verifier.h>
#include <llvm/ADT/ArrayRef.h>
#include <string>
#include <iostream>

static llvm::LLVMContext& global = llvm::getGlobalContext();
static llvm::Type* int32ty = llvm::Type::getInt32Ty(global);

llvm::ConstantInt* getInt32(int n)
{
    return llvm::ConstantInt::get(llvm::Type::getInt32Ty(global), n);
}

int main()
{
    //setup everything for a minimal example
    llvm::Module* mainModule = new llvm::Module("main", global);

    llvm::FunctionType* ftype = llvm::FunctionType::get(int32ty, false);

    llvm::Function* mainFunction = llvm::Function::Create(
        ftype, llvm::GlobalValue::InternalLinkage, "main", mainModule);

    llvm::BasicBlock* bblock = llvm::BasicBlock::Create(
        global, "entry", mainFunction, 0);

    llvm::AllocaInst* mem = new llvm::AllocaInst(llvm::Type::getInt32PtrTy(global, 0x1000)
        , getInt32(0x1000), 0x1000, "mem", bblock);

    //tests
    //this works
    std::cout << "Testing with one element vector" << std::endl;
    std::vector<llvm::Value*> vect_1;
    vect_1.push_back(getInt32(0));
    llvm::GetElementPtrInst* gep1 =
        llvm::GetElementPtrInst::CreateInBounds(mem, llvm::ArrayRef<llvm::Value*>(vect_1)
        , "retval", bblock);
    std::cout << "done" << std::endl;

    //this works too, but I can't find this signature in the documentation
    std::cout << "Testing with Value* instead of ArrayRef" << std::endl;
        llvm::GetElementPtrInst::CreateInBounds(mem, getInt32(0), "retval", bblock);
    std::cout << "done" << std::endl;

    //this segfaults
    std::cout << "Filling two element vector" << std::endl;
    std::vector<llvm::Value*> vect_2;
    vect_2.push_back(getInt32(0));
    vect_2.push_back(getInt32(1));
    std::cout << "Testing with two element vector" << std::endl;
    //segfault
    llvm::GetElementPtrInst* gep2 =
        llvm::GetElementPtrInst::CreateInBounds(mem, llvm::ArrayRef<llvm::Value*>(vect_2)
        , "retval", bblock);
    std::cout << "done" << std::endl;

    mainModule->dump();
    llvm::verifyFunction(*mainFunction);
}

Upvotes: 4

Views: 1892

Answers (1)

user1479392
user1479392

Reputation: 91

Found the error. I will try to explain the cause and my solution, but the explanation may be wrong.

The type of mem was wrong. (In my case) it needed to be declared using new llvm::AllocaInst(llvm::ArrayType::get(int32ty, 100), "mem", bblock);. Creating two levels of indirection (explanation why there are two indirections). The previous type had only one indirection and dereferencing it with GetElementPtrInst and a two element vector therefore didn't work.

I noticed this, when playing with llvm in the browser and emiting LLVM C++ Api code.

You can create the C++ Api code for a C example file on the command line like so:

clang -c -emit-llvm -o ex.bf example.c
llc -march=cpp -o ex.cpp ex.bf

Upvotes: 5

Related Questions