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:
Lars T Hansen 2020-11-05 10:15:17 +00:00
Родитель b1806d83eb
Коммит 274d1a5dde
15 изменённых файлов: 468 добавлений и 745 удалений

Просмотреть файл

@ -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