codegen-x64-test.js (7651B)
1 // Scaffolding for testing x64 Ion code generation patterns). See 2 // ../tests/wasm/README-codegen.md for general information, and the *codegen.js 3 // tests in that directory and its subdirectories for specifics. 4 // 5 // The structure of the inputs can vary for the different testing predicates but 6 // each case generally has an operator name and an expected-pattern; the latter 7 // is a string that represents a regular expression, possibly with newlines, 8 // representing the instruction or instructions we are looking for for the 9 // operator. Spaces in the expected-pattern are arbitrary, we preprocess the 10 // pattern to replace any space string with \s+. Lines are separated by 11 // newlines and leading and trailing spaces are currently stripped. 12 // 13 // The testers additionally take an optional options bag with the following 14 // optional entries: 15 // features: if present, an object to pass as the last argument to functions 16 // that compile wasm bytecode 17 // instanceBox: if present, an object with a `value` property that will 18 // receive the constructed instance 19 // no_prefix: by default, the required pattern must be immediately preceded 20 // by `x64_prefix`, and this is checked. Setting this to true skips 21 // the check. 22 // no_suffix: by default, the required pattern must be immediately followed 23 // by `x64_suffix`, and this is checked. Setting this to true skips 24 // the check. 25 // baseline: by default, the output to be tested is expected to be produced 26 // at the tier "ion". Setting this to true changes the expected 27 // tier to "baseline". 28 // memory: if present, add a memory of length given by this property 29 // log: for debugging -- print the disassembly, then the preprocessed pattern 30 31 load(libdir + "codegen-test-common.js"); 32 33 // RIP-relative address following the instruction mnemonic 34 var RIPR = `0x${HEXES}`; 35 36 // End of prologue. The move from r14 to rbp is writing the callee's wasm 37 // instance into the frame for debug checks -- see WasmFrame.h. 38 var x64_prefix = ` 39 mov %rsp, %rbp( 40 movq %r14, (0x10|0x30)\\(%rbp\\))? 41 ` 42 43 // Start of epilogue 44 var x64_suffix = `pop %rbp`; 45 46 // v128 OP v128 -> v128 47 // inputs: [[complete-opname, expected-pattern], ...] 48 function codegenTestX64_v128xv128_v128(inputs, options = {}) { 49 for ( let [op, expected] of inputs ) { 50 codegenTestX64BinopInternal(op, expected, options, 'v128', 'v128', 'v128', '0', '1'); 51 } 52 } 53 54 // v128 OP param1-type -> v128 55 // inputs: [[complete-opname, param1-type, expected-pattern], ...] 56 function codegenTestX64_v128xPTYPE_v128(inputs, options = {}) { 57 for ( let [op, p1type, expected] of inputs ) { 58 codegenTestX64BinopInternal(op, expected, options, 'v128', p1type, 'v128', '0', '1'); 59 } 60 } 61 62 // v128 OP literal -> v128 63 // inputs: [[complete-opname, rhs-literal, expected-pattern], ...] 64 function codegenTestX64_v128xLITERAL_v128(inputs, options = {}) { 65 for ( let [op, literal, expected] of inputs ) { 66 codegenTestX64_adhoc(wrap(options, ` 67 (func (export "f") (param v128) (result v128) 68 (${op} (local.get 0) ${literal}))`), 69 'f', 70 expected, 71 options) 72 } 73 } 74 75 // literal OP v128 -> v128 76 // inputs: [[complete-opname, lhs-literal, expected-pattern], ...] 77 function codegenTestX64_LITERALxv128_v128(inputs, options = {}) { 78 for ( let [op, literal, expected] of inputs ) { 79 codegenTestX64_adhoc(wrap(options, ` 80 (func (export "f") (param v128) (result v128) 81 (${op} ${literal} (local.get 0)))`), 82 'f', 83 expected, 84 options) 85 } 86 } 87 88 // v128 OP v128 -> v128, but operands are swapped 89 // inputs: [[complete-opname, expected-pattern], ...] 90 function codegenTestX64_v128xv128_v128_reversed(inputs, options = {}) { 91 for ( let [op, expected] of inputs ) { 92 codegenTestX64BinopInternal(op, expected, options, 'v128', 'v128', 'v128', '1', '0'); 93 } 94 } 95 96 // OP v128 -> v128 97 // inputs: [[complete-opname, expected-pattern], ...] 98 function codegenTestX64_v128_v128(inputs, options = {}) { 99 for ( let [op, expected] of inputs ) { 100 codegenTestX64_adhoc(wrap(options, ` 101 (func (export "f") (param v128) (result v128) 102 (${op} (local.get 0)))`), 103 'f', 104 expected, 105 options); 106 } 107 } 108 109 // OP param-type -> v128 110 // inputs [[complete-opname, param-type, expected-pattern], ...] 111 function codegenTestX64_PTYPE_v128(inputs, options = {}) { 112 for ( let [op, ptype, expected] of inputs ) { 113 codegenTestX64_adhoc(wrap(options, ` 114 (func (export "f") (param ${ptype}) (result v128) 115 (${op} (local.get 0)))`), 116 'f', 117 expected, 118 options); 119 } 120 } 121 122 // OP v128 -> v128, but the function takes two arguments and the first is ignored 123 // inputs: [[complete-opname, expected-pattern], ...] 124 function codegenTestX64_IGNOREDxv128_v128(inputs, options = {}) { 125 for ( let [op, expected] of inputs ) { 126 codegenTestX64_adhoc(wrap(options, ` 127 (func (export "f") (param v128) (param v128) (result v128) 128 (${op} (local.get 1)))`), 129 'f', 130 expected, 131 options); 132 } 133 } 134 135 // () -> v128 136 // inputs: [[complete-opname, expected-pattern], ...] 137 function codegenTestX64_unit_v128(inputs, options = {}) { 138 for ( let [op, expected] of inputs ) { 139 codegenTestX64_adhoc(wrap(options, ` 140 (func (export "f") (result v128) 141 (${op}))`), 142 'f', 143 expected, 144 options); 145 } 146 } 147 148 // For when nothing else applies: `module_text` is the complete source text of 149 // the module, `export_name` is the name of the function to be tested, 150 // `expected` is the non-preprocessed pattern, and options is an options bag, 151 // described above. 152 function codegenTestX64_adhoc(module_text, export_name, expected, options = {}) { 153 assertEq(hasDisassembler(), true); 154 155 let ins = wasmEvalText(module_text, {}, options.features); 156 if (options.instanceBox) 157 options.instanceBox.value = ins; 158 let tierTxt = options.baseline ? "baseline" : "ion"; 159 let output = wasmDis(ins.exports[export_name], 160 {tier:tierTxt, asString:true}); 161 if (!options.no_prefix) 162 expected = x64_prefix + '\n' + expected; 163 if (!options.no_suffix) 164 expected = expected + '\n' + x64_suffix; 165 const expected_pretty = striplines(expected); 166 expected = fixlines(expected); 167 168 const output_simple = stripencoding(output, `(?:${HEX}{2} )*`); 169 const success = output_simple.match(new RegExp(expected)) != null; 170 if (options.log || !success) { 171 print("Module text:") 172 print(module_text); 173 print("Actual output:") 174 print(output); 175 print("Expected output (as text):") 176 print(expected_pretty); 177 print(""); 178 print("Expected output (as regex):") 179 print(expected); 180 print(""); 181 } 182 assertEq(success, true); 183 } 184 185 // Internal code below this line 186 187 function codegenTestX64BinopInternal(op, expected, options, p0type, p1type, restype, arg0, arg1) { 188 codegenTestX64_adhoc(wrap(options, ` 189 (func (export "f") (param ${p0type}) (param ${p1type}) (result ${restype}) 190 (${op} (local.get ${arg0}) (local.get ${arg1})))`), 191 'f', 192 expected, 193 options); 194 }