Fix legalization of heap_addrs with 32-bit indices. (#480)
This makes several changes: - It adds an index_type to heap declarations, allowing heaps to specify the type for indexing. This also anticipates 64-bit heap support. - It adds a memory_type to deref global values, allowing deref globals to have types other than pointers. This is used to allow the bound variable in dynamic heaps to have type i32, to match the index type in heaps with i32 index type. - And, it fixes heap legalization to do the bounds check in the heap's index type.
This commit is contained in:
111
cranelift/filetests/isa/x86/legalize-heaps.clif
Normal file
111
cranelift/filetests/isa/x86/legalize-heaps.clif
Normal file
@@ -0,0 +1,111 @@
|
||||
test legalizer
|
||||
target x86_64
|
||||
|
||||
; Test legalization for various forms of heap addresses.
|
||||
|
||||
function %heap_addrs(i32, i64, i64 vmctx) {
|
||||
gv0 = vmctx+64
|
||||
gv1 = vmctx+72
|
||||
gv2 = vmctx+80
|
||||
gv3 = vmctx+88
|
||||
gv4 = deref(gv3): i32
|
||||
|
||||
heap0 = static gv0, min 0x1_0000, bound 0x1_0000_0000, guard 0x8000_0000, index_type i32
|
||||
heap1 = static gv0, guard 0x1000, bound 0x1_0000, index_type i32
|
||||
heap2 = static gv0, min 0x1_0000, bound 0x1_0000_0000, guard 0x8000_0000, index_type i64
|
||||
heap3 = static gv0, guard 0x1000, bound 0x1_0000, index_type i64
|
||||
heap4 = dynamic gv1, min 0x1_0000, bound gv4, guard 0x8000_0000, index_type i32
|
||||
heap5 = dynamic gv1, bound gv4, guard 0x1000, index_type i32
|
||||
heap6 = dynamic gv1, min 0x1_0000, bound gv2, guard 0x8000_0000, index_type i64
|
||||
heap7 = dynamic gv1, bound gv2, guard 0x1000, index_type i64
|
||||
|
||||
; check: heap0 = static gv0, min 0x0001_0000, bound 0x0001_0000_0000, guard 0x8000_0000, index_type i32
|
||||
; check: heap1 = static gv0, min 0, bound 0x0001_0000, guard 4096, index_type i32
|
||||
; check: heap2 = static gv0, min 0x0001_0000, bound 0x0001_0000_0000, guard 0x8000_0000, index_type i64
|
||||
; check: heap3 = static gv0, min 0, bound 0x0001_0000, guard 4096, index_type i64
|
||||
; check: heap4 = dynamic gv1, min 0x0001_0000, bound gv4, guard 0x8000_0000, index_type i32
|
||||
; check: heap5 = dynamic gv1, min 0, bound gv4, guard 4096, index_type i32
|
||||
; check: heap6 = dynamic gv1, min 0x0001_0000, bound gv2, guard 0x8000_0000, index_type i64
|
||||
; check: heap7 = dynamic gv1, min 0, bound gv2, guard 4096, index_type i64
|
||||
|
||||
ebb0(v0: i32, v1: i64, v3: i64):
|
||||
; The fast-path; 32-bit index, static heap with a sufficient bound, no bounds check needed!
|
||||
v4 = heap_addr.i64 heap0, v0, 0
|
||||
; check: v12 = uextend.i64 v0
|
||||
; check: v13 = iadd_imm v3, 64
|
||||
; check: v4 = iadd v13, v12
|
||||
|
||||
v5 = heap_addr.i64 heap1, v0, 0
|
||||
; check: v14 = icmp_imm ugt v0, 0x0001_0000
|
||||
; check: brz v14, ebb1
|
||||
; check: trap heap_oob
|
||||
; check: ebb1:
|
||||
; check: v15 = uextend.i64 v0
|
||||
; check: v16 = iadd_imm.i64 v3, 64
|
||||
; check: v5 = iadd v16, v15
|
||||
|
||||
v6 = heap_addr.i64 heap2, v1, 0
|
||||
; check: v19 = iconst.i64 0x0001_0000_0000
|
||||
; check: v17 = icmp.i64 ugt v1, v19
|
||||
; check: brz v17, ebb2
|
||||
; check: trap heap_oob
|
||||
; check: ebb2:
|
||||
; check: v18 = iadd_imm.i64 v3, 64
|
||||
; check: v6 = iadd v18, v1
|
||||
|
||||
v7 = heap_addr.i64 heap3, v1, 0
|
||||
; check: v20 = icmp_imm.i64 ugt v1, 0x0001_0000
|
||||
; check: brz v20, ebb3
|
||||
; check: trap heap_oob
|
||||
; check: ebb3:
|
||||
; check: v21 = iadd_imm.i64 v3, 64
|
||||
; check: v7 = iadd v21, v1
|
||||
|
||||
v8 = heap_addr.i64 heap4, v0, 0
|
||||
; check: v27 = iadd_imm.i64 v3, 88
|
||||
; check: v28 = load.i32 notrap aligned v27
|
||||
; check: v22 = iadd_imm v28, 0
|
||||
; check: v23 = iadd_imm v22, 0
|
||||
; check: v24 = icmp.i32 ugt v0, v23
|
||||
; check: brz v24, ebb4
|
||||
; check: trap heap_oob
|
||||
; check: ebb4:
|
||||
; check: v25 = uextend.i64 v0
|
||||
; check: v26 = iadd_imm.i64 v3, 72
|
||||
; check: v8 = iadd v26, v25
|
||||
|
||||
v9 = heap_addr.i64 heap5, v0, 0
|
||||
; check: v34 = iadd_imm.i64 v3, 88
|
||||
; check: v35 = load.i32 notrap aligned v34
|
||||
; check: v29 = iadd_imm v35, 0
|
||||
; check: v30 = iadd_imm v29, 0
|
||||
; check: v31 = icmp.i32 ugt v0, v30
|
||||
; check: brz v31, ebb5
|
||||
; check: trap heap_oob
|
||||
; check: ebb5:
|
||||
; check: v32 = uextend.i64 v0
|
||||
; check: v33 = iadd_imm.i64 v3, 72
|
||||
; check: v9 = iadd v33, v32
|
||||
|
||||
v10 = heap_addr.i64 heap6, v1, 0
|
||||
; check: v36 = iadd_imm.i64 v3, 80
|
||||
; check: v37 = iadd_imm v36, 0
|
||||
; check: v38 = icmp.i64 ugt v1, v37
|
||||
; check: brz v38, ebb6
|
||||
; check: trap heap_oob
|
||||
; check: ebb6:
|
||||
; check: v39 = iadd_imm.i64 v3, 72
|
||||
; check: v10 = iadd v39, v1
|
||||
|
||||
v11 = heap_addr.i64 heap7, v1, 0
|
||||
; check: v40 = iadd_imm.i64 v3, 80
|
||||
; check: v41 = iadd_imm v40, 0
|
||||
; check: v42 = icmp.i64 ugt v1, v41
|
||||
; check: brz v42, ebb7
|
||||
; check: trap heap_oob
|
||||
; check: ebb7:
|
||||
; check: v43 = iadd_imm.i64 v3, 72
|
||||
; check: v11 = iadd v43, v1
|
||||
|
||||
return
|
||||
}
|
||||
@@ -17,7 +17,7 @@ ebb1(v1: i64):
|
||||
|
||||
function %deref(i64 vmctx) -> i64 {
|
||||
gv1 = vmctx-16
|
||||
gv2 = deref(gv1)+32
|
||||
gv2 = deref(gv1)+32: i64
|
||||
|
||||
ebb1(v1: i64):
|
||||
v2 = global_value.i64 gv2
|
||||
|
||||
@@ -17,7 +17,7 @@ ebb0(v0: i64):
|
||||
|
||||
function %deref(i64 vmctx) -> i32 {
|
||||
gv3 = vmctx+16
|
||||
gv4 = deref(gv3)-32
|
||||
gv4 = deref(gv3)-32: i32
|
||||
; check: gv4 = deref(gv3)-32
|
||||
ebb0(v0: i64):
|
||||
v1 = global_value.i32 gv4
|
||||
@@ -27,7 +27,7 @@ ebb0(v0: i64):
|
||||
|
||||
; Refer to a global value before it's been declared.
|
||||
function %backref(i64 vmctx) -> i32 {
|
||||
gv1 = deref(gv2)-32
|
||||
gv1 = deref(gv2)-32: i32
|
||||
; check: gv1 = deref(gv2)-32
|
||||
gv2 = vmctx+16
|
||||
; check: gv2 = vmctx+16
|
||||
|
||||
19
cranelift/filetests/verifier/globals.clif
Normal file
19
cranelift/filetests/verifier/globals.clif
Normal file
@@ -0,0 +1,19 @@
|
||||
test verifier
|
||||
target x86_64
|
||||
|
||||
function %deref_base_type(i64 vmctx) {
|
||||
gv0 = vmctx+0
|
||||
gv1 = deref(gv0): i32
|
||||
gv2 = deref(gv1): i32 ; error: deref base gv1 has type i32, which is not the pointer type i64
|
||||
|
||||
ebb0(v0: i64):
|
||||
return
|
||||
}
|
||||
|
||||
function %global_value_wrong_type(i64 vmctx) {
|
||||
gv0 = vmctx+0
|
||||
|
||||
ebb0(v0: i64):
|
||||
v1 = global_value.i32 gv0 ; error: global_value instruction with type i32 references global value with type i64
|
||||
return
|
||||
}
|
||||
45
cranelift/filetests/verifier/heap.clif
Normal file
45
cranelift/filetests/verifier/heap.clif
Normal file
@@ -0,0 +1,45 @@
|
||||
test verifier
|
||||
target x86_64
|
||||
|
||||
function %heap_base_type(i64 vmctx) {
|
||||
gv0 = vmctx+0
|
||||
gv1 = deref(gv0): i32
|
||||
heap0 = static gv1, guard 0x1000, bound 0x1_0000, index_type i32 ; error: heap base has type i32, which is not the pointer type i64
|
||||
|
||||
ebb0(v0: i64):
|
||||
return
|
||||
}
|
||||
|
||||
function %invalid_base(i64 vmctx) {
|
||||
gv0 = vmctx+0
|
||||
heap0 = dynamic gv1, bound gv0, guard 0x1000, index_type i64 ; error: invalid base global value gv1
|
||||
|
||||
ebb0(v0: i64):
|
||||
return
|
||||
}
|
||||
|
||||
function %invalid_bound(i64 vmctx) {
|
||||
gv0 = vmctx+0
|
||||
heap0 = dynamic gv0, bound gv1, guard 0x1000, index_type i64 ; error: invalid bound global value gv1
|
||||
|
||||
ebb0(v0: i64):
|
||||
return
|
||||
}
|
||||
|
||||
function %heap_bound_type(i64 vmctx) {
|
||||
gv0 = vmctx+0
|
||||
gv1 = deref(gv0): i16
|
||||
heap0 = dynamic gv1, bound gv1, guard 0x1000, index_type i32 ; error: heap index type i32 differs from the type of its bound, i16
|
||||
|
||||
ebb0(v0: i64):
|
||||
return
|
||||
}
|
||||
|
||||
function %heap_addr_index_type(i64 vmctx, i64) {
|
||||
gv0 = vmctx+0
|
||||
heap0 = static gv0, guard 0x1000, bound 0x1_0000, index_type i32
|
||||
|
||||
ebb0(v0: i64, v1: i64):
|
||||
v2 = heap_addr.i64 heap0, v1, 0; error: index type i64 differs from heap index type i32
|
||||
return
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
test verifier
|
||||
|
||||
function %deref_cycle() {
|
||||
gv1 = deref(gv2)-32 ; error: deref cycle: [gv1, gv2]
|
||||
gv2 = deref(gv1)
|
||||
gv1 = deref(gv2)-32: i32 ; error: deref cycle: [gv1, gv2]
|
||||
gv2 = deref(gv1): i32
|
||||
|
||||
ebb1:
|
||||
return
|
||||
}
|
||||
|
||||
function %self_cycle() {
|
||||
gv0 = deref(gv0)-32 ; error: deref cycle: [gv0]
|
||||
gv0 = deref(gv0)-32: i32 ; error: deref cycle: [gv0]
|
||||
|
||||
ebb1:
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user