diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp index 09d8b0274e54..66ac17982081 100644 --- a/llvm/lib/CodeGen/CodeGenPrepare.cpp +++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp @@ -15,12 +15,10 @@ #include "llvm/CodeGen/Passes.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/BlockFrequencyInfo.h" #include "llvm/Analysis/BranchProbabilityInfo.h" -#include "llvm/Analysis/CFG.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/ProfileSummaryInfo.h" @@ -55,10 +53,8 @@ #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/BuildLibCalls.h" #include "llvm/Transforms/Utils/BypassSlowDivision.h" -#include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Transforms/Utils/SimplifyLibCalls.h" -#include "llvm/Transforms/Utils/ValueMapper.h" using namespace llvm; using namespace llvm::PatternMatch; @@ -226,7 +222,6 @@ class TypePromotionTransaction; unsigned CreatedInstCost); bool splitBranchCondition(Function &F); bool simplifyOffsetableRelocate(Instruction &I); - bool splitIndirectCriticalEdges(Function &F); }; } @@ -301,10 +296,6 @@ bool CodeGenPrepare::runOnFunction(Function &F) { if (!DisableBranchOpts) EverMadeChange |= splitBranchCondition(F); - // Split some critical edges where one of the sources is an indirect branch, - // to help generate sane code for PHIs involving such edges. - EverMadeChange |= splitIndirectCriticalEdges(F); - bool MadeChange = true; while (MadeChange) { MadeChange = false; @@ -438,152 +429,6 @@ BasicBlock *CodeGenPrepare::findDestBlockOfMergeableEmptyBlock(BasicBlock *BB) { return DestBB; } -// Return the unique indirectbr predecessor of a block. This may return null -// even if such a predecessor exists, if it's not useful for splitting. -// If a predecessor is found, OtherPreds will contain all other (non-indirectbr) -// predecessors of BB. -static BasicBlock * -findIBRPredecessor(BasicBlock *BB, SmallVectorImpl &OtherPreds) { - // If the block doesn't have any PHIs, we don't care about it, since there's - // no point in splitting it. - PHINode *PN = dyn_cast(BB->begin()); - if (!PN) - return nullptr; - - // Verify we have exactly one IBR predecessor. - // Conservatively bail out if one of the other predecessors is not a "regular" - // terminator (that is, not a switch or a br). - BasicBlock *IBB = nullptr; - for (unsigned Pred = 0, E = PN->getNumIncomingValues(); Pred != E; ++Pred) { - BasicBlock *PredBB = PN->getIncomingBlock(Pred); - TerminatorInst *PredTerm = PredBB->getTerminator(); - switch (PredTerm->getOpcode()) { - case Instruction::IndirectBr: - if (IBB) - return nullptr; - IBB = PredBB; - break; - case Instruction::Br: - case Instruction::Switch: - OtherPreds.push_back(PredBB); - continue; - default: - return nullptr; - } - } - - return IBB; -} - -// Split critical edges where the source of the edge is an indirectbr -// instruction. This isn't always possible, but we can handle some easy cases. -// This is useful because MI is unable to split such critical edges, -// which means it will not be able to sink instructions along those edges. -// This is especially painful for indirect branches with many successors, where -// we end up having to prepare all outgoing values in the origin block. -// -// Our normal algorithm for splitting critical edges requires us to update -// the outgoing edges of the edge origin block, but for an indirectbr this -// is hard, since it would require finding and updating the block addresses -// the indirect branch uses. But if a block only has a single indirectbr -// predecessor, with the others being regular branches, we can do it in a -// different way. -// Say we have A -> D, B -> D, I -> D where only I -> D is an indirectbr. -// We can split D into D0 and D1, where D0 contains only the PHIs from D, -// and D1 is the D block body. We can then duplicate D0 as D0A and D0B, and -// create the following structure: -// A -> D0A, B -> D0A, I -> D0B, D0A -> D1, D0B -> D1 -bool CodeGenPrepare::splitIndirectCriticalEdges(Function &F) { - // Check whether the function has any indirectbrs, and collect which blocks - // they may jump to. Since most functions don't have indirect branches, - // this lowers the common case's overhead to O(Blocks) instead of O(Edges). - SmallSetVector Targets; - for (auto &BB : F) { - auto *IBI = dyn_cast(BB.getTerminator()); - if (!IBI) - continue; - - for (unsigned Succ = 0, E = IBI->getNumSuccessors(); Succ != E; ++Succ) - Targets.insert(IBI->getSuccessor(Succ)); - } - - if (Targets.empty()) - return false; - - bool Changed = false; - for (BasicBlock *Target : Targets) { - SmallVector OtherPreds; - BasicBlock *IBRPred = findIBRPredecessor(Target, OtherPreds); - if (!IBRPred) - continue; - - // Don't even think about ehpads/landingpads. - Instruction *FirstNonPHI = Target->getFirstNonPHI(); - if (FirstNonPHI->isEHPad() || Target->isLandingPad()) - continue; - - BasicBlock *BodyBlock = Target->splitBasicBlock(FirstNonPHI, ".split"); - // It's possible Target was its own successor through an indirectbr. - // In this case, the indirectbr now comes from BodyBlock. - if (IBRPred == Target) - IBRPred = BodyBlock; - - // At this point Target only has PHIs, and BodyBlock has the rest of the - // block's body. Create a copy of Target that will be used by the "direct" - // preds. - ValueToValueMapTy VMap; - BasicBlock *DirectSucc = CloneBasicBlock(Target, VMap, ".clone", &F); - - for (BasicBlock *Pred : OtherPreds) - Pred->getTerminator()->replaceUsesOfWith(Target, DirectSucc); - - // Ok, now fix up the PHIs. We know the two blocks only have PHIs, and that - // they are clones, so the number of PHIs are the same. - // (a) Remove the edge coming from IBRPred from the "Direct" PHI - // (b) Leave that as the only edge in the "Indirect" PHI. - // (c) Merge the two in the body block. - BasicBlock::iterator Indirect = Target->begin(), - End = Target->getFirstNonPHI()->getIterator(); - BasicBlock::iterator Direct = DirectSucc->begin(); - BasicBlock::iterator MergeInsert = BodyBlock->getFirstInsertionPt(); - - assert(&*End == Target->getTerminator() && - "Block was expected to only contain PHIs"); - - while (Indirect != End) { - PHINode *DirPHI = cast(Direct); - PHINode *IndPHI = cast(Indirect); - - // Now, clean up - the direct block shouldn't get the indirect value, - // and vice versa. - DirPHI->removeIncomingValue(IBRPred); - Direct++; - - // Advance the pointer here, to avoid invalidation issues when the old - // PHI is erased. - Indirect++; - - PHINode *NewIndPHI = PHINode::Create(IndPHI->getType(), 1, "ind", IndPHI); - NewIndPHI->addIncoming(IndPHI->getIncomingValueForBlock(IBRPred), - IBRPred); - - // Create a PHI in the body block, to merge the direct and indirect - // predecessors. - PHINode *MergePHI = - PHINode::Create(IndPHI->getType(), 2, "merge", &*MergeInsert); - MergePHI->addIncoming(NewIndPHI, Target); - MergePHI->addIncoming(DirPHI, DirectSucc); - - IndPHI->replaceAllUsesWith(MergePHI); - IndPHI->eraseFromParent(); - } - - Changed = true; - } - - return Changed; -} - /// Eliminate blocks that contain only PHI nodes, debug info directives, and an /// unconditional branch. Passes before isel (e.g. LSR/loopsimplify) often split /// edges in ways that are non-optimal for isel. Start by eliminating these diff --git a/llvm/test/CodeGen/ARM/indirectbr.ll b/llvm/test/CodeGen/ARM/indirectbr.ll index 90defad43a7d..d15ef14b4493 100644 --- a/llvm/test/CodeGen/ARM/indirectbr.ll +++ b/llvm/test/CodeGen/ARM/indirectbr.ll @@ -47,7 +47,6 @@ L3: ; preds = %L4, %bb2 br label %L2 L2: ; preds = %L3, %bb2 -; THUMB-LABEL: %L1.clone ; THUMB: muls %res.2 = phi i32 [ %res.1, %L3 ], [ 1, %bb2 ] ; [#uses=1] %phitmp = mul i32 %res.2, 6 ; [#uses=1] diff --git a/llvm/test/CodeGen/MSP430/indirectbr2.ll b/llvm/test/CodeGen/MSP430/indirectbr2.ll index 55598b97d912..b0b4f1cbfd24 100644 --- a/llvm/test/CodeGen/MSP430/indirectbr2.ll +++ b/llvm/test/CodeGen/MSP430/indirectbr2.ll @@ -5,7 +5,7 @@ define internal i16 @foo(i16 %i) nounwind { entry: %tmp1 = getelementptr inbounds [5 x i8*], [5 x i8*]* @C.0.2070, i16 0, i16 %i ; [#uses=1] %gotovar.4.0 = load i8*, i8** %tmp1, align 4 ; [#uses=1] -; CHECK: br .LC.0.2070(r15) +; CHECK: br .LC.0.2070(r12) indirectbr i8* %gotovar.4.0, [label %L5, label %L4, label %L3, label %L2, label %L1] L5: ; preds = %bb2 diff --git a/llvm/test/CodeGen/PowerPC/indirectbr.ll b/llvm/test/CodeGen/PowerPC/indirectbr.ll index c040d7859a8b..d1e03ca7773a 100644 --- a/llvm/test/CodeGen/PowerPC/indirectbr.ll +++ b/llvm/test/CodeGen/PowerPC/indirectbr.ll @@ -17,35 +17,23 @@ entry: bb2: ; preds = %entry, %bb3 %gotovar.4.0 = phi i8* [ %gotovar.4.0.pre, %bb3 ], [ %0, %entry ] ; [#uses=1] ; PIC: mtctr +; PIC-NEXT: li +; PIC-NEXT: li +; PIC-NEXT: li +; PIC-NEXT: li ; PIC-NEXT: bctr -; PIC: li -; PIC: b LBB -; PIC: li -; PIC: b LBB -; PIC: li -; PIC: b LBB -; PIC: li -; PIC: b LBB ; STATIC: mtctr +; STATIC-NEXT: li +; STATIC-NEXT: li +; STATIC-NEXT: li +; STATIC-NEXT: li ; STATIC-NEXT: bctr -; STATIC: li -; STATIC: b LBB -; STATIC: li -; STATIC: b LBB -; STATIC: li -; STATIC: b LBB -; STATIC: li -; STATIC: b LBB ; PPC64: mtctr +; PPC64-NEXT: li +; PPC64-NEXT: li +; PPC64-NEXT: li +; PPC64-NEXT: li ; PPC64-NEXT: bctr -; PPC64: li -; PPC64: b LBB -; PPC64: li -; PPC64: b LBB -; PPC64: li -; PPC64: b LBB -; PPC64: li -; PPC64: b LBB indirectbr i8* %gotovar.4.0, [label %L5, label %L4, label %L3, label %L2, label %L1] bb3: ; preds = %entry diff --git a/llvm/test/Transforms/CodeGenPrepare/computedgoto.ll b/llvm/test/Transforms/CodeGenPrepare/computedgoto.ll deleted file mode 100644 index 06621e3b1dfb..000000000000 --- a/llvm/test/Transforms/CodeGenPrepare/computedgoto.ll +++ /dev/null @@ -1,254 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -codegenprepare -S < %s | FileCheck %s -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-unknown-linux-gnu" - -declare void @use(i32) local_unnamed_addr -declare void @useptr([2 x i8*]*) local_unnamed_addr - -; CHECK: @simple.targets = constant [2 x i8*] [i8* blockaddress(@simple, %bb0), i8* blockaddress(@simple, %bb1)], align 16 -@simple.targets = constant [2 x i8*] [i8* blockaddress(@simple, %bb0), i8* blockaddress(@simple, %bb1)], align 16 - -; CHECK: @multi.targets = constant [2 x i8*] [i8* blockaddress(@multi, %bb0), i8* blockaddress(@multi, %bb1)], align 16 -@multi.targets = constant [2 x i8*] [i8* blockaddress(@multi, %bb0), i8* blockaddress(@multi, %bb1)], align 16 - -; CHECK: @loop.targets = constant [2 x i8*] [i8* blockaddress(@loop, %bb0), i8* blockaddress(@loop, %bb1)], align 16 -@loop.targets = constant [2 x i8*] [i8* blockaddress(@loop, %bb0), i8* blockaddress(@loop, %bb1)], align 16 - -; CHECK: @nophi.targets = constant [2 x i8*] [i8* blockaddress(@nophi, %bb0), i8* blockaddress(@nophi, %bb1)], align 16 -@nophi.targets = constant [2 x i8*] [i8* blockaddress(@nophi, %bb0), i8* blockaddress(@nophi, %bb1)], align 16 - -; Check that we break the critical edge when an jump table has only one use. -define void @simple(i32* nocapture readonly %p) { -; CHECK-LABEL: @simple( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[INCDEC_PTR:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 1 -; CHECK-NEXT: [[INITVAL:%.*]] = load i32, i32* [[P]], align 4 -; CHECK-NEXT: [[INITOP:%.*]] = load i32, i32* [[INCDEC_PTR]], align 4 -; CHECK-NEXT: switch i32 [[INITOP]], label [[EXIT:%.*]] [ -; CHECK-NEXT: i32 0, label [[BB0_CLONE:%.*]] -; CHECK-NEXT: i32 1, label [[BB1_CLONE:%.*]] -; CHECK-NEXT: ] -; CHECK: bb0: -; CHECK-NEXT: br label [[DOTSPLIT:%.*]] -; CHECK: .split: -; CHECK-NEXT: [[MERGE:%.*]] = phi i32* [ [[PTR:%.*]], [[BB0:%.*]] ], [ [[INCDEC_PTR]], [[BB0_CLONE]] ] -; CHECK-NEXT: [[MERGE2:%.*]] = phi i32 [ 0, [[BB0]] ], [ [[INITVAL]], [[BB0_CLONE]] ] -; CHECK-NEXT: tail call void @use(i32 [[MERGE2]]) -; CHECK-NEXT: br label [[INDIRECTGOTO:%.*]] -; CHECK: bb1: -; CHECK-NEXT: br label [[DOTSPLIT3:%.*]] -; CHECK: .split3: -; CHECK-NEXT: [[MERGE5:%.*]] = phi i32* [ [[PTR]], [[BB1:%.*]] ], [ [[INCDEC_PTR]], [[BB1_CLONE]] ] -; CHECK-NEXT: [[MERGE7:%.*]] = phi i32 [ 1, [[BB1]] ], [ [[INITVAL]], [[BB1_CLONE]] ] -; CHECK-NEXT: tail call void @use(i32 [[MERGE7]]) -; CHECK-NEXT: br label [[INDIRECTGOTO]] -; CHECK: indirectgoto: -; CHECK-NEXT: [[P_ADDR_SINK:%.*]] = phi i32* [ [[MERGE5]], [[DOTSPLIT3]] ], [ [[MERGE]], [[DOTSPLIT]] ] -; CHECK-NEXT: [[PTR]] = getelementptr inbounds i32, i32* [[P_ADDR_SINK]], i64 1 -; CHECK-NEXT: [[NEWP:%.*]] = load i32, i32* [[P_ADDR_SINK]], align 4 -; CHECK-NEXT: [[IDX:%.*]] = sext i32 [[NEWP]] to i64 -; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* @simple.targets, i64 0, i64 [[IDX]] -; CHECK-NEXT: [[NEWOP:%.*]] = load i8*, i8** [[ARRAYIDX]], align 8 -; CHECK-NEXT: indirectbr i8* [[NEWOP]], [label [[BB0]], label %bb1] -; CHECK: exit: -; CHECK-NEXT: ret void -; CHECK: bb0.clone: -; CHECK-NEXT: br label [[DOTSPLIT]] -; CHECK: bb1.clone: -; CHECK-NEXT: br label [[DOTSPLIT3]] -; -entry: - %incdec.ptr = getelementptr inbounds i32, i32* %p, i64 1 - %initval = load i32, i32* %p, align 4 - %initop = load i32, i32* %incdec.ptr, align 4 - switch i32 %initop, label %exit [ - i32 0, label %bb0 - i32 1, label %bb1 - ] - -bb0: - %p.addr.0 = phi i32* [ %incdec.ptr, %entry ], [ %ptr, %indirectgoto ] - %opcode.0 = phi i32 [ %initval, %entry ], [ 0, %indirectgoto ] - tail call void @use(i32 %opcode.0) - br label %indirectgoto - -bb1: - %p.addr.1 = phi i32* [ %incdec.ptr, %entry ], [ %ptr, %indirectgoto ] - %opcode.1 = phi i32 [ %initval, %entry ], [ 1, %indirectgoto ] - tail call void @use(i32 %opcode.1) - br label %indirectgoto - -indirectgoto: - %p.addr.sink = phi i32* [ %p.addr.1, %bb1 ], [ %p.addr.0, %bb0 ] - %ptr = getelementptr inbounds i32, i32* %p.addr.sink, i64 1 - %newp = load i32, i32* %p.addr.sink, align 4 - %idx = sext i32 %newp to i64 - %arrayidx = getelementptr inbounds [2 x i8*], [2 x i8*]* @simple.targets, i64 0, i64 %idx - %newop = load i8*, i8** %arrayidx, align 8 - indirectbr i8* %newop, [label %bb0, label %bb1] - -exit: - ret void -} - -; Don't try to break critical edges when several indirectbr point to a single block -define void @multi(i32* nocapture readonly %p) { -; CHECK-LABEL: @multi( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[INCDEC_PTR:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 1 -; CHECK-NEXT: [[INITVAL:%.*]] = load i32, i32* [[P]], align 4 -; CHECK-NEXT: [[INITOP:%.*]] = load i32, i32* [[INCDEC_PTR]], align 4 -; CHECK-NEXT: switch i32 [[INITOP]], label [[EXIT:%.*]] [ -; CHECK-NEXT: i32 0, label [[BB0:%.*]] -; CHECK-NEXT: i32 1, label [[BB1:%.*]] -; CHECK-NEXT: ] -; CHECK: bb0: -; CHECK-NEXT: [[P_ADDR_0:%.*]] = phi i32* [ [[INCDEC_PTR]], [[ENTRY:%.*]] ], [ [[NEXT0:%.*]], [[BB0]] ], [ [[NEXT1:%.*]], [[BB1]] ] -; CHECK-NEXT: [[OPCODE_0:%.*]] = phi i32 [ [[INITVAL]], [[ENTRY]] ], [ 0, [[BB0]] ], [ 1, [[BB1]] ] -; CHECK-NEXT: tail call void @use(i32 [[OPCODE_0]]) -; CHECK-NEXT: [[NEXT0]] = getelementptr inbounds i32, i32* [[P_ADDR_0]], i64 1 -; CHECK-NEXT: [[NEWP0:%.*]] = load i32, i32* [[P_ADDR_0]], align 4 -; CHECK-NEXT: [[IDX0:%.*]] = sext i32 [[NEWP0]] to i64 -; CHECK-NEXT: [[ARRAYIDX0:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* @multi.targets, i64 0, i64 [[IDX0]] -; CHECK-NEXT: [[NEWOP0:%.*]] = load i8*, i8** [[ARRAYIDX0]], align 8 -; CHECK-NEXT: indirectbr i8* [[NEWOP0]], [label [[BB0]], label %bb1] -; CHECK: bb1: -; CHECK-NEXT: [[P_ADDR_1:%.*]] = phi i32* [ [[INCDEC_PTR]], [[ENTRY]] ], [ [[NEXT0]], [[BB0]] ], [ [[NEXT1]], [[BB1]] ] -; CHECK-NEXT: [[OPCODE_1:%.*]] = phi i32 [ [[INITVAL]], [[ENTRY]] ], [ 0, [[BB0]] ], [ 1, [[BB1]] ] -; CHECK-NEXT: tail call void @use(i32 [[OPCODE_1]]) -; CHECK-NEXT: [[NEXT1]] = getelementptr inbounds i32, i32* [[P_ADDR_1]], i64 1 -; CHECK-NEXT: [[NEWP1:%.*]] = load i32, i32* [[P_ADDR_1]], align 4 -; CHECK-NEXT: [[IDX1:%.*]] = sext i32 [[NEWP1]] to i64 -; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* @multi.targets, i64 0, i64 [[IDX1]] -; CHECK-NEXT: [[NEWOP1:%.*]] = load i8*, i8** [[ARRAYIDX1]], align 8 -; CHECK-NEXT: indirectbr i8* [[NEWOP1]], [label [[BB0]], label %bb1] -; CHECK: exit: -; CHECK-NEXT: ret void -; -entry: - %incdec.ptr = getelementptr inbounds i32, i32* %p, i64 1 - %initval = load i32, i32* %p, align 4 - %initop = load i32, i32* %incdec.ptr, align 4 - switch i32 %initop, label %exit [ - i32 0, label %bb0 - i32 1, label %bb1 - ] - -bb0: - %p.addr.0 = phi i32* [ %incdec.ptr, %entry ], [ %next0, %bb0 ], [ %next1, %bb1 ] - %opcode.0 = phi i32 [ %initval, %entry ], [ 0, %bb0 ], [ 1, %bb1 ] - tail call void @use(i32 %opcode.0) - %next0 = getelementptr inbounds i32, i32* %p.addr.0, i64 1 - %newp0 = load i32, i32* %p.addr.0, align 4 - %idx0 = sext i32 %newp0 to i64 - %arrayidx0 = getelementptr inbounds [2 x i8*], [2 x i8*]* @multi.targets, i64 0, i64 %idx0 - %newop0 = load i8*, i8** %arrayidx0, align 8 - indirectbr i8* %newop0, [label %bb0, label %bb1] - -bb1: - %p.addr.1 = phi i32* [ %incdec.ptr, %entry ], [ %next0, %bb0 ], [ %next1, %bb1 ] - %opcode.1 = phi i32 [ %initval, %entry ], [ 0, %bb0 ], [ 1, %bb1 ] - tail call void @use(i32 %opcode.1) - %next1 = getelementptr inbounds i32, i32* %p.addr.1, i64 1 - %newp1 = load i32, i32* %p.addr.1, align 4 - %idx1 = sext i32 %newp1 to i64 - %arrayidx1 = getelementptr inbounds [2 x i8*], [2 x i8*]* @multi.targets, i64 0, i64 %idx1 - %newop1 = load i8*, i8** %arrayidx1, align 8 - indirectbr i8* %newop1, [label %bb0, label %bb1] - -exit: - ret void -} - -; Make sure we do the right thing for cases where the indirectbr branches to -; the block it terminates. -define void @loop(i64* nocapture readonly %p) { -; CHECK-LABEL: @loop( -; CHECK-NEXT: bb0.clone: -; CHECK-NEXT: br label [[DOTSPLIT:%.*]] -; CHECK: bb0: -; CHECK-NEXT: br label [[DOTSPLIT]] -; CHECK: .split: -; CHECK-NEXT: [[MERGE:%.*]] = phi i64 [ [[I_NEXT:%.*]], [[BB0:%.*]] ], [ 0, [[BB0_CLONE:%.*]] ] -; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i64, i64* [[P:%.*]], i64 [[MERGE]] -; CHECK-NEXT: store i64 [[MERGE]], i64* [[TMP0]], align 4 -; CHECK-NEXT: [[I_NEXT]] = add nuw nsw i64 [[MERGE]], 1 -; CHECK-NEXT: [[IDX:%.*]] = srem i64 [[MERGE]], 2 -; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* @loop.targets, i64 0, i64 [[IDX]] -; CHECK-NEXT: [[TARGET:%.*]] = load i8*, i8** [[ARRAYIDX]], align 8 -; CHECK-NEXT: indirectbr i8* [[TARGET]], [label [[BB0]], label %bb1] -; CHECK: bb1: -; CHECK-NEXT: ret void -; -entry: - br label %bb0 - -bb0: - %i = phi i64 [ %i.next, %bb0 ], [ 0, %entry ] - %tmp0 = getelementptr inbounds i64, i64* %p, i64 %i - store i64 %i, i64* %tmp0, align 4 - %i.next = add nuw nsw i64 %i, 1 - %idx = srem i64 %i, 2 - %arrayidx = getelementptr inbounds [2 x i8*], [2 x i8*]* @loop.targets, i64 0, i64 %idx - %target = load i8*, i8** %arrayidx, align 8 - indirectbr i8* %target, [label %bb0, label %bb1] - -bb1: - ret void -} - -; Don't do anything for cases that contain no phis. -define void @nophi(i32* %p) { -; CHECK-LABEL: @nophi( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[INCDEC_PTR:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 1 -; CHECK-NEXT: [[INITOP:%.*]] = load i32, i32* [[INCDEC_PTR]], align 4 -; CHECK-NEXT: switch i32 [[INITOP]], label [[EXIT:%.*]] [ -; CHECK-NEXT: i32 0, label [[BB0:%.*]] -; CHECK-NEXT: i32 1, label [[BB1:%.*]] -; CHECK-NEXT: ] -; CHECK: bb0: -; CHECK-NEXT: tail call void @use(i32 0) -; CHECK-NEXT: br label [[INDIRECTGOTO:%.*]] -; CHECK: bb1: -; CHECK-NEXT: tail call void @use(i32 1) -; CHECK-NEXT: br label [[INDIRECTGOTO]] -; CHECK: indirectgoto: -; CHECK-NEXT: [[SUNKADDR:%.*]] = ptrtoint i32* [[P]] to i64 -; CHECK-NEXT: [[SUNKADDR1:%.*]] = add i64 [[SUNKADDR]], 4 -; CHECK-NEXT: [[SUNKADDR2:%.*]] = inttoptr i64 [[SUNKADDR1]] to i32* -; CHECK-NEXT: [[NEWP:%.*]] = load i32, i32* [[SUNKADDR2]], align 4 -; CHECK-NEXT: [[IDX:%.*]] = sext i32 [[NEWP]] to i64 -; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* @nophi.targets, i64 0, i64 [[IDX]] -; CHECK-NEXT: [[NEWOP:%.*]] = load i8*, i8** [[ARRAYIDX]], align 8 -; CHECK-NEXT: indirectbr i8* [[NEWOP]], [label [[BB0]], label %bb1] -; CHECK: exit: -; CHECK-NEXT: ret void -; -entry: - %incdec.ptr = getelementptr inbounds i32, i32* %p, i64 1 - %initop = load i32, i32* %incdec.ptr, align 4 - switch i32 %initop, label %exit [ - i32 0, label %bb0 - i32 1, label %bb1 - ] - -bb0: - tail call void @use(i32 0) - br label %indirectgoto - -bb1: - tail call void @use(i32 1) - br label %indirectgoto - -indirectgoto: - %newp = load i32, i32* %incdec.ptr, align 4 - %idx = sext i32 %newp to i64 - %arrayidx = getelementptr inbounds [2 x i8*], [2 x i8*]* @nophi.targets, i64 0, i64 %idx - %newop = load i8*, i8** %arrayidx, align 8 - indirectbr i8* %newop, [label %bb0, label %bb1] - -exit: - ret void -}