Skip to content

Commit

Permalink
[X86] Fix using the SJLJ jump table on x86_64
Browse files Browse the repository at this point in the history
The previous version didn't work if the jump table base address didn't
fit in 32 bit, since it was encoded as an immediate offset. And in case
the jump table is encoded as 32 bit label differences, we need to
load and add them to the table base first.

This solves the first half of the issues mentioned in PR34720.

Also fix some of the errors pointed out by -verify-machineinstrs, by
using GR32_NOSPRegClass.

Differential Revision: https://reviews.llvm.org/D38333

llvm-svn: 314876
  • Loading branch information
mstorsjo committed Oct 4, 2017
1 parent 68ea360 commit e14145d
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 11 deletions.
75 changes: 65 additions & 10 deletions llvm/lib/Target/X86/X86ISelLowering.cpp
Expand Up @@ -26653,8 +26653,8 @@ X86TargetLowering::EmitSjLjDispatchBlock(MachineInstr &MI,
SetupEntryBlockForSjLj(MI, BB, DispatchBB, FI);

// Create the jump table and associated information
MachineJumpTableInfo *JTI =
MF->getOrCreateJumpTableInfo(getJumpTableEncoding());
unsigned JTE = getJumpTableEncoding();
MachineJumpTableInfo *JTI = MF->getOrCreateJumpTableInfo(JTE);
unsigned MJTI = JTI->createJumpTableIndex(LPadList);

const X86RegisterInfo &RI = TII->getRegisterInfo();
Expand All @@ -26677,21 +26677,76 @@ X86TargetLowering::EmitSjLjDispatchBlock(MachineInstr &MI,
.addRegMask(RI.getNoPreservedMask());
}

unsigned IReg = MRI->createVirtualRegister(&X86::GR32RegClass);
// IReg is used as an index in a memory operand and therefore can't be SP
unsigned IReg = MRI->createVirtualRegister(&X86::GR32_NOSPRegClass);
addFrameReference(BuildMI(DispatchBB, DL, TII->get(X86::MOV32rm), IReg), FI,
Subtarget.is64Bit() ? 8 : 4);
BuildMI(DispatchBB, DL, TII->get(X86::CMP32ri))
.addReg(IReg)
.addImm(LPadList.size());
BuildMI(DispatchBB, DL, TII->get(X86::JAE_1)).addMBB(TrapBB);

BuildMI(DispContBB, DL,
TII->get(Subtarget.is64Bit() ? X86::JMP64m : X86::JMP32m))
.addReg(0)
.addImm(Subtarget.is64Bit() ? 8 : 4)
.addReg(IReg)
.addJumpTableIndex(MJTI)
.addReg(0);
if (Subtarget.is64Bit()) {
unsigned BReg = MRI->createVirtualRegister(&X86::GR64RegClass);
unsigned IReg64 = MRI->createVirtualRegister(&X86::GR64_NOSPRegClass);

// leaq .LJTI0_0(%rip), BReg
BuildMI(DispContBB, DL, TII->get(X86::LEA64r), BReg)
.addReg(X86::RIP)
.addImm(1)
.addReg(0)
.addJumpTableIndex(MJTI)
.addReg(0);
// movzx IReg64, IReg
BuildMI(DispContBB, DL, TII->get(TargetOpcode::SUBREG_TO_REG), IReg64)
.addImm(0)
.addReg(IReg)
.addImm(X86::sub_32bit);

switch (JTE) {
case MachineJumpTableInfo::EK_BlockAddress:
// jmpq *(BReg,IReg64,8)
BuildMI(DispContBB, DL, TII->get(X86::JMP64m))
.addReg(BReg)
.addImm(8)
.addReg(IReg64)
.addImm(0)
.addReg(0);
break;
case MachineJumpTableInfo::EK_LabelDifference32: {
unsigned OReg = MRI->createVirtualRegister(&X86::GR32RegClass);
unsigned OReg64 = MRI->createVirtualRegister(&X86::GR64RegClass);
unsigned TReg = MRI->createVirtualRegister(&X86::GR64RegClass);

// movl (BReg,IReg64,4), OReg
BuildMI(DispContBB, DL, TII->get(X86::MOV32rm), OReg)
.addReg(BReg)
.addImm(4)
.addReg(IReg64)
.addImm(0)
.addReg(0);
// movsx OReg64, OReg
BuildMI(DispContBB, DL, TII->get(X86::MOVSX64rr32), OReg64).addReg(OReg);
// addq BReg, OReg64, TReg
BuildMI(DispContBB, DL, TII->get(X86::ADD64rr), TReg)
.addReg(OReg64)
.addReg(BReg);
// jmpq *TReg
BuildMI(DispContBB, DL, TII->get(X86::JMP64r)).addReg(TReg);
break;
}
default:
llvm_unreachable("Unexpected jump table encoding");
}
} else {
// jmpl *.LJTI0_0(,IReg,4)
BuildMI(DispContBB, DL, TII->get(X86::JMP32m))
.addReg(0)
.addImm(4)
.addReg(IReg)
.addJumpTableIndex(MJTI)
.addReg(0);
}

// Add the jump table entries as successors to the MBB.
SmallPtrSet<MachineBasicBlock *, 8> SeenMBBs;
Expand Down
18 changes: 17 additions & 1 deletion llvm/test/CodeGen/X86/sjlj-eh.ll
@@ -1,5 +1,6 @@
; RUN: llc -mtriple i386-windows-gnu -exception-model sjlj -filetype asm -o - %s | FileCheck %s
; RUN: llc -mtriple x86_64-windows-gnu -exception-model sjlj -filetype asm -o - %s | FileCheck %s -check-prefix CHECK-X64
; RUN: llc -mtriple x86_64-linux -exception-model sjlj -filetype asm -o - %s | FileCheck %s -check-prefix CHECK-X64-LINUX

declare void @_Z20function_that_throwsv()
declare i32 @__gxx_personality_sj0(...)
Expand Down Expand Up @@ -116,4 +117,19 @@ try.cont:
; CHECK-X64: ud2
; CHECK-X64: [[CONT]]:
; *Handlers[UFC.__callsite]
; CHECK-X64: jmpq *.LJTI
; CHECK-X64: leaq .[[TABLE:LJTI[0-9]+_[0-9]+]](%rip), %rcx
; CHECK-X64: movl (%rcx,%rax,4), %eax
; CHECK-X64: cltq
; CHECK-X64: addq %rcx, %rax
; CHECK-X64: jmpq *%rax

; CHECK-X64-LINUX: .[[RESUME:LBB[0-9]+_[0-9]+]]:
; assert(UFC.__callsite < 1);
; CHECK-X64-LINUX: movl -120(%rbp), %eax
; CHECK-X64-LINUX: cmpl $1, %eax
; CHECK-X64-LINUX: jb .[[CONT:LBB[0-9]+_[0-9]+]]
; CHECK-X64-LINUX: ud2
; CHECK-X64-LINUX: [[CONT]]:
; *Handlers[UFC.__callsite]
; CHECK-X64-LINUX: leaq .[[TABLE:LJTI[0-9]+_[0-9]+]](%rip), %rcx
; CHECK-X64-LINUX: jmpq *(%rcx,%rax,8)

0 comments on commit e14145d

Please sign in to comment.