about summary refs log tree commit diff homepage
diff options
context:
space:
mode:
authorCristian Cadar <c.cadar@imperial.ac.uk>2013-09-25 05:58:04 -0700
committerCristian Cadar <c.cadar@imperial.ac.uk>2013-09-25 05:58:04 -0700
commit1510c721187f1e838d30fca376af2ab5af90ee6c (patch)
tree962e05f3c908ef7584836c668576b274d027d8c2
parent95521073b1a6c0eec2719a4c355c83506b325693 (diff)
parentfc29e256039d1af4979fd0a5c7170de84b19818b (diff)
downloadklee-1510c721187f1e838d30fca376af2ab5af90ee6c.tar.gz
Merge pull request #27 from antiAgainst/intrinsic-trap
Lower intrinsic instruction "llvm.trap" to a call of the abort() function.
-rw-r--r--lib/Module/IntrinsicCleaner.cpp25
-rw-r--r--lib/Module/Passes.h2
-rw-r--r--test/Feature/IntrinsicTrap.ll28
3 files changed, 52 insertions, 3 deletions
diff --git a/lib/Module/IntrinsicCleaner.cpp b/lib/Module/IntrinsicCleaner.cpp
index 9c2f4455..64a47e1b 100644
--- a/lib/Module/IntrinsicCleaner.cpp
+++ b/lib/Module/IntrinsicCleaner.cpp
@@ -60,11 +60,11 @@ bool IntrinsicCleanerPass::runOnModule(Module &M) {
   bool dirty = false;
   for (Module::iterator f = M.begin(), fe = M.end(); f != fe; ++f)
     for (Function::iterator b = f->begin(), be = f->end(); b != be; ++b)
-      dirty |= runOnBasicBlock(*b);
+      dirty |= runOnBasicBlock(*b, M);
   return dirty;
 }
 
-bool IntrinsicCleanerPass::runOnBasicBlock(BasicBlock &b) { 
+bool IntrinsicCleanerPass::runOnBasicBlock(BasicBlock &b, Module &M) {
   bool dirty = false;
   
 #if LLVM_VERSION_CODE <= LLVM_VERSION(3, 1)
@@ -195,6 +195,27 @@ bool IntrinsicCleanerPass::runOnBasicBlock(BasicBlock &b) {
         ii->eraseFromParent();
         dirty = true;
         break;
+
+      case Intrinsic::trap: {
+        // Intrisic instruction "llvm.trap" found. Directly lower it to
+        // a call of the abort() function.
+        Function *F = cast<Function>(
+          M.getOrInsertFunction(
+            "abort", Type::getVoidTy(getGlobalContext()), NULL));
+        F->setDoesNotReturn();
+        F->setDoesNotThrow();
+
+        CallInst::Create(F, Twine(), ii);
+        new UnreachableInst(getGlobalContext(), ii);
+
+        ii->eraseFromParent();
+
+        if (Function *Declare = M.getFunction("llvm.trap"))
+          Declare->eraseFromParent();
+
+        dirty = true;
+        break;
+      }
                     
       default:
         if (LowerIntrinsics)
diff --git a/lib/Module/Passes.h b/lib/Module/Passes.h
index ebe89b2b..d83e57ec 100644
--- a/lib/Module/Passes.h
+++ b/lib/Module/Passes.h
@@ -82,7 +82,7 @@ class IntrinsicCleanerPass : public llvm::ModulePass {
   llvm::IntrinsicLowering *IL;
   bool LowerIntrinsics;
 
-  bool runOnBasicBlock(llvm::BasicBlock &b);
+  bool runOnBasicBlock(llvm::BasicBlock &b, llvm::Module &M);
 public:
 #if LLVM_VERSION_CODE <= LLVM_VERSION(3, 1)
   IntrinsicCleanerPass(const llvm::TargetData &TD,
diff --git a/test/Feature/IntrinsicTrap.ll b/test/Feature/IntrinsicTrap.ll
new file mode 100644
index 00000000..5af46225
--- /dev/null
+++ b/test/Feature/IntrinsicTrap.ll
@@ -0,0 +1,28 @@
+; RUN: llvm-as %s -f -o %t1.bc
+; RUN: %klee -disable-opt %t1.bc
+; RUN: grep abort() klee-last/assembly.ll | wc -l | grep -q 2
+; RUN: echo "llvm.trap()" > %t2.ll
+; RUN: grep llvm.trap() klee-last/assembly.ll %t2.ll | wc -l | grep -q 1
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-f128:128:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+define i32 @main() nounwind {
+entry:
+  %a = add i32 1, 2
+  %b = add i32 %a, 3
+  %c = icmp ne i32 %b, 6
+  br i1 %c, label %btrue, label %bfalse
+
+btrue:
+  call void @llvm.trap() noreturn nounwind
+  unreachable
+
+bfalse:
+  br label %return
+
+return:
+  ret i32 0
+}
+
+declare void @llvm.trap() noreturn nounwind