Skip to content

Commit 02e0a91

Browse files
committed
Add pointer arithmetic experiment to tests
While questionable, it highlights some of the things that currently do not inline well.
1 parent c44cbec commit 02e0a91

File tree

3 files changed

+792
-0
lines changed

3 files changed

+792
-0
lines changed
Lines changed: 319 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,319 @@
1+
(module
2+
(type $iii (func (param i32 i32) (result i32)))
3+
(type $iv (func (param i32)))
4+
(type $ii (func (param i32) (result i32)))
5+
(type $iiiiv (func (param i32 i32 i32 i32)))
6+
(type $v (func))
7+
(import "env" "abort" (func $~lib/env/abort (param i32 i32 i32 i32)))
8+
(global $~argc (mut i32) (i32.const 0))
9+
(global $std/pointer/one (mut i32) (i32.const 0))
10+
(global $std/pointer/two (mut i32) (i32.const 0))
11+
(global $std/pointer/add (mut i32) (i32.const 0))
12+
(global $std/pointer/sub (mut i32) (i32.const 0))
13+
(memory $0 1)
14+
(data (i32.const 8) "\0e\00\00\00s\00t\00d\00/\00p\00o\00i\00n\00t\00e\00r\00.\00t\00s")
15+
(export "_setargc" (func $~setargc))
16+
(export "Pointer<Entry>#constructor" (func $std/pointer/Pointer<Entry>#constructor|trampoline))
17+
(export "Pointer<Entry>#get:offset" (func $std/pointer/Pointer<Entry>#get:offset))
18+
(export "Pointer<Entry>#get:value" (func $std/pointer/Pointer<Entry>#get:offset))
19+
(export "memory" (memory $0))
20+
(start $start)
21+
(func $std/pointer/Pointer<Entry>#constructor (; 1 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
22+
(get_local $1)
23+
)
24+
(func $std/pointer/Pointer<Entry>#constructor|trampoline (; 2 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
25+
(block $1of1
26+
(block $0of1
27+
(block $oob
28+
(br_table $0of1 $1of1 $oob
29+
(get_global $~argc)
30+
)
31+
)
32+
(unreachable)
33+
)
34+
(set_local $1
35+
(i32.const 0)
36+
)
37+
)
38+
(call $std/pointer/Pointer<Entry>#constructor
39+
(get_local $0)
40+
(get_local $1)
41+
)
42+
)
43+
(func $~setargc (; 3 ;) (type $iv) (param $0 i32)
44+
(set_global $~argc
45+
(get_local $0)
46+
)
47+
)
48+
(func $std/pointer/Pointer<Entry>#get:offset (; 4 ;) (type $ii) (param $0 i32) (result i32)
49+
(get_local $0)
50+
)
51+
(func $start (; 5 ;) (type $v)
52+
(set_global $std/pointer/one
53+
(call $std/pointer/Pointer<Entry>#constructor
54+
(i32.const 0)
55+
(i32.const 8)
56+
)
57+
)
58+
(set_global $std/pointer/two
59+
(call $std/pointer/Pointer<Entry>#constructor
60+
(i32.const 0)
61+
(i32.const 24)
62+
)
63+
)
64+
(if
65+
(i32.ne
66+
(call $std/pointer/Pointer<Entry>#get:offset
67+
(get_global $std/pointer/one)
68+
)
69+
(i32.const 8)
70+
)
71+
(block
72+
(call $~lib/env/abort
73+
(i32.const 0)
74+
(i32.const 8)
75+
(i32.const 54)
76+
(i32.const 0)
77+
)
78+
(unreachable)
79+
)
80+
)
81+
(if
82+
(i32.ne
83+
(call $std/pointer/Pointer<Entry>#get:offset
84+
(get_global $std/pointer/two)
85+
)
86+
(i32.const 24)
87+
)
88+
(block
89+
(call $~lib/env/abort
90+
(i32.const 0)
91+
(i32.const 8)
92+
(i32.const 55)
93+
(i32.const 0)
94+
)
95+
(unreachable)
96+
)
97+
)
98+
(i32.store
99+
(call $std/pointer/Pointer<Entry>#get:offset
100+
(get_global $std/pointer/one)
101+
)
102+
(i32.const 1)
103+
)
104+
(i32.store offset=4
105+
(call $std/pointer/Pointer<Entry>#get:offset
106+
(get_global $std/pointer/one)
107+
)
108+
(i32.const 2)
109+
)
110+
(if
111+
(i32.ne
112+
(i32.load
113+
(call $std/pointer/Pointer<Entry>#get:offset
114+
(get_global $std/pointer/one)
115+
)
116+
)
117+
(i32.const 1)
118+
)
119+
(block
120+
(call $~lib/env/abort
121+
(i32.const 0)
122+
(i32.const 8)
123+
(i32.const 59)
124+
(i32.const 0)
125+
)
126+
(unreachable)
127+
)
128+
)
129+
(if
130+
(i32.ne
131+
(i32.load offset=4
132+
(call $std/pointer/Pointer<Entry>#get:offset
133+
(get_global $std/pointer/one)
134+
)
135+
)
136+
(i32.const 2)
137+
)
138+
(block
139+
(call $~lib/env/abort
140+
(i32.const 0)
141+
(i32.const 8)
142+
(i32.const 60)
143+
(i32.const 0)
144+
)
145+
(unreachable)
146+
)
147+
)
148+
(set_global $std/pointer/add
149+
(i32.add
150+
(get_global $std/pointer/one)
151+
(get_global $std/pointer/two)
152+
)
153+
)
154+
(if
155+
(i32.ne
156+
(call $std/pointer/Pointer<Entry>#get:offset
157+
(get_global $std/pointer/add)
158+
)
159+
(i32.const 32)
160+
)
161+
(block
162+
(call $~lib/env/abort
163+
(i32.const 0)
164+
(i32.const 8)
165+
(i32.const 63)
166+
(i32.const 0)
167+
)
168+
(unreachable)
169+
)
170+
)
171+
(set_global $std/pointer/sub
172+
(i32.sub
173+
(get_global $std/pointer/two)
174+
(get_global $std/pointer/one)
175+
)
176+
)
177+
(if
178+
(i32.ne
179+
(call $std/pointer/Pointer<Entry>#get:offset
180+
(get_global $std/pointer/sub)
181+
)
182+
(i32.const 16)
183+
)
184+
(block
185+
(call $~lib/env/abort
186+
(i32.const 0)
187+
(i32.const 8)
188+
(i32.const 66)
189+
(i32.const 0)
190+
)
191+
(unreachable)
192+
)
193+
)
194+
(if
195+
(i32.ne
196+
(call $std/pointer/Pointer<Entry>#get:offset
197+
(get_global $std/pointer/one)
198+
)
199+
(i32.const 8)
200+
)
201+
(block
202+
(call $~lib/env/abort
203+
(i32.const 0)
204+
(i32.const 8)
205+
(i32.const 68)
206+
(i32.const 0)
207+
)
208+
(unreachable)
209+
)
210+
)
211+
(set_global $std/pointer/one
212+
(i32.add
213+
(get_global $std/pointer/one)
214+
(i32.const 8)
215+
)
216+
)
217+
(if
218+
(i32.ne
219+
(call $std/pointer/Pointer<Entry>#get:offset
220+
(get_global $std/pointer/one)
221+
)
222+
(i32.const 16)
223+
)
224+
(block
225+
(call $~lib/env/abort
226+
(i32.const 0)
227+
(i32.const 8)
228+
(i32.const 70)
229+
(i32.const 0)
230+
)
231+
(unreachable)
232+
)
233+
)
234+
(if
235+
(i32.ne
236+
(call $std/pointer/Pointer<Entry>#get:offset
237+
(get_global $std/pointer/two)
238+
)
239+
(i32.const 24)
240+
)
241+
(block
242+
(call $~lib/env/abort
243+
(i32.const 0)
244+
(i32.const 8)
245+
(i32.const 72)
246+
(i32.const 0)
247+
)
248+
(unreachable)
249+
)
250+
)
251+
(set_global $std/pointer/two
252+
(i32.sub
253+
(get_global $std/pointer/two)
254+
(i32.const 8)
255+
)
256+
)
257+
(set_global $std/pointer/two
258+
(i32.sub
259+
(get_global $std/pointer/two)
260+
(i32.const 8)
261+
)
262+
)
263+
(if
264+
(i32.ne
265+
(call $std/pointer/Pointer<Entry>#get:offset
266+
(get_global $std/pointer/two)
267+
)
268+
(i32.const 8)
269+
)
270+
(block
271+
(call $~lib/env/abort
272+
(i32.const 0)
273+
(i32.const 8)
274+
(i32.const 75)
275+
(i32.const 0)
276+
)
277+
(unreachable)
278+
)
279+
)
280+
(if
281+
(i32.ne
282+
(i32.load
283+
(call $std/pointer/Pointer<Entry>#get:offset
284+
(get_global $std/pointer/two)
285+
)
286+
)
287+
(i32.const 1)
288+
)
289+
(block
290+
(call $~lib/env/abort
291+
(i32.const 0)
292+
(i32.const 8)
293+
(i32.const 76)
294+
(i32.const 0)
295+
)
296+
(unreachable)
297+
)
298+
)
299+
(if
300+
(i32.ne
301+
(i32.load offset=4
302+
(call $std/pointer/Pointer<Entry>#get:offset
303+
(get_global $std/pointer/two)
304+
)
305+
)
306+
(i32.const 2)
307+
)
308+
(block
309+
(call $~lib/env/abort
310+
(i32.const 0)
311+
(i32.const 8)
312+
(i32.const 77)
313+
(i32.const 0)
314+
)
315+
(unreachable)
316+
)
317+
)
318+
)
319+
)

tests/compiler/std/pointer.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// A pointer arithmetic experiment
2+
3+
export class Pointer<T> {
4+
5+
// FIXME: does not inline, always yields a trampoline
6+
@inline constructor(offset: usize = 0) {
7+
return changetype<Pointer<T>>(offset);
8+
}
9+
10+
// FIXME: does not inline
11+
@inline get offset(): usize {
12+
return changetype<usize>(this);
13+
}
14+
15+
// FIXME: does not inline
16+
@inline get value(): T {
17+
return changetype<T>(changetype<usize>(this));
18+
}
19+
20+
// FIXME: in general, inlining any of the following always yields a block. one could argue that
21+
// this helps debuggability, or that it is unnecessary overhead due to the simplicity of the
22+
// functions. a compromise could be to inline a block consisting of a single 'return' as is,
23+
// where possible.
24+
25+
@inline @operator("+") add(other: Pointer<T>): Pointer<T> {
26+
return changetype<Pointer<T>>(changetype<usize>(this) + changetype<usize>(other));
27+
}
28+
29+
@inline @operator("-") sub(other: Pointer<T>): Pointer<T> {
30+
return changetype<Pointer<T>>(changetype<usize>(this) - changetype<usize>(other));
31+
}
32+
33+
@inline @operator.prefix("++") inc(): Pointer<T> {
34+
// FIXME: this should take alignment into account, but then would require a new builtin to
35+
// determine the minimal alignment of a struct by evaluating its field layout.
36+
const size = isReference<T>() ? offsetof<T>() : sizeof<T>();
37+
return changetype<Pointer<T>>(changetype<usize>(this) + size);
38+
}
39+
40+
@inline @operator.prefix("--") dec(): Pointer<T> {
41+
const size = isReference<T>() ? offsetof<T>() : sizeof<T>();
42+
return changetype<Pointer<T>>(changetype<usize>(this) - size);
43+
}
44+
}
45+
46+
@unmanaged
47+
class Entry {
48+
key: i32;
49+
val: i32;
50+
}
51+
52+
var one = new Pointer<Entry>(8);
53+
var two = new Pointer<Entry>(24);
54+
assert(one.offset == 8);
55+
assert(two.offset == 24);
56+
57+
one.value.key = 1;
58+
one.value.val = 2;
59+
assert(one.value.key == 1);
60+
assert(one.value.val == 2);
61+
62+
var add = one + two;
63+
assert(add.offset == 32);
64+
65+
var sub = two - one;
66+
assert(sub.offset == 16);
67+
68+
assert(one.offset == 8);
69+
++one; // FIXME: assigning to a var yields an 'auto to void' error
70+
assert(one.offset == 16);
71+
72+
assert(two.offset == 24);
73+
--two;
74+
--two;
75+
assert(two.offset == 8);
76+
assert(two.value.key == 1);
77+
assert(two.value.val == 2);

0 commit comments

Comments
 (0)