LLVM IR - как конвертировать массив хранилища в memcpy? - PullRequest
0 голосов
/ 22 марта 2020

LLVM IR включает массивы в качестве базового типа, поэтому инструкция «store» в IR возьмет объект массива и сохранит его по указателю на память.

Я компилирую в среду C , поэтому мне нужно преобразовать инструкции "store" в вызовы memcpy. Я пытался использовать IRBuilder для облегчения работы, но я застрял на том, как получить адрес объекта.

Функция, которую я написал, выглядит следующим образом:

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;

    /* 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();
    if (!array_type)
        fprintf(stderr, "ERROR!\n");

    /* 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 */

Это компилируется, но я получаю следующую ошибку времени выполнения при вызове IRBuilder :: CreateGEP:

... / llvm / install / include / llvm / IR / Instructions.h: 782 : llvm :: Type * llvm :: checkGEPType (llvm :: Type *): Утверждение `Ty &&" Недопустимые индексы GetElementPtrInst для типа! "'не удалось.

Обратите внимание, что я использую LLVM 3.6 под Linux.

РЕДАКТИРОВАТЬ: ясно, что вызов createGEP отправляет ноль вместо константного нуля - целью было получить адрес нулевого элемента массива. Я отредактировал вышеуказанную функцию с моей последней попыткой, которая заключается в попытке отправить массив индексов длины 1 в createGEP. Это также не работает внутри getIndexedType, который возвращает указатель NULL, который я, опять же, не понимаю.

Примечание: я использую пример из предыдущего ответа StackOverflow: Вставка инструкции GetElementpointer в LLVM IR

...