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(Which w) : which_(w) {}
MOZ_IMPLICIT Type(SimdType type) { MOZ_IMPLICIT Type(SimdType type) {
switch (type) { switch (type) {
case SimdType::Int32x4: which_ = Int32x4; return; case SimdType::Int32x4:
case SimdType::Float32x4: which_ = Float32x4; return; which_ = Int32x4;
case SimdType::Bool32x4: which_ = Bool32x4; return; return;
default: break; case SimdType::Float32x4:
which_ = Float32x4;
return;
case SimdType::Bool32x4:
which_ = Bool32x4;
return;
default:
break;
} }
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("bad SimdType"); MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("bad SimdType");
} }
@ -2294,18 +2301,6 @@ IsCallToGlobal(ModuleValidator& m, ParseNode* pn, const ModuleValidator::Global*
return !!*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 static bool
IsCoercionCall(ModuleValidator& m, ParseNode* pn, ValType* coerceTo, ParseNode** coercedExpr) 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) { if (global->isSimdOperation() && global->simdOperation() == SimdOperation::Fn_check) {
*coerceTo = ToValType(global->simdOperationType()); switch (global->simdOperationType()) {
return true; 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; return false;
@ -2721,16 +2727,6 @@ class MOZ_STACK_CLASS FunctionValidator
bool writeOp(Expr op) { bool writeOp(Expr op) {
return encoder().writeExpr(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 MOZ_WARN_UNUSED_RESULT
bool writeDebugCheckPoint() { bool writeDebugCheckPoint() {
@ -2773,15 +2769,12 @@ class MOZ_STACK_CLASS FunctionValidator
case NumLit::Double: case NumLit::Double:
return writeOp(Expr::F64Const) && encoder().writeF64(lit.toDouble()); return writeOp(Expr::F64Const) && encoder().writeF64(lit.toDouble());
case NumLit::Int32x4: case NumLit::Int32x4:
return writeOp(Expr::SimdConst) && writeExprType(ExprType::I32x4) && return writeOp(Expr::I32X4Const) && encoder().writeI32X4(lit.simdValue().asInt32x4());
encoder().writeI32X4(lit.simdValue().asInt32x4());
case NumLit::Float32x4: case NumLit::Float32x4:
return writeOp(Expr::SimdConst) && writeExprType(ExprType::F32x4) && return writeOp(Expr::F32X4Const) && encoder().writeF32X4(lit.simdValue().asFloat32x4());
encoder().writeF32X4(lit.simdValue().asFloat32x4());
case NumLit::Bool32x4: case NumLit::Bool32x4:
// Boolean vectors use the Int32x4 memory representation. // Boolean vectors use the Int32x4 memory representation.
return writeOp(Expr::SimdConst) && writeExprType(ExprType::B32x4) && return writeOp(Expr::B32X4Const) && encoder().writeI32X4(lit.simdValue().asInt32x4());
encoder().writeI32X4(lit.simdValue().asInt32x4());
case NumLit::OutOfRangeInt: case NumLit::OutOfRangeInt:
break; break;
} }
@ -4948,10 +4941,24 @@ class CheckSimdReplaceLaneArgs
} // namespace } // namespace
static bool static bool
CheckSimdUnary(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op, SwitchPackOp(FunctionValidator& f, SimdType type, Expr i32x4, Expr f32x4, Expr b32x4)
Type* type)
{ {
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; return false;
if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType))) if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType)))
return false; return false;
@ -4959,23 +4966,54 @@ CheckSimdUnary(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOpera
return true; return true;
} }
static bool template<class OpKind>
CheckSimdBinaryShift(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op, inline bool
Type *type) CheckSimdBinaryGuts(FunctionValidator& f, ParseNode* call, SimdType opType, OpKind op,
Type* type)
{ {
if (!f.writeSimdOp(opType, op)) if (!f.writeU8(uint8_t(op)))
return false; return false;
if (!CheckSimdCallArgs(f, call, 2, CheckSimdVectorScalarArgs(opType))) if (!CheckSimdCallArgs(f, call, 2, CheckArgIsSubtypeOf(opType)))
return false; return false;
*type = Type::Int32x4; *type = opType;
return true; return true;
} }
static bool static bool
CheckSimdBinaryComp(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op, CheckSimdBinary(FunctionValidator& f, ParseNode* call, SimdType opType,
Type *type) 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; return false;
if (!CheckSimdCallArgs(f, call, 2, CheckArgIsSubtypeOf(opType))) if (!CheckSimdCallArgs(f, call, 2, CheckArgIsSubtypeOf(opType)))
return false; return false;
@ -4984,27 +5022,38 @@ CheckSimdBinaryComp(FunctionValidator& f, ParseNode* call, SimdType opType, Simd
} }
static bool static bool
CheckSimdBinary(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op, CheckSimdBinary(FunctionValidator& f, ParseNode* call, SimdType opType,
Type* type) MSimdShift::Operation op, Type* type)
{ {
if (!f.writeSimdOp(opType, op)) if (!f.writeOp(Expr::I32X4BinaryShift) || !f.writeU8(uint8_t(op)))
return false; return false;
if (!CheckSimdCallArgs(f, call, 2, CheckArgIsSubtypeOf(opType))) if (!CheckSimdCallArgs(f, call, 2, CheckSimdVectorScalarArgs(opType)))
return false; return false;
*type = opType; *type = Type::Int32x4;
return true; return true;
} }
static bool static bool
CheckSimdExtractLane(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type) CheckSimdExtractLane(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
{ {
if (!f.writeSimdOp(opType, SimdOperation::Fn_extractLane))
return false;
switch (opType) { switch (opType) {
case SimdType::Int32x4: *type = Type::Signed; break; case SimdType::Int32x4:
case SimdType::Float32x4: *type = Type::Float; break; if (!f.writeOp(Expr::I32I32X4ExtractLane))
case SimdType::Bool32x4: *type = Type::Int; break; return false;
default: MOZ_CRASH("unhandled simd type"); *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)); return CheckSimdCallArgs(f, call, 2, CheckSimdExtractLaneArgs(opType));
} }
@ -5012,7 +5061,7 @@ CheckSimdExtractLane(FunctionValidator& f, ParseNode* call, SimdType opType, Typ
static bool static bool
CheckSimdReplaceLane(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type) 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; return false;
if (!CheckSimdCallArgsPatchable(f, call, 3, CheckSimdReplaceLaneArgs(opType))) if (!CheckSimdCallArgsPatchable(f, call, 3, CheckSimdReplaceLaneArgs(opType)))
return false; return false;
@ -5020,17 +5069,22 @@ CheckSimdReplaceLane(FunctionValidator& f, ParseNode* call, SimdType opType, Typ
return true; return true;
} }
typedef bool Bitcast; typedef bool IsBitCast;
namespace { namespace {
// Include CheckSimdCast in unnamed namespace to avoid MSVC name lookup bug (due to the use of Type). // Include CheckSimdCast in unnamed namespace to avoid MSVC name lookup bug (due to the use of Type).
static bool static bool
CheckSimdCast(FunctionValidator& f, ParseNode* call, SimdType fromType, SimdType toType, 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; return false;
}
if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(fromType))) if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(fromType)))
return false; return false;
*type = toType; *type = toType;
@ -5060,7 +5114,7 @@ CheckSimdSwizzle(FunctionValidator& f, ParseNode* call, SimdType opType, Type* t
if (numArgs != 5) if (numArgs != 5)
return f.failf(call, "expected 5 arguments to SIMD swizzle, got %u", numArgs); 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; return false;
Type retType = opType; Type retType = opType;
@ -5091,7 +5145,7 @@ CheckSimdShuffle(FunctionValidator& f, ParseNode* call, SimdType opType, Type* t
if (numArgs != 6) if (numArgs != 6)
return f.failf(call, "expected 6 arguments to SIMD shuffle, got %u", numArgs); 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; return false;
Type retType = opType; Type retType = opType;
@ -5118,7 +5172,8 @@ CheckSimdShuffle(FunctionValidator& f, ParseNode* call, SimdType opType, Type* t
} }
static bool static bool
CheckSimdLoadStoreArgs(FunctionValidator& f, ParseNode* call) CheckSimdLoadStoreArgs(FunctionValidator& f, ParseNode* call, SimdType opType,
Scalar::Type* viewType, NeedsBoundsCheck* needsBoundsCheck)
{ {
ParseNode* view = CallArgList(call); ParseNode* view = CallArgList(call);
if (!view->isKind(PNK_NAME)) 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"); 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); ParseNode* indexExpr = NextNode(view);
uint32_t indexLit; uint32_t indexLit;
if (IsLiteralOrConstInt(f, indexExpr, &indexLit)) { if (IsLiteralOrConstInt(f, indexExpr, &indexLit)) {
if (!f.m().tryConstantAccess(indexLit, Simd128DataSize)) if (!f.m().tryConstantAccess(indexLit, Simd128DataSize))
return f.fail(indexExpr, "constant index out of range"); return f.fail(indexExpr, "constant index out of range");
return f.writeU8(NO_BOUNDS_CHECK) && f.writeInt32Lit(indexLit);
}
if (!f.writeU8(NEEDS_BOUNDS_CHECK)) *needsBoundsCheck = NO_BOUNDS_CHECK;
return false; return f.writeInt32Lit(indexLit);
}
Type indexType; Type indexType;
if (!CheckExpr(f, indexExpr, &indexType)) if (!CheckExpr(f, indexExpr, &indexType))
@ -5154,35 +5217,52 @@ CheckSimdLoadStoreArgs(FunctionValidator& f, ParseNode* call)
} }
static bool static bool
CheckSimdLoad(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op, CheckSimdLoad(FunctionValidator& f, ParseNode* call, SimdType opType,
Type* type) unsigned numElems, Type* type)
{ {
unsigned numArgs = CallArgListLength(call); unsigned numArgs = CallArgListLength(call);
if (numArgs != 2) if (numArgs != 2)
return f.failf(call, "expected 2 arguments to SIMD load, got %u", numArgs); 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; return false;
if (!CheckSimdLoadStoreArgs(f, call)) size_t viewTypeAt;
size_t needsBoundsCheckAt;
if (!f.tempU8(&viewTypeAt) || !f.tempU8(&needsBoundsCheckAt) || !f.writeU8(numElems))
return false; 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; *type = opType;
return true; return true;
} }
static bool static bool
CheckSimdStore(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op, CheckSimdStore(FunctionValidator& f, ParseNode* call, SimdType opType,
Type* type) unsigned numElems, Type* type)
{ {
unsigned numArgs = CallArgListLength(call); unsigned numArgs = CallArgListLength(call);
if (numArgs != 3) if (numArgs != 3)
return f.failf(call, "expected 3 arguments to SIMD store, got %u", numArgs); 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; 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; return false;
Type retType = opType; Type retType = opType;
@ -5190,10 +5270,12 @@ CheckSimdStore(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOpera
Type vecType; Type vecType;
if (!CheckExpr(f, vecExpr, &vecType)) if (!CheckExpr(f, vecExpr, &vecType))
return false; return false;
if (!(vecType <= retType)) if (!(vecType <= retType))
return f.failf(vecExpr, "%s is not a subtype of %s", vecType.toChars(), retType.toChars()); 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; *type = vecType;
return true; return true;
} }
@ -5201,7 +5283,7 @@ CheckSimdStore(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOpera
static bool static bool
CheckSimdSelect(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type) 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; return false;
if (!CheckSimdCallArgs(f, call, 3, CheckSimdSelectArgs(opType))) if (!CheckSimdCallArgs(f, call, 3, CheckSimdSelectArgs(opType)))
return false; return false;
@ -5212,8 +5294,17 @@ CheckSimdSelect(FunctionValidator& f, ParseNode* call, SimdType opType, Type* ty
static bool static bool
CheckSimdAllTrue(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type) CheckSimdAllTrue(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
{ {
if (!f.writeSimdOp(opType, SimdOperation::Fn_allTrue)) switch (opType) {
return false; 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))) if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType)))
return false; return false;
*type = Type::Int; *type = Type::Int;
@ -5223,8 +5314,16 @@ CheckSimdAllTrue(FunctionValidator& f, ParseNode* call, SimdType opType, Type* t
static bool static bool
CheckSimdAnyTrue(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type) CheckSimdAnyTrue(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
{ {
if (!f.writeSimdOp(opType, SimdOperation::Fn_anyTrue)) switch (opType) {
return false; 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))) if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType)))
return false; return false;
*type = Type::Int; *type = Type::Int;
@ -5244,7 +5343,7 @@ CheckSimdCheck(FunctionValidator& f, ParseNode* call, SimdType opType, Type* typ
static bool static bool
CheckSimdSplat(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type) 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; return false;
if (!CheckSimdCallArgsPatchable(f, call, 1, CheckSimdScalarArgs(opType))) if (!CheckSimdCallArgsPatchable(f, call, 1, CheckSimdScalarArgs(opType)))
return false; return false;
@ -5260,22 +5359,36 @@ CheckSimdOperationCall(FunctionValidator& f, ParseNode* call, const ModuleValida
SimdType opType = global->simdOperationType(); SimdType opType = global->simdOperationType();
switch (SimdOperation op = global->simdOperation()) { switch (global->simdOperation()) {
case SimdOperation::Fn_check: case SimdOperation::Fn_check:
return CheckSimdCheck(f, call, opType, type); return CheckSimdCheck(f, call, opType, type);
#define _CASE(OP) case SimdOperation::Fn_##OP: #define OP_CHECK_CASE_LIST_(OP) \
FOREACH_SHIFT_SIMD_OP(_CASE) case SimdOperation::Fn_##OP: \
return CheckSimdBinaryShift(f, call, opType, op, type); 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) case SimdOperation::Fn_lessThan:
return CheckSimdBinaryComp(f, call, opType, op, type); 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) case SimdOperation::Fn_and:
FOREACH_FLOAT_SIMD_BINOP(_CASE) return CheckSimdBinary(f, call, opType, MSimdBinaryBitwise::and_, type);
FOREACH_BITWISE_SIMD_BINOP(_CASE) case SimdOperation::Fn_or:
return CheckSimdBinary(f, call, opType, op, type); return CheckSimdBinary(f, call, opType, MSimdBinaryBitwise::or_, type);
#undef _CASE case SimdOperation::Fn_xor:
return CheckSimdBinary(f, call, opType, MSimdBinaryBitwise::xor_, type);
case SimdOperation::Fn_extractLane: case SimdOperation::Fn_extractLane:
return CheckSimdExtractLane(f, call, opType, type); return CheckSimdExtractLane(f, call, opType, type);
@ -5283,19 +5396,37 @@ CheckSimdOperationCall(FunctionValidator& f, ParseNode* call, const ModuleValida
return CheckSimdReplaceLane(f, call, opType, type); return CheckSimdReplaceLane(f, call, opType, type);
case SimdOperation::Fn_fromInt32x4: case SimdOperation::Fn_fromInt32x4:
case SimdOperation::Fn_fromInt32x4Bits: return CheckSimdCast(f, call, SimdType::Int32x4, opType, IsBitCast(false), type);
return CheckSimdCast(f, call, SimdType::Int32x4, opType, op, type);
case SimdOperation::Fn_fromFloat32x4: 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: 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: case SimdOperation::Fn_abs:
return CheckSimdUnary(f, call, opType, MSimdUnaryArith::abs, type);
case SimdOperation::Fn_neg: case SimdOperation::Fn_neg:
return CheckSimdUnary(f, call, opType, MSimdUnaryArith::neg, type);
case SimdOperation::Fn_not: case SimdOperation::Fn_not:
return CheckSimdUnary(f, call, opType, MSimdUnaryArith::not_, type);
case SimdOperation::Fn_sqrt: case SimdOperation::Fn_sqrt:
return CheckSimdUnary(f, call, opType, MSimdUnaryArith::sqrt, type);
case SimdOperation::Fn_reciprocalApproximation: case SimdOperation::Fn_reciprocalApproximation:
return CheckSimdUnary(f, call, opType, MSimdUnaryArith::reciprocalApproximation, type);
case SimdOperation::Fn_reciprocalSqrtApproximation: case SimdOperation::Fn_reciprocalSqrtApproximation:
return CheckSimdUnary(f, call, opType, op, type); return CheckSimdUnary(f, call, opType, MSimdUnaryArith::reciprocalSqrtApproximation, type);
case SimdOperation::Fn_swizzle: case SimdOperation::Fn_swizzle:
return CheckSimdSwizzle(f, call, opType, type); return CheckSimdSwizzle(f, call, opType, type);
@ -5303,15 +5434,21 @@ CheckSimdOperationCall(FunctionValidator& f, ParseNode* call, const ModuleValida
return CheckSimdShuffle(f, call, opType, type); return CheckSimdShuffle(f, call, opType, type);
case SimdOperation::Fn_load: case SimdOperation::Fn_load:
return CheckSimdLoad(f, call, opType, 4, type);
case SimdOperation::Fn_load1: case SimdOperation::Fn_load1:
return CheckSimdLoad(f, call, opType, 1, type);
case SimdOperation::Fn_load2: case SimdOperation::Fn_load2:
return CheckSimdLoad(f, call, opType, 2, type);
case SimdOperation::Fn_load3: case SimdOperation::Fn_load3:
return CheckSimdLoad(f, call, opType, op, type); return CheckSimdLoad(f, call, opType, 3, type);
case SimdOperation::Fn_store: case SimdOperation::Fn_store:
return CheckSimdStore(f, call, opType, 4, type);
case SimdOperation::Fn_store1: case SimdOperation::Fn_store1:
return CheckSimdStore(f, call, opType, 1, type);
case SimdOperation::Fn_store2: case SimdOperation::Fn_store2:
return CheckSimdStore(f, call, opType, 2, type);
case SimdOperation::Fn_store3: case SimdOperation::Fn_store3:
return CheckSimdStore(f, call, opType, op, type); return CheckSimdStore(f, call, opType, 3, type);
case SimdOperation::Fn_select: case SimdOperation::Fn_select:
return CheckSimdSelect(f, call, opType, type); return CheckSimdSelect(f, call, opType, type);
@ -5325,7 +5462,7 @@ CheckSimdOperationCall(FunctionValidator& f, ParseNode* call, const ModuleValida
return CheckSimdAnyTrue(f, call, opType, type); return CheckSimdAnyTrue(f, call, opType, type);
case SimdOperation::Constructor: case SimdOperation::Constructor:
MOZ_CRASH("constructors are handled in CheckSimdCtorCall"); MOZ_CRASH("constructors are handled elsewhere");
case SimdOperation::Fn_fromUint32x4: case SimdOperation::Fn_fromUint32x4:
case SimdOperation::Fn_fromInt8x16Bits: case SimdOperation::Fn_fromInt8x16Bits:
case SimdOperation::Fn_fromInt16x8Bits: case SimdOperation::Fn_fromInt16x8Bits:
@ -5345,7 +5482,7 @@ CheckSimdCtorCall(FunctionValidator& f, ParseNode* call, const ModuleValidator::
MOZ_ASSERT(call->isKind(PNK_CALL)); MOZ_ASSERT(call->isKind(PNK_CALL));
SimdType simdType = global->simdCtorType(); SimdType simdType = global->simdCtorType();
if (!f.writeSimdOp(simdType, SimdOperation::Constructor)) if (!SwitchPackOp(f, simdType, Expr::I32X4Ctor, Expr::F32X4Ctor, Expr::B32X4Ctor))
return false; return false;
unsigned length = SimdTypeToLength(simdType); unsigned length = SimdTypeToLength(simdType);

View File

@ -25,8 +25,6 @@ namespace js {
class PropertyName; class PropertyName;
enum class SimdOperation : uint8_t;
namespace wasm { namespace wasm {
// Module header constants // Module header constants
@ -221,8 +219,53 @@ enum class Expr : uint8_t
I32AtomicsBinOp, I32AtomicsBinOp,
// SIMD // SIMD
SimdConst, I32X4Const,
SimdOp, 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 // I32 asm.js opcodes
I32Not, I32Not,
@ -340,8 +383,6 @@ class Encoder
writeValType(ValType type, size_t* offset = nullptr) { return writeEnum(type, offset); } writeValType(ValType type, size_t* offset = nullptr) { return writeEnum(type, offset); }
MOZ_WARN_UNUSED_RESULT bool MOZ_WARN_UNUSED_RESULT bool
writeExprType(ExprType type, size_t* offset = nullptr) { return writeEnum(type, offset); } 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 MOZ_WARN_UNUSED_RESULT bool
writeU8(uint8_t i, size_t* offset = nullptr) { return write<uint8_t>(i, offset); } 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) { MOZ_WARN_UNUSED_RESULT bool readExprType(ExprType* type = nullptr) {
return readEnum(type); 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) { MOZ_WARN_UNUSED_RESULT bool readCString(const char** cstr = nullptr) {
if (cstr) if (cstr)
@ -658,12 +696,6 @@ class Decoder
Expr uncheckedReadExpr() { Expr uncheckedReadExpr() {
return uncheckedReadEnum<Expr>(); return uncheckedReadEnum<Expr>();
} }
ExprType uncheckedReadExprType() {
return uncheckedReadEnum<ExprType>();
}
SimdOperation uncheckedReadSimdOp() {
return uncheckedReadEnum<SimdOperation>();
}
Expr uncheckedPeekExpr() const { Expr uncheckedPeekExpr() const {
return uncheckedPeekEnum<Expr>(); return uncheckedPeekEnum<Expr>();
} }

View File

@ -474,7 +474,7 @@ class FunctionCompiler
return; return;
bool needsBoundsCheck = chk == NEEDS_BOUNDS_CHECK; 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); MAsmJSStoreHeap* store = MAsmJSStoreHeap::New(alloc(), accessType, ptr, v, needsBoundsCheck);
curBlock_->add(store); curBlock_->add(store);
} }
@ -1175,18 +1175,16 @@ class FunctionCompiler
/************************************************************ DECODING ***/ /************************************************************ DECODING ***/
uint8_t readU8() { return decoder_.uncheckedReadU8(); } uint8_t readU8() { return decoder_.uncheckedReadU8(); }
uint32_t readU32() { return decoder_.uncheckedReadU32(); } uint32_t readU32() { return decoder_.uncheckedReadU32(); }
uint32_t readVarU32() { return decoder_.uncheckedReadVarU32(); } uint32_t readVarU32() { return decoder_.uncheckedReadVarU32(); }
int32_t readI32() { return decoder_.uncheckedReadI32(); } int32_t readI32() { return decoder_.uncheckedReadI32(); }
float readF32() { return decoder_.uncheckedReadF32(); } float readF32() { return decoder_.uncheckedReadF32(); }
double readF64() { return decoder_.uncheckedReadF64(); } double readF64() { return decoder_.uncheckedReadF64(); }
SimdConstant readI32X4() { return decoder_.uncheckedReadI32X4(); } SimdConstant readI32X4() { return decoder_.uncheckedReadI32X4(); }
SimdConstant readF32X4() { return decoder_.uncheckedReadF32X4(); } SimdConstant readF32X4() { return decoder_.uncheckedReadF32X4(); }
Expr readOpcode() { return decoder_.uncheckedReadExpr(); } Expr readOpcode() { return decoder_.uncheckedReadExpr(); }
ExprType readExprType() { return decoder_.uncheckedReadExprType(); } Expr peekOpcode() { return decoder_.uncheckedPeekExpr(); }
SimdOperation readSimdOp() { return decoder_.uncheckedReadSimdOp(); }
Expr peekOpcode() { return decoder_.uncheckedPeekExpr(); }
void readCallLineCol(uint32_t* line, uint32_t* column) { void readCallLineCol(uint32_t* line, uint32_t* column) {
const SourceCoords& sc = func_.sourceCoords(lastReadCallSite_++); 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 EmitExpr(FunctionCompiler&, MaybeType, MDefinition**, LabelVector* = nullptr);
static bool EmitExprStmt(FunctionCompiler&, MDefinition**, LabelVector* = nullptr); static bool EmitExprStmt(FunctionCompiler&, MDefinition**, LabelVector* = nullptr);
static bool EmitSimdBooleanLaneExpr(FunctionCompiler& f, MDefinition** def);
static bool static bool
EmitLoadArray(FunctionCompiler& f, Scalar::Type scalarType, MDefinition** def) EmitLoadArray(FunctionCompiler& f, Scalar::Type scalarType, MDefinition** def)
@ -1723,31 +1722,9 @@ EmitF64MathBuiltinCall(FunctionCompiler& f, Expr f64, MDefinition** def)
} }
static bool static bool
EmitSimdUnary(FunctionCompiler& f, ExprType type, SimdOperation simdOp, MDefinition** def) EmitSimdUnary(FunctionCompiler& f, ExprType type, MDefinition** def)
{ {
MSimdUnaryArith::Operation op; MSimdUnaryArith::Operation op = MSimdUnaryArith::Operation(f.readU8());
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");
}
MDefinition* in; MDefinition* in;
if (!EmitExpr(f, type, &in)) if (!EmitExpr(f, type, &in))
return false; return false;
@ -1757,7 +1734,7 @@ EmitSimdUnary(FunctionCompiler& f, ExprType type, SimdOperation simdOp, MDefinit
template<class OpKind> template<class OpKind>
inline bool inline bool
EmitSimdBinary(FunctionCompiler& f, ExprType type, OpKind op, MDefinition** def) EmitBinarySimdGuts(FunctionCompiler& f, ExprType type, OpKind op, MDefinition** def)
{ {
MDefinition* lhs; MDefinition* lhs;
if (!EmitExpr(f, type, &lhs)) if (!EmitExpr(f, type, &lhs))
@ -1770,9 +1747,23 @@ EmitSimdBinary(FunctionCompiler& f, ExprType type, OpKind op, MDefinition** def)
} }
static bool static bool
EmitSimdBinaryComp(FunctionCompiler& f, ExprType type, MSimdBinaryComp::Operation op, EmitSimdBinaryArith(FunctionCompiler& f, ExprType type, MDefinition** def)
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; MDefinition* lhs;
if (!EmitExpr(f, type, &lhs)) if (!EmitExpr(f, type, &lhs))
return false; return false;
@ -1784,10 +1775,11 @@ EmitSimdBinaryComp(FunctionCompiler& f, ExprType type, MSimdBinaryComp::Operatio
} }
static bool 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; MDefinition* lhs;
if (!EmitExpr(f, type, &lhs)) if (!EmitExpr(f, ExprType::I32x4, &lhs))
return false; return false;
MDefinition* rhs; MDefinition* rhs;
if (!EmitExpr(f, ExprType::I32, &rhs)) if (!EmitExpr(f, ExprType::I32, &rhs))
@ -1837,19 +1829,6 @@ EmitExtractLane(FunctionCompiler& f, ExprType type, MDefinition** def)
return true; 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 static bool
EmitSimdReplaceLane(FunctionCompiler& f, ExprType simdType, MDefinition** def) EmitSimdReplaceLane(FunctionCompiler& f, ExprType simdType, MDefinition** def)
{ {
@ -1927,27 +1906,12 @@ EmitSimdShuffle(FunctionCompiler& f, ExprType type, MDefinition** def)
return true; 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 static bool
EmitSimdLoad(FunctionCompiler& f, ExprType type, unsigned numElems, MDefinition** def) EmitSimdLoad(FunctionCompiler& f, MDefinition** def)
{ {
unsigned defaultNumElems; Scalar::Type viewType = Scalar::Type(f.readU8());
Scalar::Type viewType = SimdExprTypeToViewType(type, &defaultNumElems);
if (!numElems)
numElems = defaultNumElems;
NeedsBoundsCheck needsBoundsCheck = NeedsBoundsCheck(f.readU8()); NeedsBoundsCheck needsBoundsCheck = NeedsBoundsCheck(f.readU8());
uint8_t numElems = f.readU8();
MDefinition* index; MDefinition* index;
if (!EmitExpr(f, ExprType::I32, &index)) if (!EmitExpr(f, ExprType::I32, &index))
@ -1958,15 +1922,11 @@ EmitSimdLoad(FunctionCompiler& f, ExprType type, unsigned numElems, MDefinition*
} }
static bool static bool
EmitSimdStore(FunctionCompiler& f, ExprType type, unsigned numElems, MDefinition** def) EmitSimdStore(FunctionCompiler& f, ExprType type, MDefinition** def)
{ {
unsigned defaultNumElems; Scalar::Type viewType = Scalar::Type(f.readU8());
Scalar::Type viewType = SimdExprTypeToViewType(type, &defaultNumElems);
if (!numElems)
numElems = defaultNumElems;
NeedsBoundsCheck needsBoundsCheck = NeedsBoundsCheck(f.readU8()); NeedsBoundsCheck needsBoundsCheck = NeedsBoundsCheck(f.readU8());
uint8_t numElems = f.readU8();
MDefinition* index; MDefinition* index;
if (!EmitExpr(f, ExprType::I32, &index)) if (!EmitExpr(f, ExprType::I32, &index))
@ -2021,16 +1981,22 @@ static bool
EmitSimdSplat(FunctionCompiler& f, ExprType type, MDefinition** def) EmitSimdSplat(FunctionCompiler& f, ExprType type, MDefinition** def)
{ {
MDefinition* in; MDefinition* in;
if (IsSimdBoolType(type)) { if (!EmitExpr(f, SimdToLaneType(type), &in))
if (!EmitSimdBooleanLaneExpr(f, &in))
return false;
} else if (!EmitExpr(f, SimdToLaneType(type), &in)) {
return false; return false;
}
*def = f.splatSimd(in, ToMIRType(type)); *def = f.splatSimd(in, ToMIRType(type));
return true; 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 static bool
EmitSimdCtor(FunctionCompiler& f, ExprType type, MDefinition** def) EmitSimdCtor(FunctionCompiler& f, ExprType type, MDefinition** def)
{ {
@ -2307,99 +2273,17 @@ EmitBitwise<MBitNot>(FunctionCompiler& f, MDefinition** def)
return true; return true;
} }
// Emit an I32 expression and then convert it to a boolean SIMD lane value, i.e. -1 or 0.
static bool static bool
EmitSimdOp(FunctionCompiler& f, MDefinition** def) EmitSimdBooleanLaneExpr(FunctionCompiler& f, MDefinition** def)
{ {
ExprType type = f.readExprType(); MDefinition* i32;
switch (SimdOperation op = f.readSimdOp()) { if (!EmitExpr(f, ExprType::I32, &i32))
case SimdOperation::Constructor: return false;
return EmitSimdCtor(f, type, def); // Now compute !i32 - 1 to force the value range into {0, -1}.
case SimdOperation::Fn_extractLane: MDefinition* noti32 = f.unary<MNot>(i32);
return EmitExtractLane(f, type, def); *def = f.binary<MSub>(noti32, f.constant(Int32Value(1), MIRType_Int32), MIRType_Int32);
case SimdOperation::Fn_replaceLane: return true;
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");
} }
static bool static bool
@ -2839,6 +2723,14 @@ EmitExpr(FunctionCompiler& f, MaybeType type, MDefinition** def, LabelVector* ma
return EmitAtomicsStore(f, def); return EmitAtomicsStore(f, def);
case Expr::I32AtomicsBinOp: case Expr::I32AtomicsBinOp:
return EmitAtomicsBinOp(f, def); 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 // F32
case Expr::F32Const: case Expr::F32Const:
return EmitLiteral(f, ExprType::F32, def); 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); return EmitStore(f, Scalar::Float32, def);
case Expr::F32StoreMemF64: case Expr::F32StoreMemF64:
return EmitStoreWithCoercion(f, Scalar::Float32, Scalar::Float64, def); return EmitStoreWithCoercion(f, Scalar::Float32, Scalar::Float64, def);
case Expr::F32F32X4ExtractLane:
return EmitExtractLane(f, ExprType::F32x4, def);
// F64 // F64
case Expr::F64Const: case Expr::F64Const:
return EmitLiteral(f, ExprType::F64, def); 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); return EmitStore(f, Scalar::Float64, def);
case Expr::F64StoreMemF32: case Expr::F64StoreMemF32:
return EmitStoreWithCoercion(f, Scalar::Float64, Scalar::Float32, def); return EmitStoreWithCoercion(f, Scalar::Float64, Scalar::Float32, def);
// SIMD // I32x4
case Expr::SimdConst: case Expr::I32X4Const:
return EmitLiteral(f, f.readExprType(), def); return EmitLiteral(f, ExprType::I32x4, def);
case Expr::SimdOp: case Expr::I32X4Ctor:
return EmitSimdOp(f, def); 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::Loop:
case Expr::Select: case Expr::Select:
case Expr::Br: case Expr::Br: