Skip to content

Commit 4ea46c3

Browse files
authored
cranelift: Implement table_addr in interpreter (#4433)
1 parent 03ece34 commit 4ea46c3

File tree

2 files changed

+165
-1
lines changed

2 files changed

+165
-1
lines changed
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
test interpret
2+
test run
3+
target x86_64
4+
target s390x
5+
target aarch64
6+
7+
function %set_get_i64(i64 vmctx, i64, i64) -> i64 {
8+
gv0 = vmctx
9+
gv1 = load.i64 notrap aligned gv0
10+
gv2 = load.i64 notrap aligned gv0 +8
11+
table0 = dynamic gv1, element_size 8, bound gv2, index_type i64
12+
13+
block0(v0: i64, v1: i64, v2: i64):
14+
v3 = table_addr.i64 table0, v1, +0
15+
store.i64 v2, v3
16+
v4 = load.i64 v3
17+
return v4
18+
}
19+
; heap: static, size=0x1000, ptr=vmctx+0, bound=vmctx+8
20+
; run: %set_get_i64(0, 1) == 1
21+
; run: %set_get_i64(0, 10) == 10
22+
; run: %set_get_i64(1, 1) == 1
23+
; run: %set_get_i64(1, 0xC0FFEEEE_DECAFFFF) == 0xC0FFEEEE_DECAFFFF
24+
; run: %set_get_i64(10, 1) == 1
25+
; run: %set_get_i64(10, 0xC0FFEEEE_DECAFFFF) == 0xC0FFEEEE_DECAFFFF
26+
27+
28+
function %set_get_i32(i64 vmctx, i64, i32) -> i32 {
29+
gv0 = vmctx
30+
gv1 = load.i64 notrap aligned gv0
31+
gv2 = load.i64 notrap aligned gv0 +8
32+
table0 = dynamic gv1, element_size 8, bound gv2, index_type i64
33+
34+
block0(v0: i64, v1: i64, v2: i32):
35+
;; Note here the offset +4
36+
v3 = table_addr.i64 table0, v1, +4
37+
store.i32 v2, v3
38+
v4 = load.i32 v3
39+
return v4
40+
}
41+
; heap: static, size=0x1000, ptr=vmctx+0, bound=vmctx+8
42+
; run: %set_get_i32(0, 1) == 1
43+
; run: %set_get_i32(0, 10) == 10
44+
; run: %set_get_i32(1, 1) == 1
45+
; run: %set_get_i32(1, 0xC0FFEEEE) == 0xC0FFEEEE
46+
; run: %set_get_i32(10, 1) == 1
47+
; run: %set_get_i32(10, 0xC0FFEEEE) == 0xC0FFEEEE
48+
49+
50+
function %set_get_i8(i64 vmctx, i64, i8) -> i8 {
51+
gv0 = vmctx
52+
gv1 = load.i64 notrap aligned gv0
53+
gv2 = load.i64 notrap aligned gv0 +8
54+
table0 = dynamic gv1, element_size 1, bound gv2, index_type i64
55+
56+
block0(v0: i64, v1: i64, v2: i8):
57+
v3 = table_addr.i64 table0, v1, +0
58+
store.i8 v2, v3
59+
v4 = load.i8 v3
60+
return v4
61+
}
62+
; heap: static, size=2, ptr=vmctx+0, bound=vmctx+8
63+
; run: %set_get_i8(0, 1) == 1
64+
; run: %set_get_i8(0, 0xC0) == 0xC0
65+
; run: %set_get_i8(1, 1) == 1
66+
; run: %set_get_i8(1, 0xFF) == 0xFF
67+
68+
69+
70+
function %large_elm_size(i64 vmctx, i64, i64, i8) -> i8 {
71+
gv0 = vmctx
72+
gv1 = load.i64 notrap aligned gv0
73+
gv2 = load.i64 notrap aligned gv0 +8
74+
table0 = dynamic gv1, element_size 10240, bound gv2, index_type i64
75+
76+
block0(v0: i64, v1: i64, v2: i64, v3: i8):
77+
v4 = table_addr.i64 table0, v1, +0
78+
v5 = iadd.i64 v4, v2
79+
store.i8 v3, v5
80+
v6 = load.i8 v5
81+
return v6
82+
}
83+
; heap: static, size=0xC800, ptr=vmctx+0, bound=vmctx+8
84+
; run: %large_elm_size(0, 0, 1) == 1
85+
; run: %large_elm_size(1, 0, 0xC0) == 0xC0
86+
; run: %large_elm_size(0, 1, 1) == 1
87+
; run: %large_elm_size(1, 1, 0xFF) == 0xFF
88+
; run: %large_elm_size(0, 127, 1) == 1
89+
; run: %large_elm_size(1, 127, 0xFF) == 0xFF
90+
; run: %large_elm_size(0, 10239, 1) == 1
91+
; run: %large_elm_size(1, 10239, 0xBB) == 0xBB
92+
93+
94+
; Tests writing a i64 which covers 8 table entries at once
95+
; Loads the first byte and the last to confirm that the slots were written
96+
function %multi_elm_write(i64 vmctx, i64, i64) -> i8, i8 {
97+
gv0 = vmctx
98+
gv1 = load.i64 notrap aligned gv0
99+
gv2 = load.i64 notrap aligned gv0 +8
100+
table0 = dynamic gv1, element_size 1, bound gv2, index_type i64
101+
102+
block0(v0: i64, v1: i64, v2: i64):
103+
v3 = table_addr.i64 table0, v1, +0
104+
v4 = table_addr.i64 table0, v1, +7
105+
store.i64 v2, v3
106+
v5 = load.i8 v3
107+
v6 = load.i8 v4
108+
return v5, v6
109+
}
110+
; heap: static, size=16, ptr=vmctx+0, bound=vmctx+8
111+
112+
;; When writing these test cases keep in mind that s390x is big endian!
113+
;; We just make sure that the first and last byte are the same to deal with that.
114+
; run: %multi_elm_write(0, 0xC0FFEEEE_FFEEEEC0) == [0xC0, 0xC0]
115+
; run: %multi_elm_write(1, 0xAABBCCDD_EEFF00AA) == [0xAA, 0xAA]
116+
117+
118+
119+
function %heap_table(i64 vmctx, i64, i64, i64) -> i64 {
120+
gv0 = vmctx
121+
gv1 = load.i64 notrap aligned gv0
122+
gv2 = load.i64 notrap aligned gv0 +8
123+
heap0 = dynamic gv1, bound gv2, offset_guard 0, index_type i64
124+
table0 = dynamic gv1, element_size 9, bound gv2, index_type i64
125+
126+
block0(v0: i64, v1: i64, v2: i64, v3: i64):
127+
; v1 - heap offset (bytes)
128+
; v2 - table offset (elements)
129+
; v3 - store/load value
130+
v4 = heap_addr.i64 heap0, v1, 0
131+
v5 = table_addr.i64 table0, v2, +2
132+
133+
; Store via heap, load via table
134+
store.i64 v3, v4
135+
v6 = load.i64 v5
136+
137+
return v6
138+
}
139+
; heap: static, size=0x1000, ptr=vmctx+0, bound=vmctx+8
140+
; run: %heap_table(2, 0, 0xAABBCCDD_EEFF0011) == 0xAABBCCDD_EEFF0011
141+
; run: %heap_table(11, 1, 0xC0FFEEEE_DECAFFFF) == 0xC0FFEEEE_DECAFFFF
142+
; run: %heap_table(20, 2, 1) == 1
143+
; run: %heap_table(29, 3, -10) == -10

cranelift/interpreter/src/step.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,28 @@ where
410410
}
411411
Opcode::GetPinnedReg => unimplemented!("GetPinnedReg"),
412412
Opcode::SetPinnedReg => unimplemented!("SetPinnedReg"),
413-
Opcode::TableAddr => unimplemented!("TableAddr"),
413+
Opcode::TableAddr => {
414+
if let InstructionData::TableAddr { table, offset, .. } = inst {
415+
let table = &state.get_current_function().tables[table];
416+
let base = state.resolve_global_value(table.base_gv)?;
417+
let bound = state.resolve_global_value(table.bound_gv)?;
418+
let index_ty = table.index_type;
419+
let element_size = V::int(u64::from(table.element_size) as i128, index_ty)?;
420+
let inst_offset = V::int(i32::from(offset) as i128, index_ty)?;
421+
422+
let byte_offset = arg(0)?.mul(element_size.clone())?.add(inst_offset)?;
423+
let bound_bytes = bound.mul(element_size)?;
424+
if byte_offset.gt(&bound_bytes)? {
425+
return Ok(ControlFlow::Trap(CraneliftTrap::User(
426+
TrapCode::HeapOutOfBounds,
427+
)));
428+
}
429+
430+
assign(base.add(byte_offset)?)
431+
} else {
432+
unreachable!()
433+
}
434+
}
414435
Opcode::Iconst => assign(Value::int(imm().into_int()?, ctrl_ty)?),
415436
Opcode::F32const => assign(imm()),
416437
Opcode::F64const => assign(imm()),

0 commit comments

Comments
 (0)