1;;! target = "x86_64"
2;;! test = "optimize"
3;;! flags = [ "-Wfunction-references=y", "-Otable-lazy-init=y" ]
4
5;; This test is meant to simulate how typed funcrefs in a table may be
6;; used for ICs (inline caches) in a Wasm module compiled from a dynamic
7;; language. In native JIT engines, IC chains have head pointers that
8;; are raw code pointers and IC-using code can call each with a few ops
9;; (load pointer, call indirect). We'd like similar efficiency by
10;; storing funcrefs for the first IC in each chain in a typed-funcref
11;; table.
12
13(module
14  (type $ic-stub (func (param i32 i32 i32 i32) (result i32)))
15
16  ;; This syntax declares a table that is exactly 100 elements, whose
17  ;; elements are nullable function references, and whose default
18  ;; value is `null`.
19  (table $ic-sites 100 100 (ref null $ic-stub))
20
21  (func $ic1 (param i32 i32 i32 i32) (result i32)
22        local.get 0)
23
24  ;; A function which uses ICs through `table.get` plus `call_ref`
25  (func $call-ics-with-call-ref (param i32 i32 i32 i32) (result i32)
26        (local $sum i32)
27
28        ;; IC callsite index 1 (arbitrary).
29        local.get 0
30        local.get 1
31        local.get 2
32        local.get 3
33        i32.const 1
34        table.get $ic-sites
35        call_ref $ic-stub
36        local.get $sum
37        i32.add
38        local.set $sum
39
40        ;; IC callsite index 2 (arbitrary).
41        local.get 0
42        local.get 1
43        local.get 2
44        local.get 3
45        i32.const 2
46        table.get $ic-sites
47        call_ref $ic-stub
48        local.get $sum
49        i32.add
50        local.set $sum
51
52        local.get $sum)
53
54  ;; Same as the above function, but uses `call_indirect` rather than
55  ;; `call_ref`.
56  (func $call-ics-with-call-indirect (param i32 i32 i32 i32) (result i32)
57        (local $sum i32)
58
59        ;; IC callsite index 1 (arbitrary).
60        local.get 0
61        local.get 1
62        local.get 2
63        local.get 3
64        i32.const 1
65        call_indirect $ic-sites (type $ic-stub)
66        local.get $sum
67        i32.add
68        local.set $sum
69
70        ;; IC callsite index 2 (arbitrary).
71        local.get 0
72        local.get 1
73        local.get 2
74        local.get 3
75        i32.const 2
76        call_indirect $ic-sites (type $ic-stub)
77        local.get $sum
78        i32.add
79        local.set $sum
80
81        local.get $sum)
82
83  (global $ic-site0 (mut (ref $ic-stub)) (ref.func $ic1))
84  (global $ic-site1 (mut (ref $ic-stub)) (ref.func $ic1))
85
86  ;; Sort of similar to the previous two functions, but uses globals instead of
87  ;; tables to store ICs. Mostly just here for comparison in terms of codegen.
88  (func $call-ics-with-global-get (param i32 i32 i32 i32) (result i32)
89        (local $sum i32)
90
91        ;; IC callsite index 1 (arbitrary).
92        local.get 0
93        local.get 1
94        local.get 2
95        local.get 3
96        global.get $ic-site0
97        call_ref $ic-stub
98        local.get $sum
99        i32.add
100        local.set $sum
101
102        ;; IC callsite index 2 (arbitrary).
103        local.get 0
104        local.get 1
105        local.get 2
106        local.get 3
107        global.get $ic-site1
108        call_ref $ic-stub
109        local.get $sum
110        i32.add
111        local.set $sum
112
113        local.get $sum)
114)
115
116;; function u0:0(i64 vmctx, i64, i32, i32, i32, i32) -> i32 tail {
117;;     gv0 = vmctx
118;;     gv1 = load.i64 notrap aligned readonly gv0+8
119;;     gv2 = load.i64 notrap aligned gv1+24
120;;     stack_limit = gv2
121;;
122;;                                 block0(v0: i64, v1: i64, v2: i32, v3: i32, v4: i32, v5: i32):
123;; @0039                               jump block1
124;;
125;;                                 block1:
126;; @0039                               return v2
127;; }
128;;
129;; function u0:1(i64 vmctx, i64, i32, i32, i32, i32) -> i32 tail {
130;;     gv0 = vmctx
131;;     gv1 = load.i64 notrap aligned readonly gv0+8
132;;     gv2 = load.i64 notrap aligned gv1+24
133;;     gv3 = vmctx
134;;     gv4 = load.i64 notrap aligned readonly can_move gv3+48
135;;     sig0 = (i64 vmctx, i32, i64) -> i64 tail
136;;     sig1 = (i64 vmctx, i64, i32, i32, i32, i32) -> i32 tail
137;;     fn0 = colocated u805306368:9 sig0
138;;     stack_limit = gv2
139;;
140;;                                 block0(v0: i64, v1: i64, v2: i32, v3: i32, v4: i32, v5: i32):
141;; @0048                               v12 = load.i64 notrap aligned readonly can_move v0+48
142;;                                     v68 = iconst.i64 8
143;; @0048                               v14 = iadd v12, v68  ; v68 = 8
144;; @0048                               v17 = load.i64 user5 aligned table v14
145;;                                     v57 = iconst.i64 -2
146;; @0048                               v18 = band v17, v57  ; v57 = -2
147;; @0048                               brif v17, block3(v18), block2
148;;
149;;                                 block2 cold:
150;; @003c                               v7 = iconst.i32 0
151;;                                     v67 = iconst.i64 1
152;; @0048                               v23 = call fn0(v0, v7, v67)  ; v7 = 0, v67 = 1
153;; @0048                               jump block3(v23)
154;;
155;;                                 block3(v19: i64):
156;; @004a                               v24 = load.i64 user15 aligned readonly v19+8
157;; @004a                               v25 = load.i64 notrap aligned readonly v19+24
158;; @004a                               v26 = call_indirect sig1, v24(v25, v0, v2, v3, v4, v5)
159;;                                     v76 = iconst.i64 16
160;; @005b                               v39 = iadd.i64 v12, v76  ; v76 = 16
161;; @005b                               v42 = load.i64 user5 aligned table v39
162;;                                     v77 = iconst.i64 -2
163;;                                     v78 = band v42, v77  ; v77 = -2
164;; @005b                               brif v42, block5(v78), block4
165;;
166;;                                 block4 cold:
167;;                                     v79 = iconst.i32 0
168;;                                     v75 = iconst.i64 2
169;; @005b                               v48 = call fn0(v0, v79, v75)  ; v79 = 0, v75 = 2
170;; @005b                               jump block5(v48)
171;;
172;;                                 block5(v44: i64):
173;; @005d                               v49 = load.i64 user15 aligned readonly v44+8
174;; @005d                               v50 = load.i64 notrap aligned readonly v44+24
175;; @005d                               v51 = call_indirect sig1, v49(v50, v0, v2, v3, v4, v5)
176;; @0066                               jump block1
177;;
178;;                                 block1:
179;; @0061                               v53 = iadd.i32 v51, v26
180;; @0066                               return v53
181;; }
182;;
183;; function u0:2(i64 vmctx, i64, i32, i32, i32, i32) -> i32 tail {
184;;     gv0 = vmctx
185;;     gv1 = load.i64 notrap aligned readonly gv0+8
186;;     gv2 = load.i64 notrap aligned gv1+24
187;;     gv3 = vmctx
188;;     gv4 = load.i64 notrap aligned readonly can_move gv3+48
189;;     sig0 = (i64 vmctx, i64, i32, i32, i32, i32) -> i32 tail
190;;     sig1 = (i64 vmctx, i32, i64) -> i64 tail
191;;     fn0 = colocated u805306368:9 sig1
192;;     stack_limit = gv2
193;;
194;;                                 block0(v0: i64, v1: i64, v2: i32, v3: i32, v4: i32, v5: i32):
195;; @0075                               v12 = load.i64 notrap aligned readonly can_move v0+48
196;;                                     v68 = iconst.i64 8
197;; @0075                               v14 = iadd v12, v68  ; v68 = 8
198;; @0075                               v17 = load.i64 user5 aligned table v14
199;;                                     v57 = iconst.i64 -2
200;; @0075                               v18 = band v17, v57  ; v57 = -2
201;; @0075                               brif v17, block3(v18), block2
202;;
203;;                                 block2 cold:
204;; @0069                               v7 = iconst.i32 0
205;;                                     v67 = iconst.i64 1
206;; @0075                               v23 = call fn0(v0, v7, v67)  ; v7 = 0, v67 = 1
207;; @0075                               jump block3(v23)
208;;
209;;                                 block3(v19: i64):
210;; @0075                               v24 = load.i64 user6 aligned readonly v19+8
211;; @0075                               v25 = load.i64 notrap aligned readonly v19+24
212;; @0075                               v26 = call_indirect sig0, v24(v25, v0, v2, v3, v4, v5)
213;;                                     v76 = iconst.i64 16
214;; @0087                               v39 = iadd.i64 v12, v76  ; v76 = 16
215;; @0087                               v42 = load.i64 user5 aligned table v39
216;;                                     v77 = iconst.i64 -2
217;;                                     v78 = band v42, v77  ; v77 = -2
218;; @0087                               brif v42, block5(v78), block4
219;;
220;;                                 block4 cold:
221;;                                     v79 = iconst.i32 0
222;;                                     v75 = iconst.i64 2
223;; @0087                               v48 = call fn0(v0, v79, v75)  ; v79 = 0, v75 = 2
224;; @0087                               jump block5(v48)
225;;
226;;                                 block5(v44: i64):
227;; @0087                               v49 = load.i64 user6 aligned readonly v44+8
228;; @0087                               v50 = load.i64 notrap aligned readonly v44+24
229;; @0087                               v51 = call_indirect sig0, v49(v50, v0, v2, v3, v4, v5)
230;; @0091                               jump block1
231;;
232;;                                 block1:
233;; @008c                               v53 = iadd.i32 v51, v26
234;; @0091                               return v53
235;; }
236;;
237;; function u0:3(i64 vmctx, i64, i32, i32, i32, i32) -> i32 tail {
238;;     gv0 = vmctx
239;;     gv1 = load.i64 notrap aligned readonly gv0+8
240;;     gv2 = load.i64 notrap aligned gv1+24
241;;     gv3 = vmctx
242;;     sig0 = (i64 vmctx, i64, i32, i32, i32, i32) -> i32 tail
243;;     stack_limit = gv2
244;;
245;;                                 block0(v0: i64, v1: i64, v2: i32, v3: i32, v4: i32, v5: i32):
246;; @009e                               v9 = load.i64 notrap aligned table v0+64
247;; @00a0                               v10 = load.i64 user15 aligned readonly v9+8
248;; @00a0                               v11 = load.i64 notrap aligned readonly v9+24
249;; @00a0                               v12 = call_indirect sig0, v10(v11, v0, v2, v3, v4, v5)
250;; @00af                               v15 = load.i64 notrap aligned table v0+80
251;; @00b1                               v16 = load.i64 user15 aligned readonly v15+8
252;; @00b1                               v17 = load.i64 notrap aligned readonly v15+24
253;; @00b1                               v18 = call_indirect sig0, v16(v17, v0, v2, v3, v4, v5)
254;; @00ba                               jump block1
255;;
256;;                                 block1:
257;; @00b5                               v19 = iadd.i32 v18, v12
258;; @00ba                               return v19
259;; }
260