Source code

Revision control

Copy as Markdown

Other Tools

// |jit-test| skip-if: !hasDisassembler() || wasmCompileMode() != "ion" || getBuildConfiguration("windows") || (!getBuildConfiguration("x64") && !getBuildConfiguration("x86") && !getBuildConfiguration("arm64") && !getBuildConfiguration("arm")); include:adhoc-multiplatform-test.js
//
// These tests push wasm functions through the ion pipe and specify an expected
// disassembly output on all 4 primary targets, x64 / x86 / arm64 / arm(32).
// Results must be provided for the first 3, but can optionally be skipped
// for arm(32).
//
// Hence: disassembler is needed, compiler must be ion.
//
// Windows is disallowed because the argument registers are different from on
// Linux, and matching both is both difficult and not of much value.
// Tests are "end-to-end" in the sense that we don't care whether the
// tested-for code improvement is done by MIR optimisation, or later in the
// pipe. Observed defects are marked with FIXMEs for future easy finding.
// Note that identities involving AND, OR and XOR are tested by
// binop-x64-ion-folding.js
// Multiplication with magic constant on the left
//
// 0 * x => 0
// 1 * x => x
// -1 * x => -x
// 2 * x => x + x
// 4 * x => x << 2
codegenTestMultiplatform_adhoc(
`(module (func (export "mul32_zeroL") (param $p1 i32) (result i32)
(i32.mul (i32.const 0) (local.get $p1))))`,
"mul32_zeroL",
{x64: `xor %eax, %eax`,
x86: `xor %eax, %eax`,
arm64: `mov w0, wzr`,
arm: `mov r0, #0`},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "mul64_zeroL") (param $p1 i64) (result i64)
(i64.mul (i64.const 0) (local.get $p1))))`,
"mul64_zeroL",
// FIXME zero-creation insns could be improved
{x64: `xor %rax, %rax`, // REX.W is redundant
x86: `xor %eax, %eax
xor %edx, %edx`,
arm64: `mov x0, xzr`,
arm: `mov r0, #0
mov r1, #0` },
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "mul32_oneL") (param $p1 i32) (result i32)
(i32.mul (i32.const 1) (local.get $p1))))`,
"mul32_oneL",
{x64: // We move edi to eax unnecessarily via ecx (bug 1752520).
// Presumably because the folding 1 * x => x is done at the LIR
// level, not the MIR level, hence the now-pointless WasmParameter
// node is not DCE'd away, since DCE only happens at the MIR level.
// In fact all targets suffer from the latter problem, but on x86
// no_prefix_x86:true hides it, and on arm32/64 the pointless move
// is correctly transformed by RA into a no-op.
`mov %edi, %ecx
mov %ecx, %eax`,
x86: `movl 0x10\\(%rbp\\), %eax`,
arm64: ``,
arm: ``},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "mul64_oneL") (param $p1 i64) (result i64)
(i64.mul (i64.const 1) (local.get $p1))))`,
"mul64_oneL",
{x64: `mov %rdi, %rcx
mov %rcx, %rax`,
x86: `movl 0x14\\(%rbp\\), %edx
movl 0x10\\(%rbp\\), %eax`,
arm64: ``,
arm: ``},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "mul32_minusOneL") (param $p1 i32) (result i32)
(i32.mul (i32.const -1) (local.get $p1))))`,
"mul32_minusOneL",
{x64: `neg %eax`,
x86: `neg %eax`,
arm64: `neg w0, w0`,
arm: `rsb r0, r0, #0`},
{x86: {no_prefix:true}, x64: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "mul64_minusOneL") (param $p1 i64) (result i64)
(i64.mul (i64.const -1) (local.get $p1))))`,
"mul64_minusOneL",
{x64: `mov %rdi, %rcx
mov %rcx, %rax
neg %rax`,
x86: `neg %eax
adc \\$0x00, %edx
neg %edx`,
arm64: `neg x0, x0`,
arm: `rsbs r0, r0, #0
rsc r1, r1, #0`},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "mul32_twoL") (param $p1 i32) (result i32)
(i32.mul (i32.const 2) (local.get $p1))))`,
"mul32_twoL",
{x64: `lea \\(%rdi,%rdi,1\\), %eax`,
x86: `movl 0x10\\(%rbp\\), %eax
add %eax, %eax`,
arm64: `add w0, w0, w0`,
arm: `adds r0, r0, r0`},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "mul64_twoL") (param $p1 i64) (result i64)
(i64.mul (i64.const 2) (local.get $p1))))`,
"mul64_twoL",
{x64: `lea \\(%rdi,%rdi,1\\), %rax`,
x86: `movl 0x14\\(%rbp\\), %edx
movl 0x10\\(%rbp\\), %eax
add %eax, %eax
adc %edx, %edx`,
arm64: `add x0, x0, x0`,
arm: `adds r0, r0, r0
adc r1, r1, r1`},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "mul32_fourL") (param $p1 i32) (result i32)
(i32.mul (i32.const 4) (local.get $p1))))`,
"mul32_fourL",
{x64: `lea \\(,%rdi,4\\), %eax`,
x86: `movl 0x10\\(%rbp\\), %eax
shl \\$0x02, %eax`,
arm64: `lsl w0, w0, #2`,
arm: `mov r0, r0, lsl #2`},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "mul64_fourL") (param $p1 i64) (result i64)
(i64.mul (i64.const 4) (local.get $p1))))`,
"mul64_fourL",
{x64: `lea \\(,%rdi,4\\), %rax`,
x86: `movl 0x14\\(%rbp\\), %edx
movl 0x10\\(%rbp\\), %eax
shld \\$0x02, %eax, %edx
shl \\$0x02, %eax`,
arm64: `lsl x0, x0, #2`,
arm: `mov r1, r1, lsl #2
orr r1, r1, r0, lsr #30
mov r0, r0, lsl #2`},
{x86: {no_prefix:true}}
);
// Multiplication with magic constant on the right
//
// x * 0 => 0
// x * 1 => x
// x * -1 => -x
// x * 2 => x + x
// x * 4 => x << 2
codegenTestMultiplatform_adhoc(
`(module (func (export "mul32_zeroR") (param $p1 i32) (result i32)
(i32.mul (local.get $p1) (i32.const 0))))`,
"mul32_zeroR",
{x64: `xor %eax, %eax`,
x86: `xor %eax, %eax`,
arm64: `mov w0, wzr`,
arm: `mov r0, #0`},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "mul64_zeroR") (param $p1 i64) (result i64)
(i64.mul (local.get $p1) (i64.const 0))))`,
"mul64_zeroR",
{x64: `xor %rax, %rax`, // REX.W is redundant
x86: `xor %eax, %eax
xor %edx, %edx`,
arm64: `mov x0, xzr`,
arm: `mov r0, #0
mov r1, #0` },
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "mul32_oneR") (param $p1 i32) (result i32)
(i32.mul (local.get $p1) (i32.const 1))))`,
"mul32_oneR",
{x64: `mov %edi, %ecx
mov %ecx, %eax`,
x86: `movl 0x10\\(%rbp\\), %eax`,
arm64: ``,
arm: ``},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "mul64_oneR") (param $p1 i64) (result i64)
(i64.mul (local.get $p1) (i64.const 1))))`,
"mul64_oneR",
{x64: `mov %rdi, %rcx
mov %rcx, %rax`,
x86: `movl 0x14\\(%rbp\\), %edx
movl 0x10\\(%rbp\\), %eax`,
arm64: ``,
arm: ``},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "mul32_minusOneR") (param $p1 i32) (result i32)
(i32.mul (local.get $p1) (i32.const -1))))`,
"mul32_minusOneR",
{x64: `neg %eax`,
x86: `neg %eax`,
arm64: `neg w0, w0`,
arm: `rsb r0, r0, #0`},
{x86: {no_prefix:true}, x64: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "mul64_minusOneR") (param $p1 i64) (result i64)
(i64.mul (local.get $p1) (i64.const -1))))`,
"mul64_minusOneR",
{x64: `mov %rdi, %rcx
mov %rcx, %rax
neg %rax`,
x86: `neg %eax
adc \\$0x00, %edx
neg %edx`,
arm64: `neg x0, x0`,
arm: `rsbs r0, r0, #0
rsc r1, r1, #0`},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "mul32_twoR") (param $p1 i32) (result i32)
(i32.mul (local.get $p1) (i32.const 2))))`,
"mul32_twoR",
{x64: `lea \\(%rdi,%rdi,1\\), %eax`,
x86: `movl 0x10\\(%rbp\\), %eax
add %eax, %eax`,
arm64: `add w0, w0, w0`,
arm: `adds r0, r0, r0`},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "mul64_twoR") (param $p1 i64) (result i64)
(i64.mul (local.get $p1) (i64.const 2))))`,
"mul64_twoR",
{x64: `lea \\(%rdi,%rdi,1\\), %rax`,
x86: `movl 0x14\\(%rbp\\), %edx
movl 0x10\\(%rbp\\), %eax
add %eax, %eax
adc %edx, %edx`,
arm64: `add x0, x0, x0`,
arm: `adds r0, r0, r0
adc r1, r1, r1`},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "mul32_fourR") (param $p1 i32) (result i32)
(i32.mul (local.get $p1) (i32.const 4))))`,
"mul32_fourR",
{x64: `lea \\(,%rdi,4\\), %eax`,
x86: `movl 0x10\\(%rbp\\), %eax
shl \\$0x02, %eax`,
arm64: `lsl w0, w0, #2`,
arm: `mov r0, r0, lsl #2`},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "mul64_fourR") (param $p1 i64) (result i64)
(i64.mul (local.get $p1) (i64.const 4))))`,
"mul64_fourR",
{x64: `lea \\(,%rdi,4\\), %rax`,
x86: `movl 0x14\\(%rbp\\), %edx
movl 0x10\\(%rbp\\), %eax
shld \\$0x02, %eax, %edx
shl \\$0x02, %eax`,
arm64: `lsl x0, x0, #2`,
arm: `mov r1, r1, lsl #2
orr r1, r1, r0, lsr #30
mov r0, r0, lsl #2`
},
{x86: {no_prefix:true}}
);
// Shifts by zero (the right arg is zero)
//
// x >> 0 => x (any shift kind: shl, shrU, shrS)
codegenTestMultiplatform_adhoc(
`(module (func (export "shl32_zeroR") (param $p1 i32) (result i32)
(i32.shl (local.get $p1) (i32.const 0))))`,
"shl32_zeroR",
// FIXME check these are consistently folded out at the MIR level
{x64: `mov %edi, %ecx
mov %ecx, %eax`,
x86: `movl 0x10\\(%rbp\\), %eax`,
arm64: `mov w0, w0`,
arm: `` // no-op
},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "shl64_zeroR") (param $p1 i64) (result i64)
(i64.shl (local.get $p1) (i64.const 0))))`,
"shl64_zeroR",
// FIXME why is this code so much better than the 32-bit case?
{x64: `mov %rdi, %rcx
mov %rcx, %rax`,
x86: `movl 0x14\\(%rbp\\), %edx
movl 0x10\\(%rbp\\), %eax`,
arm64: ``, // no-op
arm: `` // no-op
},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "shrU32_zeroR") (param $p1 i32) (result i32)
(i32.shr_u (local.get $p1) (i32.const 0))))`,
"shrU32_zeroR",
{x64: `mov %edi, %ecx
mov %ecx, %eax`,
x86: `movl 0x10\\(%rbp\\), %eax`,
arm64: `mov w0, w0`,
arm: ``
},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "shrU64_zeroR") (param $p1 i64) (result i64)
(i64.shr_u (local.get $p1) (i64.const 0))))`,
"shrU64_zeroR",
{x64: `mov %rdi, %rcx
mov %rcx, %rax`,
x86: `movl 0x14\\(%rbp\\), %edx
movl 0x10\\(%rbp\\), %eax`,
arm64: ``,
arm: ``
},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "shrS32_zeroR") (param $p1 i32) (result i32)
(i32.shr_s (local.get $p1) (i32.const 0))))`,
"shrS32_zeroR",
{x64: `mov %edi, %ecx
mov %ecx, %eax`,
x86: `movl 0x10\\(%rbp\\), %eax`,
arm64: `mov w0, w0`,
arm: ``
},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "shrS64_zeroR") (param $p1 i64) (result i64)
(i64.shr_s (local.get $p1) (i64.const 0))))`,
"shrS64_zeroR",
{x64: `mov %rdi, %rcx
mov %rcx, %rax`,
x86: `movl 0x14\\(%rbp\\), %edx
movl 0x10\\(%rbp\\), %eax`,
arm64: ``,
arm: ``
},
{x86: {no_prefix:true}}
);
// Identities involving addition
//
// x + 0 => x
// 0 + x => x
// x + x => x << 1
codegenTestMultiplatform_adhoc(
`(module (func (export "add32_zeroR") (param $p1 i32) (result i32)
(i32.add (local.get $p1) (i32.const 0))))`,
"add32_zeroR",
{x64: `mov %edi, %ecx
mov %ecx, %eax`,
x86: `movl 0x10\\(%rbp\\), %eax`,
arm64: ``,
arm: ``
},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "add64_zeroR") (param $p1 i64) (result i64)
(i64.add (local.get $p1) (i64.const 0))))`,
"add64_zeroR",
{x64: `mov %rdi, %rcx
mov %rcx, %rax`,
x86: `movl 0x14\\(%rbp\\), %edx
movl 0x10\\(%rbp\\), %eax`,
arm64: ``,
arm: ``
},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "add32_zeroL") (param $p1 i32) (result i32)
(i32.add (i32.const 0) (local.get $p1))))`,
"add32_zeroL",
{x64: `mov %edi, %ecx
mov %ecx, %eax`,
x86: `movl 0x10\\(%rbp\\), %eax`,
arm64: ``,
arm: ``
},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "add64_zeroL") (param $p1 i64) (result i64)
(i64.add (i64.const 0) (local.get $p1))))`,
"add64_zeroL",
{x64: `mov %rdi, %rcx
mov %rcx, %rax`,
x86: `movl 0x14\\(%rbp\\), %edx
movl 0x10\\(%rbp\\), %eax`,
arm64: ``,
arm: ``
},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "add32_self") (param $p1 i32) (result i32)
(i32.add (local.get $p1) (local.get $p1))))`,
"add32_self",
{x64: `mov %edi, %ecx
mov %ecx, %eax
add %ecx, %eax`,
x86: `movl 0x10\\(%rbp\\), %eax
addl 0x10\\(%rbp\\), %eax`,
arm64: `add w0, w0, w0`,
arm: `adds r0, r0, r0 `
},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "add64_self") (param $p1 i64) (result i64)
(i64.add (local.get $p1) (local.get $p1))))`,
"add64_self",
// FIXME outstandingly bad 32-bit sequences, probably due to the RA
{x64: `mov %rdi, %rcx
mov %rcx, %rax
add %rcx, %rax`,
x86: // -0x21524111 is 0xDEADBEEF
`movl 0x14\\(%rbp\\), %ebx
movl 0x10\\(%rbp\\), %ecx
mov \\$-0x21524111, %edi
movl 0x14\\(%rbp\\), %edx
movl 0x10\\(%rbp\\), %eax
add %ecx, %eax
adc %ebx, %edx`,
arm64: `add x0, x0, x0`,
arm: // play Musical Chairs for a while
`mov r3, r1
mov r2, r0
mov r5, r3
mov r4, r2
mov r1, r3
mov r0, r2
adds r0, r0, r4
adc r1, r1, r5`
},
{x86: {no_prefix:true}}
);
// Identities involving subtraction
//
// x - 0 => x
// 0 - x => -x
// x - x => 0
codegenTestMultiplatform_adhoc(
`(module (func (export "sub32_zeroR") (param $p1 i32) (result i32)
(i32.sub (local.get $p1) (i32.const 0))))`,
"sub32_zeroR",
{x64: `mov %edi, %ecx
mov %ecx, %eax`,
x86: `movl 0x10\\(%rbp\\), %eax`,
arm64: ``,
arm: ``
},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "sub64_zeroR") (param $p1 i64) (result i64)
(i64.sub (local.get $p1) (i64.const 0))))`,
"sub64_zeroR",
{x64: `mov %rdi, %rcx
mov %rcx, %rax`,
x86: `movl 0x14\\(%rbp\\), %edx
movl 0x10\\(%rbp\\), %eax`,
arm64: ``,
arm: ``
},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "sub32_zeroL") (param $p1 i32) (result i32)
(i32.sub (i32.const 0) (local.get $p1))))`,
"sub32_zeroL",
{x64: `mov %edi, %ecx
mov %ecx, %eax
neg %eax`,
x86: `movl 0x10\\(%rbp\\), %eax
neg %eax`,
arm64: `neg w0, w0 `,
arm: `rsb r0, r0, #0`
},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "sub64_zeroL") (param $p1 i64) (result i64)
(i64.sub (i64.const 0) (local.get $p1))))`,
"sub64_zeroL",
{x64: `mov %rdi, %rcx
mov %rcx, %rax
neg %rax`,
x86: `movl 0x14\\(%rbp\\), %edx
movl 0x10\\(%rbp\\), %eax
neg %eax
adc \\$0x00, %edx
neg %edx`,
arm64: `neg x0, x0`,
arm: `rsbs r0, r0, #0
rsc r1, r1, #0`
},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "sub32_self") (param $p1 i32) (result i32)
(i32.sub (local.get $p1) (local.get $p1))))`,
"sub32_self",
{x64: `xor %eax, %eax`,
x86: `xor %eax, %eax`,
arm64: `mov w0, #0x0`,
arm: `mov r0, #0`
},
{x86: {no_prefix:true}}
);
codegenTestMultiplatform_adhoc(
`(module (func (export "sub64_self") (param $p1 i64) (result i64)
(i64.sub (local.get $p1) (local.get $p1))))`,
"sub64_self",
{x64: `xor %eax, %eax`,
x86: `xor %eax, %eax
xor %edx, %edx`,
arm64: `mov x0, #0x0`,
arm: `mov r0, #0
mov r1, #0`
},
{x86: {no_prefix:true}}
);