1;;! target = "x86_64" 2;;! test = "optimize" 3 4;; When `call_indirect` is used in a loop with the same table index on every 5;; iteration, we can hoist part of the work out of the loop. This test tracks 6;; how much we're successfully pulling out. 7 8(module 9 (type $fn (func (result i32))) 10 (table $fnptrs 2 2 funcref) 11 (func (param i32) 12 loop 13 local.get 0 14 call_indirect $fnptrs (type $fn) 15 br 0 16 end) 17 (func 18 loop 19 i32.const 1 20 call_indirect $fnptrs (type $fn) 21 br 0 22 end) 23) 24 25;; function u0:0(i64 vmctx, i64, i32) tail { 26;; gv0 = vmctx 27;; gv1 = load.i64 notrap aligned readonly gv0+8 28;; gv2 = load.i64 notrap aligned gv1+24 29;; gv3 = vmctx 30;; gv4 = load.i64 notrap aligned readonly can_move gv3+48 31;; sig0 = (i64 vmctx, i64) -> i32 tail 32;; sig1 = (i64 vmctx, i32, i64) -> i64 tail 33;; fn0 = colocated u805306368:9 sig1 34;; stack_limit = gv2 35;; 36;; block0(v0: i64, v1: i64, v2: i32): 37;; @002b v4 = iconst.i32 2 38;; @002b v5 = icmp uge v2, v4 ; v4 = 2 39;; @002b v10 = iconst.i64 0 40;; @002b v7 = load.i64 notrap aligned readonly can_move v0+48 41;; @002b v6 = uextend.i64 v2 42;; v29 = iconst.i64 3 43;; @002b v8 = ishl v6, v29 ; v29 = 3 44;; @002b v9 = iadd v7, v8 45;; @002b v11 = select_spectre_guard v5, v10, v9 ; v10 = 0 46;; v28 = iconst.i64 -2 47;; @002b v15 = iconst.i32 0 48;; @002b v20 = load.i64 notrap aligned readonly can_move v0+40 49;; @002b v21 = load.i32 notrap aligned readonly can_move v20 50;; @0027 jump block2 51;; 52;; block2: 53;; @002b v12 = load.i64 user5 aligned table v11 54;; v31 = iconst.i64 -2 55;; v32 = band v12, v31 ; v31 = -2 56;; @002b brif v12, block5(v32), block4 57;; 58;; block4 cold: 59;; v33 = iconst.i32 0 60;; @002b v18 = call fn0(v0, v33, v6) ; v33 = 0 61;; @002b jump block5(v18) 62;; 63;; block5(v14: i64): 64;; @002b v22 = load.i32 user6 aligned readonly v14+16 65;; @002b v23 = icmp eq v22, v21 66;; @002b trapz v23, user7 67;; @002b v24 = load.i64 notrap aligned readonly v14+8 68;; @002b v25 = load.i64 notrap aligned readonly v14+24 69;; @002b v26 = call_indirect sig0, v24(v25, v0) 70;; @002e jump block2 71;; } 72;; 73;; function u0:1(i64 vmctx, i64) tail { 74;; gv0 = vmctx 75;; gv1 = load.i64 notrap aligned readonly gv0+8 76;; gv2 = load.i64 notrap aligned gv1+24 77;; gv3 = vmctx 78;; gv4 = load.i64 notrap aligned readonly can_move gv3+48 79;; sig0 = (i64 vmctx, i64) -> i32 tail 80;; sig1 = (i64 vmctx, i32, i64) -> i64 tail 81;; fn0 = colocated u805306368:9 sig1 82;; stack_limit = gv2 83;; 84;; block0(v0: i64, v1: i64): 85;; @0038 v6 = load.i64 notrap aligned readonly can_move v0+48 86;; v37 = iconst.i64 8 87;; @0038 v8 = iadd v6, v37 ; v37 = 8 88;; v26 = iconst.i64 -2 89;; @0038 v14 = iconst.i32 0 90;; v36 = iconst.i64 1 91;; @0038 v19 = load.i64 notrap aligned readonly can_move v0+40 92;; @0038 v20 = load.i32 notrap aligned readonly can_move v19 93;; @0034 jump block2 94;; 95;; block2: 96;; v38 = iadd.i64 v6, v37 ; v37 = 8 97;; @0038 v11 = load.i64 user5 aligned table v38 98;; v39 = iconst.i64 -2 99;; v40 = band v11, v39 ; v39 = -2 100;; @0038 brif v11, block5(v40), block4 101;; 102;; block4 cold: 103;; v41 = iconst.i32 0 104;; v42 = iconst.i64 1 105;; @0038 v17 = call fn0(v0, v41, v42) ; v41 = 0, v42 = 1 106;; @0038 jump block5(v17) 107;; 108;; block5(v13: i64): 109;; @0038 v21 = load.i32 user6 aligned readonly v13+16 110;; @0038 v22 = icmp eq v21, v20 111;; @0038 trapz v22, user7 112;; @0038 v23 = load.i64 notrap aligned readonly v13+8 113;; @0038 v24 = load.i64 notrap aligned readonly v13+24 114;; @0038 v25 = call_indirect sig0, v23(v24, v0) 115;; @003b jump block2 116;; } 117