diff options
author | Martin Nowack <m.nowack@imperial.ac.uk> | 2019-11-04 12:33:28 +0000 |
---|---|---|
committer | Cristian Cadar <c.cadar@imperial.ac.uk> | 2019-11-07 11:51:58 +0000 |
commit | be4fd315655a1be889dc319c7ff3f89e40922e02 (patch) | |
tree | 1c20cee0b0bc15fbe9f6d54e1a3130f4459bb9db | |
parent | 5c148a6184adfed5438534b97a88fe10bc1cde37 (diff) | |
download | klee-be4fd315655a1be889dc319c7ff3f89e40922e02.tar.gz |
Handle llvm.objectsize explicitly
llvm.objectsize is used in several optimisation during compile time. Lowering these intrinsics took a conservative approach returning always the value for unknown. Instead, lower to the object's real size, if possible. Otherwise, a conservative value is used. Since LLVM 4.0, the function `llvm::lowerObjectSizeCall()` does exactly this. Use this function or preserve the old behaviour for older LLVM versions.
-rw-r--r-- | lib/Module/IntrinsicCleaner.cpp | 50 | ||||
-rw-r--r-- | test/Intrinsics/objectsize.leq80.ll | 9 | ||||
-rw-r--r-- | test/Intrinsics/objectsize.ll | 9 |
3 files changed, 30 insertions, 38 deletions
diff --git a/lib/Module/IntrinsicCleaner.cpp b/lib/Module/IntrinsicCleaner.cpp index 144be0ce..2c86d56d 100644 --- a/lib/Module/IntrinsicCleaner.cpp +++ b/lib/Module/IntrinsicCleaner.cpp @@ -10,6 +10,7 @@ #include "Passes.h" #include "klee/Config/Version.h" +#include "llvm/Analysis/MemoryBuiltins.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" @@ -294,53 +295,30 @@ bool IntrinsicCleanerPass::runOnBasicBlock(BasicBlock &b, Module &M) { break; } case Intrinsic::objectsize: { +#if LLVM_VERSION_CODE >= LLVM_VERSION(4, 0) + // Lower the call to a concrete value + auto replacement = llvm::lowerObjectSizeCall(ii, DataLayout, nullptr, + /*MustSucceed=*/true); +#else // We don't know the size of an object in general so we replace // with 0 or -1 depending on the second argument to the intrinsic. -#if LLVM_VERSION_CODE >= LLVM_VERSION(9, 0) - assert(ii->getNumArgOperands() == 4 && "wrong number of arguments"); -#elif LLVM_VERSION_CODE >= LLVM_VERSION(5, 0) - assert(ii->getNumArgOperands() == 3 && "wrong number of arguments"); -#else assert(ii->getNumArgOperands() == 2 && "wrong number of arguments"); -#endif - - Value *minArg = ii->getArgOperand(1); - assert(minArg && "Failed to get second argument"); - ConstantInt *minArgAsInt = dyn_cast<ConstantInt>(minArg); - assert(minArgAsInt && "Second arg is not a ConstantInt"); - assert(minArgAsInt->getBitWidth() == 1 && - "Second argument is not an i1"); - -#if LLVM_VERSION_CODE >= LLVM_VERSION(5, 0) - auto nullArg = ii->getArgOperand(2); - assert(nullArg && "Failed to get third argument"); - auto nullArgAsInt = dyn_cast<ConstantInt>(nullArg); - assert(nullArgAsInt && "Third arg is not a ConstantInt"); - assert(nullArgAsInt->getBitWidth() == 1 && - "Third argument is not an i1"); - // TODO: should we do something with the 3rd argument? -#endif - -#if LLVM_VERSION_CODE >= LLVM_VERSION(9, 0) - auto dynamicArg = ii->getArgOperand(3); - assert(dynamicArg && "Failed to get fourth argument"); - auto dynamicArgAsInt = dyn_cast<ConstantInt>(dynamicArg); - assert(dynamicArgAsInt && "Fourth arg is not a ConstantInt"); - assert(dynamicArgAsInt->getBitWidth() == 1 && - "Fourth argument is not an i1"); - // TODO: should we do something with the 4th argument? -#endif - - Value *replacement = NULL; + auto minArg = dyn_cast_or_null<ConstantInt>(ii->getArgOperand(1)); + assert(minArg && + "Failed to get second argument or it is not ConstantInt"); + assert(minArg->getBitWidth() == 1 && "Second argument is not an i1"); + ConstantInt *replacement = nullptr; IntegerType *intType = dyn_cast<IntegerType>(ii->getType()); assert(intType && "intrinsic does not have integer return type"); - if (minArgAsInt->isZero()) { + if (minArg->isZero()) { // min=false replacement = ConstantInt::get(intType, -1, /*isSigned=*/true); } else { // min=true replacement = ConstantInt::get(intType, 0, /*isSigned=*/false); } + +#endif ii->replaceAllUsesWith(replacement); ii->eraseFromParent(); dirty = true; diff --git a/test/Intrinsics/objectsize.leq80.ll b/test/Intrinsics/objectsize.leq80.ll index f1bcdf62..19a20334 100644 --- a/test/Intrinsics/objectsize.leq80.ll +++ b/test/Intrinsics/objectsize.leq80.ll @@ -20,7 +20,14 @@ continue.block: %2 = load i8*, i8** %a, align 8 %3 = call i64 @llvm.objectsize.i64.p0i8(i8* %2, i1 false, i1 false) %cmp1 = icmp ne i64 %3, -1 - br i1 %cmp1, label %abort.block, label %exit.block + br i1 %cmp1, label %abort.block, label %continue.block2 + +continue.block2: +; allocate one byte + %b = alloca i8, align 8 + %4 = call i64 @llvm.objectsize.i64.p0i8(i8* %b, i1 false, i1 false) + %cmp2 = icmp ne i64 %4, 1 + br i1 %cmp2, label %abort.block, label %exit.block exit.block: ret i32 0 diff --git a/test/Intrinsics/objectsize.ll b/test/Intrinsics/objectsize.ll index af77baa4..9fa84de5 100644 --- a/test/Intrinsics/objectsize.ll +++ b/test/Intrinsics/objectsize.ll @@ -19,7 +19,14 @@ continue.block: %2 = load i8*, i8** %a, align 8 %3 = call i64 @llvm.objectsize.i64.p0i8(i8* %2, i1 false, i1 false, i1 false) %cmp1 = icmp ne i64 %3, -1 - br i1 %cmp1, label %abort.block, label %exit.block + br i1 %cmp1, label %abort.block, label %continue.block2 + +continue.block2: +; allocate one byte + %b = alloca i8, align 8 + %4 = call i64 @llvm.objectsize.i64.p0i8(i8* %b, i1 false, i1 false, i1 false) + %cmp2 = icmp ne i64 %4, 1 + br i1 %cmp2, label %abort.block, label %exit.block exit.block: ret i32 0 |