Commit d950fc47 authored by Bill Budge's avatar Bill Budge Committed by Commit Bot

[wasm simd] Fuzz test the shuffle opcode

- Reorganizes shuffle tests into tabular form.
- Adds a test that composes random numbers of random shuffles to
  make new shuffles.
- Adds a test that generates functions to compute a complex expression
  consisting of shuffles, and compares interpreter results to compiled
  code results.
- Fixes a problem with temp register exhaustion on ARM 32-bit.
- Matches identity shuffles (returning first or second operand
  unchanged) and uses EmitIdentity() for these.

Bug: v8:6020
Change-Id: Ie41c14fee52a7406b1d32e731e050096400e12f5
Reviewed-on: https://chromium-review.googlesource.com/1119567
Commit-Queue: Bill Budge <bbudge@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54446}
parent 2332e4e0
...@@ -2331,18 +2331,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( ...@@ -2331,18 +2331,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
Simd128Register dst = i.OutputSimd128Register(), Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0), src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1); src1 = i.InputSimd128Register(1);
UseScratchRegisterScope temps(tasm()); DCHECK_NE(dst, src0);
// Check for in-place shuffles. DCHECK_NE(dst, src1);
// If dst == src0 == src1, then the shuffle is unary and we only use src0.
if (dst == src0) {
Simd128Register scratch = temps.AcquireQ();
__ vmov(scratch, src0);
src0 = scratch;
} else if (dst == src1) {
Simd128Register scratch = temps.AcquireQ();
__ vmov(scratch, src1);
src1 = scratch;
}
// Perform shuffle as a vmov per lane. // Perform shuffle as a vmov per lane.
int dst_code = dst.code() * 4; int dst_code = dst.code() * 4;
int src0_code = src0.code() * 4; int src0_code = src0.code() * 4;
......
...@@ -2491,9 +2491,15 @@ void InstructionSelector::VisitS8x16Shuffle(Node* node) { ...@@ -2491,9 +2491,15 @@ void InstructionSelector::VisitS8x16Shuffle(Node* node) {
DCHECK_GT(4, index); DCHECK_GT(4, index);
Emit(kArmS128Dup, g.DefineAsRegister(node), g.UseRegister(input0), Emit(kArmS128Dup, g.DefineAsRegister(node), g.UseRegister(input0),
g.UseImmediate(Neon32), g.UseImmediate(index % 4)); g.UseImmediate(Neon32), g.UseImmediate(index % 4));
} else if (TryMatchIdentity(shuffle)) {
EmitIdentity(node);
} else { } else {
Emit(kArmS32x4Shuffle, g.DefineAsRegister(node), g.UseRegister(input0), // 32x4 shuffles are implemented as s-register moves. To simplify these,
g.UseRegister(input1), g.UseImmediate(Pack4Lanes(shuffle32x4))); // make sure the destination is distinct from both sources.
InstructionOperand src0 = g.UseUniqueRegister(input0);
InstructionOperand src1 = is_swizzle ? src0 : g.UseUniqueRegister(input1);
Emit(kArmS32x4Shuffle, g.DefineAsRegister(node), src0, src1,
g.UseImmediate(Pack4Lanes(shuffle32x4)));
} }
return; return;
} }
......
...@@ -3181,6 +3181,8 @@ void InstructionSelector::VisitS8x16Shuffle(Node* node) { ...@@ -3181,6 +3181,8 @@ void InstructionSelector::VisitS8x16Shuffle(Node* node) {
DCHECK_GT(4, index); DCHECK_GT(4, index);
Emit(kArm64S128Dup, g.DefineAsRegister(node), g.UseRegister(input0), Emit(kArm64S128Dup, g.DefineAsRegister(node), g.UseRegister(input0),
g.UseImmediate(4), g.UseImmediate(index % 4)); g.UseImmediate(4), g.UseImmediate(index % 4));
} else if (TryMatchIdentity(shuffle)) {
EmitIdentity(node);
} else { } else {
Emit(kArm64S32x4Shuffle, g.DefineAsRegister(node), g.UseRegister(input0), Emit(kArm64S32x4Shuffle, g.DefineAsRegister(node), g.UseRegister(input0),
g.UseRegister(input1), g.UseImmediate(Pack4Lanes(shuffle32x4))); g.UseRegister(input1), g.UseImmediate(Pack4Lanes(shuffle32x4)));
......
...@@ -2212,7 +2212,6 @@ bool TryMatchArchShuffle(const uint8_t* shuffle, const ShuffleEntry* table, ...@@ -2212,7 +2212,6 @@ bool TryMatchArchShuffle(const uint8_t* shuffle, const ShuffleEntry* table,
} // namespace } // namespace
// TODO(bbudge) Make sure identity shuffle emits no instructions.
void InstructionSelector::VisitS8x16Shuffle(Node* node) { void InstructionSelector::VisitS8x16Shuffle(Node* node) {
uint8_t shuffle[kSimd128Size]; uint8_t shuffle[kSimd128Size];
bool is_swizzle; bool is_swizzle;
...@@ -2259,11 +2258,17 @@ void InstructionSelector::VisitS8x16Shuffle(Node* node) { ...@@ -2259,11 +2258,17 @@ void InstructionSelector::VisitS8x16Shuffle(Node* node) {
} else if (TryMatch32x4Shuffle(shuffle, shuffle32x4)) { } else if (TryMatch32x4Shuffle(shuffle, shuffle32x4)) {
uint8_t shuffle_mask = PackShuffle4(shuffle32x4); uint8_t shuffle_mask = PackShuffle4(shuffle32x4);
if (is_swizzle) { if (is_swizzle) {
if (TryMatchIdentity(shuffle)) {
// Bypass normal shuffle code generation in this case.
EmitIdentity(node);
return;
} else {
// pshufd takes a single imm8 shuffle mask. // pshufd takes a single imm8 shuffle mask.
opcode = kIA32S32x4Swizzle; opcode = kIA32S32x4Swizzle;
no_same_as_first = true; no_same_as_first = true;
src0_needs_reg = false; src0_needs_reg = false;
imms[imm_count++] = shuffle_mask; imms[imm_count++] = shuffle_mask;
}
} else { } else {
// 2 operand shuffle // 2 operand shuffle
// A blend is more efficient than a general 32x4 shuffle; try it first. // A blend is more efficient than a general 32x4 shuffle; try it first.
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment