зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1674965 - Test harness for code generation tests. r=rhunt
The commonalities of the x64 code generation test cases are factored into lib/codegen-x64-test.js and that file is included by the test cases. The harness allows the expected patterns in the test cases to be much smaller. The harness adds the pattern prefix and suffix during preprocessing, adds the address prefix for each line, and makes whitespace matching more flexible. Additionally the harness exports some variables (representing subpatterns) that can be used within the expected patterns to express common phrases, such as RIP-relative addresses. Differential Revision: https://phabricator.services.mozilla.com/D95733
This commit is contained in:
Родитель
b1806d83eb
Коммит
274d1a5dde
|
@ -1093,6 +1093,12 @@ struct DisasmBuffer {
|
|||
explicit DisasmBuffer(JSContext* cx) : builder(cx), oom(false) {}
|
||||
};
|
||||
|
||||
static bool HasDisassembler(JSContext* cx, unsigned argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
args.rval().setBoolean(jit::HasDisassembler());
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_THREAD_LOCAL(DisasmBuffer*) disasmBuf;
|
||||
|
||||
static void captureDisasmText(const char* text) {
|
||||
|
@ -6446,6 +6452,10 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = {
|
|||
"gcparam(name [, value])",
|
||||
" Wrapper for JS_[GS]etGCParameter. The name is one of:" GC_PARAMETER_ARGS_LIST),
|
||||
|
||||
JS_FN_HELP("hasDisassembler", HasDisassembler, 0, 0,
|
||||
"hasDisassembler()",
|
||||
" Return true if a disassembler is present (for disnative and wasmDis)."),
|
||||
|
||||
JS_FN_HELP("disnative", DisassembleNative, 2, 0,
|
||||
"disnative(fun,[path])",
|
||||
" Disassemble a function into its native code. Optionally write the native code bytes to a file on disk.\n"),
|
||||
|
|
|
@ -0,0 +1,203 @@
|
|||
// Scaffolding for testing x64 Ion code generation patterns (currently mostly
|
||||
// for wasm SIMD). See ../tests/wasm/simd/README-codegen.md for general
|
||||
// information, and the *codegen.js tests in that directory for specifics.
|
||||
//
|
||||
// The structure of the inputs can vary for the different testing predicates but
|
||||
// each case generally has an operator name and an expected-pattern; the latter is a
|
||||
// string that represents a regular expression, possibly with newlines,
|
||||
// representing the instruction or instructions we are looking for for the operator.
|
||||
// Spaces in the expected-pattern are arbitrary, we preprocess the pattern to
|
||||
// replace any space string with \s+. Lines are separated by newlines and leading
|
||||
// and trailing spaces are currently stripped.
|
||||
//
|
||||
// Lines in expected-pattern starting with '*' are not prefixed by an address during
|
||||
// preprocessing.
|
||||
//
|
||||
// Lines in expected-pattern that end with a space (lines that are split do) must use \s
|
||||
// to represent that space.
|
||||
//
|
||||
// The testers additionally take an optional options bag with the following optional
|
||||
// entries:
|
||||
// no_prefix: if true, do not add a prefix string (normally the end of the prologue)
|
||||
// no_suffix: if true, do not add a suffix string (normally the start of the epilogue)
|
||||
// memory: if present, add a memory of length given by this property
|
||||
// log: for debugging -- print the disassembly, then the preprocessed pattern
|
||||
|
||||
// Set to true to emit ' +' instead of the unreadable '\s+'.
|
||||
var SPACEDEBUG = false;
|
||||
|
||||
// Any hex string
|
||||
var HEXES = `[0-9a-fA-F]+`;
|
||||
|
||||
// RIP-relative address
|
||||
var RIPR = `0x${HEXES}`;
|
||||
|
||||
// End of prologue
|
||||
var x64_prefix = `48 8b ec mov %rsp, %rbp`
|
||||
|
||||
// Start of epilogue
|
||||
var x64_suffix = `5d pop %rbp`;
|
||||
|
||||
// v128 OP v128 -> v128
|
||||
// inputs: [[complete-opname, expected-pattern], ...]
|
||||
function codegenTestX64_v128xv128_v128(inputs, options = {}) {
|
||||
for ( let [op, expected] of inputs ) {
|
||||
codegenTestX64BinopInternal(op, expected, options, 'v128', 'v128', 'v128', '0', '1');
|
||||
}
|
||||
}
|
||||
|
||||
// v128 OP param1-type -> v128
|
||||
// inputs: [[complete-opname, param1-type, expected-pattern], ...]
|
||||
function codegenTestX64_v128xPTYPE_v128(inputs, options = {}) {
|
||||
for ( let [op, p1type, expected] of inputs ) {
|
||||
codegenTestX64BinopInternal(op, expected, options, 'v128', p1type, 'v128', '0', '1');
|
||||
}
|
||||
}
|
||||
|
||||
// v128 OP literal -> v128
|
||||
// inputs: [[complete-opname, rhs-literal, expected-pattern], ...]
|
||||
function codegenTestX64_v128xLITERAL_v128(inputs, options = {}) {
|
||||
for ( let [op, literal, expected] of inputs ) {
|
||||
codegenTestX64_adhoc(wrap(options, `
|
||||
(func (export "f") (param v128) (result v128)
|
||||
(${op} (local.get 0) ${literal}))`),
|
||||
'f',
|
||||
expected,
|
||||
options)
|
||||
}
|
||||
}
|
||||
|
||||
// v128 OP v128 -> v128, but operands are swapped
|
||||
// inputs: [[complete-opname, expected-pattern], ...]
|
||||
function codegenTestX64_v128xv128_v128_reversed(inputs, options = {}) {
|
||||
for ( let [op, expected] of inputs ) {
|
||||
codegenTestX64BinopInternal(op, expected, options, 'v128', 'v128', 'v128', '1', '0');
|
||||
}
|
||||
}
|
||||
|
||||
// OP v128 -> v128
|
||||
// inputs: [[complete-opname, expected-pattern], ...]
|
||||
function codegenTestX64_v128_v128(inputs, options = {}) {
|
||||
for ( let [op, expected] of inputs ) {
|
||||
codegenTestX64_adhoc(wrap(options, `
|
||||
(func (export "f") (param v128) (result v128)
|
||||
(${op} (local.get 0)))`),
|
||||
'f',
|
||||
expected,
|
||||
options);
|
||||
}
|
||||
}
|
||||
|
||||
// OP param-type -> v128
|
||||
// inputs [[complete-opname, param-type, expected-pattern], ...]
|
||||
function codegenTestX64_PTYPE_v128(inputs, options = {}) {
|
||||
for ( let [op, ptype, expected] of inputs ) {
|
||||
codegenTestX64_adhoc(wrap(options, `
|
||||
(func (export "f") (param ${ptype}) (result v128)
|
||||
(${op} (local.get 0)))`),
|
||||
'f',
|
||||
expected,
|
||||
options);
|
||||
}
|
||||
}
|
||||
|
||||
// OP v128 -> v128, but the function takes two arguments and the first is ignored
|
||||
// inputs: [[complete-opname, expected-pattern], ...]
|
||||
function codegenTestX64_IGNOREDxv128_v128(inputs, options = {}) {
|
||||
for ( let [op, expected] of inputs ) {
|
||||
codegenTestX64_adhoc(wrap(options, `
|
||||
(func (export "f") (param v128) (param v128) (result v128)
|
||||
(${op} (local.get 1)))`),
|
||||
'f',
|
||||
expected,
|
||||
options);
|
||||
}
|
||||
}
|
||||
|
||||
// () -> v128
|
||||
// inputs: [[complete-opname, expected-pattern], ...]
|
||||
function codegenTestX64_unit_v128(inputs, options = {}) {
|
||||
for ( let [op, expected] of inputs ) {
|
||||
codegenTestX64_adhoc(wrap(options, `
|
||||
(func (export "f") (result v128)
|
||||
(${op}))`),
|
||||
'f',
|
||||
expected,
|
||||
options);
|
||||
}
|
||||
}
|
||||
|
||||
// For when nothing else applies: `module_text` is the complete source text of
|
||||
// the module, `export_name` is the name of the function to be tested,
|
||||
// `expected` is the non-preprocessed pattern, and options is an options bag,
|
||||
// described above.
|
||||
function codegenTestX64_adhoc(module_text, export_name, expected, options = {}) {
|
||||
assertEq(hasDisassembler(), true);
|
||||
|
||||
let ins = wasmEvalText(module_text);
|
||||
let output = wasmDis(ins.exports[export_name], "ion", true);
|
||||
if (!options.no_prefix)
|
||||
expected = x64_prefix + '\n' + expected;
|
||||
if (!options.no_suffix)
|
||||
expected = expected + '\n' + x64_suffix;
|
||||
expected = fixlines(expected);
|
||||
if (options.log) {
|
||||
print(output);
|
||||
print(expected);
|
||||
}
|
||||
assertEq(output.match(new RegExp(expected)) != null, true);
|
||||
}
|
||||
|
||||
// Internal code below this line
|
||||
|
||||
function codegenTestX64BinopInternal(op, expected, options, p0type, p1type, restype, arg0, arg1) {
|
||||
codegenTestX64_adhoc(wrap(options, `
|
||||
(func (export "f") (param ${p0type}) (param ${p1type}) (result ${restype})
|
||||
(${op} (local.get ${arg0}) (local.get ${arg1})))`),
|
||||
'f',
|
||||
expected,
|
||||
options);
|
||||
}
|
||||
|
||||
function wrap(options, funcs) {
|
||||
if ('memory' in options)
|
||||
return `(module (memory ${options.memory}) ${funcs})`;
|
||||
return `(module ${funcs})`;
|
||||
}
|
||||
|
||||
function fixlines(s) {
|
||||
return s.split(/\n+/)
|
||||
.map(strip)
|
||||
.filter(x => x.length > 0)
|
||||
.map(x => x.charAt(0) == '*' ? x.substring(1) : (HEXES + ' ' + x))
|
||||
.map(spaces)
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
function strip(s) {
|
||||
while (s.length > 0 && isspace(s.charAt(0)))
|
||||
s = s.substring(1);
|
||||
while (s.length > 0 && isspace(s.charAt(s.length-1)))
|
||||
s = s.substring(0, s.length-1);
|
||||
return s;
|
||||
}
|
||||
|
||||
function spaces(s) {
|
||||
let t = '';
|
||||
let i = 0;
|
||||
while (i < s.length) {
|
||||
if (isspace(s.charAt(i))) {
|
||||
t += SPACEDEBUG ? ' +' : '\\s+';
|
||||
i++;
|
||||
while (i < s.length && isspace(s.charAt(i)))
|
||||
i++;
|
||||
} else {
|
||||
t += s.charAt(i++);
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
function isspace(c) {
|
||||
return c == ' ' || c == '\t';
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
About x86 ion whitebox code generation tests (*-codegen.js):
|
||||
About whitebox code generation tests (*-codegen.js):
|
||||
|
||||
These test that extraneous moves are not inserted by the register
|
||||
allocator or code generator under ideal conditions: when it is in
|
||||
|
@ -11,9 +11,9 @@ changes to the register allocator, but how else would we test that
|
|||
code generation and register allocation work when presented with the
|
||||
easiest case? And if they don't work then, when will they work?
|
||||
|
||||
For a reliable test, the inputs must be known to be in xmm0, xmm1,
|
||||
xmm2, etc (the function argument registers) and the result must be
|
||||
known to be desired in xmm0 (the function result).
|
||||
For a reliable test, the inputs must be known to be in the fixed
|
||||
parameter registers and the result must be known to be desired in the
|
||||
fixed function result register.
|
||||
|
||||
Sometimes, to test optimal codegen, we need the inputs to be in
|
||||
reversed or permuted locations so as to avoid generating moves that
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// |jit-test| skip-if: !wasmSimdEnabled() || wasmCompileMode() != "ion" || !getBuildConfiguration().x64
|
||||
// |jit-test| skip-if: !wasmSimdEnabled() || !hasDisassembler() || wasmCompileMode() != "ion" || !getBuildConfiguration().x64; include:codegen-x64-test.js
|
||||
|
||||
// Test that there are no extraneous moves or fixups for sundry SIMD binary
|
||||
// operations. See README-codegen.md for general information about this type of
|
||||
|
@ -6,85 +6,17 @@
|
|||
|
||||
// Inputs (xmm0, xmm1)
|
||||
|
||||
for ( let [op, expected] of [
|
||||
['f32x4.replace_lane 0',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. f3 0f 10 c1 movss %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f32x4.replace_lane 1',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 3a 21 c1 10 insertps \\$0x10, %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f32x4.replace_lane 3',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 3a 21 c1 30 insertps \\$0x30, %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f64x2.replace_lane 0',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. f2 0f 10 c1 movsd %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f64x2.replace_lane 1',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f c6 c1 00 shufpd \\$0x00, %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
] ) {
|
||||
let ptype = op.substring(0,3);
|
||||
let ins = wasmEvalText(`
|
||||
(module
|
||||
(func (export "f") (param v128) (param ${ptype}) (result v128)
|
||||
(${op} (local.get 0) (local.get 1))))
|
||||
`);
|
||||
let output = wasmDis(ins.exports.f, "ion", true);
|
||||
if (output.indexOf('No disassembly available') >= 0)
|
||||
continue;
|
||||
assertEq(output.match(new RegExp(expected)) != null, true);
|
||||
}
|
||||
codegenTestX64_v128xPTYPE_v128(
|
||||
[['f32x4.replace_lane 0', 'f32', `f3 0f 10 c1 movss %xmm1, %xmm0`],
|
||||
['f32x4.replace_lane 1', 'f32', `66 0f 3a 21 c1 10 insertps \\$0x10, %xmm1, %xmm0`],
|
||||
['f32x4.replace_lane 3', 'f32', `66 0f 3a 21 c1 30 insertps \\$0x30, %xmm1, %xmm0`],
|
||||
['f64x2.replace_lane 0', 'f64', `f2 0f 10 c1 movsd %xmm1, %xmm0`],
|
||||
['f64x2.replace_lane 1', 'f64', `66 0f c6 c1 00 shufpd \\$0x00, %xmm1, %xmm0`]] );
|
||||
|
||||
// Inputs (xmm1, xmm0)
|
||||
|
||||
for ( let [op, expected] of [
|
||||
['f32x4.pmin',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 0f 5d c1 minps %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f32x4.pmax',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 0f 5f c1 maxps %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f64x2.pmin',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 5d c1 minpd %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f64x2.pmax',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 5f c1 maxpd %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
] ) {
|
||||
let ins = wasmEvalText(`
|
||||
(module
|
||||
(func (export "f") (param v128) (param v128) (result v128)
|
||||
(${op} (local.get 1) (local.get 0))))
|
||||
`);
|
||||
let output = wasmDis(ins.exports.f, "ion", true);
|
||||
if (output.indexOf('No disassembly available') >= 0)
|
||||
continue;
|
||||
assertEq(output.match(new RegExp(expected)) != null, true);
|
||||
}
|
||||
codegenTestX64_v128xv128_v128_reversed(
|
||||
[['f32x4.pmin', `0f 5d c1 minps %xmm1, %xmm0`],
|
||||
['f32x4.pmax', `0f 5f c1 maxps %xmm1, %xmm0`],
|
||||
['f64x2.pmin', `66 0f 5d c1 minpd %xmm1, %xmm0`],
|
||||
['f64x2.pmax', `66 0f 5f c1 maxpd %xmm1, %xmm0`]] );
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// |jit-test| skip-if: !wasmSimdEnabled() || wasmCompileMode() != "ion" || !getBuildConfiguration().x64
|
||||
// |jit-test| skip-if: !wasmSimdEnabled() || !hasDisassembler() || wasmCompileMode() != "ion" || !getBuildConfiguration().x64; include:codegen-x64-test.js
|
||||
|
||||
// Test that there are no extraneous moves or fixups for SIMD bitselect
|
||||
// operations. See README-codegen.md for general information about this type of
|
||||
|
@ -10,21 +10,15 @@
|
|||
// The temp should be identical to the mask but the regalloc does not currently
|
||||
// allow this constraint to be enforced.
|
||||
|
||||
let expected = `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 6f da movdqa %xmm2, %xmm3
|
||||
000000.. 66 0f db c3 pand %xmm3, %xmm0
|
||||
000000.. 66 0f df d9 pandn %xmm1, %xmm3
|
||||
000000.. 66 0f eb c3 por %xmm3, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`;
|
||||
// Inputs (xmm0, xmm1, xmm2)
|
||||
|
||||
let ins = wasmEvalText(`
|
||||
(module
|
||||
codegenTestX64_adhoc(
|
||||
`(module
|
||||
(func (export "f") (param v128) (param v128) (param v128) (param v128) (result v128)
|
||||
(v128.bitselect (local.get 0) (local.get 1) (local.get 2))))
|
||||
`);
|
||||
let output = wasmDis(ins.exports.f, "ion", true);
|
||||
if (output.indexOf('No disassembly available') < 0) {
|
||||
assertEq(output.match(new RegExp(expected)) != null, true);
|
||||
}
|
||||
(v128.bitselect (local.get 0) (local.get 1) (local.get 2))))`,
|
||||
'f',
|
||||
`66 0f 6f da movdqa %xmm2, %xmm3
|
||||
66 0f db c3 pand %xmm3, %xmm0
|
||||
66 0f df d9 pandn %xmm1, %xmm3
|
||||
66 0f eb c3 por %xmm3, %xmm0`);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// |jit-test| skip-if: !wasmSimdEnabled() || wasmCompileMode() != "ion" || !getBuildConfiguration().x64
|
||||
// |jit-test| skip-if: !wasmSimdEnabled() || !hasDisassembler() || wasmCompileMode() != "ion" || !getBuildConfiguration().x64; include:codegen-x64-test.js
|
||||
|
||||
// Test that there are no extraneous moves or fixups for various SIMD comparison
|
||||
// operations. See README-codegen.md for general information about this type of
|
||||
|
@ -6,219 +6,72 @@
|
|||
|
||||
// Inputs (xmm0, xmm1)
|
||||
|
||||
for ( let [op, expected] of [
|
||||
['i8x16.gt_s',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 64 c1 pcmpgtb %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
codegenTestX64_v128xv128_v128(
|
||||
[['i8x16.gt_s', `66 0f 64 c1 pcmpgtb %xmm1, %xmm0`],
|
||||
['i16x8.gt_s', `66 0f 65 c1 pcmpgtw %xmm1, %xmm0`],
|
||||
['i32x4.gt_s', `66 0f 66 c1 pcmpgtd %xmm1, %xmm0`],
|
||||
['i8x16.le_s', `
|
||||
66 0f 64 c1 pcmpgtb %xmm1, %xmm0
|
||||
66 0f ef 05 .. 00 00 00 pxorx ${RIPR}, %xmm0
|
||||
`],
|
||||
['i16x8.gt_s',
|
||||
['i16x8.le_s',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 65 c1 pcmpgtw %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
66 0f 65 c1 pcmpgtw %xmm1, %xmm0
|
||||
66 0f ef 05 .. 00 00 00 pxorx ${RIPR}, %xmm0
|
||||
`],
|
||||
['i32x4.gt_s',
|
||||
['i32x4.le_s',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 66 c1 pcmpgtd %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
66 0f 66 c1 pcmpgtd %xmm1, %xmm0
|
||||
66 0f ef 05 .. 00 00 00 pxorx ${RIPR}, %xmm0
|
||||
`],
|
||||
['i8x16.le_s',
|
||||
['i8x16.eq', `66 0f 74 c1 pcmpeqb %xmm1, %xmm0`],
|
||||
['i16x8.eq', `66 0f 75 c1 pcmpeqw %xmm1, %xmm0`],
|
||||
['i32x4.eq', `66 0f 76 c1 pcmpeqd %xmm1, %xmm0`],
|
||||
['i8x16.ne', `
|
||||
66 0f 74 c1 pcmpeqb %xmm1, %xmm0
|
||||
66 0f ef 05 .. 00 00 00 pxorx ${RIPR}, %xmm0
|
||||
`],
|
||||
['i16x8.ne',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 64 c1 pcmpgtb %xmm1, %xmm0
|
||||
000000.. 66 0f ef 05 .. 00 00 00 pxorx 0x0000000000000040, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
66 0f 75 c1 pcmpeqw %xmm1, %xmm0
|
||||
66 0f ef 05 .. 00 00 00 pxorx ${RIPR}, %xmm0
|
||||
`],
|
||||
['i16x8.le_s',
|
||||
['i32x4.ne',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 65 c1 pcmpgtw %xmm1, %xmm0
|
||||
000000.. 66 0f ef 05 .. 00 00 00 pxorx 0x0000000000000040, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
66 0f 76 c1 pcmpeqd %xmm1, %xmm0
|
||||
66 0f ef 05 .. 00 00 00 pxorx ${RIPR}, %xmm0
|
||||
`],
|
||||
['i32x4.le_s',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 66 c1 pcmpgtd %xmm1, %xmm0
|
||||
000000.. 66 0f ef 05 .. 00 00 00 pxorx 0x0000000000000040, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i8x16.eq',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 74 c1 pcmpeqb %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i16x8.eq',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 75 c1 pcmpeqw %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i32x4.eq',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 76 c1 pcmpeqd %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i8x16.ne',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 74 c1 pcmpeqb %xmm1, %xmm0
|
||||
000000.. 66 0f ef 05 .. 00 00 00 pxorx 0x0000000000000040, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i16x8.ne',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 75 c1 pcmpeqw %xmm1, %xmm0
|
||||
000000.. 66 0f ef 05 .. 00 00 00 pxorx 0x0000000000000040, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i32x4.ne',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 76 c1 pcmpeqd %xmm1, %xmm0
|
||||
000000.. 66 0f ef 05 .. 00 00 00 pxorx 0x0000000000000040, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f32x4.eq',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 0f c2 c1 00 cmpps \\$0x00, %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f32x4.ne',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 0f c2 c1 04 cmpps \\$0x04, %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f32x4.lt',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 0f c2 c1 01 cmpps \\$0x01, %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f32x4.le',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 0f c2 c1 02 cmpps \\$0x02, %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f64x2.eq',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f c2 c1 00 cmppd \\$0x00, %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f64x2.ne',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f c2 c1 04 cmppd \\$0x04, %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f64x2.lt',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f c2 c1 01 cmppd \\$0x01, %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f64x2.le',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f c2 c1 02 cmppd \\$0x02, %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
] ) {
|
||||
let ins = wasmEvalText(`
|
||||
(module
|
||||
(func (export "f") (param v128) (param v128) (result v128)
|
||||
(${op} (local.get 0) (local.get 1))))
|
||||
`);
|
||||
let output = wasmDis(ins.exports.f, "ion", true);
|
||||
if (output.indexOf('No disassembly available') >= 0)
|
||||
continue;
|
||||
assertEq(output.match(new RegExp(expected)) != null, true);
|
||||
}
|
||||
['f32x4.eq', `0f c2 c1 00 cmpps \\$0x00, %xmm1, %xmm0`],
|
||||
['f32x4.ne', `0f c2 c1 04 cmpps \\$0x04, %xmm1, %xmm0`],
|
||||
['f32x4.lt', `0f c2 c1 01 cmpps \\$0x01, %xmm1, %xmm0`],
|
||||
['f32x4.le', `0f c2 c1 02 cmpps \\$0x02, %xmm1, %xmm0`],
|
||||
['f64x2.eq', `66 0f c2 c1 00 cmppd \\$0x00, %xmm1, %xmm0`],
|
||||
['f64x2.ne', `66 0f c2 c1 04 cmppd \\$0x04, %xmm1, %xmm0`],
|
||||
['f64x2.lt', `66 0f c2 c1 01 cmppd \\$0x01, %xmm1, %xmm0`],
|
||||
['f64x2.le', `66 0f c2 c1 02 cmppd \\$0x02, %xmm1, %xmm0`]] );
|
||||
|
||||
// Inputs (xmm1, xmm0) because the operation reverses its arguments.
|
||||
|
||||
for ( let [op, expected] of [
|
||||
['i8x16.ge_s',
|
||||
codegenTestX64_v128xv128_v128_reversed(
|
||||
[['i8x16.ge_s',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 64 c1 pcmpgtb %xmm1, %xmm0
|
||||
000000.. 66 0f ef 05 .. 00 00 00 pxorx 0x0000000000000040, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
66 0f 64 c1 pcmpgtb %xmm1, %xmm0
|
||||
66 0f ef 05 .. 00 00 00 pxorx ${RIPR}, %xmm0
|
||||
`],
|
||||
['i16x8.ge_s',
|
||||
['i16x8.ge_s',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 65 c1 pcmpgtw %xmm1, %xmm0
|
||||
000000.. 66 0f ef 05 .. 00 00 00 pxorx 0x0000000000000040, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
66 0f 65 c1 pcmpgtw %xmm1, %xmm0
|
||||
66 0f ef 05 .. 00 00 00 pxorx ${RIPR}, %xmm0
|
||||
`],
|
||||
['i32x4.ge_s',
|
||||
['i32x4.ge_s',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 66 c1 pcmpgtd %xmm1, %xmm0
|
||||
000000.. 66 0f ef 05 .. 00 00 00 pxorx 0x0000000000000040, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
66 0f 66 c1 pcmpgtd %xmm1, %xmm0
|
||||
66 0f ef 05 .. 00 00 00 pxorx ${RIPR}, %xmm0
|
||||
`],
|
||||
['i8x16.lt_s',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 64 c1 pcmpgtb %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i16x8.lt_s',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 65 c1 pcmpgtw %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i32x4.lt_s',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 66 c1 pcmpgtd %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f32x4.gt',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 0f c2 c1 01 cmpps \\$0x01, %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f32x4.ge',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 0f c2 c1 02 cmpps \\$0x02, %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f64x2.gt',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f c2 c1 01 cmppd \\$0x01, %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f64x2.ge',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f c2 c1 02 cmppd \\$0x02, %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
] ) {
|
||||
let ins = wasmEvalText(`
|
||||
(module
|
||||
(func (export "f") (param v128) (param v128) (result v128)
|
||||
(${op} (local.get 1) (local.get 0))))
|
||||
`);
|
||||
let output = wasmDis(ins.exports.f, "ion", true);
|
||||
if (output.indexOf('No disassembly available') >= 0)
|
||||
continue;
|
||||
assertEq(output.match(new RegExp(expected)) != null, true);
|
||||
}
|
||||
['i8x16.lt_s', `66 0f 64 c1 pcmpgtb %xmm1, %xmm0`],
|
||||
['i16x8.lt_s', `66 0f 65 c1 pcmpgtw %xmm1, %xmm0`],
|
||||
['i32x4.lt_s', `66 0f 66 c1 pcmpgtd %xmm1, %xmm0`],
|
||||
['f32x4.gt', `0f c2 c1 01 cmpps \\$0x01, %xmm1, %xmm0`],
|
||||
['f32x4.ge', `0f c2 c1 02 cmpps \\$0x02, %xmm1, %xmm0`],
|
||||
['f64x2.gt', `66 0f c2 c1 01 cmppd \\$0x01, %xmm1, %xmm0`],
|
||||
['f64x2.ge', `66 0f c2 c1 02 cmppd \\$0x02, %xmm1, %xmm0`]] );
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// |jit-test| skip-if: !wasmSimdEnabled() || wasmCompileMode() != "baseline" || !getBuildConfiguration().arm64
|
||||
// |jit-test| skip-if: !wasmSimdEnabled() || !hasDisassembler() || wasmCompileMode() != "baseline" || !getBuildConfiguration().arm64
|
||||
|
||||
// Test that the vixl logic for v128 constant loads is at least somewhat
|
||||
// reasonable.
|
||||
|
@ -20,26 +20,30 @@ ${lead}movi v0\\.2d, #0x0
|
|||
${suffix}
|
||||
`,
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
|
||||
|
||||
['i8x16 -1 0 -1 0 -1 0 -1 0 -1 0 -1 0 -1 0 -1 0', `
|
||||
${prefix}
|
||||
${lead}movi v0\\.2d, #0xff00ff00ff00ff
|
||||
${suffix}
|
||||
`,
|
||||
[-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0]],
|
||||
// Splattable small things (up to a byte, at a byte location)
|
||||
// can also use just one instruction
|
||||
|
||||
// Splattable small things (up to a byte, at a byte location)
|
||||
// can also use just one instruction
|
||||
['i32x4 1 1 1 1', `
|
||||
${prefix}
|
||||
${lead}movi v0\\.4s, #0x1, lsl #0
|
||||
${suffix}
|
||||
`,
|
||||
[1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0]],
|
||||
|
||||
['i32x4 0x300 0x300 0x300 0x300', `
|
||||
${prefix}
|
||||
${lead}movi v0\\.4s, #0x3, lsl #8
|
||||
${suffix}
|
||||
`,
|
||||
[1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0]],
|
||||
[0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0]],
|
||||
|
||||
// If high == low but the value is more complex then a constant load
|
||||
// plus a dup is sufficient. x16 is the designated temp.
|
||||
['i32x4 1 2 1 2', `
|
||||
|
@ -50,6 +54,7 @@ ${lead}dup v0\\.2d, x16
|
|||
${suffix}
|
||||
`,
|
||||
[1, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0]],
|
||||
|
||||
// If high != low then we degenerate to a more complicated pattern: dup the low value
|
||||
// and then overwrite the high part with the high value.
|
||||
['i32x4 1 2 2 1', `
|
||||
|
@ -63,6 +68,7 @@ ${lead}mov v0\\.d\\[1\\], x16
|
|||
${suffix}
|
||||
`,
|
||||
[1, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0]],
|
||||
|
||||
// Things are not always bleak, and vixl finds a way.
|
||||
['i32x4 1 1 2 2', `
|
||||
${prefix}
|
||||
|
@ -81,8 +87,9 @@ ${suffix}
|
|||
(func $f (export "f") (result v128)
|
||||
(v128.const ${bits})))`);
|
||||
let output = wasmDis(ins.exports.f, "baseline", true);
|
||||
if (output.indexOf('No disassembly available') >= 0)
|
||||
continue;
|
||||
print(bits);
|
||||
print(output);
|
||||
print(expected);
|
||||
assertEq(output.match(new RegExp(expected)) != null, true);
|
||||
let mem = new Int8Array(ins.exports.mem.buffer);
|
||||
set(mem, 0, iota(16).map(x => -1-x));
|
||||
|
|
|
@ -1,82 +1,28 @@
|
|||
// |jit-test| skip-if: !wasmSimdEnabled() || wasmCompileMode() != "ion" || !getBuildConfiguration().x64
|
||||
// |jit-test| skip-if: !wasmSimdEnabled() || !hasDisassembler() || wasmCompileMode() != "ion" || !getBuildConfiguration().x64; include:codegen-x64-test.js
|
||||
|
||||
// Test that constants that can be synthesized are synthesized. See README-codegen.md
|
||||
// for general information about this type of test case.
|
||||
|
||||
// Inputs (xmm0, xmm1)
|
||||
|
||||
for ( let [op, expected] of [
|
||||
['v128.const i8x16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f ef c0 pxor %xmm0, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['v128.const i8x16 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 75 c0 pcmpeqw %xmm0, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['v128.const i16x8 0 0 0 0 0 0 0 0',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f ef c0 pxor %xmm0, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['v128.const i16x8 -1 -1 -1 -1 -1 -1 -1 -1',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 75 c0 pcmpeqw %xmm0, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['v128.const i32x4 0 0 0 0',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f ef c0 pxor %xmm0, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['v128.const i32x4 -1 -1 -1 -1',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 75 c0 pcmpeqw %xmm0, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['v128.const i64x2 0 0',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f ef c0 pxor %xmm0, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['v128.const i64x2 -1 -1',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 75 c0 pcmpeqw %xmm0, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['v128.const f32x4 0 0 0 0',
|
||||
// Arguably this should be xorps but that's for later
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f ef c0 pxor %xmm0, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['v128.const f64x2 0 0',
|
||||
// Arguably this should be xorpd but that's for later
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f ef c0 pxor %xmm0, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
|
||||
] ) {
|
||||
let ins = wasmEvalText(`
|
||||
(module
|
||||
(func (export "f") (result v128)
|
||||
(${op})))
|
||||
`);
|
||||
let output = wasmDis(ins.exports.f, "ion", true);
|
||||
if (output.indexOf('No disassembly available') >= 0)
|
||||
continue;
|
||||
assertEq(output.match(new RegExp(expected)) != null, true);
|
||||
}
|
||||
codegenTestX64_unit_v128(
|
||||
[['v128.const i8x16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0',
|
||||
`66 0f ef c0 pxor %xmm0, %xmm0`],
|
||||
['v128.const i8x16 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1',
|
||||
`66 0f 75 c0 pcmpeqw %xmm0, %xmm0`],
|
||||
['v128.const i16x8 0 0 0 0 0 0 0 0',
|
||||
`66 0f ef c0 pxor %xmm0, %xmm0`],
|
||||
['v128.const i16x8 -1 -1 -1 -1 -1 -1 -1 -1',
|
||||
`66 0f 75 c0 pcmpeqw %xmm0, %xmm0`],
|
||||
['v128.const i32x4 0 0 0 0',
|
||||
`66 0f ef c0 pxor %xmm0, %xmm0`],
|
||||
['v128.const i32x4 -1 -1 -1 -1',
|
||||
`66 0f 75 c0 pcmpeqw %xmm0, %xmm0`],
|
||||
['v128.const i64x2 0 0',
|
||||
`66 0f ef c0 pxor %xmm0, %xmm0`],
|
||||
['v128.const i64x2 -1 -1',
|
||||
`66 0f 75 c0 pcmpeqw %xmm0, %xmm0`],
|
||||
['v128.const f32x4 0 0 0 0',
|
||||
// Arguably this should be xorps but that's for later
|
||||
`66 0f ef c0 pxor %xmm0, %xmm0`],
|
||||
['v128.const f64x2 0 0',
|
||||
// Arguably this should be xorpd but that's for later
|
||||
`66 0f ef c0 pxor %xmm0, %xmm0`]] );
|
||||
|
|
|
@ -1,42 +1,30 @@
|
|||
// |jit-test| skip-if: !wasmSimdEnabled() || wasmCompileMode() != "ion" || !getBuildConfiguration().x64
|
||||
// |jit-test| skip-if: !wasmSimdEnabled() || !hasDisassembler() || wasmCompileMode() != "ion" || !getBuildConfiguration().x64; include:codegen-x64-test.js
|
||||
|
||||
// Test that there are no extraneous moves for various SIMD conversion
|
||||
// operations. See README-codegen.md for general information about this type of
|
||||
// test case.
|
||||
|
||||
// Inputs (xmm0, xmm1)
|
||||
// Note, these tests test the beginning of the output but not the end.
|
||||
|
||||
for ( let [op, expected] of [
|
||||
['i32x4.trunc_sat_f32x4_s',
|
||||
codegenTestX64_v128_v128(
|
||||
[['i32x4.trunc_sat_f32x4_s',
|
||||
// The movaps is dest -> scratch and needs to be here. The test is
|
||||
// asserting that there is not an additional (redundant) move here.
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 44 0f 28 f8 movaps %xmm0, %xmm15
|
||||
000000.. 45 0f c2 ff 00 cmpps \\$0x00, %xmm15, %xmm15
|
||||
000000.. 66 41 0f db c7 pand %xmm15, %xmm0
|
||||
44 0f 28 f8 movaps %xmm0, %xmm15
|
||||
45 0f c2 ff 00 cmpps \\$0x00, %xmm15, %xmm15
|
||||
66 41 0f db c7 pand %xmm15, %xmm0
|
||||
`],
|
||||
['i32x4.trunc_sat_f32x4_u', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 45 0f ef ff pxor %xmm15, %xmm15
|
||||
000000.. 41 0f 5f c7 maxps %xmm15, %xmm0
|
||||
['i32x4.trunc_sat_f32x4_u', `
|
||||
66 45 0f ef ff pxor %xmm15, %xmm15
|
||||
41 0f 5f c7 maxps %xmm15, %xmm0
|
||||
`],
|
||||
['f32x4.convert_i32x4_u', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 45 0f ef ff pxor %xmm15, %xmm15
|
||||
000000.. 66 44 0f 3a 0e f8 55 pblendw \\$0x55, %xmm0, %xmm15
|
||||
000000.. 66 41 0f fa c7 psubd %xmm15, %xmm0
|
||||
000000.. 45 0f 5b ff cvtdq2ps %xmm15, %xmm15
|
||||
`],
|
||||
] ) {
|
||||
let ins = wasmEvalText(`
|
||||
(module
|
||||
(func (export "f") (param v128) (result v128)
|
||||
(${op} (local.get 0))))`);
|
||||
let output = wasmDis(ins.exports.f, "ion", true);
|
||||
if (output.indexOf('No disassembly available') >= 0)
|
||||
continue;
|
||||
assertEq(output.match(new RegExp(expected)) != null, true);
|
||||
}
|
||||
['f32x4.convert_i32x4_u', `
|
||||
66 45 0f ef ff pxor %xmm15, %xmm15
|
||||
66 44 0f 3a 0e f8 55 pblendw \\$0x55, %xmm0, %xmm15
|
||||
66 41 0f fa c7 psubd %xmm15, %xmm0
|
||||
45 0f 5b ff cvtdq2ps %xmm15, %xmm15
|
||||
`]],
|
||||
{no_suffix:true});
|
||||
|
||||
|
||||
|
|
|
@ -1,92 +1,36 @@
|
|||
// |jit-test| skip-if: !wasmSimdEnabled() || wasmCompileMode() != "ion" || !getBuildConfiguration().x64
|
||||
// |jit-test| skip-if: !wasmSimdEnabled() || !hasDisassembler() || wasmCompileMode() != "ion" || !getBuildConfiguration().x64; include:codegen-x64-test.js
|
||||
|
||||
// Test that there are no extraneous moves for variable SIMD negate
|
||||
// instructions. See README-codegen.md for general information about this type
|
||||
// of test case.
|
||||
// Test that there are no extraneous moves for variable SIMD negate, abs, and
|
||||
// not instructions. See README-codegen.md for general information about this
|
||||
// type of test case.
|
||||
|
||||
// Integer negates don't have to reuse the input for the output, and prefer for
|
||||
// the registers to be different.
|
||||
// the registers to be different. So use parameter 1 and ignore parameter 0.
|
||||
|
||||
// Inputs (xmm1, xmm0)
|
||||
|
||||
for ( let [ op, expected ] of [
|
||||
['i8x16.neg', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f ef c0 pxor %xmm0, %xmm0
|
||||
000000.. 66 0f f8 c1 psubb %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
codegenTestX64_IGNOREDxv128_v128(
|
||||
[['i8x16.neg', `
|
||||
66 0f ef c0 pxor %xmm0, %xmm0
|
||||
66 0f f8 c1 psubb %xmm1, %xmm0
|
||||
`],
|
||||
['i16x8.neg', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f ef c0 pxor %xmm0, %xmm0
|
||||
000000.. 66 0f f9 c1 psubw %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
['i16x8.neg', `
|
||||
66 0f ef c0 pxor %xmm0, %xmm0
|
||||
66 0f f9 c1 psubw %xmm1, %xmm0
|
||||
`],
|
||||
['i32x4.neg', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f ef c0 pxor %xmm0, %xmm0
|
||||
000000.. 66 0f fa c1 psubd %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
['i32x4.neg', `
|
||||
66 0f ef c0 pxor %xmm0, %xmm0
|
||||
66 0f fa c1 psubd %xmm1, %xmm0
|
||||
`],
|
||||
['i64x2.neg', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f ef c0 pxor %xmm0, %xmm0
|
||||
000000.. 66 0f fb c1 psubq %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
|
||||
] ) {
|
||||
|
||||
let ins = wasmEvalText(`
|
||||
(module
|
||||
(func (export "f") (param v128) (param v128) (result v128)
|
||||
(${op} (local.get 1))))
|
||||
`);
|
||||
let output = wasmDis(ins.exports.f, "ion", true);
|
||||
if (output.indexOf('No disassembly available') >= 0)
|
||||
continue;
|
||||
assertEq(output.match(new RegExp(expected)) != null, true);
|
||||
}
|
||||
['i64x2.neg', `
|
||||
66 0f ef c0 pxor %xmm0, %xmm0
|
||||
66 0f fb c1 psubq %xmm1, %xmm0
|
||||
`]] );
|
||||
|
||||
// Floating point negate and absolute value, and bitwise not, prefer for the
|
||||
// registers to be the same and guarantee that no move is inserted if so.
|
||||
|
||||
// Inputs (xmm0, xmm1)
|
||||
|
||||
for ( let [ op, expected ] of [
|
||||
['f32x4.neg', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f ef 05 .. 00 00 00 pxorx 0x00000000000000.., %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f64x2.neg', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f ef 05 .. 00 00 00 pxorx 0x00000000000000.., %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f32x4.abs', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f db 05 .. 00 00 00 pandx 0x00000000000000.., %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f64x2.abs', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f db 05 .. 00 00 00 pandx 0x00000000000000.., %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['v128.not', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f ef 05 .. 00 00 00 pxorx 0x00000000000000.., %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
] ) {
|
||||
var ins = wasmEvalText(`
|
||||
(module
|
||||
(func (export "f") (param v128) (result v128)
|
||||
(${op} (local.get 0))))
|
||||
`);
|
||||
let output = wasmDis(ins.exports.f, "ion", true);
|
||||
if (output.indexOf('No disassembly available') >= 0)
|
||||
continue;
|
||||
assertEq(output.match(new RegExp(expected)) != null, true);
|
||||
}
|
||||
codegenTestX64_v128_v128(
|
||||
[['f32x4.neg', `66 0f ef 05 .. 00 00 00 pxorx ${RIPR}, %xmm0`],
|
||||
['f64x2.neg', `66 0f ef 05 .. 00 00 00 pxorx ${RIPR}, %xmm0`],
|
||||
['f32x4.abs', `66 0f db 05 .. 00 00 00 pandx ${RIPR}, %xmm0`],
|
||||
['f64x2.abs', `66 0f db 05 .. 00 00 00 pandx ${RIPR}, %xmm0`],
|
||||
['v128.not', `66 0f ef 05 .. 00 00 00 pxorx ${RIPR}, %xmm0`]] );
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// |jit-test| skip-if: !wasmSimdEnabled() || wasmCompileMode() != "ion" || !getBuildConfiguration().x64
|
||||
// |jit-test| skip-if: !wasmSimdEnabled() || !hasDisassembler() || wasmCompileMode() != "ion" || !getBuildConfiguration().x64; include:codegen-x64-test.js
|
||||
|
||||
// Test that there are no extraneous moves for a constant integer SIMD shift
|
||||
// that can reuse its input for its output. See README-codegen.md for general
|
||||
|
@ -7,70 +7,22 @@
|
|||
// There are test cases here for all codegen cases that include a potential move
|
||||
// to set up the operation, but not for all shift operations in general.
|
||||
|
||||
// Inputs (xmm0, xmm1)
|
||||
|
||||
for ( let [op, expected] of [
|
||||
['i8x16.shl', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f fc c0 paddb %xmm0, %xmm0
|
||||
000000.. 66 0f fc c0 paddb %xmm0, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
codegenTestX64_v128xLITERAL_v128(
|
||||
[['i8x16.shl', '(i32.const 2)', `
|
||||
66 0f fc c0 paddb %xmm0, %xmm0
|
||||
66 0f fc c0 paddb %xmm0, %xmm0
|
||||
`],
|
||||
['i16x8.shl', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 71 f0 02 psllw \\$0x02, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
['i16x8.shl', '(i32.const 2)', `66 0f 71 f0 02 psllw \\$0x02, %xmm0`],
|
||||
['i32x4.shl', '(i32.const 2)', `66 0f 72 f0 02 pslld \\$0x02, %xmm0`],
|
||||
['i64x2.shl', '(i32.const 2)', `66 0f 73 f0 02 psllq \\$0x02, %xmm0`],
|
||||
['i8x16.shr_u', '(i32.const 2)', `
|
||||
66 0f db 05 .. 00 00 00 pandx ${RIPR}, %xmm0
|
||||
66 0f 71 d0 02 psrlw \\$0x02, %xmm0
|
||||
`],
|
||||
['i32x4.shl', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 72 f0 02 pslld \\$0x02, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i64x2.shl', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 73 f0 02 psllq \\$0x02, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i8x16.shr_u', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f db 05 .. 00 00 00 pandx 0x00000000000000.., %xmm0
|
||||
000000.. 66 0f 71 d0 02 psrlw \\$0x02, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i16x8.shr_s', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 71 e0 02 psraw \\$0x02, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i16x8.shr_u', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 71 d0 02 psrlw \\$0x02, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i32x4.shr_s', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 72 e0 02 psrad \\$0x02, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i32x4.shr_u', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 72 d0 02 psrld \\$0x02, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i64x2.shr_u', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 73 d0 02 psrlq \\$0x02, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
] ) {
|
||||
let ins = wasmEvalText(`
|
||||
(module
|
||||
(func (export "f") (param v128) (result v128)
|
||||
(${op} (local.get 0) (i32.const 2))))`);
|
||||
let output = wasmDis(ins.exports.f, "ion", true);
|
||||
if (output.indexOf('No disassembly available') >= 0)
|
||||
continue;
|
||||
assertEq(output.match(new RegExp(expected)) != null, true);
|
||||
}
|
||||
['i16x8.shr_s', '(i32.const 2)', `66 0f 71 e0 02 psraw \\$0x02, %xmm0`],
|
||||
['i16x8.shr_u', '(i32.const 2)', `66 0f 71 d0 02 psrlw \\$0x02, %xmm0`],
|
||||
['i32x4.shr_s', '(i32.const 2)', `66 0f 72 e0 02 psrad \\$0x02, %xmm0`],
|
||||
['i32x4.shr_u', '(i32.const 2)', `66 0f 72 d0 02 psrld \\$0x02, %xmm0`],
|
||||
['i64x2.shr_u', '(i32.const 2)', `66 0f 73 d0 02 psrlq \\$0x02, %xmm0`]] );
|
||||
|
||||
|
||||
|
|
|
@ -1,103 +1,66 @@
|
|||
// |jit-test| skip-if: !wasmSimdEnabled() || wasmCompileMode() != "ion" || !getBuildConfiguration().x64
|
||||
// |jit-test| skip-if: !wasmSimdEnabled() || !hasDisassembler() || wasmCompileMode() != "ion" || !getBuildConfiguration().x64; include:codegen-x64-test.js
|
||||
|
||||
// Test that there are no extraneous moves or fixups for SIMD shuffle
|
||||
// operations. See README-codegen.md for general information about this type of
|
||||
// test case.
|
||||
|
||||
// Inputs (xmm0, xmm1)
|
||||
|
||||
for ( let [op, expected] of [
|
||||
['i8x16.shuffle 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15',
|
||||
codegenTestX64_v128xv128_v128([
|
||||
// Identity op on first argument should generate no code
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i8x16.shuffle 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31',
|
||||
['i8x16.shuffle 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15',
|
||||
''],
|
||||
|
||||
// Identity op on second argument should generate a move
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 6f c1 movdqa %xmm1, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i8x16.shuffle 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5',
|
||||
['i8x16.shuffle 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31',
|
||||
`66 0f 6f c1 movdqa %xmm1, %xmm0`],
|
||||
|
||||
// Broadcast a byte from first argument
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 60 c0 punpcklbw %xmm0, %xmm0
|
||||
000000.. f3 0f 70 c0 55 pshufhw \\$0x55, %xmm0, %xmm0
|
||||
000000.. 66 0f 70 c0 aa pshufd \\$0xAA, %xmm0, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i8x16.shuffle 4 5 4 5 4 5 4 5 4 5 4 5 4 5 4 5',
|
||||
['i8x16.shuffle 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5',
|
||||
`
|
||||
66 0f 60 c0 punpcklbw %xmm0, %xmm0
|
||||
f3 0f 70 c0 55 pshufhw \\$0x55, %xmm0, %xmm0
|
||||
66 0f 70 c0 aa pshufd \\$0xAA, %xmm0, %xmm0`],
|
||||
|
||||
// Broadcast a word from first argument
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. f2 0f 70 c0 aa pshuflw \\$0xAA, %xmm0, %xmm0
|
||||
000000.. 66 0f 70 c0 00 pshufd \\$0x00, %xmm0, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i8x16.shuffle 2 1 4 3 6 5 8 7 10 9 12 11 14 13 0 15',
|
||||
['i8x16.shuffle 4 5 4 5 4 5 4 5 4 5 4 5 4 5 4 5',
|
||||
`
|
||||
f2 0f 70 c0 aa pshuflw \\$0xAA, %xmm0, %xmm0
|
||||
66 0f 70 c0 00 pshufd \\$0x00, %xmm0, %xmm0`],
|
||||
|
||||
// Permute bytes
|
||||
['i8x16.shuffle 2 1 4 3 6 5 8 7 10 9 12 11 14 13 0 15',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 44 0f 6f 3d .. 00 00 00
|
||||
movdqax 0x0000000000000040, %xmm15
|
||||
000000.. 66 41 0f 38 00 c7 pshufb %xmm15, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i8x16.shuffle 2 3 0 1 6 7 4 5 10 11 8 9 14 15 12 13',
|
||||
66 44 0f 6f 3d .. 00 00 00\\s
|
||||
* movdqax ${RIPR}, %xmm15
|
||||
66 41 0f 38 00 c7 pshufb %xmm15, %xmm0`],
|
||||
|
||||
// Permute words
|
||||
['i8x16.shuffle 2 3 0 1 6 7 4 5 10 11 8 9 14 15 12 13',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. f2 0f 70 c0 b1 pshuflw \\$0xB1, %xmm0, %xmm0
|
||||
000000.. f3 0f 70 c0 b1 pshufhw \\$0xB1, %xmm0, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i8x16.shuffle 4 5 6 7 0 1 2 3 12 13 14 15 8 9 10 11',
|
||||
f2 0f 70 c0 b1 pshuflw \\$0xB1, %xmm0, %xmm0
|
||||
f3 0f 70 c0 b1 pshufhw \\$0xB1, %xmm0, %xmm0`],
|
||||
|
||||
// Permute doublewords
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 70 c0 b1 pshufd \\$0xB1, %xmm0, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i8x16.shuffle 13 14 15 0 1 2 3 4 5 6 7 8 9 10 11 12',
|
||||
['i8x16.shuffle 4 5 6 7 0 1 2 3 12 13 14 15 8 9 10 11',
|
||||
`66 0f 70 c0 b1 pshufd \\$0xB1, %xmm0, %xmm0`],
|
||||
|
||||
// Rotate right
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f 3a 0f c0 0d palignr \\$0x0D, %xmm0, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i8x16.shuffle 13 14 15 0 1 2 3 4 5 6 7 8 9 10 11 12',
|
||||
`66 0f 3a 0f c0 0d palignr \\$0x0D, %xmm0, %xmm0`],
|
||||
|
||||
// General shuffle + blend. The initial movdqa to scratch is unavoidable
|
||||
// unless we can convince the compiler that it's OK to destroy xmm1.
|
||||
['i8x16.shuffle 15 29 0 1 2 1 2 0 3 4 7 8 16 8 17 9',
|
||||
// General shuffle + blend. The initial movdqa to scratch is
|
||||
// unavoidable unless we can convince the compiler that it's OK to destroy xmm1.
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 44 0f 6f f9 movdqa %xmm1, %xmm15
|
||||
000000.. 66 44 0f 38 00 3d .. 00 00 00
|
||||
pshufbx 0x0000000000000050, %xmm15
|
||||
000000.. 66 0f 38 00 05 .. 00 00 00
|
||||
pshufbx 0x0000000000000060, %xmm0
|
||||
000000.. 66 41 0f eb c7 por %xmm15, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
] ) {
|
||||
let ins = wasmEvalText(`
|
||||
(module
|
||||
(func (export "f") (param v128) (param v128) (result v128)
|
||||
(${op} (local.get 0) (local.get 1))))
|
||||
`);
|
||||
let output = wasmDis(ins.exports.f, "ion", true);
|
||||
if (output.indexOf('No disassembly available') >= 0)
|
||||
continue;
|
||||
assertEq(output.match(new RegExp(expected)) != null, true);
|
||||
}
|
||||
66 44 0f 6f f9 movdqa %xmm1, %xmm15
|
||||
66 44 0f 38 00 3d .. 00 00 00\\s
|
||||
* pshufbx ${RIPR}, %xmm15
|
||||
66 0f 38 00 05 .. 00 00 00\\s
|
||||
* pshufbx ${RIPR}, %xmm0
|
||||
66 41 0f eb c7 por %xmm15, %xmm0`],
|
||||
]);
|
||||
|
||||
// Inputs (xmm0, zero)
|
||||
|
||||
for ( let [op, expected] of [
|
||||
['i8x16.shuffle 16 16 16 0 1 2 3 4 5 6 7 8 9 10 11 12',
|
||||
// Shift left bytes, shifting in zeroes
|
||||
codegenTestX64_v128xLITERAL_v128(
|
||||
[// Shift left bytes, shifting in zeroes
|
||||
//
|
||||
// Remember the low-order bytes are at the "right" end
|
||||
//
|
||||
|
@ -105,29 +68,16 @@ for ( let [op, expected] of [
|
|||
// code should need to be generated for it, and no register should
|
||||
// be allocated to it. The lowering does not use that operand, but
|
||||
// code generation still touches it.
|
||||
['i8x16.shuffle 16 16 16 0 1 2 3 4 5 6 7 8 9 10 11 12',
|
||||
'(v128.const i32x4 0 0 0 0)',
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f ef c9 pxor %xmm1, %xmm1
|
||||
000000.. 66 0f 73 f8 03 pslldq \\$0x03, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['i8x16.shuffle 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18',
|
||||
// Shift right bytes, shifting in zeroes. See above.
|
||||
`
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f ef c9 pxor %xmm1, %xmm1
|
||||
000000.. 66 0f 73 d8 03 psrldq \\$0x03, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
66 0f ef c9 pxor %xmm1, %xmm1
|
||||
66 0f 73 f8 03 pslldq \\$0x03, %xmm0`],
|
||||
|
||||
// Shift right bytes, shifting in zeroes. See above.
|
||||
['i8x16.shuffle 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18',
|
||||
'(v128.const i32x4 0 0 0 0)',
|
||||
`
|
||||
66 0f ef c9 pxor %xmm1, %xmm1
|
||||
66 0f 73 d8 03 psrldq \\$0x03, %xmm0`]]);
|
||||
|
||||
] ) {
|
||||
let ins = wasmEvalText(`
|
||||
(module
|
||||
(func (export "f") (param v128) (result v128)
|
||||
(${op} (local.get 0) (v128.const i32x4 0 0 0 0))))
|
||||
`);
|
||||
let output = wasmDis(ins.exports.f, "ion", true);
|
||||
if (output.indexOf('No disassembly available') >= 0)
|
||||
continue;
|
||||
assertEq(output.match(new RegExp(expected)) != null, true);
|
||||
}
|
||||
|
|
|
@ -1,95 +1,30 @@
|
|||
// |jit-test| skip-if: !wasmSimdEnabled() || wasmCompileMode() != "ion" || !getBuildConfiguration().x64
|
||||
// |jit-test| skip-if: !wasmSimdEnabled() || !hasDisassembler() || wasmCompileMode() != "ion" || !getBuildConfiguration().x64; include:codegen-x64-test.js
|
||||
|
||||
// Test that there are no extraneous moves or other instructions for splat and
|
||||
// other splat-like operations that can reuse its input for its output and/or
|
||||
// has a specializable code path. See README-codegen.md for general information
|
||||
// about this type of test case.
|
||||
|
||||
// Input (xmm0)
|
||||
codegenTestX64_PTYPE_v128(
|
||||
[['f32x4.splat', 'f32', `0f c6 c0 00 shufps \\$0x00, %xmm0, %xmm0`],
|
||||
['f64x2.splat', 'f64', `66 0f c6 c0 00 shufpd \\$0x00, %xmm0, %xmm0`]] );
|
||||
|
||||
for ( let [ simd_type, expected ] of [
|
||||
['f32x4', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 0f c6 c0 00 shufps \\$0x00, %xmm0, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['f64x2', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 0f c6 c0 00 shufpd \\$0x00, %xmm0, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
] ) {
|
||||
|
||||
let type = simd_type.substring(0,3);
|
||||
let ins = wasmEvalText(`
|
||||
(module
|
||||
(func (export "f") (param ${type}) (result v128)
|
||||
(${simd_type}.splat (local.get 0))))`);
|
||||
let output = wasmDis(ins.exports.f, "ion", true);
|
||||
if (output.indexOf('No disassembly available') >= 0)
|
||||
continue;
|
||||
assertEq(output.match(new RegExp(expected)) != null, true);
|
||||
}
|
||||
|
||||
// Input (paramreg0)
|
||||
//
|
||||
// Skip these on Win64 because the ABI differs and there's a different parameter
|
||||
// register, this changes not just the name slightly but the binary encoding in
|
||||
// larger ways.
|
||||
|
||||
if (!getBuildConfiguration().windows) {
|
||||
for ( let [ op, expected ] of [
|
||||
['v128.load32_splat', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. f3 41 0f 10 04 3f movssl \\(%r15,%rdi,1\\), %xmm0
|
||||
000000.. 0f c6 c0 00 shufps \\$0x00, %xmm0, %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
codegenTestX64_PTYPE_v128(
|
||||
[['v128.load32_splat', 'i32', `
|
||||
f3 41 0f 10 04 3f movssl \\(%r15,%rdi,1\\), %xmm0
|
||||
0f c6 c0 00 shufps \\$0x00, %xmm0, %xmm0
|
||||
`],
|
||||
['v128.load64_splat', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. f2 41 0f 12 04 3f movddupq \\(%r15,%rdi,1\\), %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['v128.load8x8_s', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 41 0f 38 20 04 3f pmovsxbwq \\(%r15,%rdi,1\\), %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['v128.load8x8_u', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 41 0f 38 30 04 3f pmovzxbwq \\(%r15,%rdi,1\\), %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['v128.load16x4_s', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 41 0f 38 23 04 3f pmovsxwdq \\(%r15,%rdi,1\\), %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['v128.load16x4_u', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 41 0f 38 33 04 3f pmovzxwdq \\(%r15,%rdi,1\\), %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['v128.load32x2_s', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 41 0f 38 25 04 3f pmovsxdqq \\(%r15,%rdi,1\\), %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
['v128.load32x2_u', `
|
||||
000000.. 48 8b ec mov %rsp, %rbp
|
||||
000000.. 66 41 0f 38 35 04 3f pmovzxdqq \\(%r15,%rdi,1\\), %xmm0
|
||||
000000.. 5d pop %rbp
|
||||
`],
|
||||
] ) {
|
||||
|
||||
let ins = wasmEvalText(`
|
||||
(module
|
||||
(memory 1)
|
||||
(func (export "f") (param i32) (result v128)
|
||||
(${op} (local.get 0))))`);
|
||||
let output = wasmDis(ins.exports.f, "ion", true);
|
||||
if (output.indexOf('No disassembly available') >= 0)
|
||||
continue;
|
||||
assertEq(output.match(new RegExp(expected)) != null, true);
|
||||
}
|
||||
['v128.load64_splat', 'i32', `f2 41 0f 12 04 3f movddupq \\(%r15,%rdi,1\\), %xmm0`],
|
||||
['v128.load8x8_s', 'i32', `66 41 0f 38 20 04 3f pmovsxbwq \\(%r15,%rdi,1\\), %xmm0`],
|
||||
['v128.load8x8_u', 'i32', `66 41 0f 38 30 04 3f pmovzxbwq \\(%r15,%rdi,1\\), %xmm0`],
|
||||
['v128.load16x4_s', 'i32', `66 41 0f 38 23 04 3f pmovsxwdq \\(%r15,%rdi,1\\), %xmm0`],
|
||||
['v128.load16x4_u', 'i32', `66 41 0f 38 33 04 3f pmovzxwdq \\(%r15,%rdi,1\\), %xmm0`],
|
||||
['v128.load32x2_s', 'i32', `66 41 0f 38 25 04 3f pmovsxdqq \\(%r15,%rdi,1\\), %xmm0`],
|
||||
['v128.load32x2_u', 'i32', `66 41 0f 38 35 04 3f pmovzxdqq \\(%r15,%rdi,1\\), %xmm0`]],
|
||||
{memory:1});
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ namespace jit {
|
|||
|
||||
#if defined(JS_JITSPEW) && (defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64))
|
||||
|
||||
bool HasDisassembler() { return true; }
|
||||
|
||||
void Disassemble(uint8_t* code, size_t length, InstrCallback callback) {
|
||||
zydisDisassemble(code, length, callback);
|
||||
}
|
||||
|
@ -51,6 +53,8 @@ class ARM64Disassembler : public vixl::Disassembler {
|
|||
InstrCallback callback_;
|
||||
};
|
||||
|
||||
bool HasDisassembler() { return true; }
|
||||
|
||||
void Disassemble(uint8_t* code, size_t length, InstrCallback callback) {
|
||||
ARM64Disassembler dis(callback);
|
||||
vixl::Decoder decoder;
|
||||
|
@ -68,6 +72,8 @@ void Disassemble(uint8_t* code, size_t length, InstrCallback callback) {
|
|||
|
||||
#elif defined(JS_JITSPEW) && defined(JS_CODEGEN_ARM)
|
||||
|
||||
bool HasDisassembler() { return true; }
|
||||
|
||||
void Disassemble(uint8_t* code, size_t length, InstrCallback callback) {
|
||||
disasm::NameConverter converter;
|
||||
disasm::Disassembler d(converter);
|
||||
|
@ -91,6 +97,8 @@ void Disassemble(uint8_t* code, size_t length, InstrCallback callback) {
|
|||
|
||||
#else
|
||||
|
||||
bool HasDisassembler() { return false; }
|
||||
|
||||
void Disassemble(uint8_t* code, size_t length, InstrCallback callback) {
|
||||
callback("*** No disassembly available ***\n");
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace jit {
|
|||
|
||||
using InstrCallback = void (*)(const char* text);
|
||||
|
||||
extern bool HasDisassembler();
|
||||
extern void Disassemble(uint8_t* code, size_t length, InstrCallback callback);
|
||||
|
||||
} // namespace jit
|
||||
|
|
Загрузка…
Ссылка в новой задаче