tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }