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