llvm :: BasicBlock :: isLandingPad не работает должным образом - PullRequest
0 голосов
/ 03 марта 2020

Я немного запутался насчет isLandingPad на BasicBlock с в LLVM. У меня есть следующий код, где я создаю пустой BasicBlock и затем вызываю isLandingPad на нем:

#include "llvm/IR/IRBuilder.h"
#include <assert.h>

using namespace llvm;

int main(void)
{
    // Start with a LLVM context.
    LLVMContext TheContext;

    // Make a module.
    Module *TheModule = new Module("mymod", TheContext);

    // Make a function
    std::vector<Type*> NoArgs = {};
    Type *u32 = Type::getInt32Ty(TheContext);
    FunctionType *FT = FunctionType::get(u32, NoArgs, false);
    Function *F = Function::Create(FT, Function::ExternalLinkage, "main", TheModule);

    // Make an empty block
    IRBuilder<> Builder(TheContext);
    BasicBlock *BB = BasicBlock::Create(TheContext, "entry", F);
    Builder.SetInsertPoint(BB);

    auto fnp = BB->getFirstNonPHI();
    assert(fnp == nullptr);

    // I think this should crash.
    auto islp = BB->isLandingPad();
    printf("isLP = %d\n", islp);

    // If we inline the implementation of the above call, we have the following
    // (which *does* crash).
    auto islp2 = isa<LandingPadInst>(BB->getFirstNonPHI());
    printf("isLP2 = %d\n", islp2);

    return 0;
}

, который выводит:

isLP = 0
codegen: /usr/lib/llvm-7/include/llvm/Support/Casting.h:106: static bool llvm::isa_impl_cl<llvm::LandingPadInst, const llvm::Instruction *>::doit(const From *) [To = llvm::LandingPadInst, From = const llvm::Instruction *]: Assertion `Val && "isa<> used on a null pointer"' failed.

В соответствии с источником LLVM isLandingPad (https://llvm.org/doxygen/BasicBlock_8cpp_source.html#l00470) это должно вызвать ошибку, когда BasicBlock пуст (так как мы вызываем isa для nullptr). Однако когда я запускаю эту программу, вызов isLandingPad завершается успешно и возвращает false. Интересно, что когда я встраиваю определение функции isLandingPad (как показано ниже), он вылетает, как и ожидалось.

Я явно что-то здесь не так делаю, но не вижу, каким образом * Вызов 1021 * отличается от встроенной версии, и почему isLandingPad не обрабатывает sh, когда это следует в зависимости от источника.

Ответы [ 2 ]

1 голос
/ 03 марта 2020

Если код «должен вызывать ошибки», это означает, что код вызывает неопределенное поведение (UB) во время выполнения. Существует вероятность того, что компилятор выполняет оптимизацию на основе ложного предположения о том, что UB не возникает в вашей программе, и это ложное предположение приводит к ложному результату isLP == false, который вы наблюдаете.

Вы никогда не должны вызывать неопределенное Поведение и реструктурируйте ваш код, чтобы никогда не вызывать функции с параметрами, которые могут вызывать UB. (Например, проверьте результат getFirstNonPHI перед вызовом isa<LandingPadInst> или isLandingPad.

В частности, вы не должны предполагать, что UB (например, разыменование nullptr или адрес рядом с ним) имеет определенный эффект, такой как «он будет зависать», потому что компилятор может реорганизовать ваш код (при условии, что UB никогда не произойдет) таким образом, чтобы устранить ожидаемый эффект (например, он сгенерирует код, который не пытается загрузить из nullptr) .

Уровни встраивания и оптимизации оказывают большое влияние на сгенерированный код, и поэтому вы видите разные результаты (недопустимое возвращаемое значение в сравнении с segfault) в разных случаях.

Дополнительная информация о неопределенном поведении:

0 голосов
/ 04 марта 2020

Сам LLVM (по крайней мере, в моей системе) скомпилирован с отключенными утверждениями, поэтому утверждение не срабатывает. Когда вы встраиваете его в свой код, вы компилируете с включенными утверждениями, поэтому он срабатывает.

Обратите внимание, что, поскольку isa<...> является шаблоном, он будет скомпилирован в модуль компиляции, который создается как часть , В этом случае есть как минимум два: один в LLVM и один, включающий вашу программу. Строго говоря, они оба должны быть идентичны («правило одного определения»), иначе у вас есть UB. Практический результат в случае, подобном этому, состоит в том, что вызовы isa<...>() из любого модуля компиляции могут в конечном итоге вызвать версию, инстанцированную в другом. Тем не менее, вполне вероятно, что в случае isa<...>() вызовы являются встроенными, т. Е. Вы получаете версию isa<...>(), специфицирующую c для каждой единицы компиляции, которая его создает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...