Commit b772ef4b authored by Dusan Simicic's avatar Dusan Simicic Committed by Commit Bot

MIPS[64]: Implement Shuffle SIMD operations

Add support for S32x4Shuffle, S16x8Shuffle, S8x16Shuffle for mips and
mips64 architectures.

Bug: 
Change-Id: I2c062525ed94edfcb38a53f4bbef02131e313ba3
Reviewed-on: https://chromium-review.googlesource.com/531007
Commit-Queue: Ivica Bogosavljevic <ivica.bogosavljevic@imgtec.com>
Reviewed-by: 's avatarBill Budge <bbudge@chromium.org>
Reviewed-by: 's avatarIvica Bogosavljevic <ivica.bogosavljevic@imgtec.com>
Reviewed-by: 's avatarMircea Trofin <mtrofin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46053}
parent 87d9f757
......@@ -2392,9 +2392,11 @@ void InstructionSelector::VisitS128Select(Node* node) { UNIMPLEMENTED(); }
#endif // !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 && !V8_TARGET_ARCH_X64
// && !V8_TARGET_ARCH_MIPS && !V8_TARGET_ARCH_MIPS64
#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64
#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 && !V8_TARGET_ARCH_MIPS && \
!V8_TARGET_ARCH_MIPS64
void InstructionSelector::VisitS8x16Shuffle(Node* node) { UNIMPLEMENTED(); }
#endif // !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64
#endif // !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 && !V8_TARGET_ARCH_MIPS
// && !V8_TARGET_ARCH_MIPS64
#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 && !V8_TARGET_ARCH_MIPS && \
!V8_TARGET_ARCH_MIPS64
......
......@@ -2281,6 +2281,293 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ st_b(i.InputSimd128Register(2), i.MemoryOperand());
break;
}
case kMipsS32x4InterleaveRight: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
// dst = [5, 1, 4, 0]
__ ilvr_w(dst, src1, src0);
break;
}
case kMipsS32x4InterleaveLeft: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
// dst = [7, 3, 6, 2]
__ ilvl_w(dst, src1, src0);
break;
}
case kMipsS32x4PackEven: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
// dst = [6, 4, 2, 0]
__ pckev_w(dst, src1, src0);
break;
}
case kMipsS32x4PackOdd: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
// dst = [7, 5, 3, 1]
__ pckod_w(dst, src1, src0);
break;
}
case kMipsS32x4InterleaveEven: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
// dst = [6, 2, 4, 0]
__ ilvev_w(dst, src1, src0);
break;
}
case kMipsS32x4InterleaveOdd: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
// dst = [7, 3, 5, 1]
__ ilvod_w(dst, src1, src0);
break;
}
case kMipsS32x4Shuffle: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
int32_t shuffle = i.InputInt32(2);
if (src0.is(src1)) {
// Unary S32x4 shuffles are handled with shf.w instruction
uint32_t i8 = 0;
for (int i = 0; i < 4; i++) {
int lane = shuffle & 0xff;
DCHECK(lane < 4);
i8 |= lane << (2 * i);
shuffle >>= 8;
}
__ shf_w(dst, src0, i8);
} else {
// For binary shuffles use vshf.w instruction
if (dst.is(src0)) {
__ move_v(kSimd128ScratchReg, src0);
src0 = kSimd128ScratchReg;
} else if (dst.is(src1)) {
__ move_v(kSimd128ScratchReg, src1);
src1 = kSimd128ScratchReg;
}
__ li(kScratchReg, i.InputInt32(2));
__ insert_w(dst, 0, kScratchReg);
__ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
__ ilvr_b(dst, kSimd128RegZero, dst);
__ ilvr_h(dst, kSimd128RegZero, dst);
__ vshf_w(dst, src1, src0);
}
break;
}
case kMipsS16x8InterleaveRight: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
// dst = [11, 3, 10, 2, 9, 1, 8, 0]
__ ilvr_h(dst, src1, src0);
break;
}
case kMipsS16x8InterleaveLeft: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
// dst = [15, 7, 14, 6, 13, 5, 12, 4]
__ ilvl_h(dst, src1, src0);
break;
}
case kMipsS16x8PackEven: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
// dst = [14, 12, 10, 8, 6, 4, 2, 0]
__ pckev_h(dst, src1, src0);
break;
}
case kMipsS16x8PackOdd: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
// dst = [15, 13, 11, 9, 7, 5, 3, 1]
__ pckod_h(dst, src1, src0);
break;
}
case kMipsS16x8InterleaveEven: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
// dst = [14, 6, 12, 4, 10, 2, 8, 0]
__ ilvev_h(dst, src1, src0);
break;
}
case kMipsS16x8InterleaveOdd: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
// dst = [15, 7, ... 11, 3, 9, 1]
__ ilvod_h(dst, src1, src0);
break;
}
case kMipsS16x4Reverse: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
// src = [7, 6, 5, 4, 3, 2, 1, 0], dst = [4, 5, 6, 7, 0, 1, 2, 3]
// shf.df imm field: 0 1 2 3 = 00011011 = 0x1B
__ shf_h(i.OutputSimd128Register(), i.InputSimd128Register(0), 0x1B);
break;
}
case kMipsS16x2Reverse: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
// src = [7, 6, 5, 4, 3, 2, 1, 0], dst = [6, 7, 4, 5, 3, 2, 0, 1]
// shf.df imm field: 2 3 0 1 = 10110001 = 0xB1
__ shf_h(i.OutputSimd128Register(), i.InputSimd128Register(0), 0xB1);
break;
}
case kMipsS8x16InterleaveRight: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
// dst = [23, 7, ... 17, 1, 16, 0]
__ ilvr_b(dst, src1, src0);
break;
}
case kMipsS8x16InterleaveLeft: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
// dst = [31, 15, ... 25, 9, 24, 8]
__ ilvl_b(dst, src1, src0);
break;
}
case kMipsS8x16PackEven: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
// dst = [30, 28, ... 6, 4, 2, 0]
__ pckev_b(dst, src1, src0);
break;
}
case kMipsS8x16PackOdd: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
// dst = [31, 29, ... 7, 5, 3, 1]
__ pckod_b(dst, src1, src0);
break;
}
case kMipsS8x16InterleaveEven: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
// dst = [30, 14, ... 18, 2, 16, 0]
__ ilvev_b(dst, src1, src0);
break;
}
case kMipsS8x16InterleaveOdd: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
// dst = [31, 15, ... 19, 3, 17, 1]
__ ilvod_b(dst, src1, src0);
break;
}
case kMipsS8x16Concat: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register();
DCHECK(dst.is(i.InputSimd128Register(0)));
__ sldi_b(dst, i.InputSimd128Register(1), i.InputInt4(2));
break;
}
case kMipsS8x16Shuffle: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
if (dst.is(src0)) {
__ move_v(kSimd128ScratchReg, src0);
src0 = kSimd128ScratchReg;
} else if (dst.is(src1)) {
__ move_v(kSimd128ScratchReg, src1);
src1 = kSimd128ScratchReg;
}
__ li(kScratchReg, i.InputInt32(2));
__ insert_w(dst, 0, kScratchReg);
__ li(kScratchReg, i.InputInt32(3));
__ insert_w(dst, 1, kScratchReg);
__ li(kScratchReg, i.InputInt32(4));
__ insert_w(dst, 2, kScratchReg);
__ li(kScratchReg, i.InputInt32(5));
__ insert_w(dst, 3, kScratchReg);
__ vshf_b(dst, src1, src0);
break;
}
case kMipsS8x8Reverse: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
// src = [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
// dst = [8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7]
// [A B C D] => [B A D C]: shf.w imm: 2 3 0 1 = 10110001 = 0xB1
// C: [7, 6, 5, 4] => A': [4, 5, 6, 7]: shf.b imm: 00011011 = 0x1B
__ shf_w(kSimd128ScratchReg, i.InputSimd128Register(0), 0xB1);
__ shf_b(i.OutputSimd128Register(), kSimd128ScratchReg, 0x1B);
break;
}
case kMipsS8x4Reverse: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
// src = [15, 14, ... 3, 2, 1, 0], dst = [12, 13, 14, 15, ... 0, 1, 2, 3]
// shf.df imm field: 0 1 2 3 = 00011011 = 0x1B
__ shf_b(i.OutputSimd128Register(), i.InputSimd128Register(0), 0x1B);
break;
}
case kMipsS8x2Reverse: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
// src = [15, 14, ... 3, 2, 1, 0], dst = [14, 15, 12, 13, ... 2, 3, 0, 1]
// shf.df imm field: 2 3 0 1 = 10110001 = 0xB1
__ shf_b(i.OutputSimd128Register(), i.InputSimd128Register(0), 0xB1);
break;
}
}
return kSuccess;
} // NOLINT(readability/fn_size)
......
......@@ -233,6 +233,32 @@ namespace compiler {
V(MipsS1x8AllTrue) \
V(MipsS1x16AnyTrue) \
V(MipsS1x16AllTrue) \
V(MipsS32x4InterleaveRight) \
V(MipsS32x4InterleaveLeft) \
V(MipsS32x4PackEven) \
V(MipsS32x4PackOdd) \
V(MipsS32x4InterleaveEven) \
V(MipsS32x4InterleaveOdd) \
V(MipsS32x4Shuffle) \
V(MipsS16x8InterleaveRight) \
V(MipsS16x8InterleaveLeft) \
V(MipsS16x8PackEven) \
V(MipsS16x8PackOdd) \
V(MipsS16x8InterleaveEven) \
V(MipsS16x8InterleaveOdd) \
V(MipsS16x4Reverse) \
V(MipsS16x2Reverse) \
V(MipsS8x16InterleaveRight) \
V(MipsS8x16InterleaveLeft) \
V(MipsS8x16PackEven) \
V(MipsS8x16PackOdd) \
V(MipsS8x16InterleaveEven) \
V(MipsS8x16InterleaveOdd) \
V(MipsS8x16Shuffle) \
V(MipsS8x16Concat) \
V(MipsS8x8Reverse) \
V(MipsS8x4Reverse) \
V(MipsS8x2Reverse) \
V(MipsMsaLd) \
V(MipsMsaSt)
......
......@@ -2088,6 +2088,181 @@ void InstructionSelector::VisitS128Select(Node* node) {
VisitRRRR(this, kMipsS128Select, node);
}
namespace {
// Tries to match 8x16 byte shuffle to equivalent 32x4 word shuffle.
bool TryMatch32x4Shuffle(const uint8_t* shuffle, uint8_t* shuffle32x4) {
static const int kLanes = 4;
static const int kLaneSize = 4;
for (int i = 0; i < kLanes; ++i) {
if (shuffle[i * kLaneSize] % kLaneSize != 0) return false;
for (int j = 1; j < kLaneSize; ++j) {
if (shuffle[i * kLaneSize + j] - shuffle[i * kLaneSize + j - 1] != 1)
return false;
}
shuffle32x4[i] = shuffle[i * kLaneSize] / kLaneSize;
}
return true;
}
// Tries to match byte shuffle to concatenate (sldi) operation.
bool TryMatchConcat(const uint8_t* shuffle, uint8_t mask, uint8_t* offset) {
uint8_t start = shuffle[0];
for (int i = 1; i < kSimd128Size - start; ++i) {
if ((shuffle[i] & mask) != ((shuffle[i - 1] + 1) & mask)) return false;
}
uint8_t wrap = kSimd128Size;
for (int i = kSimd128Size - start; i < kSimd128Size; ++i, ++wrap) {
if ((shuffle[i] & mask) != (wrap & mask)) return false;
}
*offset = start;
return true;
}
struct ShuffleEntry {
uint8_t shuffle[kSimd128Size];
ArchOpcode opcode;
};
static const ShuffleEntry arch_shuffles[] = {
{{0, 1, 2, 3, 16, 17, 18, 19, 4, 5, 6, 7, 20, 21, 22, 23},
kMipsS32x4InterleaveRight},
{{8, 9, 10, 11, 24, 25, 26, 27, 12, 13, 14, 15, 28, 29, 30, 31},
kMipsS32x4InterleaveLeft},
{{0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 24, 25, 26, 27},
kMipsS32x4PackEven},
{{4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31},
kMipsS32x4PackOdd},
{{0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 24, 25, 26, 27},
kMipsS32x4InterleaveEven},
{{4, 5, 6, 7, 20, 21, 22, 23, 12, 13, 14, 15, 28, 29, 30, 31},
kMipsS32x4InterleaveOdd},
{{0, 1, 16, 17, 2, 3, 18, 19, 4, 5, 20, 21, 6, 7, 22, 23},
kMipsS16x8InterleaveRight},
{{8, 9, 24, 25, 10, 11, 26, 27, 12, 13, 28, 29, 14, 15, 30, 31},
kMipsS16x8InterleaveLeft},
{{0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25, 28, 29},
kMipsS16x8PackEven},
{{2, 3, 6, 7, 10, 11, 14, 15, 18, 19, 22, 23, 26, 27, 30, 31},
kMipsS16x8PackOdd},
{{0, 1, 16, 17, 4, 5, 20, 21, 8, 9, 24, 25, 12, 13, 28, 29},
kMipsS16x8InterleaveEven},
{{2, 3, 18, 19, 6, 7, 22, 23, 10, 11, 26, 27, 14, 15, 30, 31},
kMipsS16x8InterleaveOdd},
{{6, 7, 4, 5, 2, 3, 0, 1, 14, 15, 12, 13, 10, 11, 8, 9}, kMipsS16x4Reverse},
{{2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13}, kMipsS16x2Reverse},
{{0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23},
kMipsS8x16InterleaveRight},
{{8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31},
kMipsS8x16InterleaveLeft},
{{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30},
kMipsS8x16PackEven},
{{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31},
kMipsS8x16PackOdd},
{{0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30},
kMipsS8x16InterleaveEven},
{{1, 17, 3, 19, 5, 21, 7, 23, 9, 25, 11, 27, 13, 29, 15, 31},
kMipsS8x16InterleaveOdd},
{{7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8}, kMipsS8x8Reverse},
{{3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12}, kMipsS8x4Reverse},
{{1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14}, kMipsS8x2Reverse}};
bool TryMatchArchShuffle(const uint8_t* shuffle, const ShuffleEntry* table,
size_t num_entries, uint8_t mask, ArchOpcode* opcode) {
for (size_t i = 0; i < num_entries; ++i) {
const ShuffleEntry& entry = table[i];
int j = 0;
for (; j < kSimd128Size; ++j) {
if ((entry.shuffle[j] & mask) != (shuffle[j] & mask)) {
break;
}
}
if (j == kSimd128Size) {
*opcode = entry.opcode;
return true;
}
}
return false;
}
// Canonicalize shuffles to make pattern matching simpler. Returns a mask that
// will ignore the high bit of indices in some cases.
uint8_t CanonicalizeShuffle(InstructionSelector* selector, Node* node) {
static const int kUnaryShuffleMask = kSimd128Size - 1;
const uint8_t* shuffle = OpParameter<uint8_t*>(node);
uint8_t mask = 0xff;
// If shuffle is unary, set 'mask' to ignore the high bit of the indices.
// Replace any unused source with the other.
if (selector->GetVirtualRegister(node->InputAt(0)) ==
selector->GetVirtualRegister(node->InputAt(1))) {
// unary, src0 == src1.
mask = kUnaryShuffleMask;
} else {
bool src0_is_used = false;
bool src1_is_used = false;
for (int i = 0; i < kSimd128Size; i++) {
if (shuffle[i] < kSimd128Size) {
src0_is_used = true;
} else {
src1_is_used = true;
}
}
if (src0_is_used && !src1_is_used) {
node->ReplaceInput(1, node->InputAt(0));
mask = kUnaryShuffleMask;
} else if (src1_is_used && !src0_is_used) {
node->ReplaceInput(0, node->InputAt(1));
mask = kUnaryShuffleMask;
}
}
return mask;
}
int32_t Pack4Lanes(const uint8_t* shuffle, uint8_t mask) {
int32_t result = 0;
for (int i = 3; i >= 0; --i) {
result <<= 8;
result |= shuffle[i] & mask;
}
return result;
}
} // namespace
void InstructionSelector::VisitS8x16Shuffle(Node* node) {
const uint8_t* shuffle = OpParameter<uint8_t*>(node);
uint8_t mask = CanonicalizeShuffle(this, node);
uint8_t shuffle32x4[4];
ArchOpcode opcode;
if (TryMatchArchShuffle(shuffle, arch_shuffles, arraysize(arch_shuffles),
mask, &opcode)) {
VisitRRR(this, opcode, node);
return;
}
uint8_t offset;
MipsOperandGenerator g(this);
if (TryMatchConcat(shuffle, mask, &offset)) {
Emit(kMipsS8x16Concat, g.DefineSameAsFirst(node),
g.UseRegister(node->InputAt(1)), g.UseRegister(node->InputAt(0)),
g.UseImmediate(offset));
return;
}
if (TryMatch32x4Shuffle(shuffle, shuffle32x4)) {
Emit(kMipsS32x4Shuffle, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)),
g.UseImmediate(Pack4Lanes(shuffle32x4, mask)));
return;
}
Emit(kMipsS8x16Shuffle, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)),
g.UseImmediate(Pack4Lanes(shuffle, mask)),
g.UseImmediate(Pack4Lanes(shuffle + 4, mask)),
g.UseImmediate(Pack4Lanes(shuffle + 8, mask)),
g.UseImmediate(Pack4Lanes(shuffle + 12, mask)));
}
// static
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
......
......@@ -2600,6 +2600,293 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ st_b(i.InputSimd128Register(2), i.MemoryOperand());
break;
}
case kMips64S32x4InterleaveRight: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
// dst = [5, 1, 4, 0]
__ ilvr_w(dst, src1, src0);
break;
}
case kMips64S32x4InterleaveLeft: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
// dst = [7, 3, 6, 2]
__ ilvl_w(dst, src1, src0);
break;
}
case kMips64S32x4PackEven: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
// dst = [6, 4, 2, 0]
__ pckev_w(dst, src1, src0);
break;
}
case kMips64S32x4PackOdd: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
// dst = [7, 5, 3, 1]
__ pckod_w(dst, src1, src0);
break;
}
case kMips64S32x4InterleaveEven: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
// dst = [6, 2, 4, 0]
__ ilvev_w(dst, src1, src0);
break;
}
case kMips64S32x4InterleaveOdd: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [7, 6, 5, 4], src0 = [3, 2, 1, 0]
// dst = [7, 3, 5, 1]
__ ilvod_w(dst, src1, src0);
break;
}
case kMips64S32x4Shuffle: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
int32_t shuffle = i.InputInt32(2);
if (src0.is(src1)) {
// Unary S32x4 shuffles are handled with shf.w instruction
uint32_t i8 = 0;
for (int i = 0; i < 4; i++) {
int lane = shuffle & 0xff;
DCHECK(lane < 4);
i8 |= lane << (2 * i);
shuffle >>= 8;
}
__ shf_w(dst, src0, i8);
} else {
// For binary shuffles use vshf.w instruction
if (dst.is(src0)) {
__ move_v(kSimd128ScratchReg, src0);
src0 = kSimd128ScratchReg;
} else if (dst.is(src1)) {
__ move_v(kSimd128ScratchReg, src1);
src1 = kSimd128ScratchReg;
}
__ li(kScratchReg, i.InputInt32(2));
__ insert_w(dst, 0, kScratchReg);
__ xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero);
__ ilvr_b(dst, kSimd128RegZero, dst);
__ ilvr_h(dst, kSimd128RegZero, dst);
__ vshf_w(dst, src1, src0);
}
break;
}
case kMips64S16x8InterleaveRight: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
// dst = [11, 3, 10, 2, 9, 1, 8, 0]
__ ilvr_h(dst, src1, src0);
break;
}
case kMips64S16x8InterleaveLeft: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
// dst = [15, 7, 14, 6, 13, 5, 12, 4]
__ ilvl_h(dst, src1, src0);
break;
}
case kMips64S16x8PackEven: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
// dst = [14, 12, 10, 8, 6, 4, 2, 0]
__ pckev_h(dst, src1, src0);
break;
}
case kMips64S16x8PackOdd: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
// dst = [15, 13, 11, 9, 7, 5, 3, 1]
__ pckod_h(dst, src1, src0);
break;
}
case kMips64S16x8InterleaveEven: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
// dst = [14, 6, 12, 4, 10, 2, 8, 0]
__ ilvev_h(dst, src1, src0);
break;
}
case kMips64S16x8InterleaveOdd: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [15, ... 11, 10, 9, 8], src0 = [7, ... 3, 2, 1, 0]
// dst = [15, 7, ... 11, 3, 9, 1]
__ ilvod_h(dst, src1, src0);
break;
}
case kMips64S16x4Reverse: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
// src = [7, 6, 5, 4, 3, 2, 1, 0], dst = [4, 5, 6, 7, 0, 1, 2, 3]
// shf.df imm field: 0 1 2 3 = 00011011 = 0x1B
__ shf_h(i.OutputSimd128Register(), i.InputSimd128Register(0), 0x1B);
break;
}
case kMips64S16x2Reverse: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
// src = [7, 6, 5, 4, 3, 2, 1, 0], dst = [6, 7, 4, 5, 3, 2, 0, 1]
// shf.df imm field: 2 3 0 1 = 10110001 = 0xB1
__ shf_h(i.OutputSimd128Register(), i.InputSimd128Register(0), 0xB1);
break;
}
case kMips64S8x16InterleaveRight: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
// dst = [23, 7, ... 17, 1, 16, 0]
__ ilvr_b(dst, src1, src0);
break;
}
case kMips64S8x16InterleaveLeft: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
// dst = [31, 15, ... 25, 9, 24, 8]
__ ilvl_b(dst, src1, src0);
break;
}
case kMips64S8x16PackEven: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
// dst = [30, 28, ... 6, 4, 2, 0]
__ pckev_b(dst, src1, src0);
break;
}
case kMips64S8x16PackOdd: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
// dst = [31, 29, ... 7, 5, 3, 1]
__ pckod_b(dst, src1, src0);
break;
}
case kMips64S8x16InterleaveEven: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
// dst = [30, 14, ... 18, 2, 16, 0]
__ ilvev_b(dst, src1, src0);
break;
}
case kMips64S8x16InterleaveOdd: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
// src1 = [31, ... 19, 18, 17, 16], src0 = [15, ... 3, 2, 1, 0]
// dst = [31, 15, ... 19, 3, 17, 1]
__ ilvod_b(dst, src1, src0);
break;
}
case kMips64S8x16Concat: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register();
DCHECK(dst.is(i.InputSimd128Register(0)));
__ sldi_b(dst, i.InputSimd128Register(1), i.InputInt4(2));
break;
}
case kMips64S8x16Shuffle: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register(),
src0 = i.InputSimd128Register(0),
src1 = i.InputSimd128Register(1);
if (dst.is(src0)) {
__ move_v(kSimd128ScratchReg, src0);
src0 = kSimd128ScratchReg;
} else if (dst.is(src1)) {
__ move_v(kSimd128ScratchReg, src1);
src1 = kSimd128ScratchReg;
}
int64_t control_low =
static_cast<int64_t>(i.InputInt32(3)) << 32 | i.InputInt32(2);
int64_t control_hi =
static_cast<int64_t>(i.InputInt32(5)) << 32 | i.InputInt32(4);
__ li(kScratchReg, control_low);
__ insert_d(dst, 0, kScratchReg);
__ li(kScratchReg, control_hi);
__ insert_d(dst, 1, kScratchReg);
__ vshf_b(dst, src1, src0);
break;
}
case kMips64S8x8Reverse: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
// src = [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
// dst = [8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7]
// [A B C D] => [B A D C]: shf.w imm: 2 3 0 1 = 10110001 = 0xB1
// C: [7, 6, 5, 4] => A': [4, 5, 6, 7]: shf.b imm: 00011011 = 0x1B
__ shf_w(kSimd128ScratchReg, i.InputSimd128Register(0), 0xB1);
__ shf_b(i.OutputSimd128Register(), kSimd128ScratchReg, 0x1B);
break;
}
case kMips64S8x4Reverse: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
// src = [15, 14, ... 3, 2, 1, 0], dst = [12, 13, 14, 15, ... 0, 1, 2, 3]
// shf.df imm field: 0 1 2 3 = 00011011 = 0x1B
__ shf_b(i.OutputSimd128Register(), i.InputSimd128Register(0), 0x1B);
break;
}
case kMips64S8x2Reverse: {
CpuFeatureScope msa_scope(masm(), MIPS_SIMD);
// src = [15, 14, ... 3, 2, 1, 0], dst = [14, 15, 12, 13, ... 2, 3, 0, 1]
// shf.df imm field: 2 3 0 1 = 10110001 = 0xB1
__ shf_b(i.OutputSimd128Register(), i.InputSimd128Register(0), 0xB1);
break;
}
}
return kSuccess;
} // NOLINT(readability/fn_size)
......
......@@ -267,6 +267,32 @@ namespace compiler {
V(Mips64S1x8AllTrue) \
V(Mips64S1x16AnyTrue) \
V(Mips64S1x16AllTrue) \
V(Mips64S32x4InterleaveRight) \
V(Mips64S32x4InterleaveLeft) \
V(Mips64S32x4PackEven) \
V(Mips64S32x4PackOdd) \
V(Mips64S32x4InterleaveEven) \
V(Mips64S32x4InterleaveOdd) \
V(Mips64S32x4Shuffle) \
V(Mips64S16x8InterleaveRight) \
V(Mips64S16x8InterleaveLeft) \
V(Mips64S16x8PackEven) \
V(Mips64S16x8PackOdd) \
V(Mips64S16x8InterleaveEven) \
V(Mips64S16x8InterleaveOdd) \
V(Mips64S16x4Reverse) \
V(Mips64S16x2Reverse) \
V(Mips64S8x16InterleaveRight) \
V(Mips64S8x16InterleaveLeft) \
V(Mips64S8x16PackEven) \
V(Mips64S8x16PackOdd) \
V(Mips64S8x16InterleaveEven) \
V(Mips64S8x16InterleaveOdd) \
V(Mips64S8x16Shuffle) \
V(Mips64S8x16Concat) \
V(Mips64S8x8Reverse) \
V(Mips64S8x4Reverse) \
V(Mips64S8x2Reverse) \
V(Mips64MsaLd) \
V(Mips64MsaSt)
......
......@@ -2837,6 +2837,186 @@ void InstructionSelector::VisitS128Select(Node* node) {
VisitRRRR(this, kMips64S128Select, node);
}
namespace {
// Tries to match 8x16 byte shuffle to equivalent 32x4 word shuffle.
bool TryMatch32x4Shuffle(const uint8_t* shuffle, uint8_t* shuffle32x4) {
static const int kLanes = 4;
static const int kLaneSize = 4;
for (int i = 0; i < kLanes; ++i) {
if (shuffle[i * kLaneSize] % kLaneSize != 0) return false;
for (int j = 1; j < kLaneSize; ++j) {
if (shuffle[i * kLaneSize + j] - shuffle[i * kLaneSize + j - 1] != 1)
return false;
}
shuffle32x4[i] = shuffle[i * kLaneSize] / kLaneSize;
}
return true;
}
// Tries to match byte shuffle to concatenate (sldi) operation.
bool TryMatchConcat(const uint8_t* shuffle, uint8_t mask, uint8_t* offset) {
uint8_t start = shuffle[0];
for (int i = 1; i < kSimd128Size - start; ++i) {
if ((shuffle[i] & mask) != ((shuffle[i - 1] + 1) & mask)) return false;
}
uint8_t wrap = kSimd128Size;
for (int i = kSimd128Size - start; i < kSimd128Size; ++i, ++wrap) {
if ((shuffle[i] & mask) != (wrap & mask)) return false;
}
*offset = start;
return true;
}
struct ShuffleEntry {
uint8_t shuffle[kSimd128Size];
ArchOpcode opcode;
};
static const ShuffleEntry arch_shuffles[] = {
{{0, 1, 2, 3, 16, 17, 18, 19, 4, 5, 6, 7, 20, 21, 22, 23},
kMips64S32x4InterleaveRight},
{{8, 9, 10, 11, 24, 25, 26, 27, 12, 13, 14, 15, 28, 29, 30, 31},
kMips64S32x4InterleaveLeft},
{{0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 24, 25, 26, 27},
kMips64S32x4PackEven},
{{4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31},
kMips64S32x4PackOdd},
{{0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 24, 25, 26, 27},
kMips64S32x4InterleaveEven},
{{4, 5, 6, 7, 20, 21, 22, 23, 12, 13, 14, 15, 28, 29, 30, 31},
kMips64S32x4InterleaveOdd},
{{0, 1, 16, 17, 2, 3, 18, 19, 4, 5, 20, 21, 6, 7, 22, 23},
kMips64S16x8InterleaveRight},
{{8, 9, 24, 25, 10, 11, 26, 27, 12, 13, 28, 29, 14, 15, 30, 31},
kMips64S16x8InterleaveLeft},
{{0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25, 28, 29},
kMips64S16x8PackEven},
{{2, 3, 6, 7, 10, 11, 14, 15, 18, 19, 22, 23, 26, 27, 30, 31},
kMips64S16x8PackOdd},
{{0, 1, 16, 17, 4, 5, 20, 21, 8, 9, 24, 25, 12, 13, 28, 29},
kMips64S16x8InterleaveEven},
{{2, 3, 18, 19, 6, 7, 22, 23, 10, 11, 26, 27, 14, 15, 30, 31},
kMips64S16x8InterleaveOdd},
{{6, 7, 4, 5, 2, 3, 0, 1, 14, 15, 12, 13, 10, 11, 8, 9},
kMips64S16x4Reverse},
{{2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13},
kMips64S16x2Reverse},
{{0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23},
kMips64S8x16InterleaveRight},
{{8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31},
kMips64S8x16InterleaveLeft},
{{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30},
kMips64S8x16PackEven},
{{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31},
kMips64S8x16PackOdd},
{{0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30},
kMips64S8x16InterleaveEven},
{{1, 17, 3, 19, 5, 21, 7, 23, 9, 25, 11, 27, 13, 29, 15, 31},
kMips64S8x16InterleaveOdd},
{{7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8},
kMips64S8x8Reverse},
{{3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12},
kMips64S8x4Reverse},
{{1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14},
kMips64S8x2Reverse}};
bool TryMatchArchShuffle(const uint8_t* shuffle, const ShuffleEntry* table,
size_t num_entries, uint8_t mask, ArchOpcode* opcode) {
for (size_t i = 0; i < num_entries; ++i) {
const ShuffleEntry& entry = table[i];
int j = 0;
for (; j < kSimd128Size; ++j) {
if ((entry.shuffle[j] & mask) != (shuffle[j] & mask)) {
break;
}
}
if (j == kSimd128Size) {
*opcode = entry.opcode;
return true;
}
}
return false;
}
// Canonicalize shuffles to make pattern matching simpler. Returns a mask that
// will ignore the high bit of indices in some cases.
uint8_t CanonicalizeShuffle(InstructionSelector* selector, Node* node) {
static const int kUnaryShuffleMask = kSimd128Size - 1;
const uint8_t* shuffle = OpParameter<uint8_t*>(node);
uint8_t mask = 0xff;
// If shuffle is unary, set 'mask' to ignore the high bit of the indices.
// Replace any unused source with the other.
if (selector->GetVirtualRegister(node->InputAt(0)) ==
selector->GetVirtualRegister(node->InputAt(1))) {
// unary, src0 == src1.
mask = kUnaryShuffleMask;
} else {
bool src0_is_used = false;
bool src1_is_used = false;
for (int i = 0; i < kSimd128Size; i++) {
if (shuffle[i] < kSimd128Size) {
src0_is_used = true;
} else {
src1_is_used = true;
}
}
if (src0_is_used && !src1_is_used) {
node->ReplaceInput(1, node->InputAt(0));
mask = kUnaryShuffleMask;
} else if (src1_is_used && !src0_is_used) {
node->ReplaceInput(0, node->InputAt(1));
mask = kUnaryShuffleMask;
}
}
return mask;
}
int32_t Pack4Lanes(const uint8_t* shuffle, uint8_t mask) {
int32_t result = 0;
for (int i = 3; i >= 0; --i) {
result <<= 8;
result |= shuffle[i] & mask;
}
return result;
}
} // namespace
void InstructionSelector::VisitS8x16Shuffle(Node* node) {
const uint8_t* shuffle = OpParameter<uint8_t*>(node);
uint8_t mask = CanonicalizeShuffle(this, node);
uint8_t shuffle32x4[4];
ArchOpcode opcode;
if (TryMatchArchShuffle(shuffle, arch_shuffles, arraysize(arch_shuffles),
mask, &opcode)) {
VisitRRR(this, opcode, node);
return;
}
uint8_t offset;
Mips64OperandGenerator g(this);
if (TryMatchConcat(shuffle, mask, &offset)) {
Emit(kMips64S8x16Concat, g.DefineSameAsFirst(node),
g.UseRegister(node->InputAt(1)), g.UseRegister(node->InputAt(0)),
g.UseImmediate(offset));
return;
}
if (TryMatch32x4Shuffle(shuffle, shuffle32x4)) {
Emit(kMips64S32x4Shuffle, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)),
g.UseImmediate(Pack4Lanes(shuffle32x4, mask)));
return;
}
Emit(kMips64S8x16Shuffle, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)),
g.UseImmediate(Pack4Lanes(shuffle, mask)),
g.UseImmediate(Pack4Lanes(shuffle + 4, mask)),
g.UseImmediate(Pack4Lanes(shuffle + 8, mask)),
g.UseImmediate(Pack4Lanes(shuffle + 12, mask)));
}
// static
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
......
......@@ -1574,7 +1574,8 @@ WASM_SIMD_NON_CANONICAL_SELECT_TEST(8x16)
#endif // V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_X64 ||
// V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_X64
#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_X64 || \
V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
// Test binary ops with two lane test patterns, all lanes distinct.
template <typename T>
void RunBinaryLaneOpTest(
......@@ -1607,7 +1608,10 @@ void RunBinaryLaneOpTest(
CHECK_EQ(src0[i], expected[i]);
}
}
#endif // V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_MIPS ||
// V8_TARGET_ARCH_MIPS64
#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_X64
WASM_SIMD_TEST(I32x4AddHoriz) {
RunBinaryLaneOpTest<int32_t>(kExprI32x4AddHoriz, {{1, 5, 9, 13}});
}
......@@ -1622,7 +1626,9 @@ WASM_SIMD_TEST(I16x8AddHoriz) {
WASM_SIMD_TEST(F32x4AddHoriz) {
RunBinaryLaneOpTest<float>(kExprF32x4AddHoriz, {{1.0f, 5.0f, 9.0f, 13.0f}});
}
#endif // V8_TARGET_ARCH_ARM
#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
// Test some regular shuffles that may have special handling on some targets.
// Test a normal and unary versions (where second operand isn't used).
WASM_SIMD_TEST(S32x4ZipLeft) {
......@@ -1851,7 +1857,8 @@ WASM_SIMD_TEST(S8x16Concat) {
RunBinaryLaneOpTest(kExprS8x16Shuffle, expected);
}
}
#endif // V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64
#endif // V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_MIPS ||
// V8_TARGET_ARCH_MIPS64
#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_MIPS || \
V8_TARGET_ARCH_MIPS64
......
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