diff options
-rw-r--r-- | lib/Transforms/Utils/InlineFunction.cpp | 212 | ||||
-rw-r--r-- | test/Transforms/Inline/inline_invoke.ll | 93 |
2 files changed, 276 insertions, 29 deletions
diff --git a/lib/Transforms/Utils/InlineFunction.cpp b/lib/Transforms/Utils/InlineFunction.cpp index e69dc89fd0..8416170d90 100644 --- a/lib/Transforms/Utils/InlineFunction.cpp +++ b/lib/Transforms/Utils/InlineFunction.cpp @@ -45,31 +45,199 @@ bool llvm::InlineFunction(InvokeInst *II, InlineFunctionInfo &IFI) { return InlineFunction(CallSite(II), IFI); } -/// [LIBUNWIND] Find the (possibly absent) call to @llvm.eh.selector in -/// the given landing pad. -static EHSelectorInst *findSelectorForLandingPad(BasicBlock *lpad) { - // The llvm.eh.exception call is required to be in the landing pad. - for (BasicBlock::iterator i = lpad->begin(), e = lpad->end(); i != e; i++) { +/// [LIBUNWIND] Look for an llvm.eh.exception call in the given block. +static EHExceptionInst *findExceptionInBlock(BasicBlock *bb) { + for (BasicBlock::iterator i = bb->begin(), e = bb->end(); i != e; i++) { EHExceptionInst *exn = dyn_cast<EHExceptionInst>(i); - if (!exn) continue; + if (exn) return exn; + } + + return 0; +} + +/// [LIBUNWIND] Look for the 'best' llvm.eh.selector instruction for +/// the given llvm.eh.exception call. +static EHSelectorInst *findSelectorForException(EHExceptionInst *exn) { + BasicBlock *exnBlock = exn->getParent(); - EHSelectorInst *selector = 0; - for (Instruction::use_iterator - ui = exn->use_begin(), ue = exn->use_end(); ui != ue; ++ui) { - EHSelectorInst *sel = dyn_cast<EHSelectorInst>(*ui); - if (!sel) continue; + EHSelectorInst *outOfBlockSelector = 0; + for (Instruction::use_iterator + ui = exn->use_begin(), ue = exn->use_end(); ui != ue; ++ui) { + EHSelectorInst *sel = dyn_cast<EHSelectorInst>(*ui); + if (!sel) continue; - // Immediately accept an eh.selector in the landing pad. - if (sel->getParent() == lpad) return sel; + // Immediately accept an eh.selector in the same block as the + // excepton call. + if (sel->getParent() == exnBlock) return sel; - // Otherwise, use the first selector we see. - if (!selector) selector = sel; + // Otherwise, use the first selector we see. + if (!outOfBlockSelector) outOfBlockSelector = sel; + } + + return outOfBlockSelector; +} + +/// [LIBUNWIND] Find the (possibly absent) call to @llvm.eh.selector +/// in the given landing pad. In principle, llvm.eh.exception is +/// required to be in the landing pad; in practice, SplitCriticalEdge +/// can break that invariant, and then inlining can break it further. +/// There's a real need for a reliable solution here, but until that +/// happens, we have some fragile workarounds here. +static EHSelectorInst *findSelectorForLandingPad(BasicBlock *lpad) { + // Look for an exception call in the actual landing pad. + EHExceptionInst *exn = findExceptionInBlock(lpad); + if (exn) return findSelectorForException(exn); + + // Okay, if that failed, look for one in an obvious successor. If + // we find one, we'll fix the IR by moving things back to the + // landing pad. + + bool dominates = true; // does the lpad dominate the exn call + BasicBlock *nonDominated = 0; // if not, the first non-dominated block + BasicBlock *lastDominated = 0; // and the block which branched to it + + BasicBlock *exnBlock = lpad; + + // We need to protect against lpads that lead into infinite loops. + SmallPtrSet<BasicBlock*,4> visited; + visited.insert(exnBlock); + + do { + // We're not going to apply this hack to anything more complicated + // than a series of unconditional branches, so if the block + // doesn't terminate in an unconditional branch, just fail. More + // complicated cases can arise when, say, sinking a call into a + // split unwind edge and then inlining it; but that can do almost + // *anything* to the CFG, including leaving the selector + // completely unreachable. The only way to fix that properly is + // to (1) prohibit transforms which move the exception or selector + // values away from the landing pad, e.g. by producing them with + // instructions that are pinned to an edge like a phi, or + // producing them with not-really-instructions, and (2) making + // transforms which split edges deal with that. + BranchInst *branch = dyn_cast<BranchInst>(&exnBlock->back()); + if (!branch || branch->isConditional()) return 0; + + BasicBlock *successor = branch->getSuccessor(0); + + // Fail if we found an infinite loop. + if (!visited.insert(successor)) return 0; + + // If the successor isn't dominated by exnBlock: + if (!successor->getSinglePredecessor()) { + // We don't want to have to deal with threading the exception + // through multiple levels of phi, so give up if we've already + // followed a non-dominating edge. + if (!dominates) return 0; + + // Otherwise, remember this as a non-dominating edge. + dominates = false; + nonDominated = successor; + lastDominated = exnBlock; } + exnBlock = successor; + + // Can we stop here? + exn = findExceptionInBlock(exnBlock); + } while (!exn); + + // Look for a selector call for the exception we found. + EHSelectorInst *selector = findSelectorForException(exn); + if (!selector) return 0; + + // The easy case is when the landing pad still dominates the + // exception call, in which case we can just move both calls back to + // the landing pad. + if (dominates) { + selector->moveBefore(lpad->getFirstNonPHI()); + exn->moveBefore(selector); return selector; } - return 0; + // Otherwise, we have to split at the first non-dominating block. + // The CFG looks basically like this: + // lpad: + // phis_0 + // insnsAndBranches_1 + // br label %nonDominated + // nonDominated: + // phis_2 + // insns_3 + // %exn = call i8* @llvm.eh.exception() + // insnsAndBranches_4 + // %selector = call @llvm.eh.selector(i8* %exn, ... + // We need to turn this into: + // lpad: + // phis_0 + // %exn0 = call i8* @llvm.eh.exception() + // %selector0 = call @llvm.eh.selector(i8* %exn0, ... + // insnsAndBranches_1 + // br label %split // from lastDominated + // nonDominated: + // phis_2 (without edge from lastDominated) + // %exn1 = call i8* @llvm.eh.exception() + // %selector1 = call i8* @llvm.eh.selector(i8* %exn1, ... + // br label %split + // split: + // phis_2 (edge from lastDominated, edge from split) + // %exn = phi ... + // %selector = phi ... + // insns_3 + // insnsAndBranches_4 + + assert(nonDominated); + assert(lastDominated); + + // First, make clones of the intrinsics to go in lpad. + EHExceptionInst *lpadExn = cast<EHExceptionInst>(exn->clone()); + EHSelectorInst *lpadSelector = cast<EHSelectorInst>(selector->clone()); + lpadSelector->setArgOperand(0, lpadExn); + lpadSelector->insertBefore(lpad->getFirstNonPHI()); + lpadExn->insertBefore(lpadSelector); + + // Split the non-dominated block. + BasicBlock *split = + nonDominated->splitBasicBlock(nonDominated->getFirstNonPHI(), + nonDominated->getName() + ".lpad-fix"); + + // Redirect the last dominated branch there. + cast<BranchInst>(lastDominated->back()).setSuccessor(0, split); + + // Move the existing intrinsics to the end of the old block. + selector->moveBefore(&nonDominated->back()); + exn->moveBefore(selector); + + Instruction *splitIP = &split->front(); + + // For all the phis in nonDominated, make a new phi in split to join + // that phi with the edge from lastDominated. + for (BasicBlock::iterator + i = nonDominated->begin(), e = nonDominated->end(); i != e; ++i) { + PHINode *phi = dyn_cast<PHINode>(i); + if (!phi) break; + + PHINode *splitPhi = PHINode::Create(phi->getType(), 2, phi->getName(), + splitIP); + phi->replaceAllUsesWith(splitPhi); + splitPhi->addIncoming(phi, nonDominated); + splitPhi->addIncoming(phi->removeIncomingValue(lastDominated), + lastDominated); + } + + // Make new phis for the exception and selector. + PHINode *exnPhi = PHINode::Create(exn->getType(), 2, "", splitIP); + exn->replaceAllUsesWith(exnPhi); + selector->setArgOperand(0, exn); // except for this use + exnPhi->addIncoming(exn, nonDominated); + exnPhi->addIncoming(lpadExn, lastDominated); + + PHINode *selectorPhi = PHINode::Create(selector->getType(), 2, "", splitIP); + selector->replaceAllUsesWith(selectorPhi); + selectorPhi->addIncoming(selector, nonDominated); + selectorPhi->addIncoming(lpadSelector, lastDominated); + + return lpadSelector; } namespace { @@ -726,18 +894,6 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI) { // Leave lifetime markers for the static alloca's, scoping them to the // function we just inlined. if (!IFI.StaticAllocas.empty()) { - // Also preserve the call graph, if applicable. - CallGraphNode *StartCGN = 0, *EndCGN = 0, *CallerNode = 0; - if (CallGraph *CG = IFI.CG) { - Function *Start = Intrinsic::getDeclaration(Caller->getParent(), - Intrinsic::lifetime_start); - Function *End = Intrinsic::getDeclaration(Caller->getParent(), - Intrinsic::lifetime_end); - StartCGN = CG->getOrInsertFunction(Start); - EndCGN = CG->getOrInsertFunction(End); - CallerNode = (*CG)[Caller]; - } - IRBuilder<> builder(FirstNewBlock->begin()); for (unsigned ai = 0, ae = IFI.StaticAllocas.size(); ai != ae; ++ai) { AllocaInst *AI = IFI.StaticAllocas[ai]; diff --git a/test/Transforms/Inline/inline_invoke.ll b/test/Transforms/Inline/inline_invoke.ll index 5f657387c2..2a1b8836c7 100644 --- a/test/Transforms/Inline/inline_invoke.ll +++ b/test/Transforms/Inline/inline_invoke.ll @@ -16,6 +16,8 @@ declare void @_ZN1AD1Ev(%struct.A*) declare void @use(i32) nounwind +declare void @opaque() + declare i8* @llvm.eh.exception() nounwind readonly declare i32 @llvm.eh.selector(i8*, i8*, ...) nounwind @@ -217,8 +219,8 @@ eh.resume: ; CHECK: call void @llvm.eh.resume(i8* [[EXNJ1]], i32 [[SELJ1]]) -;; Test 2 - Don't make invalid IR for inlines into landing pads without eh.exception calls +;; Test 2 - Don't make invalid IR for inlines into landing pads without eh.exception calls define void @test2_out() uwtable ssp { entry: invoke void @test0_in() @@ -243,3 +245,92 @@ lpad: ; CHECK-NEXT: unwind label %[[LPAD2]] ; CHECK: invoke void @_ZN1AD1Ev(%struct.A* [[A]]) ; CHECK-NEXT: unwind label %[[LPAD]] + + +;; Test 3 - Deal correctly with split unwind edges. +define void @test3_out() uwtable ssp { +entry: + invoke void @test0_in() + to label %ret unwind label %lpad + +ret: + ret void + +lpad: + br label %lpad.cont + +lpad.cont: + %exn = call i8* @llvm.eh.exception() nounwind + %eh.selector = call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* %exn, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*)) nounwind + call void @_ZSt9terminatev() + unreachable +} + +; CHECK: define void @test3_out() +; CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* {{%.*}}, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i32 0, i8* bitcast (i8** @_ZTIi to i8*)) +; CHECK-NEXT: invoke void @_ZN1AD1Ev( +; CHECK-NEXT: to label %[[L:[^\s]+]] unwind +; CHECK: [[L]]: +; CHECK-NEXT: br label %[[JOIN:[^\s]+]] +; CHECK: [[JOIN]]: +; CHECK-NEXT: phi +; CHECK-NEXT: phi +; CHECK-NEXT: br label %lpad.cont +; CHECK: lpad.cont: +; CHECK-NEXT: call void @_ZSt9terminatev() + + +;; Test 4 - Split unwind edges with a dominance problem +define void @test4_out() uwtable ssp { +entry: + invoke void @test0_in() + to label %cont unwind label %lpad.crit + +cont: + invoke void @opaque() + to label %ret unwind label %lpad + +ret: + ret void + +lpad.crit: + call void @opaque() nounwind + br label %lpad + +lpad: + %phi = phi i32 [ 0, %lpad.crit ], [ 1, %cont ] + %exn = call i8* @llvm.eh.exception() nounwind + %eh.selector = call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* %exn, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*)) nounwind + call void @use(i32 %phi) + call void @_ZSt9terminatev() + unreachable +} + +; CHECK: define void @test4_out() +; CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* {{%.*}}, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i32 0, i8* bitcast (i8** @_ZTIi to i8*)) +; CHECK-NEXT: invoke void @_ZN1AD1Ev( +; CHECK-NEXT: to label %[[L:[^\s]+]] unwind +; CHECK: [[L]]: +; CHECK-NEXT: br label %[[JOIN:[^\s]+]] +; CHECK: invoke void @opaque() +; CHECK-NEXT: unwind label %lpad +; CHECK: lpad.crit: +; CHECK-NEXT: call i8* @llvm.eh.exception() +; CHECK-NEXT: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* %4, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*)) +; CHECK-NEXT: br label %[[JOIN]] +; CHECK: [[JOIN]]: +; CHECK-NEXT: phi i8* +; CHECK-NEXT: phi i32 +; CHECK-NEXT: call void @opaque() nounwind +; CHECK-NEXT: br label %[[FIX:[^\s]+]] +; CHECK: lpad: +; CHECK-NEXT: [[T0:%.*]] = phi i32 [ 1, %cont ] +; CHECK-NEXT: call i8* @llvm.eh.exception() nounwind +; CHECK-NEXT: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* %exn, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*)) +; CHECK-NEXT: br label %[[FIX]] +; CHECK: [[FIX]]: +; CHECK-NEXT: [[T1:%.*]] = phi i32 [ [[T0]], %lpad ], [ 0, %[[JOIN]] ] +; CHECK-NEXT: phi i8* +; CHECK-NEXT: phi i32 +; CHECK-NEXT: call void @use(i32 [[T1]]) +; CHECK-NEXT: call void @_ZSt9terminatev() |