// |jit-test| skip-if: !wasmSimdEnabled() || !hasDisassembler() || wasmCompileMode() != "ion" || !getBuildConfiguration("x64") || getBuildConfiguration("simulator") || !isAvxPresent(); 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.
// Note, these tests test the beginning of the output but not the end.
// Currently AVX2 exhibits a defect when function uses its first v128 arg and
// returns v128: the register allocator adds unneeded extra moves from xmm0,
// then into different temporary, and then the latter temporary is used as arg.
// In the tests below, to simplify things, don't use/ignore the first arg.
// v128 OP v128 -> v128
// inputs: [[complete-opname, expected-pattern], ...]
function codegenTestX64_v128xv128_v128_avxhack(inputs, options = {}) {
for ( let [op, expected] of inputs ) {
codegenTestX64_adhoc(wrap(options, `
(func (export "f" ) (param v128 v128 v128) (result v128)
(${op} (local.get 1 ) (local.get 2 )))`),
'f' ,
expected,
options);
}
}
// (see codegenTestX64_v128xv128_v128_avxhack comment about AVX defect)
// v128 OP const -> v128
// inputs: [[complete-opname, const, expected-pattern], ...]
function codegenTestX64_v128xLITERAL_v128_avxhack(inputs, options = {}) {
for ( let [op, const_, expected] of inputs ) {
codegenTestX64_adhoc(wrap(options, `
(func (export "f" ) (param v128 v128) (result v128)
(${op} (local.get 1 ) ${const_}))`),
'f' ,
expected,
options);
}
}
// (see codegenTestX64_v128xv128_v128_avxhack comment about AVX defect)
// const OP v128 -> v128
// inputs: [[complete-opname, const, expected-pattern], ...]
function codegenTestX64_LITERALxv128_v128_avxhack(inputs, options = {}) {
for ( let [op, const_, expected] of inputs ) {
codegenTestX64_adhoc(wrap(options, `
(func (export "f" ) (param v128 v128) (result v128)
(${op} ${const_} (local.get 1 )))`),
'f' ,
expected,
options);
}
}
// Utility function to test SIMD operations encoding, where the input argument
// has the specified type (T).
// inputs: [[type, complete-opname, expected-pattern], ...]
function codegenTestX64_T_v128_avxhack(inputs, options = {}) {
for ( let [ty, op, expected] of inputs ) {
codegenTestX64_adhoc(wrap(options, `
(func (export "f" ) (param ${ty}) (result v128)
(${op} (local.get 0 )))`),
'f' ,
expected,
options);
}
}
// Machers for any 64- and 32-bit registers.
var GPR_I64 = "%r\\w+" ;
var GPR_I32 = "%(?:e\\w+|r\\d+d)" ;
// Simple binary ops: e.g. add, sub, mul
codegenTestX64_v128xv128_v128_avxhack(
[['i8x16.avgr_u' , `vpavgb %xmm2, %xmm1, %xmm0`],
['i16x8.avgr_u' , `vpavgw %xmm2, %xmm1, %xmm0`],
['i8x16.add' , `vpaddb %xmm2, %xmm1, %xmm0`],
['i8x16.add_sat_s' , `vpaddsb %xmm2, %xmm1, %xmm0`],
['i8x16.add_sat_u' , `vpaddusb %xmm2, %xmm1, %xmm0`],
['i8x16.sub' , `vpsubb %xmm2, %xmm1, %xmm0`],
['i8x16.sub_sat_s' , `vpsubsb %xmm2, %xmm1, %xmm0`],
['i8x16.sub_sat_u' , `vpsubusb %xmm2, %xmm1, %xmm0`],
['i16x8.mul' , `vpmullw %xmm2, %xmm1, %xmm0`],
['i16x8.min_s' , `vpminsw %xmm2, %xmm1, %xmm0`],
['i16x8.min_u' , `vpminuw %xmm2, %xmm1, %xmm0`],
['i16x8.max_s' , `vpmaxsw %xmm2, %xmm1, %xmm0`],
['i16x8.max_u' , `vpmaxuw %xmm2, %xmm1, %xmm0`],
['i32x4.add' , `vpaddd %xmm2, %xmm1, %xmm0`],
['i32x4.sub' , `vpsubd %xmm2, %xmm1, %xmm0`],
['i32x4.mul' , `vpmulld %xmm2, %xmm1, %xmm0`],
['i32x4.min_s' , `vpminsd %xmm2, %xmm1, %xmm0`],
['i32x4.min_u' , `vpminud %xmm2, %xmm1, %xmm0`],
['i32x4.max_s' , `vpmaxsd %xmm2, %xmm1, %xmm0`],
['i32x4.max_u' , `vpmaxud %xmm2, %xmm1, %xmm0`],
['i64x2.add' , `vpaddq %xmm2, %xmm1, %xmm0`],
['i64x2.sub' , `vpsubq %xmm2, %xmm1, %xmm0`],
['i64x2.mul' , `
vpsrlq \\$0 x20, %xmm1, %xmm3
pmuludq %xmm2, %xmm3
vpsrlq \\$0 x20, %xmm2, %xmm15
pmuludq %xmm1, %xmm15
paddq %xmm3, %xmm15
psllq \\$0 x20, %xmm15
vpmuludq %xmm2, %xmm1, %xmm0
paddq %xmm15, %xmm0`],
['f32x4.add' , `vaddps %xmm2, %xmm1, %xmm0`],
['f32x4.sub' , `vsubps %xmm2, %xmm1, %xmm0`],
['f32x4.mul' , `vmulps %xmm2, %xmm1, %xmm0`],
['f32x4.div' , `vdivps %xmm2, %xmm1, %xmm0`],
['f64x2.add' , `vaddpd %xmm2, %xmm1, %xmm0`],
['f64x2.sub' , `vsubpd %xmm2, %xmm1, %xmm0`],
['f64x2.mul' , `vmulpd %xmm2, %xmm1, %xmm0`],
['f64x2.div' , `vdivpd %xmm2, %xmm1, %xmm0`],
['i8x16.narrow_i16x8_s' , `vpacksswb %xmm2, %xmm1, %xmm0`],
['i8x16.narrow_i16x8_u' , `vpackuswb %xmm2, %xmm1, %xmm0`],
['i16x8.narrow_i32x4_s' , `vpackssdw %xmm2, %xmm1, %xmm0`],
['i16x8.narrow_i32x4_u' , `vpackusdw %xmm2, %xmm1, %xmm0`],
['i32x4.dot_i16x8_s' , `vpmaddwd %xmm2, %xmm1, %xmm0`]]);
// Simple comparison ops
codegenTestX64_v128xv128_v128_avxhack(
[['i8x16.eq' , `vpcmpeqb %xmm2, %xmm1, %xmm0`],
['i8x16.ne' , `
vpcmpeqb %xmm2, %xmm1, %xmm0
pcmpeqw %xmm15, %xmm15
pxor %xmm15, %xmm0`],
['i8x16.lt_s' , `vpcmpgtb %xmm1, %xmm2, %xmm0`],
['i8x16.gt_u' , `
vpmaxub %xmm2, %xmm1, %xmm0
pcmpeqb %xmm2, %xmm0
pcmpeqw %xmm15, %xmm15
pxor %xmm15, %xmm0`],
['i16x8.eq' , `vpcmpeqw %xmm2, %xmm1, %xmm0`],
['i16x8.ne' , `
vpcmpeqw %xmm2, %xmm1, %xmm0
pcmpeqw %xmm15, %xmm15
pxor %xmm15, %xmm0`],
['i16x8.le_s' , `
vpcmpgtw %xmm2, %xmm1, %xmm0
pcmpeqw %xmm15, %xmm15
pxor %xmm15, %xmm0`],
['i16x8.ge_u' , `
vpminuw %xmm2, %xmm1, %xmm0
pcmpeqw %xmm2, %xmm0`],
['i32x4.eq' , `vpcmpeqd %xmm2, %xmm1, %xmm0`],
['i32x4.ne' , `
vpcmpeqd %xmm2, %xmm1, %xmm0
pcmpeqw %xmm15, %xmm15
pxor %xmm15, %xmm0`],
['i32x4.lt_s' , `vpcmpgtd %xmm1, %xmm2, %xmm0`],
['i32x4.gt_u' , `
vpmaxud %xmm2, %xmm1, %xmm0
pcmpeqd %xmm2, %xmm0
pcmpeqw %xmm15, %xmm15
pxor %xmm15, %xmm0`],
['i64x2.eq' , `vpcmpeqq %xmm2, %xmm1, %xmm0`],
['i64x2.ne' , `
vpcmpeqq %xmm2, %xmm1, %xmm0
pcmpeqw %xmm15, %xmm15
pxor %xmm15, %xmm0`],
['i64x2.lt_s' , `vpcmpgtq %xmm1, %xmm2, %xmm0`],
['i64x2.ge_s' , `
vpcmpgtq %xmm1, %xmm2, %xmm0
pcmpeqw %xmm15, %xmm15
pxor %xmm15, %xmm0`],
['f32x4.eq' , `vcmpps \\$0 x00, %xmm2, %xmm1, %xmm0`],
['f32x4.lt' , `vcmpps \\$0 x01, %xmm2, %xmm1, %xmm0`],
['f32x4.ge' , `vcmpps \\$0 x02, %xmm1, %xmm2, %xmm0`],
['f64x2.eq' , `vcmppd \\$0 x00, %xmm2, %xmm1, %xmm0`],
['f64x2.lt' , `vcmppd \\$0 x01, %xmm2, %xmm1, %xmm0`],
['f64x2.ge' , `vcmppd \\$0 x02, %xmm1, %xmm2, %xmm0`],
['f32x4.pmin' , `vminps %xmm1, %xmm2, %xmm0`],
['f32x4.pmax' , `vmaxps %xmm1, %xmm2, %xmm0`],
['f64x2.pmin' , `vminpd %xmm1, %xmm2, %xmm0`],
['f64x2.pmax' , `vmaxpd %xmm1, %xmm2, %xmm0`],
['i8x16.swizzle' , `
vpaddusbx ${RIPR}, %xmm2, %xmm15
vpshufb %xmm15, %xmm1, %xmm0`],
['i16x8.extmul_high_i8x16_s' , `
palignr \\$0 x08, %xmm2, %xmm15
vpmovsxbw %xmm15, %xmm15
palignr \\$0 x08, %xmm1, %xmm0
vpmovsxbw %xmm0, %xmm0
pmullw %xmm15, %xmm0`],
['i32x4.extmul_low_i16x8_u' , `
vpmulhuw %xmm2, %xmm1, %xmm15
vpmullw %xmm2, %xmm1, %xmm0
punpcklwd %xmm15, %xmm0`],
['i64x2.extmul_low_i32x4_s' , `
vpshufd \\$0 x10, %xmm1, %xmm15
vpshufd \\$0 x10, %xmm2, %xmm0
pmuldq %xmm15, %xmm0`],
['i16x8.q15mulr_sat_s' , `
vpmulhrsw %xmm2, %xmm1, %xmm0
vpcmpeqwx ${RIPR}, %xmm0, %xmm15
pxor %xmm15, %xmm0`],
]);
// Bitwise binary ops
codegenTestX64_v128xv128_v128_avxhack(
[['v128.and' , `vpand %xmm2, %xmm1, %xmm0`],
['v128.andnot' , `vpandn %xmm1, %xmm2, %xmm0`],
['v128.or' , `vpor %xmm2, %xmm1, %xmm0`],
['v128.xor' , `vpxor %xmm2, %xmm1, %xmm0`]]);
// Replace lane ops.
codegenTestX64_adhoc(`(module
(func (export "f" ) (param v128 v128 i32) (result v128)
(i8x16.replace_lane 7 (local.get 1 ) (local.get 2 ))))`, 'f' , `
vpinsrb \\$0 x07, ${GPR_I32}, %xmm1, %xmm0`);
codegenTestX64_adhoc(`(module
(func (export "f" ) (param v128 v128 i32) (result v128)
(i16x8.replace_lane 3 (local.get 1 ) (local.get 2 ))))`, 'f' , `
vpinsrw \\$0 x03, ${GPR_I32}, %xmm1, %xmm0`);
codegenTestX64_adhoc(`(module
(func (export "f" ) (param v128 v128 i32) (result v128)
(i32x4.replace_lane 2 (local.get 1 ) (local.get 2 ))))`, 'f' , `
vpinsrd \\$0 x02, ${GPR_I32}, %xmm1, %xmm0`);
codegenTestX64_adhoc(`(module
(func (export "f" ) (param v128 v128 i64) (result v128)
(i64x2.replace_lane 1 (local.get 1 ) (local.get 2 ))))`, 'f' , `
vpinsrq \\$0 x01, ${GPR_I64}, %xmm1, %xmm0`);
if (isAvxPresent(2 )) {
codegenTestX64_T_v128_avxhack(
[['i32' , 'i8x16.splat' , `
vmovd ${GPR_I32}, %xmm0
vpbroadcastb %xmm0, %xmm0`],
['i32' , 'i16x8.splat' , `
vmovd ${GPR_I32}, %xmm0
vpbroadcastw %xmm0, %xmm0`],
['i32' , 'i32x4.splat' , `
vmovd ${GPR_I32}, %xmm0
vpbroadcastd %xmm0, %xmm0`],
['i64' , 'i64x2.splat' , `
vmovq ${GPR_I64}, %xmm0
vpbroadcastq %xmm0, %xmm0`],
['f32' , 'f32x4.splat' , `vbroadcastss %xmm0, %xmm0`]], {log:true });
codegenTestX64_T_v128_avxhack(
[['i32' , 'v128.load8_splat' ,
'vpbroadcastbb \\(%r15,%r\\w+,1\\), %xmm0' ],
['i32' , 'v128.load16_splat' ,
'vpbroadcastww \\(%r15,%r\\w+,1\\), %xmm0' ],
['i32' , 'v128.load32_splat' ,
'vbroadcastssl \\(%r15,%r\\w+,1\\), %xmm0' ]], {memory: 1 });
}
// Using VEX during shuffle ops
codegenTestX64_v128xv128_v128_avxhack([
// Identity op on second argument should generate a move
['i8x16.shuffle 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15' ,
'vmovdqa %xmm1, %xmm0' ],
// Broadcast a byte from first argument
['i8x16.shuffle 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5' ,
`
vpunpcklbw %xmm1, %xmm1, %xmm0
vpshufhw \\$0 x55, %xmm0, %xmm0
vpshufd \\$0 xAA, %xmm0, %xmm0`],
// Broadcast a word from first argument
['i8x16.shuffle 4 5 4 5 4 5 4 5 4 5 4 5 4 5 4 5' ,
`
vpshuflw \\$0 xAA, %xmm1, %xmm0
vpshufd \\$0 x00, %xmm0, %xmm0`],
// Permute words
['i8x16.shuffle 2 3 0 1 6 7 4 5 10 11 8 9 14 15 12 13' ,
`
vpshuflw \\$0 xB1, %xmm1, %xmm0
vpshufhw \\$0 xB1, %xmm0, %xmm0`],
// Permute doublewords
['i8x16.shuffle 4 5 6 7 0 1 2 3 12 13 14 15 8 9 10 11' ,
'vpshufd \\$0xB1, %xmm1, %xmm0' ],
// Interleave doublewords
['i8x16.shuffle 0 1 2 3 16 17 18 19 4 5 6 7 20 21 22 23' ,
'vpunpckldq %xmm2, %xmm1, %xmm0' ],
// Interleave quadwords
['i8x16.shuffle 24 25 26 27 28 29 30 31 8 9 10 11 12 13 14 15' ,
'vpunpckhqdq %xmm1, %xmm2, %xmm0' ],
// Rotate right
['i8x16.shuffle 13 14 15 0 1 2 3 4 5 6 7 8 9 10 11 12' ,
`vpalignr \\$0 x0D, %xmm1, %xmm1, %xmm0`],
['i8x16.shuffle 28 29 30 31 0 1 2 3 4 5 6 7 8 9 10 11' ,
`vpalignr \\$0 x0C, %xmm2, %xmm1, %xmm0`]]);
if (isAvxPresent(2 )) {
codegenTestX64_v128xv128_v128_avxhack([
// Broadcast low byte from second argument
['i8x16.shuffle 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0' ,
'vpbroadcastb %xmm1, %xmm0' ],
// Broadcast low word from third argument
['i8x16.shuffle 16 17 16 17 16 17 16 17 16 17 16 17 16 17 16 17' ,
'vpbroadcastw %xmm2, %xmm0' ],
// Broadcast low doubleword from second argument
['i8x16.shuffle 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3' ,
'vpbroadcastd %xmm1, %xmm0' ]]);
}
// Testing AVX optimization where VPBLENDVB accepts four XMM registers as args.
codegenTestX64_adhoc(
`(func (export "f" ) (param v128 v128 v128 v128) (result v128)
(i8x16.shuffle 0 17 2 3 4 5 6 7 24 25 26 11 12 13 30 15
(local.get 2 )(local.get 3 )))`,
'f' ,
`
movdqax ${RIPR}, %xmm1
vpblendvb %xmm1, %xmm3, %xmm2, %xmm0`);
// Constant arguments that are folded into the instruction
codegenTestX64_v128xLITERAL_v128_avxhack(
[['i8x16.add' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpaddbx ${RIPR}, %xmm1, %xmm0`],
['i8x16.sub' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpsubbx ${RIPR}, %xmm1, %xmm0`],
['i8x16.add_sat_s' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpaddsbx ${RIPR}, %xmm1, %xmm0`],
['i8x16.add_sat_u' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpaddusbx ${RIPR}, %xmm1, %xmm0`],
['i8x16.sub_sat_s' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpsubsbx ${RIPR}, %xmm1, %xmm0`],
['i8x16.sub_sat_u' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpsubusbx ${RIPR}, %xmm1, %xmm0`],
['i8x16.min_s' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpminsbx ${RIPR}, %xmm1, %xmm0`],
['i8x16.min_u' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpminubx ${RIPR}, %xmm1, %xmm0`],
['i8x16.max_s' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpmaxsbx ${RIPR}, %xmm1, %xmm0`],
['i8x16.max_u' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpmaxubx ${RIPR}, %xmm1, %xmm0`],
['i8x16.eq' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpcmpeqbx ${RIPR}, %xmm1, %xmm0`],
['i8x16.ne' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' , `
vpcmpeqbx ${RIPR}, %xmm1, %xmm0
pcmpeqw %xmm15, %xmm15
pxor %xmm15, %xmm0`],
['i8x16.gt_s' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpcmpgtbx ${RIPR}, %xmm1, %xmm0`],
['i8x16.le_s' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' , `
vpcmpgtbx ${RIPR}, %xmm1, %xmm0
pcmpeqw %xmm15, %xmm15
pxor %xmm15, %xmm0`],
['i8x16.narrow_i16x8_s' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpacksswbx ${RIPR}, %xmm1, %xmm0`],
['i8x16.narrow_i16x8_u' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpackuswbx ${RIPR}, %xmm1, %xmm0`],
['i16x8.add' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpaddwx ${RIPR}, %xmm1, %xmm0`],
['i16x8.sub' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpsubwx ${RIPR}, %xmm1, %xmm0`],
['i16x8.mul' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpmullwx ${RIPR}, %xmm1, %xmm0`],
['i16x8.add_sat_s' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpaddswx ${RIPR}, %xmm1, %xmm0`],
['i16x8.add_sat_u' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpadduswx ${RIPR}, %xmm1, %xmm0`],
['i16x8.sub_sat_s' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpsubswx ${RIPR}, %xmm1, %xmm0`],
['i16x8.sub_sat_u' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpsubuswx ${RIPR}, %xmm1, %xmm0`],
['i16x8.min_s' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpminswx ${RIPR}, %xmm1, %xmm0`],
['i16x8.min_u' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpminuwx ${RIPR}, %xmm1, %xmm0`],
['i16x8.max_s' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpmaxswx ${RIPR}, %xmm1, %xmm0`],
['i16x8.max_u' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpmaxuwx ${RIPR}, %xmm1, %xmm0`],
['i16x8.eq' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpcmpeqwx ${RIPR}, %xmm1, %xmm0`],
['i16x8.ne' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' , `
vpcmpeqwx ${RIPR}, %xmm1, %xmm0
pcmpeqw %xmm15, %xmm15
pxor %xmm15, %xmm0`],
['i16x8.gt_s' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpcmpgtwx ${RIPR}, %xmm1, %xmm0`],
['i16x8.le_s' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' , `
vpcmpgtwx ${RIPR}, %xmm1, %xmm0
pcmpeqw %xmm15, %xmm15
pxor %xmm15, %xmm0`],
['i16x8.narrow_i32x4_s' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpackssdwx ${RIPR}, %xmm1, %xmm0`],
['i16x8.narrow_i32x4_u' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpackusdwx ${RIPR}, %xmm1, %xmm0`],
['i32x4.add' , '(v128.const i32x4 1 2 1 2)' ,
`vpadddx ${RIPR}, %xmm1, %xmm0`],
['i32x4.sub' , '(v128.const i32x4 1 2 1 2)' ,
`vpsubdx ${RIPR}, %xmm1, %xmm0`],
['i32x4.mul' , '(v128.const i32x4 1 2 1 2)' ,
`vpmulldx ${RIPR}, %xmm1, %xmm0`],
['i32x4.min_s' , '(v128.const i32x4 1 2 1 2)' ,
`vpminsdx ${RIPR}, %xmm1, %xmm0`],
['i32x4.min_u' , '(v128.const i32x4 1 2 1 2)' ,
`vpminudx ${RIPR}, %xmm1, %xmm0`],
['i32x4.max_s' , '(v128.const i32x4 1 2 1 2)' ,
`vpmaxsdx ${RIPR}, %xmm1, %xmm0`],
['i32x4.max_u' , '(v128.const i32x4 1 2 1 2)' ,
`vpmaxudx ${RIPR}, %xmm1, %xmm0`],
['i32x4.eq' , '(v128.const i32x4 1 2 1 2)' ,
`vpcmpeqdx ${RIPR}, %xmm1, %xmm0`],
['i32x4.ne' , '(v128.const i32x4 1 2 1 2)' , `
vpcmpeqdx ${RIPR}, %xmm1, %xmm0
pcmpeqw %xmm15, %xmm15
pxor %xmm15, %xmm0`],
['i32x4.gt_s' , '(v128.const i32x4 1 2 1 2)' ,
`vpcmpgtdx ${RIPR}, %xmm1, %xmm0`],
['i32x4.le_s' , '(v128.const i32x4 1 2 1 2)' , `
vpcmpgtdx ${RIPR}, %xmm1, %xmm0
pcmpeqw %xmm15, %xmm15
pxor %xmm15, %xmm0`],
['i32x4.dot_i16x8_s' , '(v128.const i32x4 1 2 1 2)' ,
`vpmaddwdx ${RIPR}, %xmm1, %xmm0`],
['i64x2.add' , '(v128.const i64x2 1 2)' ,
`vpaddqx ${RIPR}, %xmm1, %xmm0`],
['i64x2.sub' , '(v128.const i64x2 1 2)' ,
`vpsubqx ${RIPR}, %xmm1, %xmm0`],
['v128.and' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpandx ${RIPR}, %xmm1, %xmm0`],
['v128.or' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vporx ${RIPR}, %xmm1, %xmm0`],
['v128.xor' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpxorx ${RIPR}, %xmm1, %xmm0`],
['f32x4.add' , '(v128.const f32x4 1 2 3 4)' ,
`vaddpsx ${RIPR}, %xmm1, %xmm0`],
['f32x4.sub' , '(v128.const f32x4 1 2 3 4)' ,
`vsubpsx ${RIPR}, %xmm1, %xmm0`],
['f32x4.mul' , '(v128.const f32x4 1 2 3 4)' ,
`vmulpsx ${RIPR}, %xmm1, %xmm0`],
['f32x4.div' , '(v128.const f32x4 1 2 3 4)' ,
`vdivpsx ${RIPR}, %xmm1, %xmm0`],
['f64x2.add' , '(v128.const f64x2 1 2)' ,
`vaddpdx ${RIPR}, %xmm1, %xmm0`],
['f64x2.sub' , '(v128.const f64x2 1 2)' ,
`vsubpdx ${RIPR}, %xmm1, %xmm0`],
['f64x2.mul' , '(v128.const f64x2 1 2)' ,
`vmulpdx ${RIPR}, %xmm1, %xmm0`],
['f64x2.div' , '(v128.const f64x2 1 2)' ,
`vdivpdx ${RIPR}, %xmm1, %xmm0`],
['f32x4.eq' , '(v128.const f32x4 1 2 3 4)' ,
`vcmppsx \\$0 x00, ${RIPR}, %xmm1, %xmm0`],
['f32x4.ne' , '(v128.const f32x4 1 2 3 4)' ,
`vcmppsx \\$0 x04, ${RIPR}, %xmm1, %xmm0`],
['f32x4.lt' , '(v128.const f32x4 1 2 3 4)' ,
`vcmppsx \\$0 x01, ${RIPR}, %xmm1, %xmm0`],
['f32x4.le' , '(v128.const f32x4 1 2 3 4)' ,
`vcmppsx \\$0 x02, ${RIPR}, %xmm1, %xmm0`],
['f64x2.eq' , '(v128.const f64x2 1 2)' ,
`vcmppdx \\$0 x00, ${RIPR}, %xmm1, %xmm0`],
['f64x2.ne' , '(v128.const f64x2 1 2)' ,
`vcmppdx \\$0 x04, ${RIPR}, %xmm1, %xmm0`],
['f64x2.lt' , '(v128.const f64x2 1 2)' ,
`vcmppdx \\$0 x01, ${RIPR}, %xmm1, %xmm0`],
['f64x2.le' , '(v128.const f64x2 1 2)' ,
`vcmppdx \\$0 x02, ${RIPR}, %xmm1, %xmm0`]]);
// Commutative operations with constants on the lhs should generate the same
// code as with the constant on the rhs.
codegenTestX64_LITERALxv128_v128_avxhack(
[['i8x16.add' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpaddbx ${RIPR}, %xmm1, %xmm0`],
['i8x16.add_sat_s' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpaddsbx ${RIPR}, %xmm1, %xmm0`],
['i8x16.add_sat_u' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpaddusbx ${RIPR}, %xmm1, %xmm0`],
['i8x16.min_s' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpminsbx ${RIPR}, %xmm1, %xmm0`],
['i8x16.min_u' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpminubx ${RIPR}, %xmm1, %xmm0`],
['i8x16.max_s' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpmaxsbx ${RIPR}, %xmm1, %xmm0`],
['i8x16.max_u' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpmaxubx ${RIPR}, %xmm1, %xmm0`],
['i8x16.eq' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpcmpeqbx ${RIPR}, %xmm1, %xmm0`],
['i8x16.ne' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' , `
vpcmpeqbx ${RIPR}, %xmm1, %xmm0
pcmpeqw %xmm15, %xmm15
pxor %xmm15, %xmm0`],
['i16x8.add' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpaddwx ${RIPR}, %xmm1, %xmm0`],
['i16x8.mul' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpmullwx ${RIPR}, %xmm1, %xmm0`],
['i16x8.add_sat_s' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpaddswx ${RIPR}, %xmm1, %xmm0`],
['i16x8.add_sat_u' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpadduswx ${RIPR}, %xmm1, %xmm0`],
['i16x8.min_s' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpminswx ${RIPR}, %xmm1, %xmm0`],
['i16x8.min_u' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpminuwx ${RIPR}, %xmm1, %xmm0`],
['i16x8.max_s' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpmaxswx ${RIPR}, %xmm1, %xmm0`],
['i16x8.max_u' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpmaxuwx ${RIPR}, %xmm1, %xmm0`],
['i16x8.eq' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' ,
`vpcmpeqwx ${RIPR}, %xmm1, %xmm0`],
['i16x8.ne' , '(v128.const i16x8 1 2 1 2 1 2 1 2)' , `
vpcmpeqwx ${RIPR}, %xmm1, %xmm0
pcmpeqw %xmm15, %xmm15
pxor %xmm15, %xmm0`],
['i32x4.add' , '(v128.const i32x4 1 2 1 2)' ,
`vpadddx ${RIPR}, %xmm1, %xmm0`],
['i32x4.mul' , '(v128.const i32x4 1 2 1 2)' ,
`vpmulldx ${RIPR}, %xmm1, %xmm0`],
['i32x4.min_s' , '(v128.const i32x4 1 2 1 2)' ,
`vpminsdx ${RIPR}, %xmm1, %xmm0`],
['i32x4.min_u' , '(v128.const i32x4 1 2 1 2)' ,
`vpminudx ${RIPR}, %xmm1, %xmm0`],
['i32x4.max_s' , '(v128.const i32x4 1 2 1 2)' ,
`vpmaxsdx ${RIPR}, %xmm1, %xmm0`],
['i32x4.max_u' , '(v128.const i32x4 1 2 1 2)' ,
`vpmaxudx ${RIPR}, %xmm1, %xmm0`],
['i32x4.eq' , '(v128.const i32x4 1 2 1 2)' ,
`vpcmpeqdx ${RIPR}, %xmm1, %xmm0`],
['i32x4.ne' , '(v128.const i32x4 1 2 1 2)' , `
vpcmpeqdx ${RIPR}, %xmm1, %xmm0
pcmpeqw %xmm15, %xmm15
pxor %xmm15, %xmm0`],
['i32x4.dot_i16x8_s' , '(v128.const i32x4 1 2 1 2)' ,
`vpmaddwdx ${RIPR}, %xmm1, %xmm0`],
['i64x2.add' , '(v128.const i64x2 1 2)' ,
`vpaddqx ${RIPR}, %xmm1, %xmm0`],
['v128.and' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpandx ${RIPR}, %xmm1, %xmm0`],
['v128.or' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vporx ${RIPR}, %xmm1, %xmm0`],
['v128.xor' , '(v128.const i8x16 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)' ,
`vpxorx ${RIPR}, %xmm1, %xmm0`]]);
// Shift by constant encodings
codegenTestX64_v128xLITERAL_v128_avxhack(
[['i8x16.shl' , '(i32.const 2)' , `
vpaddb %xmm1, %xmm1, %xmm0
paddb %xmm0, %xmm0`],
['i8x16.shl' , '(i32.const 4)' , `
vpandx ${RIPR}, %xmm1, %xmm0
psllw \\$0 x04, %xmm0`],
['i16x8.shl' , '(i32.const 1)' ,
'vpsllw \\$0x01, %xmm1, %xmm0' ],
['i16x8.shr_s' , '(i32.const 3)' ,
'vpsraw \\$0x03, %xmm1, %xmm0' ],
['i16x8.shr_u' , '(i32.const 2)' ,
'vpsrlw \\$0x02, %xmm1, %xmm0' ],
['i32x4.shl' , '(i32.const 5)' ,
'vpslld \\$0x05, %xmm1, %xmm0' ],
['i32x4.shr_s' , '(i32.const 2)' ,
'vpsrad \\$0x02, %xmm1, %xmm0' ],
['i32x4.shr_u' , '(i32.const 5)' ,
'vpsrld \\$0x05, %xmm1, %xmm0' ],
['i64x2.shr_s' , '(i32.const 7)' , `
vpshufd \\$0 xF5, %xmm1, %xmm15
psrad \\$0 x1F, %xmm15
vpxor %xmm15, %xmm1, %xmm0
psrlq \\$0 x07, %xmm0
pxor %xmm15, %xmm0`]]);
// vpblendvp optimization when bitselect follows comparison.
codegenTestX64_adhoc(
`(module
(func (export "f" ) (param v128) (param v128) (param v128) (param v128) (result v128)
(v128.bitselect (local.get 2 ) (local.get 3 )
(i32x4.eq (local.get 0 ) (local.get 1 )))))`,
'f' , `
pcmpeqd %xmm1, %xmm0
vpblendvb %xmm0, %xmm2, %xmm3, %xmm0`);
Messung V0.5 in Prozent C=95 H=89 G=91
¤ Dauer der Verarbeitung: 0.7 Sekunden
¤
*© Formatika GbR, Deutschland