Ошибка при использовании GetElementPtrInst с ArrayRef, содержащим более одного значения

Я пытаюсь написать игрушечный компилятор с LLVM и C++. Но всякий раз, когда я пытаюсь создать GetElementPtrInst с несколькими индексами, возникает ошибка Segfault. Документация по этой инструкции мне не помогла ( API-Documentation Language-Documentation)

Моя версия llvm 3.1, и это на Arch Linux. Просто проверил его на другом компьютере Arch и получил ту же ошибку.

Я делаю что-то неправильно?

Вот небольшая рабочая программа, чтобы проиллюстрировать мою проблему. Может быть скомпилировано с:

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);
}

1 ответ

Нашел ошибку. Я постараюсь объяснить причину и свое решение, но объяснение может быть неверным.

Тип mem был неправ. (В моем случае) это нужно было объявить с помощью new llvm::AllocaInst(llvm::ArrayType::get(int32ty, 100), "mem", bblock);, Создание двух уровней косвенности ( объяснение, почему существует две косвенности). Предыдущий тип имел только одно косвенное обращение и разыменовывал его GetElementPtrInst и поэтому двухэлементный вектор не работал.

Я заметил это, когда играл с llvm в браузере и испускал код LLVM C++ Api.

Вы можете создать код C++ Api для файла примера C в командной строке следующим образом:

clang -c -emit-llvm -o ex.bf example.c
llc -march=cpp -o ex.cpp ex.bf
Другие вопросы по тегам