diff options
-rw-r--r-- | include/llvm/Transforms/Utils/Local.h | 2 | ||||
-rw-r--r-- | lib/CodeGen/WinEHPrepare.cpp | 6 | ||||
-rw-r--r-- | lib/Transforms/IPO/PruneEH.cpp | 2 | ||||
-rw-r--r-- | lib/Transforms/Scalar/SCCP.cpp | 3 | ||||
-rw-r--r-- | lib/Transforms/Utils/InlineFunction.cpp | 2 | ||||
-rw-r--r-- | lib/Transforms/Utils/Local.cpp | 62 | ||||
-rw-r--r-- | lib/Transforms/Utils/LoopSimplify.cpp | 2 | ||||
-rw-r--r-- | test/Transforms/SimplifyCFG/invoke.ll | 2 | ||||
-rw-r--r-- | test/Transforms/SimplifyCFG/trap-debugloc.ll | 22 | ||||
-rw-r--r-- | test/Transforms/SimplifyCFG/trapping-load-unreachable.ll | 1 |
10 files changed, 73 insertions, 31 deletions
diff --git a/include/llvm/Transforms/Utils/Local.h b/include/llvm/Transforms/Utils/Local.h index 0decd511aae..43b376cf806 100644 --- a/include/llvm/Transforms/Utils/Local.h +++ b/include/llvm/Transforms/Utils/Local.h @@ -296,7 +296,7 @@ unsigned removeAllNonTerminatorAndEHPadInstructions(BasicBlock *BB); /// Insert an unreachable instruction before the specified /// instruction, making it and the rest of the code in the block dead. -unsigned changeToUnreachable(Instruction *I); +unsigned changeToUnreachable(Instruction *I, bool UseLLVMTrap); /// Replace 'BB's terminator with one that does not have an unwind successor /// block. Rewrites `invoke` to `call`, etc. Updates any PHIs in unwind diff --git a/lib/CodeGen/WinEHPrepare.cpp b/lib/CodeGen/WinEHPrepare.cpp index a8e089a23d2..041fb7b912b 100644 --- a/lib/CodeGen/WinEHPrepare.cpp +++ b/lib/CodeGen/WinEHPrepare.cpp @@ -963,9 +963,9 @@ void WinEHPrepare::removeImplausibleInstructions(Function &F) { BasicBlock::iterator CallI = std::prev(BB->getTerminator()->getIterator()); auto *CI = cast<CallInst>(&*CallI); - changeToUnreachable(CI); + changeToUnreachable(CI, /*UseLLVMTrap=*/false); } else { - changeToUnreachable(&I); + changeToUnreachable(&I, /*UseLLVMTrap=*/false); } // There are no more instructions in the block (except for unreachable), @@ -986,7 +986,7 @@ void WinEHPrepare::removeImplausibleInstructions(Function &F) { IsUnreachableCleanupret = CRI->getCleanupPad() != CleanupPad; if (IsUnreachableRet || IsUnreachableCatchret || IsUnreachableCleanupret) { - changeToUnreachable(TI); + changeToUnreachable(TI, /*UseLLVMTrap=*/false); } else if (isa<InvokeInst>(TI)) { if (Personality == EHPersonality::MSVC_CXX && CleanupPad) { // Invokes within a cleanuppad for the MSVC++ personality never diff --git a/lib/Transforms/IPO/PruneEH.cpp b/lib/Transforms/IPO/PruneEH.cpp index abde3d3609a..04383f4f3fa 100644 --- a/lib/Transforms/IPO/PruneEH.cpp +++ b/lib/Transforms/IPO/PruneEH.cpp @@ -258,7 +258,7 @@ void PruneEH::DeleteBasicBlock(BasicBlock *BB) { if (TokenInst) { if (!isa<TerminatorInst>(TokenInst)) - changeToUnreachable(TokenInst->getNextNode()); + changeToUnreachable(TokenInst->getNextNode(), /*UseLLVMTrap=*/false); } else { // Get the list of successors of this block. std::vector<BasicBlock *> Succs(succ_begin(BB), succ_end(BB)); diff --git a/lib/Transforms/Scalar/SCCP.cpp b/lib/Transforms/Scalar/SCCP.cpp index 264bdb6f353..91e625b7aac 100644 --- a/lib/Transforms/Scalar/SCCP.cpp +++ b/lib/Transforms/Scalar/SCCP.cpp @@ -1802,7 +1802,8 @@ static bool runIPSCCP(Module &M, const DataLayout &DL, DEBUG(dbgs() << " BasicBlock Dead:" << *BB); ++NumDeadBlocks; - NumInstRemoved += changeToUnreachable(BB->getFirstNonPHI()); + NumInstRemoved += + changeToUnreachable(BB->getFirstNonPHI(), /*UseLLVMTrap=*/false); MadeChanges = true; diff --git a/lib/Transforms/Utils/InlineFunction.cpp b/lib/Transforms/Utils/InlineFunction.cpp index e4a4da8f0ed..a06c8499e19 100644 --- a/lib/Transforms/Utils/InlineFunction.cpp +++ b/lib/Transforms/Utils/InlineFunction.cpp @@ -1833,7 +1833,7 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI, // As such, we replace the cleanupret with unreachable. if (auto *CleanupRet = dyn_cast<CleanupReturnInst>(BB->getTerminator())) if (CleanupRet->unwindsToCaller() && EHPadForCallUnwindsLocally) - changeToUnreachable(CleanupRet); + changeToUnreachable(CleanupRet, /*UseLLVMTrap=*/false); Instruction *I = BB->getFirstNonPHI(); if (!I->isEHPad()) diff --git a/lib/Transforms/Utils/Local.cpp b/lib/Transforms/Utils/Local.cpp index a37e4911d8d..edacfd20f99 100644 --- a/lib/Transforms/Utils/Local.cpp +++ b/lib/Transforms/Utils/Local.cpp @@ -42,13 +42,11 @@ #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Operator.h" -#include "llvm/IR/PatternMatch.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; -using namespace llvm::PatternMatch; #define DEBUG_TYPE "local" @@ -1312,13 +1310,21 @@ unsigned llvm::removeAllNonTerminatorAndEHPadInstructions(BasicBlock *BB) { return NumDeadInst; } -unsigned llvm::changeToUnreachable(Instruction *I) { +unsigned llvm::changeToUnreachable(Instruction *I, bool UseLLVMTrap) { BasicBlock *BB = I->getParent(); // Loop over all of the successors, removing BB's entry from any PHI // nodes. - for (BasicBlock *Succ : successors(BB)) - Succ->removePredecessor(BB); - + for (succ_iterator SI = succ_begin(BB), SE = succ_end(BB); SI != SE; ++SI) + (*SI)->removePredecessor(BB); + + // Insert a call to llvm.trap right before this. This turns the undefined + // behavior into a hard fail instead of falling through into random code. + if (UseLLVMTrap) { + Function *TrapFn = + Intrinsic::getDeclaration(BB->getParent()->getParent(), Intrinsic::trap); + CallInst *CallTrap = CallInst::Create(TrapFn, "", I); + CallTrap->setDebugLoc(I->getDebugLoc()); + } new UnreachableInst(I->getContext(), I); // All instructions after this are dead. @@ -1368,14 +1374,22 @@ static bool markAliveBlocks(Function &F, // Do a quick scan of the basic block, turning any obviously unreachable // instructions into LLVM unreachable insts. The instruction combining pass // canonicalizes unreachable insts into stores to null or undef. - for (Instruction &I : *BB) { + for (BasicBlock::iterator BBI = BB->begin(), E = BB->end(); BBI != E;++BBI){ // Assumptions that are known to be false are equivalent to unreachable. // Also, if the condition is undefined, then we make the choice most // beneficial to the optimizer, and choose that to also be unreachable. - if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I)) { + if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(BBI)) { if (II->getIntrinsicID() == Intrinsic::assume) { - if (match(II->getArgOperand(0), m_CombineOr(m_Zero(), m_Undef()))) { - changeToUnreachable(II); + bool MakeUnreachable = false; + if (isa<UndefValue>(II->getArgOperand(0))) + MakeUnreachable = true; + else if (ConstantInt *Cond = + dyn_cast<ConstantInt>(II->getArgOperand(0))) + MakeUnreachable = Cond->isZero(); + + if (MakeUnreachable) { + // Don't insert a call to llvm.trap right before the unreachable. + changeToUnreachable(&*BBI, false); Changed = true; break; } @@ -1390,19 +1404,19 @@ static bool markAliveBlocks(Function &F, // Note: unlike in llvm.assume, it is not "obviously profitable" for // guards to treat `undef` as `false` since a guard on `undef` can // still be useful for widening. - if (match(II->getArgOperand(0), m_Zero())) - if (!isa<UnreachableInst>(II->getNextNode())) { - changeToUnreachable(II->getNextNode()); + if (auto *CI = dyn_cast<ConstantInt>(II->getArgOperand(0))) + if (CI->isZero() && !isa<UnreachableInst>(II->getNextNode())) { + changeToUnreachable(II->getNextNode(), /*UseLLVMTrap=*/ false); Changed = true; break; } } } - if (auto *CI = dyn_cast<CallInst>(&I)) { + if (CallInst *CI = dyn_cast<CallInst>(BBI)) { Value *Callee = CI->getCalledValue(); if (isa<ConstantPointerNull>(Callee) || isa<UndefValue>(Callee)) { - changeToUnreachable(CI); + changeToUnreachable(CI, /*UseLLVMTrap=*/false); Changed = true; break; } @@ -1410,8 +1424,10 @@ static bool markAliveBlocks(Function &F, // If we found a call to a no-return function, insert an unreachable // instruction after it. Make sure there isn't *already* one there // though. - if (!isa<UnreachableInst>(CI->getNextNode())) { - changeToUnreachable(CI->getNextNode()); + ++BBI; + if (!isa<UnreachableInst>(BBI)) { + // Don't insert a call to llvm.trap right before the unreachable. + changeToUnreachable(&*BBI, false); Changed = true; } break; @@ -1421,7 +1437,7 @@ static bool markAliveBlocks(Function &F, // Store to undef and store to null are undefined and used to signal that // they should be changed to unreachable by passes that can't modify the // CFG. - if (auto *SI = dyn_cast<StoreInst>(&I)) { + if (StoreInst *SI = dyn_cast<StoreInst>(BBI)) { // Don't touch volatile stores. if (SI->isVolatile()) continue; @@ -1430,7 +1446,7 @@ static bool markAliveBlocks(Function &F, if (isa<UndefValue>(Ptr) || (isa<ConstantPointerNull>(Ptr) && SI->getPointerAddressSpace() == 0)) { - changeToUnreachable(SI); + changeToUnreachable(SI, true); Changed = true; break; } @@ -1442,7 +1458,7 @@ static bool markAliveBlocks(Function &F, // Turn invokes that call 'nounwind' functions into ordinary calls. Value *Callee = II->getCalledValue(); if (isa<ConstantPointerNull>(Callee) || isa<UndefValue>(Callee)) { - changeToUnreachable(II); + changeToUnreachable(II, true); Changed = true; } else if (II->doesNotThrow() && canSimplifyInvokeNoUnwind(&F)) { if (II->use_empty() && II->onlyReadsMemory()) { @@ -1495,9 +1511,9 @@ static bool markAliveBlocks(Function &F, } Changed |= ConstantFoldTerminator(BB, true); - for (BasicBlock *Succ : successors(BB)) - if (Reachable.insert(Succ).second) - Worklist.push_back(Succ); + for (succ_iterator SI = succ_begin(BB), SE = succ_end(BB); SI != SE; ++SI) + if (Reachable.insert(*SI).second) + Worklist.push_back(*SI); } while (!Worklist.empty()); return Changed; } diff --git a/lib/Transforms/Utils/LoopSimplify.cpp b/lib/Transforms/Utils/LoopSimplify.cpp index a2dd581f45c..2509b0a058f 100644 --- a/lib/Transforms/Utils/LoopSimplify.cpp +++ b/lib/Transforms/Utils/LoopSimplify.cpp @@ -491,7 +491,7 @@ ReprocessLoop: // Zap the dead pred's terminator and replace it with unreachable. TerminatorInst *TI = P->getTerminator(); - changeToUnreachable(TI); + changeToUnreachable(TI, /*UseLLVMTrap=*/false); Changed = true; } } diff --git a/test/Transforms/SimplifyCFG/invoke.ll b/test/Transforms/SimplifyCFG/invoke.ll index 506fef0ef92..b7fd7d62ccf 100644 --- a/test/Transforms/SimplifyCFG/invoke.ll +++ b/test/Transforms/SimplifyCFG/invoke.ll @@ -12,6 +12,7 @@ declare i32 @fn() ; CHECK-LABEL: @f1( define i8* @f1() nounwind uwtable ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { entry: +; CHECK: call void @llvm.trap() ; CHECK: unreachable %call = invoke noalias i8* undef() to label %invoke.cont unwind label %lpad @@ -30,6 +31,7 @@ lpad: ; CHECK-LABEL: @f2( define i8* @f2() nounwind uwtable ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { entry: +; CHECK: call void @llvm.trap() ; CHECK: unreachable %call = invoke noalias i8* null() to label %invoke.cont unwind label %lpad diff --git a/test/Transforms/SimplifyCFG/trap-debugloc.ll b/test/Transforms/SimplifyCFG/trap-debugloc.ll new file mode 100644 index 00000000000..a912dc561a4 --- /dev/null +++ b/test/Transforms/SimplifyCFG/trap-debugloc.ll @@ -0,0 +1,22 @@ +; RUN: opt -S -simplifycfg < %s | FileCheck %s +; Radar 9342286 +; Assign DebugLoc to trap instruction. +define void @foo() nounwind ssp !dbg !0 { +; CHECK: call void @llvm.trap(), !dbg + store i32 42, i32* null, !dbg !5 + ret void, !dbg !7 +} + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!10} + +!0 = distinct !DISubprogram(name: "foo", line: 3, isLocal: false, isDefinition: true, virtualIndex: 6, isOptimized: false, unit: !2, file: !8, scope: !1, type: !3) +!1 = !DIFile(filename: "foo.c", directory: "/private/tmp") +!2 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "Apple clang version 3.0 (tags/Apple/clang-206.1) (based on LLVM 3.0svn)", isOptimized: true, emissionKind: FullDebug, file: !8, enums: !{}, retainedTypes: !{}) +!3 = !DISubroutineType(types: !4) +!4 = !{null} +!5 = !DILocation(line: 4, column: 2, scope: !6) +!6 = distinct !DILexicalBlock(line: 3, column: 12, file: !8, scope: !0) +!7 = !DILocation(line: 5, column: 1, scope: !6) +!8 = !DIFile(filename: "foo.c", directory: "/private/tmp") +!10 = !{i32 1, !"Debug Info Version", i32 3} diff --git a/test/Transforms/SimplifyCFG/trapping-load-unreachable.ll b/test/Transforms/SimplifyCFG/trapping-load-unreachable.ll index 818c454398b..5881367d961 100644 --- a/test/Transforms/SimplifyCFG/trapping-load-unreachable.ll +++ b/test/Transforms/SimplifyCFG/trapping-load-unreachable.ll @@ -28,6 +28,7 @@ entry: ret void ; CHECK-LABEL: @test2( +; CHECK: call void @llvm.trap ; CHECK: unreachable } |