Add uadd_overflow_trap (#5123)
Add a new instruction uadd_overflow_trap, which is a fused version of iadd_ifcout and trapif. Adding this instruction removes a dependency on the iflags type, and would allow us to move closer to removing it entirely. The instruction is defined for the i32 and i64 types only, and is currently only used in the legalization of heap_addr.
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
test compile precise-output
|
||||
target aarch64
|
||||
|
||||
function %f0(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = iconst.i32 127
|
||||
v2 = uadd_overflow_trap v0, v1, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; block0:
|
||||
; movz x3, #127
|
||||
; adds w0, w0, w3
|
||||
; b.lo 8 ; udf
|
||||
; ret
|
||||
|
||||
function %f1(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = iconst.i32 127
|
||||
v2 = uadd_overflow_trap v1, v0, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; block0:
|
||||
; movz x3, #127
|
||||
; adds w0, w3, w0
|
||||
; b.lo 8 ; udf
|
||||
; ret
|
||||
|
||||
function %f2(i32, i32) -> i32 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = uadd_overflow_trap v0, v1, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; block0:
|
||||
; adds w0, w0, w1
|
||||
; b.lo 8 ; udf
|
||||
; ret
|
||||
|
||||
function %f3(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 127
|
||||
v2 = uadd_overflow_trap v0, v1, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; block0:
|
||||
; movz x3, #127
|
||||
; adds x0, x0, x3
|
||||
; b.lo 8 ; udf
|
||||
; ret
|
||||
|
||||
function %f3(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 127
|
||||
v2 = uadd_overflow_trap v1, v0, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; block0:
|
||||
; movz x3, #127
|
||||
; adds x0, x3, x0
|
||||
; b.lo 8 ; udf
|
||||
; ret
|
||||
|
||||
function %f4(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = uadd_overflow_trap v0, v1, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; block0:
|
||||
; adds x0, x0, x1
|
||||
; b.lo 8 ; udf
|
||||
; ret
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
test compile precise-output
|
||||
target riscv64
|
||||
|
||||
function %f0(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = iconst.i32 127
|
||||
v2 = uadd_overflow_trap v0, v1, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; block0:
|
||||
; mv a6,a0
|
||||
; li a0,127
|
||||
; uext.w a2,a6
|
||||
; uext.w a4,a0
|
||||
; add a0,a2,a4
|
||||
; srli t3,a0,32
|
||||
; trap_if t3,user0
|
||||
; ret
|
||||
|
||||
function %f1(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = iconst.i32 127
|
||||
v2 = uadd_overflow_trap v1, v0, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; block0:
|
||||
; li a1,127
|
||||
; uext.w a2,a1
|
||||
; uext.w a4,a0
|
||||
; add a0,a2,a4
|
||||
; srli t3,a0,32
|
||||
; trap_if t3,user0
|
||||
; ret
|
||||
|
||||
function %f2(i32, i32) -> i32 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = uadd_overflow_trap v0, v1, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; block0:
|
||||
; mv a6,a1
|
||||
; uext.w a1,a0
|
||||
; uext.w a3,a6
|
||||
; add a0,a1,a3
|
||||
; srli a7,a0,32
|
||||
; trap_if a7,user0
|
||||
; ret
|
||||
|
||||
function %f3(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 127
|
||||
v2 = uadd_overflow_trap v0, v1, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; block0:
|
||||
; li a1,127
|
||||
; add a2,a0,a1
|
||||
; mv a5,a2
|
||||
; ult a4,a5,a0##ty=i64
|
||||
; mv a2,a5
|
||||
; trap_if a4,user0
|
||||
; mv a0,a2
|
||||
; ret
|
||||
|
||||
function %f3(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 127
|
||||
v2 = uadd_overflow_trap v1, v0, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; block0:
|
||||
; li a1,127
|
||||
; add a0,a1,a0
|
||||
; ult a4,a0,a1##ty=i64
|
||||
; trap_if a4,user0
|
||||
; ret
|
||||
|
||||
function %f4(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = uadd_overflow_trap v0, v1, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; block0:
|
||||
; add a1,a0,a1
|
||||
; mv a4,a1
|
||||
; ult a3,a4,a0##ty=i64
|
||||
; mv a1,a4
|
||||
; trap_if a3,user0
|
||||
; mv a0,a1
|
||||
; ret
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
test compile precise-output
|
||||
target s390x
|
||||
|
||||
function %f0(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = iconst.i32 127
|
||||
v2 = uadd_overflow_trap v0, v1, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; block0:
|
||||
; alfi %r2, 127
|
||||
; jle 6 ; trap
|
||||
; br %r14
|
||||
|
||||
function %f1(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = iconst.i32 127
|
||||
v2 = uadd_overflow_trap v1, v0, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; block0:
|
||||
; alfi %r2, 127
|
||||
; jle 6 ; trap
|
||||
; br %r14
|
||||
|
||||
function %f2(i32, i32) -> i32 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = uadd_overflow_trap v0, v1, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; block0:
|
||||
; alr %r2, %r3
|
||||
; jle 6 ; trap
|
||||
; br %r14
|
||||
|
||||
function %f3(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 127
|
||||
v2 = uadd_overflow_trap v0, v1, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; block0:
|
||||
; algfi %r2, 127
|
||||
; jle 6 ; trap
|
||||
; br %r14
|
||||
|
||||
function %f3(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 127
|
||||
v2 = uadd_overflow_trap v1, v0, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; block0:
|
||||
; algfi %r2, 127
|
||||
; jle 6 ; trap
|
||||
; br %r14
|
||||
|
||||
function %f4(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = uadd_overflow_trap v0, v1, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; block0:
|
||||
; algr %r2, %r3
|
||||
; jle 6 ; trap
|
||||
; br %r14
|
||||
|
||||
103
cranelift/filetests/filetests/isa/x64/uadd_overflow_trap.clif
Normal file
103
cranelift/filetests/filetests/isa/x64/uadd_overflow_trap.clif
Normal file
@@ -0,0 +1,103 @@
|
||||
test compile precise-output
|
||||
target x86_64
|
||||
|
||||
function %f0(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = iconst.i32 127
|
||||
v2 = uadd_overflow_trap v0, v1, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; pushq %rbp
|
||||
; movq %rsp, %rbp
|
||||
; block0:
|
||||
; movq %rdi, %rax
|
||||
; addl %eax, $127, %eax
|
||||
; jnb ; ud2 user0 ;
|
||||
; movq %rbp, %rsp
|
||||
; popq %rbp
|
||||
; ret
|
||||
|
||||
function %f1(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = iconst.i32 127
|
||||
v2 = uadd_overflow_trap v1, v0, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; pushq %rbp
|
||||
; movq %rsp, %rbp
|
||||
; block0:
|
||||
; movq %rdi, %rax
|
||||
; addl %eax, $127, %eax
|
||||
; jnb ; ud2 user0 ;
|
||||
; movq %rbp, %rsp
|
||||
; popq %rbp
|
||||
; ret
|
||||
|
||||
function %f2(i32, i32) -> i32 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = uadd_overflow_trap v0, v1, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; pushq %rbp
|
||||
; movq %rsp, %rbp
|
||||
; block0:
|
||||
; movq %rdi, %rax
|
||||
; addl %eax, %esi, %eax
|
||||
; jnb ; ud2 user0 ;
|
||||
; movq %rbp, %rsp
|
||||
; popq %rbp
|
||||
; ret
|
||||
|
||||
function %f3(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 127
|
||||
v2 = uadd_overflow_trap v0, v1, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; pushq %rbp
|
||||
; movq %rsp, %rbp
|
||||
; block0:
|
||||
; movq %rdi, %rax
|
||||
; addq %rax, $127, %rax
|
||||
; jnb ; ud2 user0 ;
|
||||
; movq %rbp, %rsp
|
||||
; popq %rbp
|
||||
; ret
|
||||
|
||||
function %f3(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 127
|
||||
v2 = uadd_overflow_trap v1, v0, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; pushq %rbp
|
||||
; movq %rsp, %rbp
|
||||
; block0:
|
||||
; movq %rdi, %rax
|
||||
; addq %rax, $127, %rax
|
||||
; jnb ; ud2 user0 ;
|
||||
; movq %rbp, %rsp
|
||||
; popq %rbp
|
||||
; ret
|
||||
|
||||
function %f4(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = uadd_overflow_trap v0, v1, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; pushq %rbp
|
||||
; movq %rsp, %rbp
|
||||
; block0:
|
||||
; movq %rdi, %rax
|
||||
; addq %rax, %rsi, %rax
|
||||
; jnb ; ud2 user0 ;
|
||||
; movq %rbp, %rsp
|
||||
; popq %rbp
|
||||
; ret
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
test run
|
||||
test interpret
|
||||
target x86_64
|
||||
target aarch64
|
||||
target riscv64
|
||||
target s390x
|
||||
|
||||
; NOTE: we don't currently have infrastructure for testing for traps, so these
|
||||
; tests can only test the happy path. Once we eventually have annotations for
|
||||
; expected traps, the cases here should be expanded.
|
||||
|
||||
function %f0(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = iconst.i32 0x7f
|
||||
v2 = uadd_overflow_trap v0, v1, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; run: %f0(0) == 0x7f
|
||||
; run: %f0(0x80) == 0xff
|
||||
|
||||
function %f1(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = iconst.i32 0x7f
|
||||
v2 = uadd_overflow_trap v1, v0, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; run: %f0(0) == 0x7f
|
||||
; run: %f0(0x80) == 0xff
|
||||
|
||||
function %f2(i32, i32) -> i32 {
|
||||
block0(v0: i32, v1: i32):
|
||||
v2 = uadd_overflow_trap v0, v1, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; run: %f2(0, 0) == 0x0
|
||||
; run: %f2(0x80, 0x7f) == 0xff
|
||||
|
||||
function %f3(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 0x7f
|
||||
v2 = uadd_overflow_trap v0, v1, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; run: %f3(0) == 0x7f
|
||||
; run: %f3(0x80) == 0xff
|
||||
|
||||
function %f4(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = iconst.i64 0x7f
|
||||
v2 = uadd_overflow_trap v1, v0, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; run: %f4(0) == 0x7f
|
||||
; run: %f4(0x80) == 0xff
|
||||
|
||||
function %f5(i64, i64) -> i64 {
|
||||
block0(v0: i64, v1: i64):
|
||||
v2 = uadd_overflow_trap v0, v1, user0
|
||||
return v2
|
||||
}
|
||||
|
||||
; run: %f5(0, 0) == 0x0
|
||||
; run: %f5(0x80, 0x7f) == 0xff
|
||||
Reference in New Issue
Block a user