diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h --- a/llvm/include/llvm/CodeGen/TargetLowering.h +++ b/llvm/include/llvm/CodeGen/TargetLowering.h @@ -1652,6 +1652,10 @@ virtual bool isJumpTableRelative() const; + /// Whether the default case should be included in the list of MBB jump table + /// destinations. It will be the final element in the list. + virtual bool isDefaultInJumpTable() const { return false; } + /// Return true if a mulh[s|u] node for a specific type is cheaper than /// a multiply followed by a shift. This is false by default. virtual bool isMulhCheaperThanMulShift(EVT Type) const { return false; } diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -10216,13 +10216,16 @@ } } - if (FallthroughUnreachable) { - // Skip the range check if the fallthrough block is unreachable. + const TargetLowering &TLI = DAG.getTargetLoweringInfo(); + + // Skip the range check if the jump table itself will handle the default + // case or if the fallthrough block is unreachable. + if (TLI.isDefaultInJumpTable() || FallthroughUnreachable) JTH->OmitRangeCheck = true; - } if (!JTH->OmitRangeCheck) addSuccessorWithProb(CurMBB, Fallthrough, FallthroughProb); + addSuccessorWithProb(CurMBB, JumpMBB, JumpProb); CurMBB->normalizeSuccProbs(); diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -1911,10 +1911,14 @@ MachineBasicBlock *PHIBB = PHI->getParent(); assert(PHI->isPHI() && "This is not a machine PHI node that we are updating!"); - // "default" BB. We can go there only from header BB. - if (PHIBB == SDB->SL->JTCases[i].second.Default) - PHI.addReg(FuncInfo->PHINodesToUpdate[pi].second) - .addMBB(SDB->SL->JTCases[i].first.HeaderBB); + // "default" BB. We can go there only from header BB, unless the jump + // table includes the default destination. + if (PHIBB == SDB->SL->JTCases[i].second.Default) { + auto *SrcMBB = TLI->isDefaultInJumpTable() + ? SDB->SL->JTCases[i].second.MBB + : SDB->SL->JTCases[i].first.HeaderBB; + PHI.addReg(FuncInfo->PHINodesToUpdate[pi].second).addMBB(SrcMBB); + } // JT BB. Just iterate over successors here if (FuncInfo->MBB->isSuccessor(PHIBB)) PHI.addReg(FuncInfo->PHINodesToUpdate[pi].second).addMBB(FuncInfo->MBB); diff --git a/llvm/lib/CodeGen/SwitchLoweringUtils.cpp b/llvm/lib/CodeGen/SwitchLoweringUtils.cpp --- a/llvm/lib/CodeGen/SwitchLoweringUtils.cpp +++ b/llvm/lib/CodeGen/SwitchLoweringUtils.cpp @@ -11,8 +11,9 @@ // //===----------------------------------------------------------------------===// -#include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/SwitchLoweringUtils.h" +#include "llvm/CodeGen/MachineJumpTableInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/Target/TargetMachine.h" using namespace llvm; @@ -196,6 +197,7 @@ unsigned NumCmps = 0; std::vector Table; DenseMap JTProbs; + MachineFunction *CurMF = FuncInfo.MF; // Initialize probabilities in JTProbs. for (unsigned I = First; I <= Last; ++I) @@ -221,6 +223,9 @@ JTProbs[Clusters[I].MBB] += Clusters[I].Prob; } + if (CurMF->getSubtarget().getTargetLowering()->isDefaultInJumpTable()) + Table.push_back(DefaultMBB); + unsigned NumDests = JTProbs.size(); if (TLI->isSuitableForBitTests(NumDests, NumCmps, Clusters[First].Low->getValue(), @@ -231,7 +236,6 @@ // Create the MBB that will load from and jump through the table. // Note: We create it here, but it's not inserted into the function yet. - MachineFunction *CurMF = FuncInfo.MF; MachineBasicBlock *JumpTableMBB = CurMF->CreateMachineBasicBlock(SI->getParent()); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h @@ -71,6 +71,7 @@ bool *Fast) const override; bool isIntDivCheap(EVT VT, AttributeList Attr) const override; bool isVectorLoadExtDesirable(SDValue ExtVal) const override; + bool isDefaultInJumpTable() const override; EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context, EVT VT) const override; bool getTgtMemIntrinsic(IntrinsicInfo &Info, const CallInst &I, diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -606,6 +606,8 @@ (ExtT == MVT::v2i64 && MemT == MVT::v2i32); } +bool WebAssemblyTargetLowering::isDefaultInJumpTable() const { return true; } + EVT WebAssemblyTargetLowering::getSetCCResultType(const DataLayout &DL, LLVMContext &C, EVT VT) const { @@ -1279,11 +1281,6 @@ for (auto MBB : MBBs) Ops.push_back(DAG.getBasicBlock(MBB)); - // TODO: For now, we just pick something arbitrary for a default case for now. - // We really want to sniff out the guard and put in the real default case (and - // delete the guard). - Ops.push_back(DAG.getBasicBlock(MBBs[0])); - return DAG.getNode(WebAssemblyISD::BR_TABLE, DL, MVT::Other, Ops); } diff --git a/llvm/test/CodeGen/WebAssembly/cfg-stackify.ll b/llvm/test/CodeGen/WebAssembly/cfg-stackify.ll --- a/llvm/test/CodeGen/WebAssembly/cfg-stackify.ll +++ b/llvm/test/CodeGen/WebAssembly/cfg-stackify.ll @@ -382,14 +382,9 @@ ; CHECK-LABEL: test4: ; CHECK-NEXT: .functype test4 (i32) -> (){{$}} -; CHECK: block {{$}} ; CHECK-NEXT: block {{$}} -; CHECK: br_if 0, $pop{{[0-9]+}}{{$}} -; CHECK: br 1{{$}} -; CHECK-NEXT: .LBB{{[0-9]+}}_2: -; CHECK-NEXT: end_block{{$}} ; CHECK-NEXT: br_table $0, 0, 0, 0, 0, 0, 0{{$}} -; CHECK-NEXT: .LBB{{[0-9]+}}_3: +; CHECK-NEXT: .LBB{{[0-9]+}}_1: ; CHECK-NEXT: end_block{{$}} ; CHECK-NEXT: return{{$}} define void @test4(i32 %t) { @@ -649,20 +644,17 @@ ; CHECK: br_if 0, {{[^,]+}}{{$}} ; CHECK-NEXT: end_loop{{$}} ; CHECK-NEXT: block {{$}} -; CHECK: br_if 0, {{[^,]+}}{{$}} -; CHECK: br 3{{$}} -; CHECK-NEXT: .LBB{{[0-9]+}}_7: -; CHECK-NEXT: end_block{{$}} -; CHECK: block {{$}} -; CHECK-NEXT: br_table $0, 0, 3, 1, 2, 0 -; CHECK-NEXT: .LBB{{[0-9]+}}_8: +; CHECK-NEXT: i32.const +; CHECK-NEXT: i32.add $push[[DEST:[0-9]+]]=, +; CHECK-NEXT: br_table $pop[[DEST]], 0, 3, 1, 2, 3 +; CHECK-NEXT: .LBB{{[0-9]+}}_6: ; CHECK-NEXT: end_block{{$}} ; CHECK-NEXT: end_loop{{$}} ; CHECK-NEXT: return{{$}} -; CHECK-NEXT: .LBB{{[0-9]+}}_9: +; CHECK-NEXT: .LBB{{[0-9]+}}_7: ; CHECK-NEXT: end_block{{$}} ; CHECK: br 0{{$}} -; CHECK-NEXT: .LBB{{[0-9]+}}_10: +; CHECK-NEXT: .LBB{{[0-9]+}}_8: ; CHECK-NEXT: end_loop{{$}} define void @test10() { bb0: @@ -767,25 +759,17 @@ ; CHECK-LABEL: test12: ; CHECK: .LBB{{[0-9]+}}_1: -; CHECK-NEXT: loop {{$}} -; CHECK-NEXT: block {{$}} ; CHECK-NEXT: block {{$}} +; CHECK-NEXT: loop {{$}} ; CHECK-NEXT: block {{$}} -; CHECK: br_if 0, {{[^,]+}}{{$}} -; CHECK: br_if 2, {{[^,]+}}{{$}} -; CHECK: br_if 1, {{[^,]+}}{{$}} -; CHECK-NEXT: br 2{{$}} -; CHECK-NEXT: .LBB{{[0-9]+}}_4: +; CHECK: br_table $pop{{[0-9]+}}, 0, 2, 2, 2, 0, 2{{$}} +; CHECK-NEXT: .LBB{{[0-9]+}}_2: ; CHECK-NEXT: end_block{{$}} -; CHECK-NEXT: br_table $2, 1, 0, 0, 0, 1, 1{{$}} -; CHECK-NEXT: .LBB{{[0-9]+}}_5: +; CHECK: br +; CHECK-NEXT: .LBB{{[0-9]+}}_3: +; CHECK-NEXT: end_loop{{$}} ; CHECK-NEXT: end_block{{$}} ; CHECK-NEXT: return{{$}} -; CHECK-NEXT: .LBB{{[0-9]+}}_6: -; CHECK-NEXT: end_block{{$}} -; CHECK: br 0{{$}} -; CHECK-NEXT: .LBB{{[0-9]+}}_7: -; CHECK-NEXT: end_loop{{$}} define void @test12(i8* %arg) { bb: br label %bb1 diff --git a/llvm/test/CodeGen/WebAssembly/indirectbr.ll b/llvm/test/CodeGen/WebAssembly/indirectbr.ll --- a/llvm/test/CodeGen/WebAssembly/indirectbr.ll +++ b/llvm/test/CodeGen/WebAssembly/indirectbr.ll @@ -13,18 +13,20 @@ ; Just check the barest skeleton of the structure ; CHECK-LABEL: test1: +; CHECK: block +; CHECK: block +; CHECK: block +; CHECK: block ; CHECK: i32.load -; CHECK: i32.load $[[DEST:.+]]= +; CHECK: i32.const $push[[OFF:[0-9]+]]=, -2 +; CHECK: i32.add $push[[DEST:[0-9]+]]=, {{.*}}, $pop[[OFF]] +; CHECK: br_table $pop[[DEST]] ; CHECK: loop ; CHECK: block ; CHECK: block -; CHECK: end_block ; CHECK: block ; CHECK: block -; CHECK: br_table $[[DEST]] -; CHECK: end_block -; CHECK: end_block -; CHECK: i32.load $[[DEST]]= +; CHECK: br_table ; CHECK: end_loop ; CHECK: test1.targets: diff --git a/llvm/test/CodeGen/WebAssembly/stack-insts.ll b/llvm/test/CodeGen/WebAssembly/stack-insts.ll --- a/llvm/test/CodeGen/WebAssembly/stack-insts.ll +++ b/llvm/test/CodeGen/WebAssembly/stack-insts.ll @@ -8,7 +8,7 @@ ; Tests if br_table is printed correctly with a tab. ; CHECK-LABEL: test0: -; CHECK: br_table {0, 1, 0, 1, 0} +; CHECK: br_table {0, 1, 0, 1, 2} define void @test0(i32 %n) { entry: switch i32 %n, label %sw.epilog [ diff --git a/llvm/test/CodeGen/WebAssembly/switch.ll b/llvm/test/CodeGen/WebAssembly/switch.ll --- a/llvm/test/CodeGen/WebAssembly/switch.ll +++ b/llvm/test/CodeGen/WebAssembly/switch.ll @@ -21,20 +21,20 @@ ; CHECK: block {{$}} ; CHECK: block {{$}} ; CHECK: block {{$}} -; CHECK: br_table {{[^,]+}}, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 4, 5, 0{{$}} -; CHECK: .LBB{{[0-9]+}}_2: +; CHECK: br_table {{[^,]+}}, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 4, 5, 6{{$}} +; CHECK: .LBB{{[0-9]+}}_1: ; CHECK: call foo0{{$}} -; CHECK: .LBB{{[0-9]+}}_3: +; CHECK: .LBB{{[0-9]+}}_2: ; CHECK: call foo1{{$}} -; CHECK: .LBB{{[0-9]+}}_4: +; CHECK: .LBB{{[0-9]+}}_3: ; CHECK: call foo2{{$}} -; CHECK: .LBB{{[0-9]+}}_5: +; CHECK: .LBB{{[0-9]+}}_4: ; CHECK: call foo3{{$}} -; CHECK: .LBB{{[0-9]+}}_6: +; CHECK: .LBB{{[0-9]+}}_5: ; CHECK: call foo4{{$}} -; CHECK: .LBB{{[0-9]+}}_7: +; CHECK: .LBB{{[0-9]+}}_6: ; CHECK: call foo5{{$}} -; CHECK: .LBB{{[0-9]+}}_8: +; CHECK: .LBB{{[0-9]+}}_7: ; CHECK: return{{$}} define void @bar32(i32 %n) { entry: @@ -101,20 +101,20 @@ ; CHECK: block {{$}} ; CHECK: block {{$}} ; CHECK: block {{$}} -; CHECK: br_table {{[^,]+}}, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 4, 5, 0{{$}} -; CHECK: .LBB{{[0-9]+}}_2: +; CHECK: br_table {{[^,]+}}, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 4, 5, 6{{$}} +; CHECK: .LBB{{[0-9]+}}_1: ; CHECK: call foo0{{$}} -; CHECK: .LBB{{[0-9]+}}_3: +; CHECK: .LBB{{[0-9]+}}_2: ; CHECK: call foo1{{$}} -; CHECK: .LBB{{[0-9]+}}_4: +; CHECK: .LBB{{[0-9]+}}_3: ; CHECK: call foo2{{$}} -; CHECK: .LBB{{[0-9]+}}_5: +; CHECK: .LBB{{[0-9]+}}_4: ; CHECK: call foo3{{$}} -; CHECK: .LBB{{[0-9]+}}_6: +; CHECK: .LBB{{[0-9]+}}_5: ; CHECK: call foo4{{$}} -; CHECK: .LBB{{[0-9]+}}_7: +; CHECK: .LBB{{[0-9]+}}_6: ; CHECK: call foo5{{$}} -; CHECK: .LBB{{[0-9]+}}_8: +; CHECK: .LBB{{[0-9]+}}_7: ; CHECK: return{{$}} define void @bar64(i64 %n) { entry: