baseline-opt.js (4005B)
1 // Point-testing various optimizations in the wasm baseline compiler. 2 3 // Boolean optimization for control (bug 1286816). 4 // 5 // These optimizations combine a test (a comparison or Eqz) with an 6 // immediately following conditional branch (BrIf, If, and Select), to 7 // avoid generating a boolean value that is then tested with a 8 // compare-to-zero. 9 // 10 // On AngryBots as of November 2016, 84% of all test instructions 11 // (measured statically) are optimized by this method. 12 13 function testEqzBrIf(value, type, untaken, taken, expected) { 14 var f = wasmEvalText(`(module 15 (func (result i32) 16 (local ${type}) 17 (local i32) 18 (local.set 0 (${type}.const ${value})) 19 (local.set 1 (i32.const ${taken})) 20 (block $b 21 (br_if $b (${type}.eqz (local.get 0))) 22 (local.set 1 (i32.const ${untaken}))) 23 (local.get 1)) 24 (export "f" (func 0)))`).exports["f"]; 25 assertEq(f(), expected); 26 } 27 28 ["i32", "i64"].forEach(t => testEqzBrIf(0, t, 37, 42, 42)); // Taken 29 ["i32", "i64"].forEach(t => testEqzBrIf(1, t, 37, 42, 37)); // Untaken 30 31 function testCmpBrIf(value, type, untaken, taken, expected) { 32 var f = wasmEvalText(`(module 33 (func (result i32) 34 (local ${type}) 35 (local i32) 36 (local.set 1 (i32.const ${taken})) 37 (block $b 38 (br_if $b (${type}.eq (local.get 0) (${type}.const ${value}))) 39 (local.set 1 (i32.const ${untaken}))) 40 (local.get 1)) 41 (export "f" (func 0)))`).exports["f"]; 42 assertEq(f(), expected); 43 } 44 45 ["i32", "i64", "f32", "f64"].forEach(t => testCmpBrIf(0, t, 37, 42, 42)); // Branch taken 46 ["i32", "i64", "f32", "f64"].forEach(t => testCmpBrIf(1, t, 37, 42, 37)); // Branch untaken 47 48 function testEqzSelect(value, type, iftrue, iffalse, expected) { 49 var f = wasmEvalText(`(module 50 (func (result i32) 51 (local ${type}) 52 (local.set 0 (${type}.const ${value})) 53 (select (i32.const ${iftrue}) 54 (i32.const ${iffalse}) 55 (${type}.eqz (local.get 0)))) 56 (export "f" (func 0)))`).exports["f"]; 57 assertEq(f(), expected); 58 } 59 60 ["i32", "i64"].forEach(t => testEqzSelect(0, t, 42, 37, 42)); // Select first 61 ["i32", "i64"].forEach(t => testEqzSelect(1, t, 42, 37, 37)); // Select second 62 63 function testCmpSelect(value, type, iftrue, iffalse, expected) { 64 var f = wasmEvalText(`(module 65 (func (result i32) 66 (local ${type}) 67 (select (i32.const ${iftrue}) 68 (i32.const ${iffalse}) 69 (${type}.eq (local.get 0) (${type}.const ${value})))) 70 (export "f" (func 0)))`).exports["f"]; 71 assertEq(f(), expected); 72 } 73 74 ["i32", "i64", "f32", "f64"].forEach(t => testCmpSelect(0, t, 42, 37, 42)); // Select first 75 ["i32", "i64", "f32", "f64"].forEach(t => testCmpSelect(1, t, 42, 37, 37)); // Select second 76 77 function testEqzIf(value, type, trueBranch, falseBranch, expected) { 78 var f = wasmEvalText(`(module 79 (func (result i32) 80 (local ${type}) 81 (local i32) 82 (local.set 0 (${type}.const ${value})) 83 (if (${type}.eqz (local.get 0)) 84 (then (local.set 1 (i32.const ${trueBranch}))) 85 (else (local.set 1 (i32.const ${falseBranch})))) 86 (local.get 1)) 87 (export "f" (func 0)))`).exports["f"]; 88 assertEq(f(), expected); 89 } 90 91 ["i32", "i64"].forEach(t => testEqzIf(0, t, 42, 37, 42)); // Taken 92 ["i32", "i64"].forEach(t => testEqzIf(1, t, 42, 37, 37)); // Untaken 93 94 function testCmpIf(value, type, trueBranch, falseBranch, expected) { 95 var f = wasmEvalText(`(module 96 (func (result i32) 97 (local ${type}) 98 (local i32) 99 (if (${type}.eq (local.get 0) (${type}.const ${value})) 100 (then (local.set 1 (i32.const ${trueBranch}))) 101 (else (local.set 1 (i32.const ${falseBranch})))) 102 (local.get 1)) 103 (export "f" (func 0)))`).exports["f"]; 104 assertEq(f(), expected); 105 } 106 107 ["i32", "i64", "f32", "f64"].forEach(t => testCmpIf(0, t, 42, 37, 42)); // Taken 108 ["i32", "i64", "f32", "f64"].forEach(t => testCmpIf(1, t, 42, 37, 37)); // Untaken