diff --git a/llvm/include/llvm/CodeGen/TargetInstrInfo.h b/llvm/include/llvm/CodeGen/TargetInstrInfo.h --- a/llvm/include/llvm/CodeGen/TargetInstrInfo.h +++ b/llvm/include/llvm/CodeGen/TargetInstrInfo.h @@ -1005,6 +1005,10 @@ return false; } + /// Return an index for MachineJumpTableInfo if \p insn is an indirect jump + /// using a jump table, otherwise -1. + virtual int getJumpTableIndex(const MachineInstr &MI) const { return -1; } + protected: /// Target-dependent implementation for IsCopyInstr. /// If the specific machine instruction is a instruction that moves/copies diff --git a/llvm/lib/CodeGen/MachineBasicBlock.cpp b/llvm/lib/CodeGen/MachineBasicBlock.cpp --- a/llvm/lib/CodeGen/MachineBasicBlock.cpp +++ b/llvm/lib/CodeGen/MachineBasicBlock.cpp @@ -18,6 +18,7 @@ #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineLoopInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/SlotIndexes.h" @@ -664,6 +665,15 @@ getParent()->splice(++NewBefore->getIterator(), getIterator()); } +static int findJumpTableIndex(const MachineBasicBlock &MBB) { + MachineBasicBlock::const_iterator TerminatorI = MBB.getFirstTerminator(); + if (TerminatorI == MBB.end()) + return -1; + const MachineInstr &Terminator = *TerminatorI; + const TargetInstrInfo *TII = MBB.getParent()->getSubtarget().getInstrInfo(); + return TII->getJumpTableIndex(Terminator); +} + void MachineBasicBlock::updateTerminator( MachineBasicBlock *PreviousLayoutSuccessor) { LLVM_DEBUG(dbgs() << "Updating terminators on " << printMBBReference(*this) @@ -1033,6 +1043,50 @@ return SplitBB; } +// Returns `true` if there are possibly other users of the jump table at +// `JumpTableIndex` except for the ones in `IgnoreMBB`. +static bool jumpTableHasOtherUses(const MachineFunction &MF, + const MachineBasicBlock &IgnoreMBB, + int JumpTableIndex) { + assert(JumpTableIndex >= 0 && "need valid index"); + const MachineJumpTableInfo &MJTI = *MF.getJumpTableInfo(); + const MachineJumpTableEntry &MJTE = MJTI.getJumpTables()[JumpTableIndex]; + // Take any basic block from the table; every user of the jump table must + // show up in the predecessor list. + const MachineBasicBlock *MBB = nullptr; + for (MachineBasicBlock *B : MJTE.MBBs) { + if (B != nullptr) { + MBB = B; + break; + } + } + if (MBB == nullptr) + return true; // can't rule out other users if there isn't any block. + const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); + SmallVector Cond; + for (MachineBasicBlock *Pred : MBB->predecessors()) { + if (Pred == &IgnoreMBB) + continue; + MachineBasicBlock *DummyT = nullptr; + MachineBasicBlock *DummyF = nullptr; + Cond.clear(); + if (!TII.analyzeBranch(*Pred, DummyT, DummyF, Cond, + /*AllowModify=*/false)) { + // analyzable direct jump + continue; + } + int PredJTI = findJumpTableIndex(*Pred); + if (PredJTI >= 0) { + if (PredJTI == JumpTableIndex) + return true; + continue; + } + // Be conservative for unanalyzable jumps. + return true; + } + return false; +} + MachineBasicBlock *MachineBasicBlock::SplitCriticalEdge( MachineBasicBlock *Succ, Pass &P, std::vector> *LiveInSets) { @@ -1044,6 +1098,16 @@ DebugLoc DL; // FIXME: this is nowhere MachineBasicBlock *NMBB = MF->CreateMachineBasicBlock(); + + // Is there an indirect jump with jump table? + bool ChangedIndirectJump = false; + int JTI = findJumpTableIndex(*this); + if (JTI >= 0) { + MachineJumpTableInfo &MJTI = *MF->getJumpTableInfo(); + MJTI.ReplaceMBBInJumpTable(JTI, Succ, NMBB); + ChangedIndirectJump = true; + } + MF->insert(std::next(MachineFunction::iterator(this)), NMBB); LLVM_DEBUG(dbgs() << "Splitting critical edge: " << printMBBReference(*this) << " -- " << printMBBReference(*NMBB) << " -- " @@ -1109,7 +1173,9 @@ // as the fallthrough successor if (Succ == PrevFallthrough) PrevFallthrough = NMBB; - updateTerminator(PrevFallthrough); + + if (!ChangedIndirectJump) + updateTerminator(PrevFallthrough); if (Indexes) { SmallVector NewTerminators; @@ -1284,8 +1350,13 @@ if (MF->getTarget().requiresStructuredCFG()) return false; + // Do we have an Indirect jump with a jumptable that we can rewrite? + int JTI = findJumpTableIndex(*this); + if (JTI >= 0 && !jumpTableHasOtherUses(*MF, *this, JTI)) + return true; + // We may need to update this's terminator, but we can't do that if - // analyzeBranch fails. If this uses a jump table, we won't touch it. + // analyzeBranch fails. const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo(); MachineBasicBlock *TBB = nullptr, *FBB = nullptr; SmallVector Cond; diff --git a/llvm/lib/Target/X86/X86InstrInfo.h b/llvm/lib/Target/X86/X86InstrInfo.h --- a/llvm/lib/Target/X86/X86InstrInfo.h +++ b/llvm/lib/Target/X86/X86InstrInfo.h @@ -327,6 +327,8 @@ SmallVectorImpl &Cond, bool AllowModify) const override; + int getJumpTableIndex(const MachineInstr &MI) const override; + std::optional getAddrModeFromMemoryOp(const MachineInstr &MemI, const TargetRegisterInfo *TRI) const override; diff --git a/llvm/lib/Target/X86/X86InstrInfo.cpp b/llvm/lib/Target/X86/X86InstrInfo.cpp --- a/llvm/lib/Target/X86/X86InstrInfo.cpp +++ b/llvm/lib/Target/X86/X86InstrInfo.cpp @@ -3204,6 +3204,65 @@ return AnalyzeBranchImpl(MBB, TBB, FBB, Cond, CondBranches, AllowModify); } +static int getJumpTableIndexFromAddr(const MachineInstr &MI) { + const MCInstrDesc &Desc = MI.getDesc(); + int MemRefBegin = X86II::getMemoryOperandNo(Desc.TSFlags); + assert(MemRefBegin >= 0 && "instr should have memory operand"); + MemRefBegin += X86II::getOperandBias(Desc); + + const MachineOperand &MO = MI.getOperand(MemRefBegin + X86::AddrDisp); + if (!MO.isJTI()) + return -1; + + return MO.getIndex(); +} + +static int getJumpTableIndexFromReg(const MachineRegisterInfo &MRI, + Register Reg) { + if (!Reg.isVirtual()) + return -1; + MachineInstr *MI = MRI.getUniqueVRegDef(Reg); + if (MI == nullptr) + return -1; + unsigned Opcode = MI->getOpcode(); + if (Opcode != X86::LEA64r && Opcode != X86::LEA32r) + return -1; + return getJumpTableIndexFromAddr(*MI); +} + +int X86InstrInfo::getJumpTableIndex(const MachineInstr &MI) const { + unsigned Opcode = MI.getOpcode(); + // Switch-jump pattern for non-PIC code looks like: + // JMP64m $noreg, 8, %X, %jump-table.X, $noreg + if (Opcode == X86::JMP64m || Opcode == X86::JMP32m) { + return getJumpTableIndexFromAddr(MI); + } + // The pattern for PIC code looks like: + // %0 = LEA64r $rip, 1, $noreg, %jump-table.X + // %1 = MOVSX64rm32 %0, 4, XX, 0, $noreg + // %2 = ADD64rr %1, %0 + // JMP64r %2 + if (Opcode == X86::JMP64r || Opcode == X86::JMP32r) { + Register Reg = MI.getOperand(0).getReg(); + if (!Reg.isVirtual()) + return -1; + const MachineFunction &MF = *MI.getParent()->getParent(); + const MachineRegisterInfo &MRI = MF.getRegInfo(); + MachineInstr *Add = MRI.getUniqueVRegDef(Reg); + if (Add == nullptr) + return -1; + if (Add->getOpcode() != X86::ADD64rr && Add->getOpcode() != X86::ADD32rr) + return -1; + int JTI1 = getJumpTableIndexFromReg(MRI, Add->getOperand(1).getReg()); + if (JTI1 >= 0) + return JTI1; + int JTI2 = getJumpTableIndexFromReg(MRI, Add->getOperand(2).getReg()); + if (JTI2 >= 0) + return JTI2; + } + return -1; +} + bool X86InstrInfo::analyzeBranchPredicate(MachineBasicBlock &MBB, MachineBranchPredicate &MBP, bool AllowModify) const { diff --git a/llvm/test/CodeGen/X86/switch-jmp-edge-split.mir b/llvm/test/CodeGen/X86/switch-jmp-edge-split.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/switch-jmp-edge-split.mir @@ -0,0 +1,251 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -mtriple=x86_64-- -run-pass=machine-sink -verify-machineinstrs -o - %s | FileCheck %s + +--- +name: func_no_pic +tracksRegLiveness: true +jumpTable: + kind: block-address + entries: + - id: 0 + blocks: [ '%bb.4', '%bb.1', '%bb.2', '%bb.3' ] +body: | + ; CHECK-LABEL: name: func_no_pic + ; CHECK: bb.0: + ; CHECK-NEXT: successors: %bb.5(0x20000000), %bb.1(0x20000000), %bb.2(0x20000000), %bb.3(0x20000000) + ; CHECK-NEXT: liveins: $edi + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gr64_nosp = COPY $rdi + ; CHECK-NEXT: JMP64m $noreg, 8, [[COPY]], %jump-table.0, $noreg :: (load (s64) from jump-table) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.5: + ; CHECK-NEXT: successors: %bb.4(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[MOV32ri:%[0-9]+]]:gr32 = MOV32ri 42 + ; CHECK-NEXT: JMP_1 %bb.4 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.1: + ; CHECK-NEXT: successors: %bb.4(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[MOV32ri1:%[0-9]+]]:gr32 = MOV32ri 6 + ; CHECK-NEXT: JMP_1 %bb.4 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.2: + ; CHECK-NEXT: successors: %bb.4(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[MOV32ri2:%[0-9]+]]:gr32 = MOV32ri 1 + ; CHECK-NEXT: JMP_1 %bb.4 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.3: + ; CHECK-NEXT: successors: %bb.4(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[MOV32ri3:%[0-9]+]]:gr32 = MOV32ri 92 + ; CHECK-NEXT: JMP_1 %bb.4 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.4: + ; CHECK-NEXT: [[PHI:%[0-9]+]]:gr32 = PHI [[MOV32ri]], %bb.5, [[MOV32ri1]], %bb.1, [[MOV32ri2]], %bb.2, [[MOV32ri3]], %bb.3 + ; CHECK-NEXT: $eax = COPY [[PHI]] + ; CHECK-NEXT: RET 0 + bb.0: + successors: %bb.4, %bb.1, %bb.2, %bb.3 + liveins: $edi + + %0:gr64_nosp = COPY $rdi + ; MachineSink should split the critical edges and sink the next two + ; insns out of the switch-jump header into new less frequently executed + ; blocks. + %1:gr32 = MOV32ri 42 + JMP64m $noreg, 8, %0, %jump-table.0, $noreg :: (load (s64) from jump-table) + + bb.1: + %2:gr32 = MOV32ri 6 + JMP_1 %bb.4 + + bb.2: + %3:gr32 = MOV32ri 1 + JMP_1 %bb.4 + + bb.3: + %4:gr32 = MOV32ri 92 + JMP_1 %bb.4 + + bb.4: + %5:gr32 = PHI %1, %bb.0, %2, %bb.1, %3, %bb.2, %4, %bb.3 + $eax = COPY %5 + RET 0 + +... +--- +name: func_pic +tracksRegLiveness: true +jumpTable: + kind: label-difference32 + entries: + - id: 0 + blocks: [ '%bb.4', '%bb.1', '%bb.2', '%bb.3' ] +body: | + ; CHECK-LABEL: name: func_pic + ; CHECK: bb.0: + ; CHECK-NEXT: successors: %bb.5(0x20000000), %bb.1(0x20000000), %bb.2(0x20000000), %bb.3(0x20000000) + ; CHECK-NEXT: liveins: $edi + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gr64_nosp = COPY $rdi + ; CHECK-NEXT: [[LEA64r:%[0-9]+]]:gr64 = LEA64r $rip, 1, $noreg, %jump-table.0, $noreg + ; CHECK-NEXT: [[MOVSX64rm32_:%[0-9]+]]:gr64 = MOVSX64rm32 [[LEA64r]], 4, [[COPY]], 0, $noreg :: (load (s32) from jump-table) + ; CHECK-NEXT: [[ADD64rr:%[0-9]+]]:gr64 = ADD64rr [[MOVSX64rm32_]], [[LEA64r]], implicit-def dead $eflags + ; CHECK-NEXT: JMP64r killed [[ADD64rr]] + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.5: + ; CHECK-NEXT: successors: %bb.4(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[MOV32ri:%[0-9]+]]:gr32 = MOV32ri 42 + ; CHECK-NEXT: JMP_1 %bb.4 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.1: + ; CHECK-NEXT: successors: %bb.4(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[MOV32ri1:%[0-9]+]]:gr32 = MOV32ri 6 + ; CHECK-NEXT: JMP_1 %bb.4 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.2: + ; CHECK-NEXT: successors: %bb.4(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[MOV32ri2:%[0-9]+]]:gr32 = MOV32ri 1 + ; CHECK-NEXT: JMP_1 %bb.4 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.3: + ; CHECK-NEXT: successors: %bb.4(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[MOV32ri3:%[0-9]+]]:gr32 = MOV32ri 92 + ; CHECK-NEXT: JMP_1 %bb.4 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.4: + ; CHECK-NEXT: [[PHI:%[0-9]+]]:gr32 = PHI [[MOV32ri]], %bb.5, [[MOV32ri1]], %bb.1, [[MOV32ri2]], %bb.2, [[MOV32ri3]], %bb.3 + ; CHECK-NEXT: $eax = COPY [[PHI]] + ; CHECK-NEXT: RET 0 + bb.0: + successors: %bb.4, %bb.1, %bb.2, %bb.3 + liveins: $edi + + %0:gr64_nosp = COPY $rdi + ; MachineSink should split the critical edges and sink the next two + ; insns out of the switch-jump header into new less frequently executed + ; blocks. + %1:gr32 = MOV32ri 42 + %2:gr64 = LEA64r $rip, 1, $noreg, %jump-table.0, $noreg + %3:gr64 = MOVSX64rm32 %2, 4, %0, 0, $noreg :: (load (s32) from jump-table) + %4:gr64 = ADD64rr %3, %2, implicit-def dead $eflags + JMP64r killed %4 + + bb.1: + %5:gr32 = MOV32ri 6 + JMP_1 %bb.4 + + bb.2: + %6:gr32 = MOV32ri 1 + JMP_1 %bb.4 + + bb.3: + %7:gr32 = MOV32ri 92 + JMP_1 %bb.4 + + bb.4: + %8:gr32 = PHI %1, %bb.0, %5, %bb.1, %6, %bb.2, %7, %bb.3 + $eax = COPY %8 + RET 0 + +... +--- +name: multiple_jump_table_users +tracksRegLiveness: true +jumpTable: + kind: block-address + entries: + - id: 0 + blocks: [ '%bb.6', '%bb.3', '%bb.4', '%bb.5' ] +body: | + ; CHECK-LABEL: name: multiple_jump_table_users + ; CHECK: bb.0: + ; CHECK-NEXT: successors: %bb.1(0x40000000), %bb.2(0x40000000) + ; CHECK-NEXT: liveins: $edi + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gr64_nosp = COPY $rdi + ; CHECK-NEXT: CMP64ri8 [[COPY]], 42, implicit-def $eflags + ; CHECK-NEXT: JCC_1 %bb.1, 15, implicit $eflags + ; CHECK-NEXT: JMP_1 %bb.2 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.1: + ; CHECK-NEXT: successors: %bb.6(0x20000000), %bb.3(0x20000000), %bb.4(0x20000000), %bb.5(0x20000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: INLINEASM &"", 1 /* sideeffect attdialect */ + ; CHECK-NEXT: [[MOV32ri:%[0-9]+]]:gr32 = MOV32ri 13 + ; CHECK-NEXT: JMP64m $noreg, 8, [[COPY]], %jump-table.0, $noreg :: (load (s64) from jump-table) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.2: + ; CHECK-NEXT: successors: %bb.6(0x20000000), %bb.3(0x20000000), %bb.4(0x20000000), %bb.5(0x20000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: INLINEASM &"", 1 /* sideeffect attdialect */ + ; CHECK-NEXT: [[MOV32ri1:%[0-9]+]]:gr32 = MOV32ri 42 + ; CHECK-NEXT: JMP64m $noreg, 8, [[COPY]], %jump-table.0, $noreg :: (load (s64) from jump-table) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.3: + ; CHECK-NEXT: successors: %bb.6(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[MOV32ri2:%[0-9]+]]:gr32 = MOV32ri 6 + ; CHECK-NEXT: JMP_1 %bb.6 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.4: + ; CHECK-NEXT: successors: %bb.6(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[MOV32ri3:%[0-9]+]]:gr32 = MOV32ri 1 + ; CHECK-NEXT: JMP_1 %bb.6 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.5: + ; CHECK-NEXT: successors: %bb.6(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[MOV32ri4:%[0-9]+]]:gr32 = MOV32ri 92 + ; CHECK-NEXT: JMP_1 %bb.6 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.6: + ; CHECK-NEXT: [[PHI:%[0-9]+]]:gr32 = PHI [[MOV32ri]], %bb.1, [[MOV32ri1]], %bb.2, [[MOV32ri2]], %bb.3, [[MOV32ri3]], %bb.4, [[MOV32ri4]], %bb.5 + ; CHECK-NEXT: $eax = COPY [[PHI]] + ; CHECK-NEXT: RET 0 + bb.0: + liveins: $edi + %0:gr64_nosp = COPY $rdi + + CMP64ri8 %0:gr64_nosp, 42, implicit-def $eflags + JCC_1 %bb.1, 15, implicit $eflags + JMP_1 %bb.2 + + bb.1: + successors: %bb.6, %bb.3, %bb.4, %bb.5 + INLINEASM &"", 1 /* sideeffect attdialect */ + %1:gr32 = MOV32ri 13 + JMP64m $noreg, 8, %0, %jump-table.0, $noreg :: (load (s64) from jump-table) + + bb.2: + successors: %bb.6, %bb.3, %bb.4, %bb.5 + INLINEASM &"", 1 /* sideeffect attdialect */ + %2:gr32 = MOV32ri 42 + ; This is a 2d user of jump-table.0 . This case is not supported yet; + ; Should not attempt edge splitting. + JMP64m $noreg, 8, %0, %jump-table.0, $noreg :: (load (s64) from jump-table) + + bb.3: + %3:gr32 = MOV32ri 6 + JMP_1 %bb.6 + + bb.4: + %4:gr32 = MOV32ri 1 + JMP_1 %bb.6 + + bb.5: + %5:gr32 = MOV32ri 92 + JMP_1 %bb.6 + + bb.6: + %6:gr32 = PHI %1, %bb.1, %2, %bb.2, %3, %bb.3, %4, %bb.4, %5, %bb.5 + $eax = COPY %6 + RET 0 +... diff --git a/llvm/test/CodeGen/X86/switch-phi-const.ll b/llvm/test/CodeGen/X86/switch-phi-const.ll --- a/llvm/test/CodeGen/X86/switch-phi-const.ll +++ b/llvm/test/CodeGen/X86/switch-phi-const.ll @@ -7,35 +7,37 @@ ; CHECK-LABEL: switch_phi_const: ; CHECK: # %bb.0: # %bb0 ; CHECK-NEXT: # kill: def $edi killed $edi def $rdi -; CHECK-NEXT: leal -1(%rdi), %ecx -; CHECK-NEXT: cmpl $54, %ecx -; CHECK-NEXT: ja .LBB0_8 +; CHECK-NEXT: leal -1(%rdi), %eax +; CHECK-NEXT: cmpl $54, %eax +; CHECK-NEXT: ja .LBB0_9 ; CHECK-NEXT: # %bb.1: # %bb0 -; CHECK-NEXT: movl $42, %eax -; CHECK-NEXT: jmpq *.LJTI0_0(,%rcx,8) -; CHECK-NEXT: .LBB0_2: # %case_7 +; CHECK-NEXT: jmpq *.LJTI0_0(,%rax,8) +; CHECK-NEXT: .LBB0_3: # %case_7 ; CHECK-NEXT: movq g@GOTPCREL(%rip), %rax ; CHECK-NEXT: movl (%rax), %edi ; CHECK-NEXT: movq effect@GOTPCREL(%rip), %rax ; CHECK-NEXT: movl $7, (%rax) -; CHECK-NEXT: .LBB0_3: # %case_1_loop +; CHECK-NEXT: .LBB0_4: # %case_1_loop ; CHECK-NEXT: movq effect@GOTPCREL(%rip), %rax ; CHECK-NEXT: movl $1, (%rax) -; CHECK-NEXT: .LBB0_4: # %case_5 +; CHECK-NEXT: .LBB0_5: # %case_5 ; CHECK-NEXT: movq effect@GOTPCREL(%rip), %rax ; CHECK-NEXT: movl $5, (%rax) -; CHECK-NEXT: .LBB0_5: # %case_13 +; CHECK-NEXT: .LBB0_6: # %case_13 ; CHECK-NEXT: movq effect@GOTPCREL(%rip), %rax ; CHECK-NEXT: movl $13, (%rax) -; CHECK-NEXT: .LBB0_6: # %case_42 +; CHECK-NEXT: .LBB0_7: # %case_42 ; CHECK-NEXT: movq effect@GOTPCREL(%rip), %rax ; CHECK-NEXT: movl %edi, (%rax) ; CHECK-NEXT: movl $55, %eax -; CHECK-NEXT: .LBB0_7: # %case_55 +; CHECK-NEXT: .LBB0_8: # %case_55 ; CHECK-NEXT: movq effect@GOTPCREL(%rip), %rcx ; CHECK-NEXT: movl %eax, (%rcx) -; CHECK-NEXT: .LBB0_8: # %default +; CHECK-NEXT: .LBB0_9: # %default ; CHECK-NEXT: retq +; CHECK-NEXT: .LBB0_2: +; CHECK-NEXT: movl $42, %eax +; CHECK-NEXT: jmp .LBB0_8 bb0: switch i32 %x, label %default [ i32 1, label %case_1_loop @@ -94,34 +96,36 @@ ; CHECK-NEXT: movzbl %dil, %eax ; CHECK-NEXT: leal -1(%rax), %ecx ; CHECK-NEXT: cmpl $54, %ecx -; CHECK-NEXT: ja .LBB1_8 +; CHECK-NEXT: ja .LBB1_9 ; CHECK-NEXT: # %bb.1: # %bb0 -; CHECK-NEXT: movl $3895, %edx # imm = 0xF37 ; CHECK-NEXT: jmpq *.LJTI1_0(,%rcx,8) -; CHECK-NEXT: .LBB1_8: # %default +; CHECK-NEXT: .LBB1_2: +; CHECK-NEXT: movl $3895, %eax # imm = 0xF37 +; CHECK-NEXT: jmp .LBB1_7 +; CHECK-NEXT: .LBB1_9: # %default ; CHECK-NEXT: retq -; CHECK-NEXT: .LBB1_2: # %case_1_loop +; CHECK-NEXT: .LBB1_3: # %case_1_loop ; CHECK-NEXT: movq effect64@GOTPCREL(%rip), %rcx ; CHECK-NEXT: movq $1, (%rcx) -; CHECK-NEXT: .LBB1_3: # %case_5 +; CHECK-NEXT: .LBB1_4: # %case_5 ; CHECK-NEXT: movq effect64@GOTPCREL(%rip), %rcx ; CHECK-NEXT: movq $5, (%rcx) -; CHECK-NEXT: .LBB1_4: # %case_13 +; CHECK-NEXT: .LBB1_5: # %case_13 ; CHECK-NEXT: movq effect64@GOTPCREL(%rip), %rcx ; CHECK-NEXT: movq $13, (%rcx) -; CHECK-NEXT: .LBB1_5: # %case_42 +; CHECK-NEXT: .LBB1_6: # %case_42 +; CHECK-NEXT: movq effect64@GOTPCREL(%rip), %rcx +; CHECK-NEXT: movq %rax, (%rcx) +; CHECK-NEXT: movl $55, %eax +; CHECK-NEXT: .LBB1_7: # %case_55 ; CHECK-NEXT: movq effect64@GOTPCREL(%rip), %rcx ; CHECK-NEXT: movq %rax, (%rcx) -; CHECK-NEXT: movl $55, %edx -; CHECK-NEXT: .LBB1_6: # %case_55 -; CHECK-NEXT: movq effect64@GOTPCREL(%rip), %rax -; CHECK-NEXT: movq %rdx, (%rax) -; CHECK-NEXT: .LBB1_7: # %case_7 +; CHECK-NEXT: .LBB1_8: # %case_7 ; CHECK-NEXT: movq g64@GOTPCREL(%rip), %rax ; CHECK-NEXT: movq (%rax), %rax ; CHECK-NEXT: movq effect64@GOTPCREL(%rip), %rcx ; CHECK-NEXT: movq $7, (%rcx) -; CHECK-NEXT: jmp .LBB1_2 +; CHECK-NEXT: jmp .LBB1_3 bb0: %x_trunc = trunc i32 %x to i8 switch i8 %x_trunc, label %default [