Index: src/wasm/function-body-decoder.cc |
diff --git a/src/wasm/function-body-decoder.cc b/src/wasm/function-body-decoder.cc |
index 7c755b1a06a36c8f8995bbffcc0a62450f1361d6..2d47e855d146a22b18415b0b0bddfc19ff712fbd 100644 |
--- a/src/wasm/function-body-decoder.cc |
+++ b/src/wasm/function-body-decoder.cc |
@@ -148,16 +148,28 @@ struct Control { |
(build() ? CheckForException(builder_->func(__VA_ARGS__)) : nullptr) |
#define BUILD0(func) (build() ? CheckForException(builder_->func()) : nullptr) |
-struct LaneOperand { |
+// Operand for SIMD lane operations. |
+struct SimdLaneOperand { |
uint8_t lane; |
unsigned length; |
- inline LaneOperand(Decoder* decoder, const byte* pc) { |
+ inline SimdLaneOperand(Decoder* decoder, const byte* pc) { |
lane = decoder->checked_read_u8(pc, 2, "lane"); |
length = 1; |
} |
}; |
+// Operand for SIMD shift operations. |
+struct SimdShiftOperand { |
+ uint8_t shift; |
+ unsigned length; |
+ |
+ inline SimdShiftOperand(Decoder* decoder, const byte* pc) { |
+ shift = decoder->checked_read_u8(pc, 2, "shift"); |
+ length = 1; |
+ } |
+}; |
+ |
// Generic Wasm bytecode decoder with utilities for decoding operands, |
// lengths, etc. |
class WasmDecoder : public Decoder { |
@@ -349,7 +361,7 @@ class WasmDecoder : public Decoder { |
} |
inline bool Validate(const byte* pc, WasmOpcode opcode, |
- LaneOperand& operand) { |
+ SimdLaneOperand& operand) { |
uint8_t num_lanes = 0; |
switch (opcode) { |
case kExprF32x4ExtractLane: |
@@ -371,7 +383,38 @@ class WasmDecoder : public Decoder { |
break; |
} |
if (operand.lane < 0 || operand.lane >= num_lanes) { |
- error(pc_, pc_ + 2, "invalid lane value"); |
+ error(pc_, pc_ + 2, "invalid lane index"); |
+ return false; |
+ } else { |
+ return true; |
+ } |
+ } |
+ |
+ inline bool Validate(const byte* pc, WasmOpcode opcode, |
+ SimdShiftOperand& operand) { |
+ uint8_t max_shift = 0; |
+ switch (opcode) { |
+ case kExprI32x4Shl: |
+ case kExprI32x4ShrS: |
+ case kExprI32x4ShrU: |
+ max_shift = 32; |
+ break; |
+ case kExprI16x8Shl: |
+ case kExprI16x8ShrS: |
+ case kExprI16x8ShrU: |
+ max_shift = 16; |
+ break; |
+ case kExprI8x16Shl: |
+ case kExprI8x16ShrS: |
+ case kExprI8x16ShrU: |
+ max_shift = 8; |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ break; |
+ } |
+ if (operand.shift < 0 || operand.shift >= max_shift) { |
+ error(pc_, pc_ + 2, "invalid shift amount"); |
return false; |
} else { |
return true; |
@@ -1357,8 +1400,8 @@ class WasmFullDecoder : public WasmDecoder { |
return 1 + operand.length; |
} |
- unsigned ExtractLane(WasmOpcode opcode, ValueType type) { |
- LaneOperand operand(this, pc_); |
+ unsigned SimdExtractLane(WasmOpcode opcode, ValueType type) { |
+ SimdLaneOperand operand(this, pc_); |
if (Validate(pc_, opcode, operand)) { |
compiler::NodeVector inputs(1, zone_); |
inputs[0] = Pop(0, ValueType::kSimd128).node; |
@@ -1368,8 +1411,8 @@ class WasmFullDecoder : public WasmDecoder { |
return operand.length; |
} |
- unsigned ReplaceLane(WasmOpcode opcode, ValueType type) { |
- LaneOperand operand(this, pc_); |
+ unsigned SimdReplaceLane(WasmOpcode opcode, ValueType type) { |
+ SimdLaneOperand operand(this, pc_); |
if (Validate(pc_, opcode, operand)) { |
compiler::NodeVector inputs(2, zone_); |
inputs[1] = Pop(1, type).node; |
@@ -1380,27 +1423,50 @@ class WasmFullDecoder : public WasmDecoder { |
return operand.length; |
} |
+ unsigned SimdShiftOp(WasmOpcode opcode) { |
+ SimdShiftOperand operand(this, pc_); |
+ if (Validate(pc_, opcode, operand)) { |
+ compiler::NodeVector inputs(1, zone_); |
+ inputs[0] = Pop(0, ValueType::kSimd128).node; |
+ TFNode* node = BUILD(SimdShiftOp, opcode, operand.shift, inputs); |
+ Push(ValueType::kSimd128, node); |
+ } |
+ return operand.length; |
+ } |
+ |
unsigned DecodeSimdOpcode(WasmOpcode opcode) { |
unsigned len = 0; |
switch (opcode) { |
case kExprF32x4ExtractLane: { |
- len = ExtractLane(opcode, ValueType::kFloat32); |
+ len = SimdExtractLane(opcode, ValueType::kFloat32); |
break; |
} |
case kExprI32x4ExtractLane: |
case kExprI16x8ExtractLane: |
case kExprI8x16ExtractLane: { |
- len = ExtractLane(opcode, ValueType::kWord32); |
+ len = SimdExtractLane(opcode, ValueType::kWord32); |
break; |
} |
case kExprF32x4ReplaceLane: { |
- len = ReplaceLane(opcode, ValueType::kFloat32); |
+ len = SimdReplaceLane(opcode, ValueType::kFloat32); |
break; |
} |
case kExprI32x4ReplaceLane: |
case kExprI16x8ReplaceLane: |
case kExprI8x16ReplaceLane: { |
- len = ReplaceLane(opcode, ValueType::kWord32); |
+ len = SimdReplaceLane(opcode, ValueType::kWord32); |
+ break; |
+ } |
+ case kExprI32x4Shl: |
+ case kExprI32x4ShrS: |
+ case kExprI32x4ShrU: |
+ case kExprI16x8Shl: |
+ case kExprI16x8ShrS: |
+ case kExprI16x8ShrU: |
+ case kExprI8x16Shl: |
+ case kExprI8x16ShrS: |
+ case kExprI8x16ShrU: { |
+ len = SimdShiftOp(opcode); |
break; |
} |
default: { |