Source code
Revision control
Copy as Markdown
Other Tools
// |jit-test| skip-if: !hasDisassembler() || wasmCompileMode() != "ion" || !getBuildConfiguration("arm"); include:codegen-arm-test.js
const WasmTrapIns = `constant pool begin \\(length 0\\) \\[undefined insn\\]`;
// Signed 32-bit division with constants.
const i32_div_s = [
// Division by zero.
{
divisor: 0,
expected: `mov r2, r0
mov r1, r2
${WasmTrapIns}`,
},
// Power of two divisor
{
divisor: 1,
expected: ``,
},
{
divisor: 2,
expected: `add ip, r0, r0, lsr #31
mov r0, ip, asr #1`,
},
{
divisor: 4,
expected: `mov ip, r0, asr #31
add ip, r0, ip, lsr #30
mov r0, ip, asr #2`,
},
// Division by -1 needs an overflow check.
{
divisor: -1,
expected: `cmp r0, #-2147483648
bne \\+8 -> 0x${HEX}+
${WasmTrapIns}
rsb r0, r0, #0`,
},
// Other divisors.
{
divisor: 3,
expected: `mov r2, r0
mov r1, r2
movw ip, #21846
movt ip, #21845
smull ip, r0, ip, r1
sub r0, r0, r1, asr #31`,
},
{
divisor: 5,
expected: `mov r2, r0
mov r1, r2
movw ip, #26215
movt ip, #26214
smull ip, r0, ip, r1
mov r0, r0, asr #1
sub r0, r0, r1, asr #31`,
},
{
divisor: 7,
expected: `mov r2, r0
mov r1, r2
movw ip, #9363
movt ip, #37449
smull ip, r0, ip, r1
add r0, r0, r1
mov r0, r0, asr #2
sub r0, r0, r1, asr #31`,
},
{
divisor: 9,
expected: `mov r2, r0
mov r1, r2
movw ip, #36409
movt ip, #14563
smull ip, r0, ip, r1
mov r0, r0, asr #1
sub r0, r0, r1, asr #31`,
},
];
for (let {divisor, expected} of i32_div_s) {
let divs32 =
`(module
(func (export "f") (param i32) (result i32)
(i32.div_s (local.get 0) (i32.const ${divisor}))))`
codegenTestARM_adhoc(divs32, 'f', expected);
// Test negative divisors, too.
if (divisor > 1) {
let divs32 =
`(module
(func (export "f") (param i32) (result i32)
(i32.div_s (local.get 0) (i32.const -${divisor}))))`
codegenTestARM_adhoc(divs32, 'f', expected + `
rsb r0, r0, #0`
);
}
}
// Unsigned 32-bit division with constants.
const i32_div_u = [
// Division by zero.
{
divisor: 0,
expected: `mov r2, r0
mov r1, r2
${WasmTrapIns}`,
},
// Power of two divisor
{
divisor: 1,
expected: ``,
},
{
divisor: 2,
expected: `mov r0, r0, lsr #1`,
},
{
divisor: 4,
expected: `mov r0, r0, lsr #2`,
},
// Other divisors.
{
divisor: 3,
expected: `mov r2, r0
mov r1, r2
movw ip, #43691
movt ip, #43690
umull ip, r0, ip, r1
mov r0, r0, lsr #1`,
},
{
divisor: 5,
expected: `mov r2, r0
mov r1, r2
movw ip, #52429
movt ip, #52428
umull ip, r0, ip, r1
mov r0, r0, lsr #2`,
},
{
divisor: 7,
expected: `mov r2, r0
mov r1, r2
movw ip, #18725
movt ip, #9362
umull ip, r0, ip, r1
sub ip, r1, r0
mov ip, ip, lsr #1
add r0, r0, ip
mov r0, r0, lsr #2`,
},
{
divisor: 9,
expected: `mov r2, r0
mov r1, r2
movw ip, #36409
movt ip, #14563
umull ip, r0, ip, r1
mov r0, r0, lsr #1`,
},
// Special case: Zero (additional) shift amount.
{
divisor: 641,
expected: `mov r2, r0
mov r1, r2
movw ip, #15745
movt ip, #102
umull ip, r0, ip, r1`,
},
];
for (let {divisor, expected} of i32_div_u) {
let divu32 =
`(module
(func (export "f") (param i32) (result i32)
(i32.div_u (local.get 0) (i32.const ${divisor}))))`
codegenTestARM_adhoc(divu32, 'f', expected);
}
// Signed 32-bit remainder with constants.
const i32_rem_s = [
// Division by zero.
{
divisor: 0,
expected: `mov r2, r0
mov r1, r2
${WasmTrapIns}`,
},
// Power of two divisor
{
divisor: 1,
expected: `movs r0, r0
beq \\+16 -> 0x${HEX}+
rsbmi r0, r0, #0
and r0, r0, #0
rsbmis r0, r0, #0`,
},
{
divisor: 2,
expected: `movs r0, r0
beq \\+16 -> 0x${HEX}+
rsbmi r0, r0, #0
and r0, r0, #1
rsbmis r0, r0, #0`,
},
{
divisor: 4,
expected: `movs r0, r0
beq \\+16 -> 0x${HEX}+
rsbmi r0, r0, #0
and r0, r0, #3
rsbmis r0, r0, #0`,
},
{
divisor: 0x100,
expected: `movs r0, r0
beq \\+16 -> 0x${HEX}+
rsbmi r0, r0, #0
and r0, r0, #255
rsbmis r0, r0, #0`,
},
{
divisor: 0x10000,
expected: `movs r0, r0
beq \\+20 -> 0x${HEX}+
rsbmi r0, r0, #0
bic r0, r0, #-16777216
bic r0, r0, #16711680
rsbmis r0, r0, #0`,
},
{
divisor: 0x80000000,
expected: `movs r0, r0
beq \\+16 -> 0x${HEX}+
rsbmi r0, r0, #0
bic r0, r0, #-2147483648
rsbmis r0, r0, #0`,
},
// Other divisors.
{
divisor: 3,
expected: `mov r2, r0
mov r1, r2
movw ip, #21846
movt ip, #21845
smull ip, r0, ip, r1
sub r0, r0, r1, asr #31
mov ip, #3
mls r0, ip, r0, r1`,
negative: `mov r2, r0
mov r1, r2
movw ip, #21846
movt ip, #21845
smull ip, r0, ip, r1
sub r0, r0, r1, asr #31
rsb r0, r0, #0
mvn ip, #2
mls r0, ip, r0, r1`,
},
];
for (let {divisor, expected, negative = expected} of i32_rem_s) {
let rems32 =
`(module
(func (export "f") (param i32) (result i32)
(i32.rem_s (local.get 0) (i32.const ${divisor}))))`
codegenTestARM_adhoc(rems32, 'f', expected);
// Test negative divisors, too.
if (divisor > 0) {
let rems32 =
`(module
(func (export "f") (param i32) (result i32)
(i32.rem_s (local.get 0) (i32.const -${divisor}))))`
codegenTestARM_adhoc(rems32, 'f', negative);
}
}
// Unsigned 32-bit remainder with constants.
const i32_rem_u = [
// Division by zero.
{
divisor: 0,
expected: `mov r2, r0
mov r1, r2
${WasmTrapIns}`,
},
// Power of two divisor
{
divisor: 1,
expected: `and r0, r0, #0`,
},
{
divisor: 2,
expected: `and r0, r0, #1`,
},
{
divisor: 4,
expected: `and r0, r0, #3`,
},
{
divisor: 0x100,
expected: `and r0, r0, #255`,
},
{
divisor: 0x10000,
expected: `bic r0, r0, #-16777216
bic r0, r0, #16711680`,
},
{
divisor: 0x80000000,
expected: `bic r0, r0, #-2147483648`,
},
// Other divisors.
{
divisor: 3,
expected: `mov r2, r0
mov r1, r2
movw ip, #43691
movt ip, #43690
umull ip, r0, ip, r1
mov r0, r0, lsr #1
mov ip, #3
mls r0, ip, r0, r1`,
},
];
for (let {divisor, expected} of i32_rem_u) {
let remu32 =
`(module
(func (export "f") (param i32) (result i32)
(i32.rem_u (local.get 0) (i32.const ${divisor}))))`
codegenTestARM_adhoc(remu32, 'f', expected);
}