tor-browser

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

binop-divrem-with-constant-x64-ion-codegen.js (16547B)


      1 // |jit-test| skip-if: !hasDisassembler() || wasmCompileMode() != "ion" || getBuildConfiguration("windows") || !getBuildConfiguration("x64") || getBuildConfiguration("simulator"); include:codegen-x64-test.js
      2 
      3 // Windows is disallowed because the argument registers are different from on
      4 // Linux, and matching both is both difficult and not of much value.
      5 
      6 // Signed 32-bit division with constants.
      7 const i32_div_s = [
      8  // Division by zero.
      9  {
     10    divisor: 0,
     11    expected: `ud2`,
     12  },
     13 
     14  // Power of two divisor
     15  {
     16    divisor: 1,
     17    expected: `mov %edi, %eax`,
     18  },
     19  {
     20    divisor: 2,
     21    expected: `mov %edi, %eax
     22               shr \\$0x1F, %eax
     23               add %edi, %eax
     24               sar \\$0x01, %eax`,
     25  },
     26  {
     27    divisor: 4,
     28    expected: `mov %edi, %eax
     29               sar \\$0x1F, %eax
     30               shr \\$0x1E, %eax
     31               add %edi, %eax
     32               sar \\$0x02, %eax`,
     33  },
     34 
     35  // Division by -1 needs an overflow check.
     36  {
     37    divisor: -1,
     38    expected: `mov %edi, %eax
     39               neg %eax
     40               jno 0x${HEX}+
     41               ud2`,
     42  },
     43 
     44  // Other divisors.
     45  {
     46    divisor: 3,
     47    expected:  `movsxd %edi, %rax
     48                imul \\$0x55555556, %rax, %rax
     49                shr \\$0x20, %rax
     50                mov %edi, %ecx
     51                sar \\$0x1F, %ecx
     52                sub %ecx, %eax`,
     53  },
     54  {
     55    divisor: 5,
     56    expected: `movsxd %edi, %rax
     57               imul \\$0x66666667, %rax, %rax
     58               sar \\$0x21, %rax
     59               mov %edi, %ecx
     60               sar \\$0x1F, %ecx
     61               sub %ecx, %eax`,
     62  },
     63  {
     64    divisor: 7,
     65    expected: `movsxd %edi, %rax
     66               imul \\$-0x6DB6DB6D, %rax, %rax
     67               shr \\$0x20, %rax
     68               add %edi, %eax
     69               sar \\$0x02, %eax
     70               mov %edi, %ecx
     71               sar \\$0x1F, %ecx
     72               sub %ecx, %eax`,
     73  },
     74  {
     75    divisor: 9,
     76    expected: `movsxd %edi, %rax
     77               imul \\$0x38E38E39, %rax, %rax
     78               sar \\$0x21, %rax
     79               mov %edi, %ecx
     80               sar \\$0x1F, %ecx
     81               sub %ecx, %eax`,
     82  },
     83 ];
     84 
     85 for (let {divisor, expected} of i32_div_s) {
     86  let divs32 =
     87    `(module
     88       (func (export "f") (param i32) (result i32)
     89         (i32.div_s (local.get 0) (i32.const ${divisor}))))`
     90  codegenTestX64_adhoc(divs32, 'f', expected);
     91 
     92  // Test negative divisors, too.
     93  if (divisor > 1) {
     94    let divs32 =
     95      `(module
     96         (func (export "f") (param i32) (result i32)
     97           (i32.div_s (local.get 0) (i32.const -${divisor}))))`
     98    codegenTestX64_adhoc(divs32, 'f', expected + `
     99      neg %eax`
    100    );
    101  }
    102 }
    103 
    104 // Unsigned 32-bit division with constants.
    105 const i32_div_u = [
    106  // Division by zero.
    107  {
    108    divisor: 0,
    109    expected: `ud2`,
    110  },
    111 
    112  // Power of two divisor
    113  {
    114    divisor: 1,
    115    expected: `mov %edi, %ecx
    116               mov %ecx, %eax`,
    117  },
    118  {
    119    divisor: 2,
    120    expected: `mov %edi, %ecx
    121               mov %ecx, %eax
    122               shr \\$0x01, %eax`,
    123  },
    124  {
    125    divisor: 4,
    126    expected: `mov %edi, %ecx
    127               mov %ecx, %eax
    128               shr \\$0x02, %eax`,
    129  },
    130 
    131  // Other divisors.
    132  {
    133    divisor: 3,
    134    expected:  `mov %edi, %eax
    135                mov \\$-0x55555555, %ecx
    136                imul %rcx, %rax
    137                shr \\$0x21, %rax`,
    138  },
    139  {
    140    divisor: 5,
    141    expected: `mov %edi, %eax
    142               mov \\$-0x33333333, %ecx
    143               imul %rcx, %rax
    144               shr \\$0x22, %rax`,
    145  },
    146  {
    147    divisor: 7,
    148    expected: `mov %edi, %eax
    149               imul \\$0x24924925, %rax, %rax
    150               shr \\$0x20, %rax
    151               mov %edi, %ecx
    152               sub %eax, %ecx
    153               shr \\$0x01, %ecx
    154               add %ecx, %eax
    155               shr \\$0x02, %eax`,
    156  },
    157  {
    158    divisor: 9,
    159    expected: `mov %edi, %eax
    160               imul \\$0x38E38E39, %rax, %rax
    161               shr \\$0x21, %rax`,
    162  },
    163 
    164  // Special case: Zero (additional) shift amount.
    165  {
    166    divisor: 641,
    167    expected: `mov %edi, %eax
    168               imul \\$0x663D81, %rax, %rax
    169               shr \\$0x20, %rax`,
    170  },
    171 ];
    172 
    173 for (let {divisor, expected} of i32_div_u) {
    174  let divu32 =
    175    `(module
    176       (func (export "f") (param i32) (result i32)
    177         (i32.div_u (local.get 0) (i32.const ${divisor}))))`
    178  codegenTestX64_adhoc(divu32, 'f', expected);
    179 }
    180 
    181 // Signed 64-bit division with constants.
    182 const i64_div_s = [
    183  // Division by zero.
    184  {
    185    divisor: 0,
    186    expected: `ud2`,
    187  },
    188 
    189  // Power of two divisor
    190  {
    191    divisor: 1,
    192    expected: `mov %rdi, %rax`,
    193  },
    194  {
    195    divisor: 2,
    196    expected: `mov %rdi, %rax
    197               shr \\$0x3F, %rax
    198               add %rdi, %rax
    199               sar \\$0x01, %rax`,
    200  },
    201  {
    202    divisor: 4,
    203    expected: `mov %rdi, %rax
    204               sar \\$0x3F, %rax
    205               shr \\$0x3E, %rax
    206               add %rdi, %rax
    207               sar \\$0x02, %rax`,
    208  },
    209  {
    210    divisor: 0x1_0000_0000,
    211    expected: `mov %rdi, %rax
    212               sar \\$0x3F, %rax
    213               shr \\$0x20, %rax
    214               add %rdi, %rax
    215               sar \\$0x20, %rax`,
    216  },
    217 
    218  // Division by -1 needs an overflow check.
    219  {
    220    divisor: -1,
    221    expected: `mov %rdi, %rax
    222               neg %rax
    223               jno 0x${HEX}+
    224               ud2`,
    225  },
    226 
    227  // Other divisors.
    228  {
    229    divisor: 3,
    230    expected:  `mov \\$0x5555555555555556, %rax
    231                imul %rdi
    232                mov %rdi, %rax
    233                sar \\$0x3F, %rax
    234                sub %rax, %rdx`,
    235  },
    236  {
    237    divisor: 5,
    238    expected: `mov \\$0x6666666666666667, %rax
    239               imul %rdi
    240               sar \\$0x01, %rdx
    241               mov %rdi, %rax
    242               sar \\$0x3F, %rax
    243               sub %rax, %rdx`,
    244  },
    245  {
    246    divisor: 7,
    247    expected: `mov \\$0x4924924924924925, %rax
    248               imul %rdi
    249               sar \\$0x01, %rdx
    250               mov %rdi, %rax
    251               sar \\$0x3F, %rax
    252               sub %rax, %rdx`,
    253  },
    254  {
    255    divisor: 9,
    256    expected: `mov \\$0x1C71C71C71C71C72, %rax
    257               imul %rdi
    258               mov %rdi, %rax
    259               sar \\$0x3F, %rax
    260               sub %rax, %rdx`,
    261  },
    262 ];
    263 
    264 for (let {divisor, expected} of i64_div_s) {
    265  let result = IsPowerOfTwo(divisor) ? "rax" : "rdx";
    266  let mov_rdx_to_rax = result !== "rax" ? `
    267    mov %rdx, %rax` : ``;
    268 
    269  let divs64 =
    270    `(module
    271       (func (export "f") (param i64) (result i64)
    272         (i64.div_s (local.get 0) (i64.const ${divisor}))))`
    273  codegenTestX64_adhoc(divs64, 'f', expected + mov_rdx_to_rax);
    274 
    275  // Test negative divisors, too.
    276  if (divisor > 1) {
    277    let divs64 =
    278      `(module
    279         (func (export "f") (param i64) (result i64)
    280           (i64.div_s (local.get 0) (i64.const -${divisor}))))`
    281    codegenTestX64_adhoc(divs64, 'f', expected + `
    282      neg %${result}` + mov_rdx_to_rax
    283    );
    284  }
    285 }
    286 
    287 function IsPowerOfTwo(x) {
    288  x = BigInt(x);
    289  if (x < 0) {
    290    x = -x;
    291  }
    292  return x && (x & (x - 1n)) === 0n;
    293 }
    294 
    295 // Unsigned 64-bit division with constants.
    296 const i64_div_u = [
    297  // Division by zero.
    298  {
    299    divisor: 0,
    300    expected: `ud2
    301               mov %rdx, %rax`,
    302  },
    303 
    304  // Power of two divisor
    305  {
    306    divisor: 1,
    307    expected: `mov %rdi, %rcx
    308               mov %rcx, %rax`,
    309  },
    310  {
    311    divisor: 2,
    312    expected: `mov %rdi, %rcx
    313               mov %rcx, %rax
    314               shr \\$0x01, %rax`,
    315  },
    316  {
    317    divisor: 4,
    318    expected: `mov %rdi, %rcx
    319               mov %rcx, %rax
    320               shr \\$0x02, %rax`,
    321  },
    322  {
    323    divisor: 0x1_0000_0000,
    324    expected: `mov %rdi, %rcx
    325               mov %rcx, %rax
    326               shr \\$0x20, %rax`,
    327  },
    328 
    329  // Other divisors.
    330  {
    331    divisor: 3,
    332    expected:  `mov \\$-0x5555555555555555, %rax
    333                mul %rdi
    334                shr \\$0x01, %rdx
    335                mov %rdx, %rax`,
    336  },
    337  {
    338    divisor: 5,
    339    expected: `mov \\$-0x3333333333333333, %rax
    340               mul %rdi
    341               shr \\$0x02, %rdx
    342               mov %rdx, %rax`,
    343  },
    344  {
    345    divisor: 7,
    346    expected: `mov \\$0x2492492492492493, %rax
    347               mul %rdi
    348               mov %rdi, %rax
    349               sub %rdx, %rax
    350               shr \\$0x01, %rax
    351               add %rax, %rdx
    352               shr \\$0x02, %rdx
    353               mov %rdx, %rax`,
    354  },
    355  {
    356    divisor: 9,
    357    expected: `mov \\$-0x1C71C71C71C71C71, %rax
    358               mul %rdi
    359               shr \\$0x03, %rdx
    360               mov %rdx, %rax`,
    361  },
    362 
    363  // Special case: Zero shift amount.
    364  {
    365    divisor: 274177,
    366    expected: `mov \\$0x3D30F19CD101, %rax
    367               mul %rdi
    368               mov %rdx, %rax`,
    369  },
    370 ];
    371 
    372 for (let {divisor, expected} of i64_div_u) {
    373  let divu64 =
    374    `(module
    375       (func (export "f") (param i64) (result i64)
    376         (i64.div_u (local.get 0) (i64.const ${divisor}))))`
    377  codegenTestX64_adhoc(divu64, 'f', expected);
    378 }
    379 
    380 //////////////
    381 
    382 
    383 
    384 // Signed 32-bit remainder with constants.
    385 const i32_rem_s = [
    386  // Division by zero.
    387  {
    388    divisor: 0,
    389    expected: `ud2`,
    390  },
    391 
    392  // Power of two divisor
    393  {
    394    divisor: 1,
    395    expected: `mov %edi, %ecx
    396               mov %ecx, %eax
    397               xor %eax, %eax`,
    398  },
    399  {
    400    divisor: 2,
    401    expected: `mov %edi, %ecx
    402               mov %ecx, %eax
    403               test %eax, %eax
    404               js 0x${HEX}+
    405               and \\$0x01, %eax
    406               jmp 0x${HEX}+
    407               neg %eax
    408               and \\$0x01, %eax
    409               neg %eax`,
    410  },
    411  {
    412    divisor: 4,
    413    expected: `mov %edi, %ecx
    414               mov %ecx, %eax
    415               test %eax, %eax
    416               js 0x${HEX}+
    417               and \\$0x03, %eax
    418               jmp 0x${HEX}+
    419               neg %eax
    420               and \\$0x03, %eax
    421               neg %eax`,
    422  },
    423  {
    424    divisor: 0x100,
    425    expected: `mov %edi, %ecx
    426               mov %ecx, %eax
    427               test %eax, %eax
    428               js 0x${HEX}+
    429               movzx %al, %eax
    430               jmp 0x${HEX}+
    431               neg %eax
    432               movzx %al, %eax
    433               neg %eax`,
    434  },
    435  {
    436    divisor: 0x10000,
    437    expected: `mov %edi, %ecx
    438               mov %ecx, %eax
    439               test %eax, %eax
    440               js 0x${HEX}+
    441               movzx %ax, %eax
    442               jmp 0x${HEX}+
    443               neg %eax
    444               movzx %ax, %eax
    445               neg %eax`,
    446  },
    447  {
    448    divisor: 0x8000_0000,
    449    expected: `mov %edi, %ecx
    450               mov %ecx, %eax
    451               test %eax, %eax
    452               js 0x${HEX}+
    453               and \\$0x7FFFFFFF, %eax
    454               jmp 0x${HEX}+
    455               neg %eax
    456               and \\$0x7FFFFFFF, %eax
    457               neg %eax`,
    458  },
    459 ];
    460 
    461 for (let {divisor, expected} of i32_rem_s) {
    462  let rems32 =
    463    `(module
    464       (func (export "f") (param i32) (result i32)
    465         (i32.rem_s (local.get 0) (i32.const ${divisor}))))`
    466  codegenTestX64_adhoc(rems32, 'f', expected);
    467 
    468  // Test negative divisors, too.
    469  if (divisor > 0) {
    470    let rems32 =
    471      `(module
    472         (func (export "f") (param i32) (result i32)
    473           (i32.rem_s (local.get 0) (i32.const -${divisor}))))`
    474    codegenTestX64_adhoc(rems32, 'f', expected);
    475  }
    476 }
    477 
    478 // Unigned 32-bit remainder with constants.
    479 const u32_rem_s = [
    480  // Division by zero.
    481  {
    482    divisor: 0,
    483    expected: `ud2`,
    484  },
    485 
    486  // Power of two divisor
    487  {
    488    divisor: 1,
    489    expected: `mov %edi, %ecx
    490               mov %ecx, %eax
    491               xor %eax, %eax`,
    492  },
    493  {
    494    divisor: 2,
    495    expected: `mov %edi, %ecx
    496               mov %ecx, %eax
    497               and \\$0x01, %eax`,
    498  },
    499  {
    500    divisor: 4,
    501    expected: `mov %edi, %ecx
    502               mov %ecx, %eax
    503               and \\$0x03, %eax`,
    504  },
    505  {
    506    divisor: 0x100,
    507    expected: `mov %edi, %ecx
    508               mov %ecx, %eax
    509               movzx %al, %eax`,
    510  },
    511  {
    512    divisor: 0x10000,
    513    expected: `mov %edi, %ecx
    514               mov %ecx, %eax
    515               movzx %ax, %eax`,
    516  },
    517  {
    518    divisor: 0x8000_0000,
    519    expected: `mov %edi, %ecx
    520               mov %ecx, %eax
    521               and \\$0x7FFFFFFF, %eax`,
    522  },
    523 ];
    524 
    525 for (let {divisor, expected} of u32_rem_s) {
    526  let remu32 =
    527    `(module
    528       (func (export "f") (param i32) (result i32)
    529         (i32.rem_u (local.get 0) (i32.const ${divisor}))))`
    530  codegenTestX64_adhoc(remu32, 'f', expected);
    531 }
    532 
    533 // Signed 64-bit remainder with constants.
    534 const i64_rem_s = [
    535  // Division by zero.
    536  {
    537    divisor: 0,
    538    expected: `ud2`,
    539  },
    540 
    541  // Power of two divisor
    542  {
    543    divisor: 1,
    544    expected: `mov %rdi, %rcx
    545               mov %rcx, %rax
    546               xor %eax, %eax`,
    547  },
    548  {
    549    divisor: 2,
    550    expected: `mov %rdi, %rcx
    551               mov %rcx, %rax
    552               test %rax, %rax
    553               js 0x${HEX}+
    554               and \\$0x01, %eax
    555               jmp 0x${HEX}+
    556               neg %rax
    557               and \\$0x01, %eax
    558               neg %rax`,
    559  },
    560  {
    561    divisor: 4,
    562    expected: `mov %rdi, %rcx
    563               mov %rcx, %rax
    564               test %rax, %rax
    565               js 0x${HEX}+
    566               and \\$0x03, %eax
    567               jmp 0x${HEX}+
    568               neg %rax
    569               and \\$0x03, %eax
    570               neg %rax`,
    571  },
    572  {
    573    divisor: 0x100,
    574    expected: `mov %rdi, %rcx
    575               mov %rcx, %rax
    576               test %rax, %rax
    577               js 0x${HEX}+
    578               movzx %al, %eax
    579               jmp 0x${HEX}+
    580               neg %rax
    581               movzx %al, %eax
    582               neg %rax`,
    583  },
    584  {
    585    divisor: 0x10000,
    586    expected: `mov %rdi, %rcx
    587               mov %rcx, %rax
    588               test %rax, %rax
    589               js 0x${HEX}+
    590               movzx %ax, %eax
    591               jmp 0x${HEX}+
    592               neg %rax
    593               movzx %ax, %eax
    594               neg %rax`,
    595  },
    596  {
    597    divisor: 0x8000_0000,
    598    expected: `mov %rdi, %rcx
    599               mov %rcx, %rax
    600               test %rax, %rax
    601               js 0x${HEX}+
    602               and \\$0x7FFFFFFF, %eax
    603               jmp 0x${HEX}+
    604               neg %rax
    605               and \\$0x7FFFFFFF, %eax
    606               neg %rax`,
    607  },
    608  {
    609    divisor: 0x1_0000_0000,
    610    expected: `mov %rdi, %rcx
    611               mov %rcx, %rax
    612               test %rax, %rax
    613               js 0x${HEX}+
    614               mov %eax, %eax
    615               jmp 0x${HEX}+
    616               neg %rax
    617               mov %eax, %eax
    618               neg %rax`,
    619  },
    620  {
    621    divisor: 0x8000_0000_0000_0000n,
    622    expected: `mov %rdi, %rcx
    623               mov %rcx, %rax
    624               test %rax, %rax
    625               js 0x${HEX}+
    626               mov \\$0x7FFFFFFFFFFFFFFF, %r11
    627               and %r11, %rax
    628               jmp 0x${HEX}+
    629               neg %rax
    630               mov \\$0x7FFFFFFFFFFFFFFF, %r11
    631               and %r11, %rax
    632               neg %rax`,
    633  },
    634 ];
    635 
    636 for (let {divisor, expected} of i64_rem_s) {
    637  let rems64 =
    638    `(module
    639       (func (export "f") (param i64) (result i64)
    640         (i64.rem_s (local.get 0) (i64.const ${divisor}))))`
    641  codegenTestX64_adhoc(rems64, 'f', expected);
    642 
    643  // Test negative divisors, too.
    644  if (divisor > 0) {
    645    let rems64 =
    646      `(module
    647         (func (export "f") (param i64) (result i64)
    648           (i64.rem_s (local.get 0) (i64.const -${divisor}))))`
    649    codegenTestX64_adhoc(rems64, 'f', expected);
    650  }
    651 }
    652 
    653 // Unsigned 64-bit remainder with constants.
    654 const i64_rem_u = [
    655  // Division by zero.
    656  {
    657    divisor: 0,
    658    expected: `ud2`,
    659  },
    660 
    661  // Power of two divisor
    662  {
    663    divisor: 1,
    664    expected: `mov %rdi, %rcx
    665               mov %rcx, %rax
    666               xor %eax, %eax`,
    667  },
    668  {
    669    divisor: 2,
    670    expected: `mov %rdi, %rcx
    671               mov %rcx, %rax
    672               and \\$0x01, %eax`,
    673  },
    674  {
    675    divisor: 4,
    676    expected: `mov %rdi, %rcx
    677               mov %rcx, %rax
    678               and \\$0x03, %eax`,
    679  },
    680  {
    681    divisor: 0x100,
    682    expected: `mov %rdi, %rcx
    683               mov %rcx, %rax
    684               movzx %al, %eax`,
    685  },
    686  {
    687    divisor: 0x10000,
    688    expected: `mov %rdi, %rcx
    689               mov %rcx, %rax
    690               movzx %ax, %eax`,
    691  },
    692  {
    693    divisor: 0x8000_0000,
    694    expected: `mov %rdi, %rcx
    695               mov %rcx, %rax
    696               and \\$0x7FFFFFFF, %eax`,
    697  },
    698  {
    699    divisor: 0x1_0000_0000,
    700    expected: `mov %rdi, %rcx
    701               mov %rcx, %rax
    702               mov %eax, %eax`,
    703  },
    704  {
    705    divisor: 0x8000_0000_0000_0000n,
    706    expected: `mov %rdi, %rcx
    707               mov %rcx, %rax
    708               mov \\$0x7FFFFFFFFFFFFFFF, %r11
    709               and %r11, %rax`,
    710  },
    711 ];
    712 
    713 for (let {divisor, expected} of i64_rem_u) {
    714  let remu64 =
    715    `(module
    716       (func (export "f") (param i64) (result i64)
    717         (i64.rem_u (local.get 0) (i64.const ${divisor}))))`
    718  codegenTestX64_adhoc(remu64, 'f', expected);
    719 }