1;;! target = "x86_64" 2;;! test = "optimize" 3;;! flags = [ "-Wfunction-references=y", "-Otable-lazy-init=n" ] 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, i64, i32, i32, i32, i32) -> i32 tail 136;; stack_limit = gv2 137;; 138;; block0(v0: i64, v1: i64, v2: i32, v3: i32, v4: i32, v5: i32): 139;; @0048 v12 = load.i64 notrap aligned readonly can_move v0+48 140;; v48 = iconst.i64 8 141;; @0048 v14 = iadd v12, v48 ; v48 = 8 142;; @0048 v17 = load.i64 user5 aligned table v14 143;; @004a v18 = load.i64 user15 aligned readonly v17+8 144;; @004a v19 = load.i64 notrap aligned readonly v17+24 145;; @004a v20 = call_indirect sig0, v18(v19, v0, v2, v3, v4, v5) 146;; v56 = iconst.i64 16 147;; @005b v28 = iadd v12, v56 ; v56 = 16 148;; @005b v31 = load.i64 user5 aligned table v28 149;; @005d v32 = load.i64 user15 aligned readonly v31+8 150;; @005d v33 = load.i64 notrap aligned readonly v31+24 151;; @005d v34 = call_indirect sig0, v32(v33, v0, v2, v3, v4, v5) 152;; @0066 jump block1 153;; 154;; block1: 155;; @0061 v35 = iadd.i32 v34, v20 156;; @0066 return v35 157;; } 158;; 159;; function u0:2(i64 vmctx, i64, i32, i32, i32, i32) -> i32 tail { 160;; gv0 = vmctx 161;; gv1 = load.i64 notrap aligned readonly gv0+8 162;; gv2 = load.i64 notrap aligned gv1+24 163;; gv3 = vmctx 164;; gv4 = load.i64 notrap aligned readonly can_move gv3+48 165;; sig0 = (i64 vmctx, i64, i32, i32, i32, i32) -> i32 tail 166;; stack_limit = gv2 167;; 168;; block0(v0: i64, v1: i64, v2: i32, v3: i32, v4: i32, v5: i32): 169;; @0075 v12 = load.i64 notrap aligned readonly can_move v0+48 170;; v48 = iconst.i64 8 171;; @0075 v14 = iadd v12, v48 ; v48 = 8 172;; @0075 v17 = load.i64 user5 aligned table v14 173;; @0075 v18 = load.i64 user6 aligned readonly v17+8 174;; @0075 v19 = load.i64 notrap aligned readonly v17+24 175;; @0075 v20 = call_indirect sig0, v18(v19, v0, v2, v3, v4, v5) 176;; v56 = iconst.i64 16 177;; @0087 v28 = iadd v12, v56 ; v56 = 16 178;; @0087 v31 = load.i64 user5 aligned table v28 179;; @0087 v32 = load.i64 user6 aligned readonly v31+8 180;; @0087 v33 = load.i64 notrap aligned readonly v31+24 181;; @0087 v34 = call_indirect sig0, v32(v33, v0, v2, v3, v4, v5) 182;; @0091 jump block1 183;; 184;; block1: 185;; @008c v35 = iadd.i32 v34, v20 186;; @0091 return v35 187;; } 188;; 189;; function u0:3(i64 vmctx, i64, i32, i32, i32, i32) -> i32 tail { 190;; gv0 = vmctx 191;; gv1 = load.i64 notrap aligned readonly gv0+8 192;; gv2 = load.i64 notrap aligned gv1+24 193;; gv3 = vmctx 194;; sig0 = (i64 vmctx, i64, i32, i32, i32, i32) -> i32 tail 195;; stack_limit = gv2 196;; 197;; block0(v0: i64, v1: i64, v2: i32, v3: i32, v4: i32, v5: i32): 198;; @009e v9 = load.i64 notrap aligned table v0+64 199;; @00a0 v10 = load.i64 user15 aligned readonly v9+8 200;; @00a0 v11 = load.i64 notrap aligned readonly v9+24 201;; @00a0 v12 = call_indirect sig0, v10(v11, v0, v2, v3, v4, v5) 202;; @00af v15 = load.i64 notrap aligned table v0+80 203;; @00b1 v16 = load.i64 user15 aligned readonly v15+8 204;; @00b1 v17 = load.i64 notrap aligned readonly v15+24 205;; @00b1 v18 = call_indirect sig0, v16(v17, v0, v2, v3, v4, v5) 206;; @00ba jump block1 207;; 208;; block1: 209;; @00b5 v19 = iadd.i32 v18, v12 210;; @00ba return v19 211;; } 212