Add a MachBuffer::defer_trap method (#6011)

* Add a `MachBuffer::defer_trap` method

This commit adds a new method to `MachBuffer` to defer trap opcodes to
the end of a function in a similar manner to how constants are deferred
to the end of the function. This is useful for backends which frequently
use `TrapIf`-style opcodes. Currently a jump is emitted which skips the
next instruction, a trap, and then execution continues normally. While
there isn't any pressing problem with this construction the trap opcode
is in the middle of the instruction stream as opposed to "off on the
side" despite rarely being taken.

With this method in place all the backends (except riscv64 since I
couldn't figure it out easily enough) have a new lowering of their
`TrapIf` opcode. Now a trap is deferred, which returns a label, and then
that label is jumped to when executing the trap. A fixup is then
recorded in `MachBuffer` to get patched later on during emission, or at
the end of the function. Subsequently all `TrapIf` instructions
translate to a single branch plus a single trap at the end of the
function.

I've additionally further updated some more lowerings in the x64 backend
which were explicitly using traps to instead use `TrapIf` where
applicable to avoid jumping over traps mid-function. Other backends
didn't appear to have many jump-over-the-next-trap patterns.

Lots of tests have had their expectations updated here which should
reflect all the traps being sunk to the end of functions.

* Print trap code on all platforms

* Emit traps before constants

* Preserve source location information for traps

* Fix test expectations

* Attempt to fix s390x

The MachBuffer was registering trap codes with the first byte of the
trap, but the SIGILL handler was expecting it to be registered with the
last byte of the trap. Exploit that SIGILL is always represented with a
2-byte instruction and always march 2-backwards for SIGILL, continuing
to march backwards 1 byte for SIGFPE-generating instructions.

* Back out s390x changes

* Back out more s390x bits

* Review comments
This commit is contained in:
Alex Crichton
2023-03-20 16:24:47 -05:00
committed by GitHub
parent 6a03398faf
commit a3b21031d4
52 changed files with 702 additions and 588 deletions

View File

@@ -527,33 +527,33 @@ block0(v0: f32):
; VCode:
; block0:
; fcmp s0, s0
; b.vc 8 ; udf
; b.vs #trap=bad_toint
; fmov s4, #-1
; fcmp s0, s4
; b.gt 8 ; udf
; b.le #trap=int_ovf
; movz w8, #20352, LSL #16
; fmov s18, w8
; fcmp s0, s18
; b.lt 8 ; udf
; b.ge #trap=int_ovf
; fcvtzu w0, s0
; ret
;
; Disassembled:
; block0: ; offset 0x0
; fcmp s0, s0
; b.vc #0xc
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: bad_toint
; b.vs #0x2c
; fmov s4, #-1.00000000
; fcmp s0, s4
; b.gt #0x1c
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; b.le #0x30
; mov w8, #0x4f800000
; fmov s18, w8
; fcmp s0, s18
; b.lt #0x30
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; b.ge #0x34
; fcvtzu w0, s0
; ret
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: bad_toint
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
function %f34(f32) -> i32 {
block0(v0: f32):
@@ -564,35 +564,35 @@ block0(v0: f32):
; VCode:
; block0:
; fcmp s0, s0
; b.vc 8 ; udf
; b.vs #trap=bad_toint
; movz w4, #52992, LSL #16
; fmov s6, w4
; fcmp s0, s6
; b.ge 8 ; udf
; b.lt #trap=int_ovf
; movz w10, #20224, LSL #16
; fmov s20, w10
; fcmp s0, s20
; b.lt 8 ; udf
; b.ge #trap=int_ovf
; fcvtzs w0, s0
; ret
;
; Disassembled:
; block0: ; offset 0x0
; fcmp s0, s0
; b.vc #0xc
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: bad_toint
; b.vs #0x30
; mov w4, #-0x31000000
; fmov s6, w4
; fcmp s0, s6
; b.ge #0x20
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; b.lt #0x34
; mov w10, #0x4f000000
; fmov s20, w10
; fcmp s0, s20
; b.lt #0x34
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; b.ge #0x38
; fcvtzs w0, s0
; ret
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: bad_toint
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
function %f35(f32) -> i64 {
block0(v0: f32):
@@ -603,33 +603,33 @@ block0(v0: f32):
; VCode:
; block0:
; fcmp s0, s0
; b.vc 8 ; udf
; b.vs #trap=bad_toint
; fmov s4, #-1
; fcmp s0, s4
; b.gt 8 ; udf
; b.le #trap=int_ovf
; movz w8, #24448, LSL #16
; fmov s18, w8
; fcmp s0, s18
; b.lt 8 ; udf
; b.ge #trap=int_ovf
; fcvtzu x0, s0
; ret
;
; Disassembled:
; block0: ; offset 0x0
; fcmp s0, s0
; b.vc #0xc
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: bad_toint
; b.vs #0x2c
; fmov s4, #-1.00000000
; fcmp s0, s4
; b.gt #0x1c
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; b.le #0x30
; mov w8, #0x5f800000
; fmov s18, w8
; fcmp s0, s18
; b.lt #0x30
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; b.ge #0x34
; fcvtzu x0, s0
; ret
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: bad_toint
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
function %f36(f32) -> i64 {
block0(v0: f32):
@@ -640,35 +640,35 @@ block0(v0: f32):
; VCode:
; block0:
; fcmp s0, s0
; b.vc 8 ; udf
; b.vs #trap=bad_toint
; movz w4, #57088, LSL #16
; fmov s6, w4
; fcmp s0, s6
; b.ge 8 ; udf
; b.lt #trap=int_ovf
; movz w10, #24320, LSL #16
; fmov s20, w10
; fcmp s0, s20
; b.lt 8 ; udf
; b.ge #trap=int_ovf
; fcvtzs x0, s0
; ret
;
; Disassembled:
; block0: ; offset 0x0
; fcmp s0, s0
; b.vc #0xc
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: bad_toint
; b.vs #0x30
; mov w4, #-0x21000000
; fmov s6, w4
; fcmp s0, s6
; b.ge #0x20
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; b.lt #0x34
; mov w10, #0x5f000000
; fmov s20, w10
; fcmp s0, s20
; b.lt #0x34
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; b.ge #0x38
; fcvtzs x0, s0
; ret
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: bad_toint
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
function %f37(f64) -> i32 {
block0(v0: f64):
@@ -679,33 +679,33 @@ block0(v0: f64):
; VCode:
; block0:
; fcmp d0, d0
; b.vc 8 ; udf
; b.vs #trap=bad_toint
; fmov d4, #-1
; fcmp d0, d4
; b.gt 8 ; udf
; b.le #trap=int_ovf
; movz x8, #16880, LSL #48
; fmov d18, x8
; fcmp d0, d18
; b.lt 8 ; udf
; b.ge #trap=int_ovf
; fcvtzu w0, d0
; ret
;
; Disassembled:
; block0: ; offset 0x0
; fcmp d0, d0
; b.vc #0xc
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: bad_toint
; b.vs #0x2c
; fmov d4, #-1.00000000
; fcmp d0, d4
; b.gt #0x1c
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; b.le #0x30
; mov x8, #0x41f0000000000000
; fmov d18, x8
; fcmp d0, d18
; b.lt #0x30
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; b.ge #0x34
; fcvtzu w0, d0
; ret
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: bad_toint
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
function %f38(f64) -> i32 {
block0(v0: f64):
@@ -716,33 +716,33 @@ block0(v0: f64):
; VCode:
; block0:
; fcmp d0, d0
; b.vc 8 ; udf
; b.vs #trap=bad_toint
; ldr d4, [const(0)]
; fcmp d0, d4
; b.gt 8 ; udf
; b.le #trap=int_ovf
; movz x8, #16864, LSL #48
; fmov d18, x8
; fcmp d0, d18
; b.lt 8 ; udf
; b.ge #trap=int_ovf
; fcvtzs w0, d0
; ret
;
; Disassembled:
; block0: ; offset 0x0
; fcmp d0, d0
; b.vc #0xc
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: bad_toint
; b.vs #0x2c
; ldr d4, #0x38
; fcmp d0, d4
; b.gt #0x1c
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; b.le #0x30
; mov x8, #0x41e0000000000000
; fmov d18, x8
; fcmp d0, d18
; b.lt #0x30
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; b.ge #0x34
; fcvtzs w0, d0
; ret
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: bad_toint
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; .byte 0x00, 0x00, 0x20, 0x00
; .byte 0x00, 0x00, 0xe0, 0xc1
@@ -755,33 +755,33 @@ block0(v0: f64):
; VCode:
; block0:
; fcmp d0, d0
; b.vc 8 ; udf
; b.vs #trap=bad_toint
; fmov d4, #-1
; fcmp d0, d4
; b.gt 8 ; udf
; b.le #trap=int_ovf
; movz x8, #17392, LSL #48
; fmov d18, x8
; fcmp d0, d18
; b.lt 8 ; udf
; b.ge #trap=int_ovf
; fcvtzu x0, d0
; ret
;
; Disassembled:
; block0: ; offset 0x0
; fcmp d0, d0
; b.vc #0xc
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: bad_toint
; b.vs #0x2c
; fmov d4, #-1.00000000
; fcmp d0, d4
; b.gt #0x1c
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; b.le #0x30
; mov x8, #0x43f0000000000000
; fmov d18, x8
; fcmp d0, d18
; b.lt #0x30
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; b.ge #0x34
; fcvtzu x0, d0
; ret
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: bad_toint
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
function %f40(f64) -> i64 {
block0(v0: f64):
@@ -792,35 +792,35 @@ block0(v0: f64):
; VCode:
; block0:
; fcmp d0, d0
; b.vc 8 ; udf
; b.vs #trap=bad_toint
; movz x4, #50144, LSL #48
; fmov d6, x4
; fcmp d0, d6
; b.ge 8 ; udf
; b.lt #trap=int_ovf
; movz x10, #17376, LSL #48
; fmov d20, x10
; fcmp d0, d20
; b.lt 8 ; udf
; b.ge #trap=int_ovf
; fcvtzs x0, d0
; ret
;
; Disassembled:
; block0: ; offset 0x0
; fcmp d0, d0
; b.vc #0xc
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: bad_toint
; b.vs #0x30
; mov x4, #-0x3c20000000000000
; fmov d6, x4
; fcmp d0, d6
; b.ge #0x20
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; b.lt #0x34
; mov x10, #0x43e0000000000000
; fmov d20, x10
; fcmp d0, d20
; b.lt #0x34
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; b.ge #0x38
; fcvtzs x0, d0
; ret
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: bad_toint
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
; .byte 0x1f, 0xc1, 0x00, 0x00 ; trap: int_ovf
function %f41(i32) -> f32 {
block0(v0: i32):