Commit 11f88ef5 authored by bbudge's avatar bbudge Committed by Commit bot

[Turbofan] Add more non-arithmetic SIMD operations.

- Renames select, swizzle, and shuffle to be consistent with the S128 and
  existing S32x4 ops, and reflect that these aren't arithmetic.
  e.g. I16x8Swizzle -> S16x8Swizzle.
- Implements S16x8 and S8x16 Select operations and tests.
- Implements S128And, Or, Xor, Not operations and tests.
- Implements Swizzle for 32x4 formats.
- Refactors test macros that generate SIMD code.

TEST=cctest/test-run-wasm-simd/*

LOG=N
BUG=v8:4124

Review-Url: https://codereview.chromium.org/2683713003
Cr-Commit-Position: refs/heads/master@{#43168}
parent 673bbcbb
......@@ -1664,15 +1664,6 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
i.InputSimd128Register(1));
break;
}
case kArmSimd32x4Select: {
// Select is a ternary op, so we need to move one input into the
// destination. Use vtst to canonicalize the 'boolean' input #0.
__ vtst(Neon32, i.OutputSimd128Register(), i.InputSimd128Register(0),
i.InputSimd128Register(0));
__ vbsl(i.OutputSimd128Register(), i.InputSimd128Register(1),
i.InputSimd128Register(2));
break;
}
case kArmInt16x8Splat: {
__ vdup(Neon16, i.OutputSimd128Register(), i.InputRegister(0));
break;
......@@ -1916,6 +1907,49 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
i.InputSimd128Register(1));
break;
}
case kArmSimd128And: {
__ vand(i.OutputSimd128Register(), i.InputSimd128Register(0),
i.InputSimd128Register(1));
break;
}
case kArmSimd128Or: {
__ vorr(i.OutputSimd128Register(), i.InputSimd128Register(0),
i.InputSimd128Register(1));
break;
}
case kArmSimd128Xor: {
__ veor(i.OutputSimd128Register(), i.InputSimd128Register(0),
i.InputSimd128Register(1));
break;
}
case kArmSimd128Not: {
__ vmvn(i.OutputSimd128Register(), i.InputSimd128Register(0));
break;
}
case kArmSimd32x4Select: {
// Canonicalize input 0 lanes to all 0's or all 1's and move to dest.
__ vtst(Neon32, i.OutputSimd128Register(), i.InputSimd128Register(0),
i.InputSimd128Register(0));
__ vbsl(i.OutputSimd128Register(), i.InputSimd128Register(1),
i.InputSimd128Register(2));
break;
}
case kArmSimd16x8Select: {
// Canonicalize input 0 lanes to all 0's or all 1's and move to dest.
__ vtst(Neon16, i.OutputSimd128Register(), i.InputSimd128Register(0),
i.InputSimd128Register(0));
__ vbsl(i.OutputSimd128Register(), i.InputSimd128Register(1),
i.InputSimd128Register(2));
break;
}
case kArmSimd8x16Select: {
// Canonicalize input 0 lanes to all 0's or all 1's and move to dest.
__ vtst(Neon8, i.OutputSimd128Register(), i.InputSimd128Register(0),
i.InputSimd128Register(0));
__ vbsl(i.OutputSimd128Register(), i.InputSimd128Register(1),
i.InputSimd128Register(2));
break;
}
case kCheckedLoadInt8:
ASSEMBLE_CHECKED_LOAD_INTEGER(ldrsb);
break;
......
......@@ -153,7 +153,6 @@ namespace compiler {
V(ArmUint32x4Max) \
V(ArmUint32x4GreaterThan) \
V(ArmUint32x4GreaterThanOrEqual) \
V(ArmSimd32x4Select) \
V(ArmInt16x8Splat) \
V(ArmInt16x8ExtractLane) \
V(ArmInt16x8ReplaceLane) \
......@@ -201,7 +200,14 @@ namespace compiler {
V(ArmUint8x16Min) \
V(ArmUint8x16Max) \
V(ArmUint8x16GreaterThan) \
V(ArmUint8x16GreaterThanOrEqual)
V(ArmUint8x16GreaterThanOrEqual) \
V(ArmSimd128And) \
V(ArmSimd128Or) \
V(ArmSimd128Xor) \
V(ArmSimd128Not) \
V(ArmSimd32x4Select) \
V(ArmSimd16x8Select) \
V(ArmSimd8x16Select)
// Addressing modes represent the "shape" of inputs to an instruction.
// Many instructions support multiple addressing modes. Addressing modes
......
......@@ -141,7 +141,6 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kArmUint32x4Max:
case kArmUint32x4GreaterThan:
case kArmUint32x4GreaterThanOrEqual:
case kArmSimd32x4Select:
case kArmInt16x8Splat:
case kArmInt16x8ExtractLane:
case kArmInt16x8ReplaceLane:
......@@ -190,6 +189,13 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kArmUint8x16Max:
case kArmUint8x16GreaterThan:
case kArmUint8x16GreaterThanOrEqual:
case kArmSimd128And:
case kArmSimd128Or:
case kArmSimd128Xor:
case kArmSimd128Not:
case kArmSimd32x4Select:
case kArmSimd16x8Select:
case kArmSimd8x16Select:
return kNoOpcodeFlags;
case kArmVldrF32:
......
......@@ -92,6 +92,13 @@ void VisitRRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
g.UseRegister(node->InputAt(1)));
}
void VisitRRRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
ArmOperandGenerator g(selector);
selector->Emit(
opcode, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
g.UseRegister(node->InputAt(1)), g.UseRegister(node->InputAt(2)));
}
void VisitRRI(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
ArmOperandGenerator g(selector);
int32_t imm = OpParameter<int32_t>(node);
......@@ -2167,6 +2174,11 @@ void InstructionSelector::VisitAtomicStore(Node* node) {
V(Int16x8) \
V(Int8x16)
#define SIMD_FORMAT_LIST(V) \
V(32x4) \
V(16x8) \
V(8x16)
#define SIMD_UNOP_LIST(V) \
V(Float32x4FromInt32x4) \
V(Float32x4FromUint32x4) \
......@@ -2176,7 +2188,8 @@ void InstructionSelector::VisitAtomicStore(Node* node) {
V(Uint32x4FromFloat32x4) \
V(Int32x4Neg) \
V(Int16x8Neg) \
V(Int8x16Neg)
V(Int8x16Neg) \
V(Simd128Not)
#define SIMD_BINOP_LIST(V) \
V(Float32x4Add) \
......@@ -2229,7 +2242,10 @@ void InstructionSelector::VisitAtomicStore(Node* node) {
V(Uint8x16Min) \
V(Uint8x16Max) \
V(Uint8x16GreaterThan) \
V(Uint8x16GreaterThanOrEqual)
V(Uint8x16GreaterThanOrEqual) \
V(Simd128And) \
V(Simd128Or) \
V(Simd128Xor)
#define SIMD_SHIFT_OP_LIST(V) \
V(Int32x4ShiftLeftByScalar) \
......@@ -2284,12 +2300,12 @@ SIMD_BINOP_LIST(SIMD_VISIT_BINOP)
SIMD_SHIFT_OP_LIST(SIMD_VISIT_SHIFT_OP)
#undef SIMD_VISIT_SHIFT_OP
void InstructionSelector::VisitSimd32x4Select(Node* node) {
ArmOperandGenerator g(this);
Emit(kArmSimd32x4Select, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)),
g.UseRegister(node->InputAt(2)));
}
#define SIMD_VISIT_SELECT_OP(format) \
void InstructionSelector::VisitSimd##format##Select(Node* node) { \
VisitRRRR(this, kArmSimd##format##Select, node); \
}
SIMD_FORMAT_LIST(SIMD_VISIT_SELECT_OP)
#undef SIMD_VISIT_SELECT_OP
// static
MachineOperatorBuilder::Flags
......
......@@ -206,11 +206,11 @@ typedef int32_t InstructionCode;
// for code generation. We encode the instruction, addressing mode, and flags
// continuation into a single InstructionCode which is stored as part of
// the instruction.
typedef BitField<ArchOpcode, 0, 8> ArchOpcodeField;
typedef BitField<AddressingMode, 8, 5> AddressingModeField;
typedef BitField<FlagsMode, 13, 3> FlagsModeField;
typedef BitField<FlagsCondition, 16, 5> FlagsConditionField;
typedef BitField<int, 21, 11> MiscField;
typedef BitField<ArchOpcode, 0, 9> ArchOpcodeField;
typedef BitField<AddressingMode, 9, 5> AddressingModeField;
typedef BitField<FlagsMode, 14, 3> FlagsModeField;
typedef BitField<FlagsCondition, 17, 5> FlagsConditionField;
typedef BitField<int, 22, 10> MiscField;
} // namespace compiler
} // namespace internal
......
......@@ -1522,8 +1522,6 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsSimd128(node), VisitUint32x4GreaterThan(node);
case IrOpcode::kUint32x4GreaterThanOrEqual:
return MarkAsSimd128(node), VisitUint32x4GreaterThanOrEqual(node);
case IrOpcode::kSimd32x4Select:
return MarkAsSimd128(node), VisitSimd32x4Select(node);
case IrOpcode::kCreateInt16x8:
return MarkAsSimd128(node), VisitCreateInt16x8(node);
case IrOpcode::kInt16x8ExtractLane:
......@@ -1620,6 +1618,20 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsSimd128(node), VisitUint8x16GreaterThan(node);
case IrOpcode::kUint8x16GreaterThanOrEqual:
return MarkAsSimd128(node), VisitUint16x8GreaterThanOrEqual(node);
case IrOpcode::kSimd128And:
return MarkAsSimd128(node), VisitSimd128And(node);
case IrOpcode::kSimd128Or:
return MarkAsSimd128(node), VisitSimd128Or(node);
case IrOpcode::kSimd128Xor:
return MarkAsSimd128(node), VisitSimd128Xor(node);
case IrOpcode::kSimd128Not:
return MarkAsSimd128(node), VisitSimd128Not(node);
case IrOpcode::kSimd32x4Select:
return MarkAsSimd128(node), VisitSimd32x4Select(node);
case IrOpcode::kSimd16x8Select:
return MarkAsSimd128(node), VisitSimd16x8Select(node);
case IrOpcode::kSimd8x16Select:
return MarkAsSimd128(node), VisitSimd8x16Select(node);
default:
V8_Fatal(__FILE__, __LINE__, "Unexpected operator #%d:%s @ node #%d",
node->opcode(), node->op()->mnemonic(), node->id());
......@@ -2053,8 +2065,6 @@ void InstructionSelector::VisitUint32x4GreaterThanOrEqual(Node* node) {
UNIMPLEMENTED();
}
void InstructionSelector::VisitSimd32x4Select(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitCreateInt16x8(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitInt16x8ExtractLane(Node* node) {
......@@ -2214,6 +2224,20 @@ void InstructionSelector::VisitUint8x16GreaterThan(Node* node) {
void InstructionSelector::VisitUint8x16GreaterThanOrEqual(Node* node) {
UNIMPLEMENTED();
}
void InstructionSelector::VisitSimd32x4Select(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitSimd16x8Select(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitSimd8x16Select(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitSimd128And(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitSimd128Or(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitSimd128Xor(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitSimd128Not(Node* node) { UNIMPLEMENTED(); }
#endif // !V8_TARGET_ARCH_ARM
void InstructionSelector::VisitFinishRegion(Node* node) { EmitIdentity(node); }
......
......@@ -289,9 +289,6 @@ MachineRepresentation AtomicStoreRepresentationOf(Operator const* op) {
V(Int16x8LessThanOrEqual, Operator::kNoProperties, 2, 0, 1) \
V(Int16x8GreaterThan, Operator::kNoProperties, 2, 0, 1) \
V(Int16x8GreaterThanOrEqual, Operator::kNoProperties, 2, 0, 1) \
V(Int16x8Select, Operator::kNoProperties, 3, 0, 1) \
V(Int16x8Swizzle, Operator::kNoProperties, 9, 0, 1) \
V(Int16x8Shuffle, Operator::kNoProperties, 10, 0, 1) \
V(Uint16x8AddSaturate, Operator::kCommutative, 2, 0, 1) \
V(Uint16x8SubSaturate, Operator::kNoProperties, 2, 0, 1) \
V(Uint16x8Min, Operator::kCommutative, 2, 0, 1) \
......@@ -326,9 +323,6 @@ MachineRepresentation AtomicStoreRepresentationOf(Operator const* op) {
V(Int8x16LessThanOrEqual, Operator::kNoProperties, 2, 0, 1) \
V(Int8x16GreaterThan, Operator::kNoProperties, 2, 0, 1) \
V(Int8x16GreaterThanOrEqual, Operator::kNoProperties, 2, 0, 1) \
V(Int8x16Select, Operator::kNoProperties, 3, 0, 1) \
V(Int8x16Swizzle, Operator::kNoProperties, 17, 0, 1) \
V(Int8x16Shuffle, Operator::kNoProperties, 18, 0, 1) \
V(Uint8x16AddSaturate, Operator::kCommutative, 2, 0, 1) \
V(Uint8x16SubSaturate, Operator::kNoProperties, 2, 0, 1) \
V(Uint8x16Min, Operator::kCommutative, 2, 0, 1) \
......@@ -361,8 +355,8 @@ MachineRepresentation AtomicStoreRepresentationOf(Operator const* op) {
V(Simd128Xor, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \
V(Simd128Not, Operator::kNoProperties, 1, 0, 1) \
V(Simd32x4Select, Operator::kNoProperties, 3, 0, 1) \
V(Simd32x4Swizzle, Operator::kNoProperties, 5, 0, 1) \
V(Simd32x4Shuffle, Operator::kNoProperties, 6, 0, 1)
V(Simd16x8Select, Operator::kNoProperties, 3, 0, 1) \
V(Simd8x16Select, Operator::kNoProperties, 3, 0, 1)
#define PURE_OPTIONAL_OP_LIST(V) \
V(Word32Ctz, Operator::kNoProperties, 1, 0, 1) \
......@@ -441,9 +435,9 @@ MachineRepresentation AtomicStoreRepresentationOf(Operator const* op) {
V(Int8x16, 16) \
V(Bool8x16, 16)
#define SIMD_SHIFT_OP_LIST(V) \
V(32x4, 32) \
V(16x8, 16) \
#define SIMD_FORMAT_LIST(V) \
V(32x4, 32) \
V(16x8, 16) \
V(8x16, 8)
#define STACK_SLOT_CACHED_SIZES_LIST(V) V(4) V(8) V(16)
......@@ -889,9 +883,20 @@ SIMD_LANE_OP_LIST(SIMD_LANE_OPS)
IrOpcode::kUint##format##ShiftRightByScalar, Operator::kPure, \
"Shift right", 1, 0, 0, 1, 0, 0, shift); \
}
SIMD_SHIFT_OP_LIST(SIMD_SHIFT_OPS)
SIMD_FORMAT_LIST(SIMD_SHIFT_OPS)
#undef SIMD_SHIFT_OPS
// TODO(bbudge) Add Shuffle, DCHECKs based on format.
#define SIMD_PERMUTE_OPS(format, bits) \
const Operator* MachineOperatorBuilder::Simd##format##Swizzle( \
uint32_t swizzle) { \
return new (zone_) \
Operator1<uint32_t>(IrOpcode::kSimd##format##Swizzle, Operator::kPure, \
"Swizzle", 2, 0, 0, 1, 0, 0, swizzle); \
}
SIMD_FORMAT_LIST(SIMD_PERMUTE_OPS)
#undef SIMD_PERMUTE_OPS
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -511,9 +511,6 @@ class V8_EXPORT_PRIVATE MachineOperatorBuilder final
const Operator* Int16x8LessThanOrEqual();
const Operator* Int16x8GreaterThan();
const Operator* Int16x8GreaterThanOrEqual();
const Operator* Int16x8Select();
const Operator* Int16x8Swizzle();
const Operator* Int16x8Shuffle();
const Operator* Uint16x8AddSaturate();
const Operator* Uint16x8SubSaturate();
......@@ -558,9 +555,6 @@ class V8_EXPORT_PRIVATE MachineOperatorBuilder final
const Operator* Int8x16LessThanOrEqual();
const Operator* Int8x16GreaterThan();
const Operator* Int8x16GreaterThanOrEqual();
const Operator* Int8x16Select();
const Operator* Int8x16Swizzle();
const Operator* Int8x16Shuffle();
const Operator* Uint8x16AddSaturate();
const Operator* Uint8x16SubSaturate();
......@@ -599,8 +593,14 @@ class V8_EXPORT_PRIVATE MachineOperatorBuilder final
const Operator* Simd128Xor();
const Operator* Simd128Not();
const Operator* Simd32x4Select();
const Operator* Simd32x4Swizzle();
const Operator* Simd32x4Swizzle(uint32_t);
const Operator* Simd32x4Shuffle();
const Operator* Simd16x8Select();
const Operator* Simd16x8Swizzle(uint32_t);
const Operator* Simd16x8Shuffle();
const Operator* Simd8x16Select();
const Operator* Simd8x16Swizzle(uint32_t);
const Operator* Simd8x16Shuffle();
// load [base + index]
const Operator* Load(LoadRepresentation rep);
......
......@@ -628,9 +628,6 @@
V(Int16x8LessThanOrEqual) \
V(Int16x8GreaterThan) \
V(Int16x8GreaterThanOrEqual) \
V(Int16x8Select) \
V(Int16x8Swizzle) \
V(Int16x8Shuffle) \
V(Uint16x8AddSaturate) \
V(Uint16x8SubSaturate) \
V(Uint16x8Min) \
......@@ -669,9 +666,6 @@
V(Int8x16LessThanOrEqual) \
V(Int8x16GreaterThan) \
V(Int8x16GreaterThanOrEqual) \
V(Int8x16Select) \
V(Int8x16Swizzle) \
V(Int8x16Shuffle) \
V(Uint8x16AddSaturate) \
V(Uint8x16SubSaturate) \
V(Uint8x16Min) \
......@@ -691,7 +685,20 @@
V(Bool8x16Swizzle) \
V(Bool8x16Shuffle) \
V(Bool8x16Equal) \
V(Bool8x16NotEqual)
V(Bool8x16NotEqual) \
V(Simd128And) \
V(Simd128Or) \
V(Simd128Xor) \
V(Simd128Not) \
V(Simd32x4Select) \
V(Simd32x4Swizzle) \
V(Simd32x4Shuffle) \
V(Simd16x8Select) \
V(Simd16x8Swizzle) \
V(Simd16x8Shuffle) \
V(Simd8x16Select) \
V(Simd8x16Swizzle) \
V(Simd8x16Shuffle)
#define MACHINE_SIMD_RETURN_NUM_OP_LIST(V) \
V(Float32x4ExtractLane) \
......@@ -718,14 +725,7 @@
V(Simd128Store) \
V(Simd128Store1) \
V(Simd128Store2) \
V(Simd128Store3) \
V(Simd128And) \
V(Simd128Or) \
V(Simd128Xor) \
V(Simd128Not) \
V(Simd32x4Select) \
V(Simd32x4Swizzle) \
V(Simd32x4Shuffle)
V(Simd128Store3)
#define MACHINE_SIMD_OP_LIST(V) \
MACHINE_SIMD_RETURN_SIMD_OP_LIST(V) \
......
......@@ -3443,9 +3443,6 @@ Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode,
return graph()->NewNode(
jsgraph()->machine()->Uint32x4GreaterThanOrEqual(), inputs[0],
inputs[1]);
case wasm::kExprS32x4Select:
return graph()->NewNode(jsgraph()->machine()->Simd32x4Select(), inputs[0],
inputs[1], inputs[2]);
case wasm::kExprI16x8Splat:
return graph()->NewNode(jsgraph()->machine()->CreateInt16x8(), inputs[0],
inputs[0], inputs[0], inputs[0], inputs[0],
......@@ -3590,6 +3587,26 @@ Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode,
return graph()->NewNode(
jsgraph()->machine()->Uint8x16GreaterThanOrEqual(), inputs[0],
inputs[1]);
case wasm::kExprS32x4Select:
return graph()->NewNode(jsgraph()->machine()->Simd32x4Select(), inputs[0],
inputs[1], inputs[2]);
case wasm::kExprS16x8Select:
return graph()->NewNode(jsgraph()->machine()->Simd16x8Select(), inputs[0],
inputs[1], inputs[2]);
case wasm::kExprS8x16Select:
return graph()->NewNode(jsgraph()->machine()->Simd8x16Select(), inputs[0],
inputs[1], inputs[2]);
case wasm::kExprS128And:
return graph()->NewNode(jsgraph()->machine()->Simd128And(), inputs[0],
inputs[1]);
case wasm::kExprS128Or:
return graph()->NewNode(jsgraph()->machine()->Simd128Or(), inputs[0],
inputs[1]);
case wasm::kExprS128Xor:
return graph()->NewNode(jsgraph()->machine()->Simd128Xor(), inputs[0],
inputs[1]);
case wasm::kExprS128Not:
return graph()->NewNode(jsgraph()->machine()->Simd128Not(), inputs[0]);
default:
return graph()->NewNode(UnsupportedOpcode(opcode), nullptr);
}
......@@ -3664,6 +3681,24 @@ Node* WasmGraphBuilder::SimdShiftOp(wasm::WasmOpcode opcode, uint8_t shift,
}
}
Node* WasmGraphBuilder::SimdSwizzleOp(wasm::WasmOpcode opcode, uint32_t swizzle,
const NodeVector& inputs) {
has_simd_ = true;
switch (opcode) {
case wasm::kExprS32x4Swizzle:
return graph()->NewNode(jsgraph()->machine()->Simd32x4Swizzle(swizzle),
inputs[0]);
case wasm::kExprS16x8Swizzle:
return graph()->NewNode(jsgraph()->machine()->Simd16x8Swizzle(swizzle),
inputs[0]);
case wasm::kExprS8x16Swizzle:
return graph()->NewNode(jsgraph()->machine()->Simd8x16Swizzle(swizzle),
inputs[0]);
default:
return graph()->NewNode(UnsupportedOpcode(opcode), nullptr);
}
}
static void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
Isolate* isolate, Handle<Code> code,
const char* message, uint32_t index,
......
......@@ -235,6 +235,9 @@ class WasmGraphBuilder {
Node* SimdShiftOp(wasm::WasmOpcode opcode, uint8_t shift,
const NodeVector& inputs);
Node* SimdSwizzleOp(wasm::WasmOpcode opcode, uint32_t swizzle,
const NodeVector& inputs);
bool has_simd() const { return has_simd_; }
wasm::ModuleEnv* module_env() const { return module_; }
......
......@@ -621,43 +621,32 @@ class LocalDeclEncoder {
//------------------------------------------------------------------------------
// Simd Operations.
//------------------------------------------------------------------------------
#define WASM_SIMD_F32x4_SPLAT(x) x, kSimdPrefix, kExprF32x4Splat & 0xff
#define WASM_SIMD_F32x4_EXTRACT_LANE(lane, x) \
x, kSimdPrefix, kExprF32x4ExtractLane & 0xff, static_cast<byte>(lane)
#define WASM_SIMD_F32x4_REPLACE_LANE(lane, x, y) \
x, y, kSimdPrefix, kExprF32x4ReplaceLane & 0xff, static_cast<byte>(lane)
#define WASM_SIMD_F32x4_FROM_I32x4(x) \
x, kSimdPrefix, kExprF32x4SConvertI32x4 & 0xff
#define WASM_SIMD_F32x4_FROM_U32x4(x) \
x, kSimdPrefix, kExprF32x4UConvertI32x4 & 0xff
#define WASM_SIMD_F32x4_ADD(x, y) x, y, kSimdPrefix, kExprF32x4Add & 0xff
#define WASM_SIMD_F32x4_SUB(x, y) x, y, kSimdPrefix, kExprF32x4Sub & 0xff
#define WASM_SIMD_I32x4_SPLAT(x) x, kSimdPrefix, kExprI32x4Splat & 0xff
#define WASM_SIMD_I32x4_EXTRACT_LANE(lane, x) \
x, kSimdPrefix, kExprI32x4ExtractLane & 0xff, static_cast<byte>(lane)
#define WASM_SIMD_I32x4_REPLACE_LANE(lane, x, y) \
x, y, kSimdPrefix, kExprI32x4ReplaceLane & 0xff, static_cast<byte>(lane)
#define WASM_SIMD_I32x4_FROM_F32x4(x) \
x, kSimdPrefix, kExprI32x4SConvertF32x4 & 0xff
#define WASM_SIMD_U32x4_FROM_F32x4(x) \
x, kSimdPrefix, kExprI32x4UConvertF32x4 & 0xff
#define WASM_SIMD_S32x4_SELECT(x, y, z) \
x, y, z, kSimdPrefix, kExprS32x4Select & 0xff
#define WASM_SIMD_I32x4_ADD(x, y) x, y, kSimdPrefix, kExprI32x4Add & 0xff
#define WASM_SIMD_I32x4_SUB(x, y) x, y, kSimdPrefix, kExprI32x4Sub & 0xff
#define WASM_SIMD_I16x8_SPLAT(x) x, kSimdPrefix, kExprI16x8Splat & 0xff
#define WASM_SIMD_I16x8_EXTRACT_LANE(lane, x) \
x, kSimdPrefix, kExprI16x8ExtractLane & 0xff, static_cast<byte>(lane)
#define WASM_SIMD_I16x8_REPLACE_LANE(lane, x, y) \
x, y, kSimdPrefix, kExprI16x8ReplaceLane & 0xff, static_cast<byte>(lane)
#define WASM_SIMD_I8x16_SPLAT(x) x, kSimdPrefix, kExprI8x16Splat & 0xff
#define WASM_SIMD_I8x16_EXTRACT_LANE(lane, x) \
x, kSimdPrefix, kExprI8x16ExtractLane & 0xff, static_cast<byte>(lane)
#define WASM_SIMD_I8x16_REPLACE_LANE(lane, x, y) \
x, y, kSimdPrefix, kExprI8x16ReplaceLane & 0xff, static_cast<byte>(lane)
// TODO(bbudge) Migrate these into tests.
#define WASM_SIMD_F32x4_SPLAT(x) \
x, kSimdPrefix, static_cast<byte>(kExprF32x4Splat)
#define WASM_SIMD_F32x4_EXTRACT_LANE(lane, x) \
x, kSimdPrefix, static_cast<byte>(kExprF32x4ExtractLane), \
static_cast<byte>(lane)
#define WASM_SIMD_F32x4_REPLACE_LANE(lane, x, y) \
x, y, kSimdPrefix, static_cast<byte>(kExprF32x4ReplaceLane), \
static_cast<byte>(lane)
#define WASM_SIMD_F32x4_ADD(x, y) \
x, y, kSimdPrefix, static_cast<byte>(kExprF32x4Add)
#define WASM_SIMD_F32x4_SUB(x, y) \
x, y, kSimdPrefix, static_cast<byte>(kExprF32x4Sub)
#define WASM_SIMD_I32x4_SPLAT(x) \
x, kSimdPrefix, static_cast<byte>(kExprI32x4Splat)
#define WASM_SIMD_I32x4_EXTRACT_LANE(lane, x) \
x, kSimdPrefix, static_cast<byte>(kExprI32x4ExtractLane), \
static_cast<byte>(lane)
#define WASM_SIMD_I32x4_REPLACE_LANE(lane, x, y) \
x, y, kSimdPrefix, static_cast<byte>(kExprI32x4ReplaceLane), \
static_cast<byte>(lane)
#define WASM_SIMD_I32x4_ADD(x, y) \
x, y, kSimdPrefix, static_cast<byte>(kExprI32x4Add)
#define WASM_SIMD_I32x4_SUB(x, y) \
x, y, kSimdPrefix, static_cast<byte>(kExprI32x4Sub)
#define SIG_ENTRY_v_v kWasmFunctionTypeForm, 0, 0
#define SIZEOF_SIG_ENTRY_v_v 3
......
......@@ -26,6 +26,8 @@ typedef Signature<ValueType> FunctionSig;
#define CASE_I16x8_OP(name, str) CASE_OP(I16x8##name, "i16x8." str)
#define CASE_I8x16_OP(name, str) CASE_OP(I8x16##name, "i8x16." str)
#define CASE_S32x4_OP(name, str) CASE_OP(S32x4##name, "s32x4." str)
#define CASE_S16x8_OP(name, str) CASE_OP(S16x8##name, "s16x8." str)
#define CASE_S8x16_OP(name, str) CASE_OP(S8x16##name, "s8x16." str)
#define CASE_INT_OP(name, str) CASE_I32_OP(name, str) CASE_I64_OP(name, str)
#define CASE_FLOAT_OP(name, str) CASE_F32_OP(name, str) CASE_F64_OP(name, str)
#define CASE_ALL_OP(name, str) CASE_FLOAT_OP(name, str) CASE_INT_OP(name, str)
......@@ -183,6 +185,7 @@ const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
CASE_F32x4_OP(Gt, "gt")
CASE_F32x4_OP(Ge, "ge")
CASE_CONVERT_OP(Convert, F32x4, I32x4, "i32", "convert")
CASE_CONVERT_OP(Convert, I32x4, F32x4, "f32", "convert")
CASE_F32x4_OP(ExtractLane, "extract_lane")
CASE_F32x4_OP(ReplaceLane, "replace_lane")
CASE_SIMDI_OP(ExtractLane, "extract_lane")
......@@ -195,21 +198,23 @@ const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
CASE_SIGN_OP(SIMDI, Ge, "ge")
CASE_SIGN_OP(SIMDI, Shr, "shr")
CASE_SIMDI_OP(Shl, "shl")
CASE_SIMDI_OP(Swizzle, "swizzle")
CASE_SIMDI_OP(Shuffle, "shuffle")
CASE_SIMDI_OP(Select, "select")
CASE_S128_OP(Ior, "or")
CASE_SIGN_OP(I16x8, AddSaturate, "add_saturate")
CASE_SIGN_OP(I8x16, AddSaturate, "add_saturate")
CASE_SIGN_OP(I16x8, SubSaturate, "sub_saturate")
CASE_SIGN_OP(I8x16, SubSaturate, "sub_saturate")
CASE_S128_OP(Or, "or")
CASE_S128_OP(Xor, "xor")
CASE_S128_OP(And, "and")
CASE_S128_OP(Not, "not")
CASE_S32x4_OP(Select, "select")
CASE_S32x4_OP(Swizzle, "swizzle")
CASE_S32x4_OP(Shuffle, "shuffle")
CASE_CONVERT_OP(Convert, I32x4, F32x4, "f32", "convert")
CASE_SIGN_OP(I16x8, AddSaturate, "add_saturate")
CASE_SIGN_OP(I8x16, AddSaturate, "add_saturate")
CASE_SIGN_OP(I16x8, SubSaturate, "sub_saturate")
CASE_SIGN_OP(I8x16, SubSaturate, "sub_saturate")
CASE_S16x8_OP(Select, "select")
CASE_S16x8_OP(Swizzle, "swizzle")
CASE_S16x8_OP(Shuffle, "shuffle")
CASE_S8x16_OP(Select, "select")
CASE_S8x16_OP(Swizzle, "swizzle")
CASE_S8x16_OP(Shuffle, "shuffle")
// Atomic operations.
CASE_L32_OP(AtomicAdd, "atomic_add")
......
......@@ -309,9 +309,6 @@ const WasmCodePosition kNoCodePosition = -1;
V(I32x4LeS, 0xe529, s_ss) \
V(I32x4GtS, 0xe52a, s_ss) \
V(I32x4GeS, 0xe52b, s_ss) \
V(I32x4Select, 0xe52c, s_sss) \
V(I32x4Swizzle, 0xe52d, s_s) \
V(I32x4Shuffle, 0xe52e, s_ss) \
V(I32x4SConvertF32x4, 0xe52f, s_s) \
V(I32x4MinU, 0xe530, s_ss) \
V(I32x4MaxU, 0xe531, s_ss) \
......@@ -335,9 +332,6 @@ const WasmCodePosition kNoCodePosition = -1;
V(I16x8LeS, 0xe548, s_ss) \
V(I16x8GtS, 0xe549, s_ss) \
V(I16x8GeS, 0xe54a, s_ss) \
V(I16x8Select, 0xe54b, s_sss) \
V(I16x8Swizzle, 0xe54c, s_s) \
V(I16x8Shuffle, 0xe54d, s_ss) \
V(I16x8AddSaturateU, 0xe54e, s_ss) \
V(I16x8SubSaturateU, 0xe54f, s_ss) \
V(I16x8MinU, 0xe550, s_ss) \
......@@ -361,9 +355,6 @@ const WasmCodePosition kNoCodePosition = -1;
V(I8x16LeS, 0xe567, s_ss) \
V(I8x16GtS, 0xe568, s_ss) \
V(I8x16GeS, 0xe569, s_ss) \
V(I8x16Select, 0xe56a, s_sss) \
V(I8x16Swizzle, 0xe56b, s_s) \
V(I8x16Shuffle, 0xe56c, s_ss) \
V(I8x16AddSaturateU, 0xe56d, s_ss) \
V(I8x16SubSaturateU, 0xe56e, s_ss) \
V(I8x16MinU, 0xe56f, s_ss) \
......@@ -373,12 +364,18 @@ const WasmCodePosition kNoCodePosition = -1;
V(I8x16GtU, 0xe574, s_ss) \
V(I8x16GeU, 0xe575, s_ss) \
V(S128And, 0xe576, s_ss) \
V(S128Ior, 0xe577, s_ss) \
V(S128Or, 0xe577, s_ss) \
V(S128Xor, 0xe578, s_ss) \
V(S128Not, 0xe579, s_s) \
V(S32x4Select, 0xe580, s_sss) \
V(S32x4Swizzle, 0xe581, s_s) \
V(S32x4Shuffle, 0xe582, s_ss)
V(S32x4Select, 0xe52c, s_sss) \
V(S32x4Swizzle, 0xe52d, s_s) \
V(S32x4Shuffle, 0xe52e, s_ss) \
V(S16x8Select, 0xe54b, s_sss) \
V(S16x8Swizzle, 0xe54c, s_s) \
V(S16x8Shuffle, 0xe54d, s_ss) \
V(S8x16Select, 0xe56a, s_sss) \
V(S8x16Swizzle, 0xe56b, s_s) \
V(S8x16Shuffle, 0xe56c, s_ss)
#define FOREACH_SIMD_1_OPERAND_OPCODE(V) \
V(F32x4ExtractLane, 0xe501, _) \
......
......@@ -187,6 +187,26 @@ T UnsignedSubSaturate(T a, T b) {
return Clamp<UnsignedT>(UnsignedWiden(a) - UnsignedWiden(b));
}
template <typename T>
T And(T a, T b) {
return a & b;
}
template <typename T>
T Or(T a, T b) {
return a | b;
}
template <typename T>
T Xor(T a, T b) {
return a ^ b;
}
template <typename T>
T Not(T a) {
return ~a;
}
} // namespace
// TODO(gdeepti): These are tests using sample values to verify functional
......@@ -264,11 +284,29 @@ T UnsignedSubSaturate(T a, T b) {
#define WASM_SIMD_CHECK_SPLAT4_F32(TYPE, value, lv) \
WASM_SIMD_CHECK4_F32(TYPE, value, lv, lv, lv, lv)
#define WASM_SIMD_UNOP(opcode, x) x, kSimdPrefix, static_cast<byte>(opcode)
#define WASM_SIMD_BINOP(opcode, x, y) \
x, y, kSimdPrefix, static_cast<byte>(opcode)
#define WASM_SIMD_SHIFT_OP(opcode, x, shift) \
x, kSimdPrefix, static_cast<byte>(opcode), static_cast<byte>(shift)
#define TO_BYTE(val) static_cast<byte>(val)
#define WASM_SIMD_OP(op) kSimdPrefix, TO_BYTE(op)
#define WASM_SIMD_UNOP(op, x) x, WASM_SIMD_OP(op)
#define WASM_SIMD_BINOP(op, x, y) x, y, WASM_SIMD_OP(op)
#define WASM_SIMD_SHIFT_OP(op, shift, x) x, WASM_SIMD_OP(op), TO_BYTE(shift)
#define WASM_SIMD_SELECT(format, x, y, z) \
x, y, z, WASM_SIMD_OP(kExprS##format##Select)
#define WASM_SIMD_I16x8_SPLAT(x) x, WASM_SIMD_OP(kExprI16x8Splat)
#define WASM_SIMD_I16x8_EXTRACT_LANE(lane, x) \
x, WASM_SIMD_OP(kExprI16x8ExtractLane), TO_BYTE(lane)
#define WASM_SIMD_I16x8_REPLACE_LANE(lane, x, y) \
x, y, WASM_SIMD_OP(kExprI16x8ReplaceLane), TO_BYTE(lane)
#define WASM_SIMD_I8x16_SPLAT(x) x, WASM_SIMD_OP(kExprI8x16Splat)
#define WASM_SIMD_I8x16_EXTRACT_LANE(lane, x) \
x, WASM_SIMD_OP(kExprI8x16ExtractLane), TO_BYTE(lane)
#define WASM_SIMD_I8x16_REPLACE_LANE(lane, x, y) \
x, y, WASM_SIMD_OP(kExprI8x16ReplaceLane), TO_BYTE(lane)
#define WASM_SIMD_F32x4_FROM_I32x4(x) x, WASM_SIMD_OP(kExprF32x4SConvertI32x4)
#define WASM_SIMD_F32x4_FROM_U32x4(x) x, WASM_SIMD_OP(kExprF32x4UConvertI32x4)
#define WASM_SIMD_I32x4_FROM_F32x4(x) x, WASM_SIMD_OP(kExprI32x4SConvertF32x4)
#define WASM_SIMD_U32x4_FROM_F32x4(x) x, WASM_SIMD_OP(kExprI32x4UConvertF32x4)
#if V8_TARGET_ARCH_ARM
WASM_EXEC_TEST(F32x4Splat) {
......@@ -334,34 +372,6 @@ WASM_EXEC_TEST(F32x4FromInt32x4) {
}
}
WASM_EXEC_TEST(S32x4Select) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t, int32_t, int32_t> r(kExecuteCompiled);
byte val1 = 0;
byte val2 = 1;
byte mask = r.AllocateLocal(kWasmS128);
byte src1 = r.AllocateLocal(kWasmS128);
byte src2 = r.AllocateLocal(kWasmS128);
BUILD(r,
WASM_SET_LOCAL(mask, WASM_SIMD_I32x4_SPLAT(WASM_ZERO)),
WASM_SET_LOCAL(src1, WASM_SIMD_I32x4_SPLAT(WASM_GET_LOCAL(val1))),
WASM_SET_LOCAL(src2, WASM_SIMD_I32x4_SPLAT(WASM_GET_LOCAL(val2))),
WASM_SET_LOCAL(mask, WASM_SIMD_I32x4_REPLACE_LANE(
1, WASM_GET_LOCAL(mask), WASM_I32V(-1))),
WASM_SET_LOCAL(mask, WASM_SIMD_I32x4_REPLACE_LANE(
2, WASM_GET_LOCAL(mask), WASM_I32V(-1))),
WASM_SET_LOCAL(mask, WASM_SIMD_S32x4_SELECT(WASM_GET_LOCAL(mask),
WASM_GET_LOCAL(src1),
WASM_GET_LOCAL(src2))),
WASM_SIMD_CHECK_LANE(I32x4, mask, I32, val2, 0),
WASM_SIMD_CHECK_LANE(I32x4, mask, I32, val1, 1),
WASM_SIMD_CHECK_LANE(I32x4, mask, I32, val1, 2),
WASM_SIMD_CHECK_LANE(I32x4, mask, I32, val2, 3), WASM_ONE);
CHECK_EQ(1, r.Call(0x1234, 0x5678));
}
void RunF32x4UnOpTest(WasmOpcode simd_op, FloatUnOp expected_op) {
FLAG_wasm_simd_prototype = true;
WasmRunner<int32_t, float, float> r(kExecuteCompiled);
......@@ -753,6 +763,8 @@ void RunI32x4UnOpTest(WasmOpcode simd_op, Int32UnOp expected_op) {
}
WASM_EXEC_TEST(I32x4Neg) { RunI32x4UnOpTest(kExprI32x4Neg, Negate); }
WASM_EXEC_TEST(S128Not) { RunI32x4UnOpTest(kExprS128Not, Not); }
#endif // V8_TARGET_ARCH_ARM
void RunI32x4BinOpTest(WasmOpcode simd_op, Int32BinOp expected_op) {
......@@ -821,6 +833,12 @@ WASM_EXEC_TEST(Ui32x4LessEqual) {
RunI32x4BinOpTest(kExprI32x4LeU, UnsignedLessEqual);
}
WASM_EXEC_TEST(S128And) { RunI32x4BinOpTest(kExprS128And, And); }
WASM_EXEC_TEST(S128Or) { RunI32x4BinOpTest(kExprS128Or, Or); }
WASM_EXEC_TEST(S128Xor) { RunI32x4BinOpTest(kExprS128Xor, Xor); }
void RunI32x4ShiftOpTest(WasmOpcode simd_op, Int32ShiftOp expected_op,
int shift) {
FLAG_wasm_simd_prototype = true;
......@@ -830,7 +848,7 @@ void RunI32x4ShiftOpTest(WasmOpcode simd_op, Int32ShiftOp expected_op,
byte simd = r.AllocateLocal(kWasmS128);
BUILD(r, WASM_SET_LOCAL(simd, WASM_SIMD_I32x4_SPLAT(WASM_GET_LOCAL(a))),
WASM_SET_LOCAL(
simd, WASM_SIMD_SHIFT_OP(simd_op, WASM_GET_LOCAL(simd), shift)),
simd, WASM_SIMD_SHIFT_OP(simd_op, shift, WASM_GET_LOCAL(simd))),
WASM_SIMD_CHECK_SPLAT4(I32x4, simd, I32, expected), WASM_ONE);
FOR_INT32_INPUTS(i) { CHECK_EQ(1, r.Call(*i, expected_op(*i, shift))); }
......@@ -953,7 +971,7 @@ void RunI16x8ShiftOpTest(WasmOpcode simd_op, Int16ShiftOp expected_op,
byte simd = r.AllocateLocal(kWasmS128);
BUILD(r, WASM_SET_LOCAL(simd, WASM_SIMD_I16x8_SPLAT(WASM_GET_LOCAL(a))),
WASM_SET_LOCAL(
simd, WASM_SIMD_SHIFT_OP(simd_op, WASM_GET_LOCAL(simd), shift)),
simd, WASM_SIMD_SHIFT_OP(simd_op, shift, WASM_GET_LOCAL(simd))),
WASM_SIMD_CHECK_SPLAT8(I16x8, simd, I32, expected), WASM_ONE);
FOR_INT16_INPUTS(i) { CHECK_EQ(1, r.Call(*i, expected_op(*i, shift))); }
......@@ -1076,7 +1094,7 @@ void RunI8x16ShiftOpTest(WasmOpcode simd_op, Int8ShiftOp expected_op,
byte simd = r.AllocateLocal(kWasmS128);
BUILD(r, WASM_SET_LOCAL(simd, WASM_SIMD_I8x16_SPLAT(WASM_GET_LOCAL(a))),
WASM_SET_LOCAL(
simd, WASM_SIMD_SHIFT_OP(simd_op, WASM_GET_LOCAL(simd), shift)),
simd, WASM_SIMD_SHIFT_OP(simd_op, shift, WASM_GET_LOCAL(simd))),
WASM_SIMD_CHECK_SPLAT16(I8x16, simd, I32, expected), WASM_ONE);
FOR_INT8_INPUTS(i) { CHECK_EQ(1, r.Call(*i, expected_op(*i, shift))); }
......@@ -1093,4 +1111,37 @@ WASM_EXEC_TEST(I8x16ShrS) {
WASM_EXEC_TEST(I8x16ShrU) {
RunI8x16ShiftOpTest(kExprI8x16ShrU, LogicalShiftRight, 1);
}
#define WASM_SIMD_SELECT_TEST(format) \
WASM_EXEC_TEST(S##format##Select) { \
FLAG_wasm_simd_prototype = true; \
WasmRunner<int32_t, int32_t, int32_t> r(kExecuteCompiled); \
byte val1 = 0; \
byte val2 = 1; \
byte mask = r.AllocateLocal(kWasmS128); \
byte src1 = r.AllocateLocal(kWasmS128); \
byte src2 = r.AllocateLocal(kWasmS128); \
BUILD(r, WASM_SET_LOCAL(mask, WASM_SIMD_I##format##_SPLAT(WASM_ZERO)), \
WASM_SET_LOCAL(src1, \
WASM_SIMD_I##format##_SPLAT(WASM_GET_LOCAL(val1))), \
WASM_SET_LOCAL(src2, \
WASM_SIMD_I##format##_SPLAT(WASM_GET_LOCAL(val2))), \
WASM_SET_LOCAL(mask, WASM_SIMD_I##format##_REPLACE_LANE( \
1, WASM_GET_LOCAL(mask), WASM_I32V(-1))), \
WASM_SET_LOCAL(mask, WASM_SIMD_I##format##_REPLACE_LANE( \
2, WASM_GET_LOCAL(mask), WASM_I32V(-1))), \
WASM_SET_LOCAL(mask, WASM_SIMD_SELECT(format, WASM_GET_LOCAL(mask), \
WASM_GET_LOCAL(src1), \
WASM_GET_LOCAL(src2))), \
WASM_SIMD_CHECK_LANE(I##format, mask, I32, val2, 0), \
WASM_SIMD_CHECK_LANE(I##format, mask, I32, val1, 1), \
WASM_SIMD_CHECK_LANE(I##format, mask, I32, val1, 2), \
WASM_SIMD_CHECK_LANE(I##format, mask, I32, val2, 3), WASM_ONE); \
\
CHECK_EQ(1, r.Call(0x12, 0x34)); \
}
WASM_SIMD_SELECT_TEST(32x4)
WASM_SIMD_SELECT_TEST(16x8)
WASM_SIMD_SELECT_TEST(8x16)
#endif // V8_TARGET_ARCH_ARM
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