Index: src/wasm/function-body-decoder.cc |
diff --git a/src/wasm/function-body-decoder.cc b/src/wasm/function-body-decoder.cc |
index adbaacc0c0081ac7978d16941b9b01510b9ab34b..42b6554c803060fe52427d3b5840fea8995a9639 100644 |
--- a/src/wasm/function-body-decoder.cc |
+++ b/src/wasm/function-body-decoder.cc |
@@ -146,6 +146,22 @@ struct Control { |
} |
}; |
+namespace { |
+inline unsigned GetShuffleMaskSize(WasmOpcode opcode) { |
+ switch (opcode) { |
+ case kExprS32x4Shuffle: |
+ return 4; |
+ case kExprS16x8Shuffle: |
+ return 8; |
+ case kExprS8x16Shuffle: |
+ return 16; |
+ default: |
+ UNREACHABLE(); |
+ return 0; |
+ } |
+} |
+} // namespace |
+ |
// Macros that build nodes only if there is a graph and the current SSA |
// environment is reachable from start. This avoids problems with malformed |
// TF graphs when decoding inputs that have unreachable code. |
@@ -412,10 +428,13 @@ class WasmDecoder : public Decoder { |
} |
inline bool Validate(const byte* pc, WasmOpcode opcode, |
- SimdConcatOperand<true>& operand) { |
- DCHECK_EQ(wasm::kExprS8x16Concat, opcode); |
- if (operand.bytes <= 0 || operand.bytes >= kSimd128Size) { |
- error(pc_ + 2, "invalid byte amount"); |
+ SimdShuffleOperand<true>& operand) { |
+ unsigned lanes = GetShuffleMaskSize(opcode); |
+ uint8_t max_lane = 0; |
+ for (unsigned i = 0; i < lanes; i++) |
+ max_lane = std::max(max_lane, operand.shuffle[i]); |
+ if (operand.lanes != lanes || max_lane > 2 * lanes) { |
+ error(pc_ + 2, "invalid shuffle mask"); |
return false; |
} else { |
return true; |
@@ -423,7 +442,8 @@ class WasmDecoder : public Decoder { |
} |
static unsigned OpcodeLength(Decoder* decoder, const byte* pc) { |
- switch (static_cast<byte>(*pc)) { |
+ WasmOpcode opcode = static_cast<WasmOpcode>(*pc); |
+ switch (opcode) { |
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: |
FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE) |
FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) |
@@ -506,6 +526,11 @@ class WasmDecoder : public Decoder { |
{ |
return 3; |
} |
+ // Shuffles contain a byte array to determine the shuffle. |
+ case kExprS32x4Shuffle: |
+ case kExprS16x8Shuffle: |
+ case kExprS8x16Shuffle: |
+ return 2 + GetShuffleMaskSize(opcode); |
default: |
decoder->error(pc, "invalid SIMD opcode"); |
return 2; |
@@ -1548,17 +1573,17 @@ class WasmFullDecoder : public WasmDecoder { |
return operand.length; |
} |
- unsigned SimdConcatOp(WasmOpcode opcode) { |
- DCHECK_EQ(wasm::kExprS8x16Concat, opcode); |
- SimdConcatOperand<true> operand(this, pc_); |
+ unsigned SimdShuffleOp(WasmOpcode opcode) { |
+ SimdShuffleOperand<true> operand(this, pc_, GetShuffleMaskSize(opcode)); |
if (Validate(pc_, opcode, operand)) { |
compiler::NodeVector inputs(2, zone_); |
inputs[1] = Pop(1, ValueType::kSimd128).node; |
inputs[0] = Pop(0, ValueType::kSimd128).node; |
- TFNode* node = BUILD(SimdConcatOp, operand.bytes, inputs); |
+ TFNode* node = |
+ BUILD(SimdShuffleOp, operand.shuffle, operand.lanes, inputs); |
Push(ValueType::kSimd128, node); |
} |
- return operand.length; |
+ return operand.lanes; |
} |
unsigned DecodeSimdOpcode(WasmOpcode opcode) { |
@@ -1596,8 +1621,10 @@ class WasmFullDecoder : public WasmDecoder { |
len = SimdShiftOp(opcode); |
break; |
} |
- case kExprS8x16Concat: { |
- len = SimdConcatOp(opcode); |
+ case kExprS32x4Shuffle: |
+ case kExprS16x8Shuffle: |
+ case kExprS8x16Shuffle: { |
+ len = SimdShuffleOp(opcode); |
break; |
} |
default: { |