Backed out changeset cfb447308e8a (bug 1241454) for bustage on a CLOSED TREE

This commit is contained in:
Carsten "Tomcat" Book 2016-01-26 13:22:47 +01:00
parent 0021043626
commit 0aef8e65b5
3 changed files with 433 additions and 298 deletions

View File

@ -1082,10 +1082,17 @@ class Type
MOZ_IMPLICIT Type(Which w) : which_(w) {}
MOZ_IMPLICIT Type(SimdType type) {
switch (type) {
case SimdType::Int32x4: which_ = Int32x4; return;
case SimdType::Float32x4: which_ = Float32x4; return;
case SimdType::Bool32x4: which_ = Bool32x4; return;
default: break;
case SimdType::Int32x4:
which_ = Int32x4;
return;
case SimdType::Float32x4:
which_ = Float32x4;
return;
case SimdType::Bool32x4:
which_ = Bool32x4;
return;
default:
break;
}
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("bad SimdType");
}
@ -2294,18 +2301,6 @@ IsCallToGlobal(ModuleValidator& m, ParseNode* pn, const ModuleValidator::Global*
return !!*global;
}
static ValType
ToValType(SimdType type)
{
switch (type) {
case SimdType::Int32x4: return ValType::I32x4;
case SimdType::Float32x4: return ValType::F32x4;
case SimdType::Bool32x4: return ValType::B32x4;
default: break;
}
MOZ_CRASH("unexpected SIMD type");
}
static bool
IsCoercionCall(ModuleValidator& m, ParseNode* pn, ValType* coerceTo, ParseNode** coercedExpr)
{
@ -2325,8 +2320,19 @@ IsCoercionCall(ModuleValidator& m, ParseNode* pn, ValType* coerceTo, ParseNode**
}
if (global->isSimdOperation() && global->simdOperation() == SimdOperation::Fn_check) {
*coerceTo = ToValType(global->simdOperationType());
return true;
switch (global->simdOperationType()) {
case SimdType::Int32x4:
*coerceTo = ValType::I32x4;
return true;
case SimdType::Float32x4:
*coerceTo = ValType::F32x4;
return true;
case SimdType::Bool32x4:
*coerceTo = ValType::B32x4;
return true;
default:
MOZ_CRASH("unexpected SIMD type");
}
}
return false;
@ -2721,16 +2727,6 @@ class MOZ_STACK_CLASS FunctionValidator
bool writeOp(Expr op) {
return encoder().writeExpr(op);
}
MOZ_WARN_UNUSED_RESULT
bool writeExprType(ExprType type) {
return encoder().writeExprType(type);
}
MOZ_WARN_UNUSED_RESULT
bool writeSimdOp(SimdType simdType, SimdOperation op) {
return writeOp(Expr::SimdOp) &&
encoder().writeExprType(ToExprType(simdType)) &&
encoder().writeSimdOp(op);
}
MOZ_WARN_UNUSED_RESULT
bool writeDebugCheckPoint() {
@ -2773,15 +2769,12 @@ class MOZ_STACK_CLASS FunctionValidator
case NumLit::Double:
return writeOp(Expr::F64Const) && encoder().writeF64(lit.toDouble());
case NumLit::Int32x4:
return writeOp(Expr::SimdConst) && writeExprType(ExprType::I32x4) &&
encoder().writeI32X4(lit.simdValue().asInt32x4());
return writeOp(Expr::I32X4Const) && encoder().writeI32X4(lit.simdValue().asInt32x4());
case NumLit::Float32x4:
return writeOp(Expr::SimdConst) && writeExprType(ExprType::F32x4) &&
encoder().writeF32X4(lit.simdValue().asFloat32x4());
return writeOp(Expr::F32X4Const) && encoder().writeF32X4(lit.simdValue().asFloat32x4());
case NumLit::Bool32x4:
// Boolean vectors use the Int32x4 memory representation.
return writeOp(Expr::SimdConst) && writeExprType(ExprType::B32x4) &&
encoder().writeI32X4(lit.simdValue().asInt32x4());
return writeOp(Expr::B32X4Const) && encoder().writeI32X4(lit.simdValue().asInt32x4());
case NumLit::OutOfRangeInt:
break;
}
@ -4948,10 +4941,24 @@ class CheckSimdReplaceLaneArgs
} // namespace
static bool
CheckSimdUnary(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op,
Type* type)
SwitchPackOp(FunctionValidator& f, SimdType type, Expr i32x4, Expr f32x4, Expr b32x4)
{
if (!f.writeSimdOp(opType, op))
switch (type) {
case SimdType::Int32x4: return f.writeOp(i32x4);
case SimdType::Float32x4: return f.writeOp(f32x4);
case SimdType::Bool32x4: return f.writeOp(b32x4);
default: break;
}
MOZ_CRASH("unexpected simd type");
}
static bool
CheckSimdUnary(FunctionValidator& f, ParseNode* call, SimdType opType,
MSimdUnaryArith::Operation op, Type* type)
{
if (!SwitchPackOp(f, opType, Expr::I32X4Unary, Expr::F32X4Unary, Expr::B32X4Unary))
return false;
if (!f.writeU8(uint8_t(op)))
return false;
if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType)))
return false;
@ -4959,23 +4966,54 @@ CheckSimdUnary(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOpera
return true;
}
static bool
CheckSimdBinaryShift(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op,
Type *type)
template<class OpKind>
inline bool
CheckSimdBinaryGuts(FunctionValidator& f, ParseNode* call, SimdType opType, OpKind op,
Type* type)
{
if (!f.writeSimdOp(opType, op))
if (!f.writeU8(uint8_t(op)))
return false;
if (!CheckSimdCallArgs(f, call, 2, CheckSimdVectorScalarArgs(opType)))
if (!CheckSimdCallArgs(f, call, 2, CheckArgIsSubtypeOf(opType)))
return false;
*type = Type::Int32x4;
*type = opType;
return true;
}
static bool
CheckSimdBinaryComp(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op,
Type *type)
CheckSimdBinary(FunctionValidator& f, ParseNode* call, SimdType opType,
MSimdBinaryArith::Operation op, Type* type)
{
if (!f.writeSimdOp(opType, op))
return SwitchPackOp(f, opType, Expr::I32X4Binary, Expr::F32X4Binary, Expr::B32X4Binary) &&
CheckSimdBinaryGuts(f, call, opType, op, type);
}
static bool
CheckSimdBinary(FunctionValidator& f, ParseNode* call, SimdType opType,
MSimdBinaryBitwise::Operation op, Type* type)
{
return SwitchPackOp(f, opType, Expr::I32X4BinaryBitwise, Expr::Unreachable, Expr::B32X4BinaryBitwise) &&
CheckSimdBinaryGuts(f, call, opType, op, type);
}
static bool
CheckSimdBinary(FunctionValidator& f, ParseNode* call, SimdType opType,
MSimdBinaryComp::Operation op, Type* type)
{
switch (opType) {
case SimdType::Int32x4:
if (!f.writeOp(Expr::B32X4BinaryCompI32X4))
return false;
break;
case SimdType::Float32x4:
if (!f.writeOp(Expr::B32X4BinaryCompF32X4))
return false;
break;
case SimdType::Bool32x4:
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Can't compare boolean vectors");
default:
MOZ_CRASH("unhandled SIMD type");
}
if (!f.writeU8(uint8_t(op)))
return false;
if (!CheckSimdCallArgs(f, call, 2, CheckArgIsSubtypeOf(opType)))
return false;
@ -4984,27 +5022,38 @@ CheckSimdBinaryComp(FunctionValidator& f, ParseNode* call, SimdType opType, Simd
}
static bool
CheckSimdBinary(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op,
Type* type)
CheckSimdBinary(FunctionValidator& f, ParseNode* call, SimdType opType,
MSimdShift::Operation op, Type* type)
{
if (!f.writeSimdOp(opType, op))
if (!f.writeOp(Expr::I32X4BinaryShift) || !f.writeU8(uint8_t(op)))
return false;
if (!CheckSimdCallArgs(f, call, 2, CheckArgIsSubtypeOf(opType)))
if (!CheckSimdCallArgs(f, call, 2, CheckSimdVectorScalarArgs(opType)))
return false;
*type = opType;
*type = Type::Int32x4;
return true;
}
static bool
CheckSimdExtractLane(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
{
if (!f.writeSimdOp(opType, SimdOperation::Fn_extractLane))
return false;
switch (opType) {
case SimdType::Int32x4: *type = Type::Signed; break;
case SimdType::Float32x4: *type = Type::Float; break;
case SimdType::Bool32x4: *type = Type::Int; break;
default: MOZ_CRASH("unhandled simd type");
case SimdType::Int32x4:
if (!f.writeOp(Expr::I32I32X4ExtractLane))
return false;
*type = Type::Signed;
break;
case SimdType::Float32x4:
if (!f.writeOp(Expr::F32F32X4ExtractLane))
return false;
*type = Type::Float;
break;
case SimdType::Bool32x4:
if (!f.writeOp(Expr::I32B32X4ExtractLane))
return false;
*type = Type::Int;
break;
default:
MOZ_CRASH("unhandled simd type");
}
return CheckSimdCallArgs(f, call, 2, CheckSimdExtractLaneArgs(opType));
}
@ -5012,7 +5061,7 @@ CheckSimdExtractLane(FunctionValidator& f, ParseNode* call, SimdType opType, Typ
static bool
CheckSimdReplaceLane(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
{
if (!f.writeSimdOp(opType, SimdOperation::Fn_replaceLane))
if (!SwitchPackOp(f, opType, Expr::I32X4ReplaceLane, Expr::F32X4ReplaceLane, Expr::B32X4ReplaceLane))
return false;
if (!CheckSimdCallArgsPatchable(f, call, 3, CheckSimdReplaceLaneArgs(opType)))
return false;
@ -5020,17 +5069,22 @@ CheckSimdReplaceLane(FunctionValidator& f, ParseNode* call, SimdType opType, Typ
return true;
}
typedef bool Bitcast;
typedef bool IsBitCast;
namespace {
// Include CheckSimdCast in unnamed namespace to avoid MSVC name lookup bug (due to the use of Type).
static bool
CheckSimdCast(FunctionValidator& f, ParseNode* call, SimdType fromType, SimdType toType,
SimdOperation op, Type* type)
bool bitcast, Type* type)
{
if (!f.writeSimdOp(toType, op))
if (!SwitchPackOp(f, toType,
bitcast ? Expr::I32X4FromF32X4Bits : Expr::I32X4FromF32X4,
bitcast ? Expr::F32X4FromI32X4Bits : Expr::F32X4FromI32X4,
Expr::Unreachable))
{
return false;
}
if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(fromType)))
return false;
*type = toType;
@ -5060,7 +5114,7 @@ CheckSimdSwizzle(FunctionValidator& f, ParseNode* call, SimdType opType, Type* t
if (numArgs != 5)
return f.failf(call, "expected 5 arguments to SIMD swizzle, got %u", numArgs);
if (!f.writeSimdOp(opType, SimdOperation::Fn_swizzle))
if (!SwitchPackOp(f, opType, Expr::I32X4Swizzle, Expr::F32X4Swizzle, Expr::Unreachable))
return false;
Type retType = opType;
@ -5091,7 +5145,7 @@ CheckSimdShuffle(FunctionValidator& f, ParseNode* call, SimdType opType, Type* t
if (numArgs != 6)
return f.failf(call, "expected 6 arguments to SIMD shuffle, got %u", numArgs);
if (!f.writeSimdOp(opType, SimdOperation::Fn_shuffle))
if (!SwitchPackOp(f, opType, Expr::I32X4Shuffle, Expr::F32X4Shuffle, Expr::Unreachable))
return false;
Type retType = opType;
@ -5118,7 +5172,8 @@ CheckSimdShuffle(FunctionValidator& f, ParseNode* call, SimdType opType, Type* t
}
static bool
CheckSimdLoadStoreArgs(FunctionValidator& f, ParseNode* call)
CheckSimdLoadStoreArgs(FunctionValidator& f, ParseNode* call, SimdType opType,
Scalar::Type* viewType, NeedsBoundsCheck* needsBoundsCheck)
{
ParseNode* view = CallArgList(call);
if (!view->isKind(PNK_NAME))
@ -5132,16 +5187,24 @@ CheckSimdLoadStoreArgs(FunctionValidator& f, ParseNode* call)
return f.fail(view, "expected Uint8Array view as SIMD.*.load/store first argument");
}
*needsBoundsCheck = NEEDS_BOUNDS_CHECK;
switch (opType) {
case SimdType::Int32x4: *viewType = Scalar::Int32x4; break;
case SimdType::Float32x4: *viewType = Scalar::Float32x4; break;
case SimdType::Bool32x4: MOZ_CRASH("Cannot load/store boolean SIMD type");
default: MOZ_CRASH("unhandled SIMD type");
}
ParseNode* indexExpr = NextNode(view);
uint32_t indexLit;
if (IsLiteralOrConstInt(f, indexExpr, &indexLit)) {
if (!f.m().tryConstantAccess(indexLit, Simd128DataSize))
return f.fail(indexExpr, "constant index out of range");
return f.writeU8(NO_BOUNDS_CHECK) && f.writeInt32Lit(indexLit);
}
if (!f.writeU8(NEEDS_BOUNDS_CHECK))
return false;
*needsBoundsCheck = NO_BOUNDS_CHECK;
return f.writeInt32Lit(indexLit);
}
Type indexType;
if (!CheckExpr(f, indexExpr, &indexType))
@ -5154,35 +5217,52 @@ CheckSimdLoadStoreArgs(FunctionValidator& f, ParseNode* call)
}
static bool
CheckSimdLoad(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op,
Type* type)
CheckSimdLoad(FunctionValidator& f, ParseNode* call, SimdType opType,
unsigned numElems, Type* type)
{
unsigned numArgs = CallArgListLength(call);
if (numArgs != 2)
return f.failf(call, "expected 2 arguments to SIMD load, got %u", numArgs);
if (!f.writeSimdOp(opType, op))
if (!SwitchPackOp(f, opType, Expr::I32X4Load, Expr::F32X4Load, Expr::Unreachable))
return false;
if (!CheckSimdLoadStoreArgs(f, call))
size_t viewTypeAt;
size_t needsBoundsCheckAt;
if (!f.tempU8(&viewTypeAt) || !f.tempU8(&needsBoundsCheckAt) || !f.writeU8(numElems))
return false;
Scalar::Type viewType;
NeedsBoundsCheck needsBoundsCheck;
if (!CheckSimdLoadStoreArgs(f, call, opType, &viewType, &needsBoundsCheck))
return false;
f.patchU8(needsBoundsCheckAt, uint8_t(needsBoundsCheck));
f.patchU8(viewTypeAt, uint8_t(viewType));
*type = opType;
return true;
}
static bool
CheckSimdStore(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op,
Type* type)
CheckSimdStore(FunctionValidator& f, ParseNode* call, SimdType opType,
unsigned numElems, Type* type)
{
unsigned numArgs = CallArgListLength(call);
if (numArgs != 3)
return f.failf(call, "expected 3 arguments to SIMD store, got %u", numArgs);
if (!f.writeSimdOp(opType, op))
if (!SwitchPackOp(f, opType, Expr::I32X4Store, Expr::F32X4Store, Expr::Unreachable))
return false;
if (!CheckSimdLoadStoreArgs(f, call))
size_t viewTypeAt;
size_t needsBoundsCheckAt;
if (!f.tempU8(&viewTypeAt) || !f.tempU8(&needsBoundsCheckAt) || !f.writeU8(numElems))
return false;
Scalar::Type viewType;
NeedsBoundsCheck needsBoundsCheck;
if (!CheckSimdLoadStoreArgs(f, call, opType, &viewType, &needsBoundsCheck))
return false;
Type retType = opType;
@ -5190,10 +5270,12 @@ CheckSimdStore(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOpera
Type vecType;
if (!CheckExpr(f, vecExpr, &vecType))
return false;
if (!(vecType <= retType))
return f.failf(vecExpr, "%s is not a subtype of %s", vecType.toChars(), retType.toChars());
f.patchU8(needsBoundsCheckAt, uint8_t(needsBoundsCheck));
f.patchU8(viewTypeAt, uint8_t(viewType));
*type = vecType;
return true;
}
@ -5201,7 +5283,7 @@ CheckSimdStore(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOpera
static bool
CheckSimdSelect(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
{
if (!f.writeSimdOp(opType, SimdOperation::Fn_select))
if (!SwitchPackOp(f, opType, Expr::I32X4Select, Expr::F32X4Select, Expr::Unreachable))
return false;
if (!CheckSimdCallArgs(f, call, 3, CheckSimdSelectArgs(opType)))
return false;
@ -5212,8 +5294,17 @@ CheckSimdSelect(FunctionValidator& f, ParseNode* call, SimdType opType, Type* ty
static bool
CheckSimdAllTrue(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
{
if (!f.writeSimdOp(opType, SimdOperation::Fn_allTrue))
return false;
switch (opType) {
case SimdType::Bool32x4:
if (!f.writeOp(Expr::I32B32X4AllTrue))
return false;
break;
case SimdType::Int32x4:
case SimdType::Float32x4:
MOZ_CRASH("allTrue is only defined on bool SIMD types");
default:
MOZ_CRASH("unhandled SIMD type");
}
if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType)))
return false;
*type = Type::Int;
@ -5223,8 +5314,16 @@ CheckSimdAllTrue(FunctionValidator& f, ParseNode* call, SimdType opType, Type* t
static bool
CheckSimdAnyTrue(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
{
if (!f.writeSimdOp(opType, SimdOperation::Fn_anyTrue))
return false;
switch (opType) {
case SimdType::Bool32x4:
if (!f.writeOp(Expr::I32B32X4AnyTrue))
return false;
break;
case SimdType::Int32x4:
case SimdType::Float32x4:
MOZ_CRASH("anyTrue is only defined on bool SIMD types");
default: MOZ_CRASH("unhandled simd type");
}
if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType)))
return false;
*type = Type::Int;
@ -5244,7 +5343,7 @@ CheckSimdCheck(FunctionValidator& f, ParseNode* call, SimdType opType, Type* typ
static bool
CheckSimdSplat(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
{
if (!f.writeSimdOp(opType, SimdOperation::Fn_splat))
if (!SwitchPackOp(f, opType, Expr::I32X4Splat, Expr::F32X4Splat, Expr::B32X4Splat))
return false;
if (!CheckSimdCallArgsPatchable(f, call, 1, CheckSimdScalarArgs(opType)))
return false;
@ -5260,22 +5359,36 @@ CheckSimdOperationCall(FunctionValidator& f, ParseNode* call, const ModuleValida
SimdType opType = global->simdOperationType();
switch (SimdOperation op = global->simdOperation()) {
switch (global->simdOperation()) {
case SimdOperation::Fn_check:
return CheckSimdCheck(f, call, opType, type);
#define _CASE(OP) case SimdOperation::Fn_##OP:
FOREACH_SHIFT_SIMD_OP(_CASE)
return CheckSimdBinaryShift(f, call, opType, op, type);
#define OP_CHECK_CASE_LIST_(OP) \
case SimdOperation::Fn_##OP: \
return CheckSimdBinary(f, call, opType, MSimdBinaryArith::Op_##OP, type);
FOREACH_NUMERIC_SIMD_BINOP(OP_CHECK_CASE_LIST_)
FOREACH_FLOAT_SIMD_BINOP(OP_CHECK_CASE_LIST_)
#undef OP_CHECK_CASE_LIST_
FOREACH_COMP_SIMD_OP(_CASE)
return CheckSimdBinaryComp(f, call, opType, op, type);
case SimdOperation::Fn_lessThan:
return CheckSimdBinary(f, call, opType, MSimdBinaryComp::lessThan, type);
case SimdOperation::Fn_lessThanOrEqual:
return CheckSimdBinary(f, call, opType, MSimdBinaryComp::lessThanOrEqual, type);
case SimdOperation::Fn_equal:
return CheckSimdBinary(f, call, opType, MSimdBinaryComp::equal, type);
case SimdOperation::Fn_notEqual:
return CheckSimdBinary(f, call, opType, MSimdBinaryComp::notEqual, type);
case SimdOperation::Fn_greaterThan:
return CheckSimdBinary(f, call, opType, MSimdBinaryComp::greaterThan, type);
case SimdOperation::Fn_greaterThanOrEqual:
return CheckSimdBinary(f, call, opType, MSimdBinaryComp::greaterThanOrEqual, type);
FOREACH_NUMERIC_SIMD_BINOP(_CASE)
FOREACH_FLOAT_SIMD_BINOP(_CASE)
FOREACH_BITWISE_SIMD_BINOP(_CASE)
return CheckSimdBinary(f, call, opType, op, type);
#undef _CASE
case SimdOperation::Fn_and:
return CheckSimdBinary(f, call, opType, MSimdBinaryBitwise::and_, type);
case SimdOperation::Fn_or:
return CheckSimdBinary(f, call, opType, MSimdBinaryBitwise::or_, type);
case SimdOperation::Fn_xor:
return CheckSimdBinary(f, call, opType, MSimdBinaryBitwise::xor_, type);
case SimdOperation::Fn_extractLane:
return CheckSimdExtractLane(f, call, opType, type);
@ -5283,19 +5396,37 @@ CheckSimdOperationCall(FunctionValidator& f, ParseNode* call, const ModuleValida
return CheckSimdReplaceLane(f, call, opType, type);
case SimdOperation::Fn_fromInt32x4:
case SimdOperation::Fn_fromInt32x4Bits:
return CheckSimdCast(f, call, SimdType::Int32x4, opType, op, type);
return CheckSimdCast(f, call, SimdType::Int32x4, opType, IsBitCast(false), type);
case SimdOperation::Fn_fromFloat32x4:
return CheckSimdCast(f, call, SimdType::Float32x4, opType, IsBitCast(false), type);
case SimdOperation::Fn_fromInt32x4Bits:
return CheckSimdCast(f, call, SimdType::Int32x4, opType, IsBitCast(true), type);
case SimdOperation::Fn_fromFloat32x4Bits:
return CheckSimdCast(f, call, SimdType::Float32x4, opType, op, type);
return CheckSimdCast(f, call, SimdType::Float32x4, opType, IsBitCast(true), type);
case SimdOperation::Fn_shiftLeftByScalar:
return CheckSimdBinary(f, call, opType, MSimdShift::lsh, type);
case SimdOperation::Fn_shiftRightByScalar:
return CheckSimdBinary(f, call, opType,
IsSignedIntSimdType(opType) ? MSimdShift::rsh : MSimdShift::ursh,
type);
case SimdOperation::Fn_shiftRightArithmeticByScalar:
return CheckSimdBinary(f, call, opType, MSimdShift::rsh, type);
case SimdOperation::Fn_shiftRightLogicalByScalar:
return CheckSimdBinary(f, call, opType, MSimdShift::ursh, type);
case SimdOperation::Fn_abs:
return CheckSimdUnary(f, call, opType, MSimdUnaryArith::abs, type);
case SimdOperation::Fn_neg:
return CheckSimdUnary(f, call, opType, MSimdUnaryArith::neg, type);
case SimdOperation::Fn_not:
return CheckSimdUnary(f, call, opType, MSimdUnaryArith::not_, type);
case SimdOperation::Fn_sqrt:
return CheckSimdUnary(f, call, opType, MSimdUnaryArith::sqrt, type);
case SimdOperation::Fn_reciprocalApproximation:
return CheckSimdUnary(f, call, opType, MSimdUnaryArith::reciprocalApproximation, type);
case SimdOperation::Fn_reciprocalSqrtApproximation:
return CheckSimdUnary(f, call, opType, op, type);
return CheckSimdUnary(f, call, opType, MSimdUnaryArith::reciprocalSqrtApproximation, type);
case SimdOperation::Fn_swizzle:
return CheckSimdSwizzle(f, call, opType, type);
@ -5303,15 +5434,21 @@ CheckSimdOperationCall(FunctionValidator& f, ParseNode* call, const ModuleValida
return CheckSimdShuffle(f, call, opType, type);
case SimdOperation::Fn_load:
return CheckSimdLoad(f, call, opType, 4, type);
case SimdOperation::Fn_load1:
return CheckSimdLoad(f, call, opType, 1, type);
case SimdOperation::Fn_load2:
return CheckSimdLoad(f, call, opType, 2, type);
case SimdOperation::Fn_load3:
return CheckSimdLoad(f, call, opType, op, type);
return CheckSimdLoad(f, call, opType, 3, type);
case SimdOperation::Fn_store:
return CheckSimdStore(f, call, opType, 4, type);
case SimdOperation::Fn_store1:
return CheckSimdStore(f, call, opType, 1, type);
case SimdOperation::Fn_store2:
return CheckSimdStore(f, call, opType, 2, type);
case SimdOperation::Fn_store3:
return CheckSimdStore(f, call, opType, op, type);
return CheckSimdStore(f, call, opType, 3, type);
case SimdOperation::Fn_select:
return CheckSimdSelect(f, call, opType, type);
@ -5325,7 +5462,7 @@ CheckSimdOperationCall(FunctionValidator& f, ParseNode* call, const ModuleValida
return CheckSimdAnyTrue(f, call, opType, type);
case SimdOperation::Constructor:
MOZ_CRASH("constructors are handled in CheckSimdCtorCall");
MOZ_CRASH("constructors are handled elsewhere");
case SimdOperation::Fn_fromUint32x4:
case SimdOperation::Fn_fromInt8x16Bits:
case SimdOperation::Fn_fromInt16x8Bits:
@ -5345,7 +5482,7 @@ CheckSimdCtorCall(FunctionValidator& f, ParseNode* call, const ModuleValidator::
MOZ_ASSERT(call->isKind(PNK_CALL));
SimdType simdType = global->simdCtorType();
if (!f.writeSimdOp(simdType, SimdOperation::Constructor))
if (!SwitchPackOp(f, simdType, Expr::I32X4Ctor, Expr::F32X4Ctor, Expr::B32X4Ctor))
return false;
unsigned length = SimdTypeToLength(simdType);

View File

@ -25,8 +25,6 @@ namespace js {
class PropertyName;
enum class SimdOperation : uint8_t;
namespace wasm {
// Module header constants
@ -221,8 +219,53 @@ enum class Expr : uint8_t
I32AtomicsBinOp,
// SIMD
SimdConst,
SimdOp,
I32X4Const,
B32X4Const,
F32X4Const,
I32I32X4ExtractLane,
I32B32X4ExtractLane,
I32B32X4AllTrue,
I32B32X4AnyTrue,
F32F32X4ExtractLane,
I32X4Ctor,
I32X4Unary,
I32X4Binary,
I32X4BinaryBitwise,
I32X4BinaryShift,
I32X4ReplaceLane,
I32X4FromF32X4,
I32X4FromF32X4Bits,
I32X4Swizzle,
I32X4Shuffle,
I32X4Select,
I32X4Splat,
I32X4Load,
I32X4Store,
F32X4Ctor,
F32X4Unary,
F32X4Binary,
F32X4ReplaceLane,
F32X4FromI32X4,
F32X4FromI32X4Bits,
F32X4Swizzle,
F32X4Shuffle,
F32X4Select,
F32X4Splat,
F32X4Load,
F32X4Store,
B32X4Ctor,
B32X4Unary,
B32X4Binary,
B32X4BinaryCompI32X4,
B32X4BinaryCompF32X4,
B32X4BinaryBitwise,
B32X4ReplaceLane,
B32X4Splat,
// I32 asm.js opcodes
I32Not,
@ -340,8 +383,6 @@ class Encoder
writeValType(ValType type, size_t* offset = nullptr) { return writeEnum(type, offset); }
MOZ_WARN_UNUSED_RESULT bool
writeExprType(ExprType type, size_t* offset = nullptr) { return writeEnum(type, offset); }
MOZ_WARN_UNUSED_RESULT bool
writeSimdOp(SimdOperation op, size_t* offset = nullptr) { return writeEnum(op, offset); }
MOZ_WARN_UNUSED_RESULT bool
writeU8(uint8_t i, size_t* offset = nullptr) { return write<uint8_t>(i, offset); }
@ -566,9 +607,6 @@ class Decoder
MOZ_WARN_UNUSED_RESULT bool readExprType(ExprType* type = nullptr) {
return readEnum(type);
}
MOZ_WARN_UNUSED_RESULT bool readSimdOp(SimdOperation* op = nullptr) {
return readEnum(op);
}
MOZ_WARN_UNUSED_RESULT bool readCString(const char** cstr = nullptr) {
if (cstr)
@ -658,12 +696,6 @@ class Decoder
Expr uncheckedReadExpr() {
return uncheckedReadEnum<Expr>();
}
ExprType uncheckedReadExprType() {
return uncheckedReadEnum<ExprType>();
}
SimdOperation uncheckedReadSimdOp() {
return uncheckedReadEnum<SimdOperation>();
}
Expr uncheckedPeekExpr() const {
return uncheckedPeekEnum<Expr>();
}

View File

@ -474,7 +474,7 @@ class FunctionCompiler
return;
bool needsBoundsCheck = chk == NEEDS_BOUNDS_CHECK;
MOZ_ASSERT(!Scalar::isSimdType(accessType), "SIMD stores should use storeSimdHeap");
MOZ_ASSERT(!Scalar::isSimdType(accessType), "SIMD stores should use loadSimdHeap");
MAsmJSStoreHeap* store = MAsmJSStoreHeap::New(alloc(), accessType, ptr, v, needsBoundsCheck);
curBlock_->add(store);
}
@ -1175,18 +1175,16 @@ class FunctionCompiler
/************************************************************ DECODING ***/
uint8_t readU8() { return decoder_.uncheckedReadU8(); }
uint32_t readU32() { return decoder_.uncheckedReadU32(); }
uint32_t readVarU32() { return decoder_.uncheckedReadVarU32(); }
int32_t readI32() { return decoder_.uncheckedReadI32(); }
float readF32() { return decoder_.uncheckedReadF32(); }
double readF64() { return decoder_.uncheckedReadF64(); }
SimdConstant readI32X4() { return decoder_.uncheckedReadI32X4(); }
SimdConstant readF32X4() { return decoder_.uncheckedReadF32X4(); }
Expr readOpcode() { return decoder_.uncheckedReadExpr(); }
ExprType readExprType() { return decoder_.uncheckedReadExprType(); }
SimdOperation readSimdOp() { return decoder_.uncheckedReadSimdOp(); }
Expr peekOpcode() { return decoder_.uncheckedPeekExpr(); }
uint8_t readU8() { return decoder_.uncheckedReadU8(); }
uint32_t readU32() { return decoder_.uncheckedReadU32(); }
uint32_t readVarU32() { return decoder_.uncheckedReadVarU32(); }
int32_t readI32() { return decoder_.uncheckedReadI32(); }
float readF32() { return decoder_.uncheckedReadF32(); }
double readF64() { return decoder_.uncheckedReadF64(); }
SimdConstant readI32X4() { return decoder_.uncheckedReadI32X4(); }
SimdConstant readF32X4() { return decoder_.uncheckedReadF32X4(); }
Expr readOpcode() { return decoder_.uncheckedReadExpr(); }
Expr peekOpcode() { return decoder_.uncheckedPeekExpr(); }
void readCallLineCol(uint32_t* line, uint32_t* column) {
const SourceCoords& sc = func_.sourceCoords(lastReadCallSite_++);
@ -1378,6 +1376,7 @@ EmitLoadGlobal(FunctionCompiler& f, MaybeType type, MDefinition** def)
static bool EmitExpr(FunctionCompiler&, MaybeType, MDefinition**, LabelVector* = nullptr);
static bool EmitExprStmt(FunctionCompiler&, MDefinition**, LabelVector* = nullptr);
static bool EmitSimdBooleanLaneExpr(FunctionCompiler& f, MDefinition** def);
static bool
EmitLoadArray(FunctionCompiler& f, Scalar::Type scalarType, MDefinition** def)
@ -1723,31 +1722,9 @@ EmitF64MathBuiltinCall(FunctionCompiler& f, Expr f64, MDefinition** def)
}
static bool
EmitSimdUnary(FunctionCompiler& f, ExprType type, SimdOperation simdOp, MDefinition** def)
EmitSimdUnary(FunctionCompiler& f, ExprType type, MDefinition** def)
{
MSimdUnaryArith::Operation op;
switch (simdOp) {
case SimdOperation::Fn_abs:
op = MSimdUnaryArith::abs;
break;
case SimdOperation::Fn_neg:
op = MSimdUnaryArith::neg;
break;
case SimdOperation::Fn_not:
op = MSimdUnaryArith::not_;
break;
case SimdOperation::Fn_sqrt:
op = MSimdUnaryArith::sqrt;
break;
case SimdOperation::Fn_reciprocalApproximation:
op = MSimdUnaryArith::reciprocalApproximation;
break;
case SimdOperation::Fn_reciprocalSqrtApproximation:
op = MSimdUnaryArith::reciprocalSqrtApproximation;
break;
default:
MOZ_CRASH("not a simd unary arithmetic operation");
}
MSimdUnaryArith::Operation op = MSimdUnaryArith::Operation(f.readU8());
MDefinition* in;
if (!EmitExpr(f, type, &in))
return false;
@ -1757,7 +1734,7 @@ EmitSimdUnary(FunctionCompiler& f, ExprType type, SimdOperation simdOp, MDefinit
template<class OpKind>
inline bool
EmitSimdBinary(FunctionCompiler& f, ExprType type, OpKind op, MDefinition** def)
EmitBinarySimdGuts(FunctionCompiler& f, ExprType type, OpKind op, MDefinition** def)
{
MDefinition* lhs;
if (!EmitExpr(f, type, &lhs))
@ -1770,9 +1747,23 @@ EmitSimdBinary(FunctionCompiler& f, ExprType type, OpKind op, MDefinition** def)
}
static bool
EmitSimdBinaryComp(FunctionCompiler& f, ExprType type, MSimdBinaryComp::Operation op,
MDefinition** def)
EmitSimdBinaryArith(FunctionCompiler& f, ExprType type, MDefinition** def)
{
MSimdBinaryArith::Operation op = MSimdBinaryArith::Operation(f.readU8());
return EmitBinarySimdGuts(f, type, op, def);
}
static bool
EmitSimdBinaryBitwise(FunctionCompiler& f, ExprType type, MDefinition** def)
{
MSimdBinaryBitwise::Operation op = MSimdBinaryBitwise::Operation(f.readU8());
return EmitBinarySimdGuts(f, type, op, def);
}
static bool
EmitSimdBinaryComp(FunctionCompiler& f, ExprType type, MDefinition** def)
{
MSimdBinaryComp::Operation op = MSimdBinaryComp::Operation(f.readU8());
MDefinition* lhs;
if (!EmitExpr(f, type, &lhs))
return false;
@ -1784,10 +1775,11 @@ EmitSimdBinaryComp(FunctionCompiler& f, ExprType type, MSimdBinaryComp::Operatio
}
static bool
EmitSimdShift(FunctionCompiler& f, ExprType type, MSimdShift::Operation op, MDefinition** def)
EmitSimdBinaryShift(FunctionCompiler& f, MDefinition** def)
{
MSimdShift::Operation op = MSimdShift::Operation(f.readU8());
MDefinition* lhs;
if (!EmitExpr(f, type, &lhs))
if (!EmitExpr(f, ExprType::I32x4, &lhs))
return false;
MDefinition* rhs;
if (!EmitExpr(f, ExprType::I32, &rhs))
@ -1837,19 +1829,6 @@ EmitExtractLane(FunctionCompiler& f, ExprType type, MDefinition** def)
return true;
}
// Emit an I32 expression and then convert it to a boolean SIMD lane value, i.e. -1 or 0.
static bool
EmitSimdBooleanLaneExpr(FunctionCompiler& f, MDefinition** def)
{
MDefinition* i32;
if (!EmitExpr(f, ExprType::I32, &i32))
return false;
// Now compute !i32 - 1 to force the value range into {0, -1}.
MDefinition* noti32 = f.unary<MNot>(i32);
*def = f.binary<MSub>(noti32, f.constant(Int32Value(1), MIRType_Int32), MIRType_Int32);
return true;
}
static bool
EmitSimdReplaceLane(FunctionCompiler& f, ExprType simdType, MDefinition** def)
{
@ -1927,27 +1906,12 @@ EmitSimdShuffle(FunctionCompiler& f, ExprType type, MDefinition** def)
return true;
}
static inline Scalar::Type
SimdExprTypeToViewType(ExprType type, unsigned* defaultNumElems)
{
switch (type) {
case ExprType::I32x4: *defaultNumElems = 4; return Scalar::Int32x4;
case ExprType::F32x4: *defaultNumElems = 4; return Scalar::Float32x4;
default: break;
}
MOZ_CRASH("type not handled in SimdExprTypeToViewType");
}
static bool
EmitSimdLoad(FunctionCompiler& f, ExprType type, unsigned numElems, MDefinition** def)
EmitSimdLoad(FunctionCompiler& f, MDefinition** def)
{
unsigned defaultNumElems;
Scalar::Type viewType = SimdExprTypeToViewType(type, &defaultNumElems);
if (!numElems)
numElems = defaultNumElems;
Scalar::Type viewType = Scalar::Type(f.readU8());
NeedsBoundsCheck needsBoundsCheck = NeedsBoundsCheck(f.readU8());
uint8_t numElems = f.readU8();
MDefinition* index;
if (!EmitExpr(f, ExprType::I32, &index))
@ -1958,15 +1922,11 @@ EmitSimdLoad(FunctionCompiler& f, ExprType type, unsigned numElems, MDefinition*
}
static bool
EmitSimdStore(FunctionCompiler& f, ExprType type, unsigned numElems, MDefinition** def)
EmitSimdStore(FunctionCompiler& f, ExprType type, MDefinition** def)
{
unsigned defaultNumElems;
Scalar::Type viewType = SimdExprTypeToViewType(type, &defaultNumElems);
if (!numElems)
numElems = defaultNumElems;
Scalar::Type viewType = Scalar::Type(f.readU8());
NeedsBoundsCheck needsBoundsCheck = NeedsBoundsCheck(f.readU8());
uint8_t numElems = f.readU8();
MDefinition* index;
if (!EmitExpr(f, ExprType::I32, &index))
@ -2021,16 +1981,22 @@ static bool
EmitSimdSplat(FunctionCompiler& f, ExprType type, MDefinition** def)
{
MDefinition* in;
if (IsSimdBoolType(type)) {
if (!EmitSimdBooleanLaneExpr(f, &in))
return false;
} else if (!EmitExpr(f, SimdToLaneType(type), &in)) {
if (!EmitExpr(f, SimdToLaneType(type), &in))
return false;
}
*def = f.splatSimd(in, ToMIRType(type));
return true;
}
static bool
EmitSimdBooleanSplat(FunctionCompiler& f, MDefinition** def)
{
MDefinition* in;
if (!EmitSimdBooleanLaneExpr(f, &in))
return false;
*def = f.splatSimd(in, MIRType_Bool32x4);
return true;
}
static bool
EmitSimdCtor(FunctionCompiler& f, ExprType type, MDefinition** def)
{
@ -2307,99 +2273,17 @@ EmitBitwise<MBitNot>(FunctionCompiler& f, MDefinition** def)
return true;
}
// Emit an I32 expression and then convert it to a boolean SIMD lane value, i.e. -1 or 0.
static bool
EmitSimdOp(FunctionCompiler& f, MDefinition** def)
EmitSimdBooleanLaneExpr(FunctionCompiler& f, MDefinition** def)
{
ExprType type = f.readExprType();
switch (SimdOperation op = f.readSimdOp()) {
case SimdOperation::Constructor:
return EmitSimdCtor(f, type, def);
case SimdOperation::Fn_extractLane:
return EmitExtractLane(f, type, def);
case SimdOperation::Fn_replaceLane:
return EmitSimdReplaceLane(f, type, def);
case SimdOperation::Fn_check:
MOZ_CRASH("only used in asm.js' type system");
case SimdOperation::Fn_splat:
return EmitSimdSplat(f, type, def);
case SimdOperation::Fn_select:
return EmitSimdSelect(f, type, def);
case SimdOperation::Fn_swizzle:
return EmitSimdSwizzle(f, type, def);
case SimdOperation::Fn_shuffle:
return EmitSimdShuffle(f, type, def);
case SimdOperation::Fn_load:
return EmitSimdLoad(f, type, 0, def);
case SimdOperation::Fn_load1:
return EmitSimdLoad(f, type, 1, def);
case SimdOperation::Fn_load2:
return EmitSimdLoad(f, type, 2, def);
case SimdOperation::Fn_load3:
return EmitSimdLoad(f, type, 3, def);
case SimdOperation::Fn_store:
return EmitSimdStore(f, type, 0, def);
case SimdOperation::Fn_store1:
return EmitSimdStore(f, type, 1, def);
case SimdOperation::Fn_store2:
return EmitSimdStore(f, type, 2, def);
case SimdOperation::Fn_store3:
return EmitSimdStore(f, type, 3, def);
case SimdOperation::Fn_allTrue:
return EmitSimdAllTrue(f, type, def);
case SimdOperation::Fn_anyTrue:
return EmitSimdAnyTrue(f, type, def);
case SimdOperation::Fn_abs:
case SimdOperation::Fn_neg:
case SimdOperation::Fn_not:
case SimdOperation::Fn_sqrt:
case SimdOperation::Fn_reciprocalApproximation:
case SimdOperation::Fn_reciprocalSqrtApproximation:
return EmitSimdUnary(f, type, op, def);
case SimdOperation::Fn_shiftLeftByScalar:
return EmitSimdShift(f, type, MSimdShift::lsh, def);
case SimdOperation::Fn_shiftRightByScalar:
return EmitSimdShift(f, type,
type == ExprType::I32x4 ? MSimdShift::rsh : MSimdShift::ursh,
def);
case SimdOperation::Fn_shiftRightArithmeticByScalar:
return EmitSimdShift(f, type, MSimdShift::rsh, def);
case SimdOperation::Fn_shiftRightLogicalByScalar:
return EmitSimdShift(f, type, MSimdShift::ursh, def);
#define _CASE(OP) \
case SimdOperation::Fn_##OP: \
return EmitSimdBinaryComp(f, type, MSimdBinaryComp::OP, def);
FOREACH_COMP_SIMD_OP(_CASE)
#undef _CASE
case SimdOperation::Fn_and:
return EmitSimdBinary(f, type, MSimdBinaryBitwise::and_, def);
case SimdOperation::Fn_or:
return EmitSimdBinary(f, type, MSimdBinaryBitwise::or_, def);
case SimdOperation::Fn_xor:
return EmitSimdBinary(f, type, MSimdBinaryBitwise::xor_, def);
#define _CASE(OP) \
case SimdOperation::Fn_##OP: \
return EmitSimdBinary(f, type, MSimdBinaryArith::Op_##OP, def);
FOREACH_NUMERIC_SIMD_BINOP(_CASE)
FOREACH_FLOAT_SIMD_BINOP(_CASE)
#undef _CASE
case SimdOperation::Fn_fromFloat32x4:
return EmitSimdCast<MSimdConvert>(f, ExprType::F32x4, type, def);
case SimdOperation::Fn_fromInt32x4:
return EmitSimdCast<MSimdConvert>(f, ExprType::I32x4, type, def);
case SimdOperation::Fn_fromInt32x4Bits:
return EmitSimdCast<MSimdReinterpretCast>(f, ExprType::I32x4, type, def);
case SimdOperation::Fn_fromFloat32x4Bits:
return EmitSimdCast<MSimdReinterpretCast>(f, ExprType::F32x4, type, def);
case SimdOperation::Fn_fromUint32x4:
case SimdOperation::Fn_fromInt8x16Bits:
case SimdOperation::Fn_fromInt16x8Bits:
case SimdOperation::Fn_fromUint8x16Bits:
case SimdOperation::Fn_fromUint16x8Bits:
case SimdOperation::Fn_fromUint32x4Bits:
case SimdOperation::Fn_fromFloat64x2Bits:
MOZ_CRASH("NYI");
}
MOZ_CRASH("unexpected opcode");
MDefinition* i32;
if (!EmitExpr(f, ExprType::I32, &i32))
return false;
// Now compute !i32 - 1 to force the value range into {0, -1}.
MDefinition* noti32 = f.unary<MNot>(i32);
*def = f.binary<MSub>(noti32, f.constant(Int32Value(1), MIRType_Int32), MIRType_Int32);
return true;
}
static bool
@ -2839,6 +2723,14 @@ EmitExpr(FunctionCompiler& f, MaybeType type, MDefinition** def, LabelVector* ma
return EmitAtomicsStore(f, def);
case Expr::I32AtomicsBinOp:
return EmitAtomicsBinOp(f, def);
case Expr::I32I32X4ExtractLane:
return EmitExtractLane(f, ExprType::I32x4, def);
case Expr::I32B32X4ExtractLane:
return EmitExtractLane(f, ExprType::B32x4, def);
case Expr::I32B32X4AllTrue:
return EmitSimdAllTrue(f, ExprType::B32x4, def);
case Expr::I32B32X4AnyTrue:
return EmitSimdAnyTrue(f, ExprType::B32x4, def);
// F32
case Expr::F32Const:
return EmitLiteral(f, ExprType::F32, def);
@ -2875,6 +2767,8 @@ EmitExpr(FunctionCompiler& f, MaybeType type, MDefinition** def, LabelVector* ma
return EmitStore(f, Scalar::Float32, def);
case Expr::F32StoreMemF64:
return EmitStoreWithCoercion(f, Scalar::Float32, Scalar::Float64, def);
case Expr::F32F32X4ExtractLane:
return EmitExtractLane(f, ExprType::F32x4, def);
// F64
case Expr::F64Const:
return EmitLiteral(f, ExprType::F64, def);
@ -2923,11 +2817,83 @@ EmitExpr(FunctionCompiler& f, MaybeType type, MDefinition** def, LabelVector* ma
return EmitStore(f, Scalar::Float64, def);
case Expr::F64StoreMemF32:
return EmitStoreWithCoercion(f, Scalar::Float64, Scalar::Float32, def);
// SIMD
case Expr::SimdConst:
return EmitLiteral(f, f.readExprType(), def);
case Expr::SimdOp:
return EmitSimdOp(f, def);
// I32x4
case Expr::I32X4Const:
return EmitLiteral(f, ExprType::I32x4, def);
case Expr::I32X4Ctor:
return EmitSimdCtor(f, ExprType::I32x4, def);
case Expr::I32X4Unary:
return EmitSimdUnary(f, ExprType::I32x4, def);
case Expr::I32X4Binary:
return EmitSimdBinaryArith(f, ExprType::I32x4, def);
case Expr::I32X4BinaryBitwise:
return EmitSimdBinaryBitwise(f, ExprType::I32x4, def);
case Expr::I32X4BinaryShift:
return EmitSimdBinaryShift(f, def);
case Expr::I32X4ReplaceLane:
return EmitSimdReplaceLane(f, ExprType::I32x4, def);
case Expr::I32X4FromF32X4:
return EmitSimdCast<MSimdConvert>(f, ExprType::F32x4, ExprType::I32x4, def);
case Expr::I32X4FromF32X4Bits:
return EmitSimdCast<MSimdReinterpretCast>(f, ExprType::F32x4, ExprType::I32x4, def);
case Expr::I32X4Swizzle:
return EmitSimdSwizzle(f, ExprType::I32x4, def);
case Expr::I32X4Shuffle:
return EmitSimdShuffle(f, ExprType::I32x4, def);
case Expr::I32X4Select:
return EmitSimdSelect(f, ExprType::I32x4, def);
case Expr::I32X4Splat:
return EmitSimdSplat(f, ExprType::I32x4, def);
case Expr::I32X4Load:
return EmitSimdLoad(f, def);
case Expr::I32X4Store:
return EmitSimdStore(f, ExprType::I32x4, def);
// F32x4
case Expr::F32X4Const:
return EmitLiteral(f, ExprType::F32x4, def);
case Expr::F32X4Ctor:
return EmitSimdCtor(f, ExprType::F32x4, def);
case Expr::F32X4Unary:
return EmitSimdUnary(f, ExprType::F32x4, def);
case Expr::F32X4Binary:
return EmitSimdBinaryArith(f, ExprType::F32x4, def);
case Expr::F32X4ReplaceLane:
return EmitSimdReplaceLane(f, ExprType::F32x4, def);
case Expr::F32X4FromI32X4:
return EmitSimdCast<MSimdConvert>(f, ExprType::I32x4, ExprType::F32x4, def);
case Expr::F32X4FromI32X4Bits:
return EmitSimdCast<MSimdReinterpretCast>(f, ExprType::I32x4, ExprType::F32x4, def);
case Expr::F32X4Swizzle:
return EmitSimdSwizzle(f, ExprType::F32x4, def);
case Expr::F32X4Shuffle:
return EmitSimdShuffle(f, ExprType::F32x4, def);
case Expr::F32X4Select:
return EmitSimdSelect(f, ExprType::F32x4, def);
case Expr::F32X4Splat:
return EmitSimdSplat(f, ExprType::F32x4, def);
case Expr::F32X4Load:
return EmitSimdLoad(f, def);
case Expr::F32X4Store:
return EmitSimdStore(f, ExprType::F32x4, def);
// B32x4
case Expr::B32X4Const:
return EmitLiteral(f, ExprType::B32x4, def);
case Expr::B32X4Ctor:
return EmitSimdCtor(f, ExprType::B32x4, def);
case Expr::B32X4Unary:
return EmitSimdUnary(f, ExprType::B32x4, def);
case Expr::B32X4Binary:
return EmitSimdBinaryArith(f, ExprType::B32x4, def);
case Expr::B32X4BinaryBitwise:
return EmitSimdBinaryBitwise(f, ExprType::B32x4, def);
case Expr::B32X4BinaryCompI32X4:
return EmitSimdBinaryComp(f, ExprType::I32x4, def);
case Expr::B32X4BinaryCompF32X4:
return EmitSimdBinaryComp(f, ExprType::F32x4, def);
case Expr::B32X4ReplaceLane:
return EmitSimdReplaceLane(f, ExprType::B32x4, def);
case Expr::B32X4Splat:
return EmitSimdBooleanSplat(f, def);
case Expr::Loop:
case Expr::Select:
case Expr::Br: