Bug 1241454: Change SIMD opcodes encoding in wasm; r=luke, r=jolesen

--HG--
extra : commitid : 4Pb1lbtI2PR
extra : rebase_source : aef1fd1fa5c99db3b17960e567f6a7e18ea1f30c
extra : histedit_source : 5c8e820573043540797486e4b8f13bfc523f7c57%2C1b3030f2f903dce710c697d2e23e7e3f5dd31f6a
This commit is contained in:
Benjamin Bouvier 2016-01-26 14:22:24 +01:00
Родитель c2d519ab45
Коммит b433b6eb43
3 изменённых файлов: 375 добавлений и 460 удалений

Просмотреть файл

@ -1082,17 +1082,10 @@ 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");
}
@ -2301,6 +2294,18 @@ 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)
{
@ -2320,19 +2325,8 @@ IsCoercionCall(ModuleValidator& m, ParseNode* pn, ValType* coerceTo, ParseNode**
}
if (global->isSimdOperation() && global->simdOperation() == SimdOperation::Fn_check) {
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");
}
*coerceTo = ToValType(global->simdOperationType());
return true;
}
return false;
@ -2580,6 +2574,41 @@ IsLiteralInt(ModuleValidator& m, ParseNode* pn, uint32_t* u32)
namespace {
#define CASE(TYPE, OP) case SimdOperation::Fn_##OP: return Expr::TYPE##OP;
#define I32CASE(OP) CASE(I32x4, OP)
#define F32CASE(OP) CASE(F32x4, OP)
#define B32CASE(OP) CASE(B32x4, OP)
#define ENUMERATE(TYPE, FOR_ALL, DO) \
switch(op) { \
case SimdOperation::Constructor: return Expr::TYPE##Constructor; \
FOR_ALL(DO) \
default: break; \
}
static inline Expr
SimdToExpr(SimdType type, SimdOperation op)
{
switch (type) {
case SimdType::Int32x4: {
ENUMERATE(I32x4, FORALL_INT32X4_ASMJS_OP, I32CASE)
}
case SimdType::Float32x4: {
ENUMERATE(F32x4, FORALL_FLOAT32X4_ASMJS_OP, F32CASE)
}
case SimdType::Bool32x4: {
ENUMERATE(B32x4, FORALL_BOOL_SIMD_OP, B32CASE)
}
default: break;
}
MOZ_CRASH("unexpected SIMD type x operator combination");
}
#undef CASE
#undef I32CASE
#undef F32CASE
#undef B32CASE
#undef ENUMERATE
// Encapsulates the building of an asm bytecode function from an asm.js function
// source code, packing the asm.js code into the asm bytecode form that can
// be decoded and compiled with a FunctionCompiler.
@ -2727,6 +2756,14 @@ 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(SimdToExpr(simdType, op));
}
MOZ_WARN_UNUSED_RESULT
bool writeDebugCheckPoint() {
@ -2769,12 +2806,12 @@ class MOZ_STACK_CLASS FunctionValidator
case NumLit::Double:
return writeOp(Expr::F64Const) && encoder().writeF64(lit.toDouble());
case NumLit::Int32x4:
return writeOp(Expr::I32X4Const) && encoder().writeI32X4(lit.simdValue().asInt32x4());
return writeOp(Expr::I32x4Const) && encoder().writeI32X4(lit.simdValue().asInt32x4());
case NumLit::Float32x4:
return writeOp(Expr::F32X4Const) && 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::B32X4Const) && encoder().writeI32X4(lit.simdValue().asInt32x4());
return writeOp(Expr::B32x4Const) && encoder().writeI32X4(lit.simdValue().asInt32x4());
case NumLit::OutOfRangeInt:
break;
}
@ -4941,24 +4978,10 @@ class CheckSimdReplaceLaneArgs
} // namespace
static bool
SwitchPackOp(FunctionValidator& f, SimdType type, Expr i32x4, Expr f32x4, Expr b32x4)
CheckSimdUnary(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op,
Type* type)
{
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)))
if (!f.writeSimdOp(opType, op))
return false;
if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType)))
return false;
@ -4966,66 +4989,11 @@ CheckSimdUnary(FunctionValidator& f, ParseNode* call, SimdType opType,
return true;
}
template<class OpKind>
inline bool
CheckSimdBinaryGuts(FunctionValidator& f, ParseNode* call, SimdType opType, OpKind op,
Type* type)
{
if (!f.writeU8(uint8_t(op)))
return false;
if (!CheckSimdCallArgs(f, call, 2, CheckArgIsSubtypeOf(opType)))
return false;
*type = opType;
return true;
}
static bool
CheckSimdBinary(FunctionValidator& f, ParseNode* call, SimdType opType,
MSimdBinaryArith::Operation op, Type* type)
CheckSimdBinaryShift(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op,
Type *type)
{
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;
*type = Type::Bool32x4;
return true;
}
static bool
CheckSimdBinary(FunctionValidator& f, ParseNode* call, SimdType opType,
MSimdShift::Operation op, Type* type)
{
if (!f.writeOp(Expr::I32X4BinaryShift) || !f.writeU8(uint8_t(op)))
if (!f.writeSimdOp(opType, op))
return false;
if (!CheckSimdCallArgs(f, call, 2, CheckSimdVectorScalarArgs(opType)))
return false;
@ -5033,27 +5001,40 @@ CheckSimdBinary(FunctionValidator& f, ParseNode* call, SimdType opType,
return true;
}
static bool
CheckSimdBinaryComp(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op,
Type *type)
{
if (!f.writeSimdOp(opType, op))
return false;
if (!CheckSimdCallArgs(f, call, 2, CheckArgIsSubtypeOf(opType)))
return false;
*type = Type::Bool32x4;
return true;
}
static bool
CheckSimdBinary(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op,
Type* type)
{
if (!f.writeSimdOp(opType, op))
return false;
if (!CheckSimdCallArgs(f, call, 2, CheckArgIsSubtypeOf(opType)))
return false;
*type = opType;
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:
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");
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");
}
return CheckSimdCallArgs(f, call, 2, CheckSimdExtractLaneArgs(opType));
}
@ -5061,7 +5042,7 @@ CheckSimdExtractLane(FunctionValidator& f, ParseNode* call, SimdType opType, Typ
static bool
CheckSimdReplaceLane(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
{
if (!SwitchPackOp(f, opType, Expr::I32X4ReplaceLane, Expr::F32X4ReplaceLane, Expr::B32X4ReplaceLane))
if (!f.writeSimdOp(opType, SimdOperation::Fn_replaceLane))
return false;
if (!CheckSimdCallArgsPatchable(f, call, 3, CheckSimdReplaceLaneArgs(opType)))
return false;
@ -5069,22 +5050,17 @@ CheckSimdReplaceLane(FunctionValidator& f, ParseNode* call, SimdType opType, Typ
return true;
}
typedef bool IsBitCast;
typedef bool Bitcast;
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,
bool bitcast, Type* type)
SimdOperation op, Type* type)
{
if (!SwitchPackOp(f, toType,
bitcast ? Expr::I32X4FromF32X4Bits : Expr::I32X4FromF32X4,
bitcast ? Expr::F32X4FromI32X4Bits : Expr::F32X4FromI32X4,
Expr::Unreachable))
{
if (!f.writeSimdOp(toType, op))
return false;
}
if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(fromType)))
return false;
*type = toType;
@ -5114,7 +5090,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 (!SwitchPackOp(f, opType, Expr::I32X4Swizzle, Expr::F32X4Swizzle, Expr::Unreachable))
if (!f.writeSimdOp(opType, SimdOperation::Fn_swizzle))
return false;
Type retType = opType;
@ -5145,7 +5121,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 (!SwitchPackOp(f, opType, Expr::I32X4Shuffle, Expr::F32X4Shuffle, Expr::Unreachable))
if (!f.writeSimdOp(opType, SimdOperation::Fn_shuffle))
return false;
Type retType = opType;
@ -5172,8 +5148,7 @@ CheckSimdShuffle(FunctionValidator& f, ParseNode* call, SimdType opType, Type* t
}
static bool
CheckSimdLoadStoreArgs(FunctionValidator& f, ParseNode* call, SimdType opType,
Scalar::Type* viewType, NeedsBoundsCheck* needsBoundsCheck)
CheckSimdLoadStoreArgs(FunctionValidator& f, ParseNode* call)
{
ParseNode* view = CallArgList(call);
if (!view->isKind(PNK_NAME))
@ -5187,25 +5162,17 @@ CheckSimdLoadStoreArgs(FunctionValidator& f, ParseNode* call, SimdType opType,
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");
*needsBoundsCheck = NO_BOUNDS_CHECK;
return f.writeInt32Lit(indexLit);
return f.writeU8(NO_BOUNDS_CHECK) && f.writeInt32Lit(indexLit);
}
if (!f.writeU8(NEEDS_BOUNDS_CHECK))
return false;
Type indexType;
if (!CheckExpr(f, indexExpr, &indexType))
return false;
@ -5217,52 +5184,35 @@ CheckSimdLoadStoreArgs(FunctionValidator& f, ParseNode* call, SimdType opType,
}
static bool
CheckSimdLoad(FunctionValidator& f, ParseNode* call, SimdType opType,
unsigned numElems, Type* type)
CheckSimdLoad(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op,
Type* type)
{
unsigned numArgs = CallArgListLength(call);
if (numArgs != 2)
return f.failf(call, "expected 2 arguments to SIMD load, got %u", numArgs);
if (!SwitchPackOp(f, opType, Expr::I32X4Load, Expr::F32X4Load, Expr::Unreachable))
if (!f.writeSimdOp(opType, op))
return false;
size_t viewTypeAt;
size_t needsBoundsCheckAt;
if (!f.tempU8(&viewTypeAt) || !f.tempU8(&needsBoundsCheckAt) || !f.writeU8(numElems))
if (!CheckSimdLoadStoreArgs(f, call))
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,
unsigned numElems, Type* type)
CheckSimdStore(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op,
Type* type)
{
unsigned numArgs = CallArgListLength(call);
if (numArgs != 3)
return f.failf(call, "expected 3 arguments to SIMD store, got %u", numArgs);
if (!SwitchPackOp(f, opType, Expr::I32X4Store, Expr::F32X4Store, Expr::Unreachable))
if (!f.writeSimdOp(opType, op))
return false;
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))
if (!CheckSimdLoadStoreArgs(f, call))
return false;
Type retType = opType;
@ -5270,12 +5220,10 @@ CheckSimdStore(FunctionValidator& f, ParseNode* call, SimdType opType,
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;
}
@ -5283,7 +5231,7 @@ CheckSimdStore(FunctionValidator& f, ParseNode* call, SimdType opType,
static bool
CheckSimdSelect(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
{
if (!SwitchPackOp(f, opType, Expr::I32X4Select, Expr::F32X4Select, Expr::Unreachable))
if (!f.writeSimdOp(opType, SimdOperation::Fn_select))
return false;
if (!CheckSimdCallArgs(f, call, 3, CheckSimdSelectArgs(opType)))
return false;
@ -5294,17 +5242,8 @@ CheckSimdSelect(FunctionValidator& f, ParseNode* call, SimdType opType, Type* ty
static bool
CheckSimdAllTrue(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
{
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 (!f.writeSimdOp(opType, SimdOperation::Fn_allTrue))
return false;
if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType)))
return false;
*type = Type::Int;
@ -5314,16 +5253,8 @@ CheckSimdAllTrue(FunctionValidator& f, ParseNode* call, SimdType opType, Type* t
static bool
CheckSimdAnyTrue(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
{
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 (!f.writeSimdOp(opType, SimdOperation::Fn_anyTrue))
return false;
if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType)))
return false;
*type = Type::Int;
@ -5343,7 +5274,7 @@ CheckSimdCheck(FunctionValidator& f, ParseNode* call, SimdType opType, Type* typ
static bool
CheckSimdSplat(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
{
if (!SwitchPackOp(f, opType, Expr::I32X4Splat, Expr::F32X4Splat, Expr::B32X4Splat))
if (!f.writeSimdOp(opType, SimdOperation::Fn_splat))
return false;
if (!CheckSimdCallArgsPatchable(f, call, 1, CheckSimdScalarArgs(opType)))
return false;
@ -5359,36 +5290,22 @@ CheckSimdOperationCall(FunctionValidator& f, ParseNode* call, const ModuleValida
SimdType opType = global->simdOperationType();
switch (global->simdOperation()) {
switch (SimdOperation op = global->simdOperation()) {
case SimdOperation::Fn_check:
return CheckSimdCheck(f, call, opType, 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_
#define _CASE(OP) case SimdOperation::Fn_##OP:
FOREACH_SHIFT_SIMD_OP(_CASE)
return CheckSimdBinaryShift(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_COMP_SIMD_OP(_CASE)
return CheckSimdBinaryComp(f, call, opType, op, type);
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);
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_extractLane:
return CheckSimdExtractLane(f, call, opType, type);
@ -5396,37 +5313,19 @@ CheckSimdOperationCall(FunctionValidator& f, ParseNode* call, const ModuleValida
return CheckSimdReplaceLane(f, call, opType, type);
case SimdOperation::Fn_fromInt32x4:
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);
return CheckSimdCast(f, call, SimdType::Int32x4, opType, op, type);
case SimdOperation::Fn_fromFloat32x4:
case SimdOperation::Fn_fromFloat32x4Bits:
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);
return CheckSimdCast(f, call, SimdType::Float32x4, opType, op, 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, MSimdUnaryArith::reciprocalSqrtApproximation, type);
return CheckSimdUnary(f, call, opType, op, type);
case SimdOperation::Fn_swizzle:
return CheckSimdSwizzle(f, call, opType, type);
@ -5434,21 +5333,15 @@ 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, 3, type);
return CheckSimdLoad(f, call, opType, op, 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, 3, type);
return CheckSimdStore(f, call, opType, op, type);
case SimdOperation::Fn_select:
return CheckSimdSelect(f, call, opType, type);
@ -5462,7 +5355,7 @@ CheckSimdOperationCall(FunctionValidator& f, ParseNode* call, const ModuleValida
return CheckSimdAnyTrue(f, call, opType, type);
case SimdOperation::Constructor:
MOZ_CRASH("constructors are handled elsewhere");
MOZ_CRASH("constructors are handled in CheckSimdCtorCall");
case SimdOperation::Fn_fromUint32x4:
case SimdOperation::Fn_fromInt8x16Bits:
case SimdOperation::Fn_fromInt16x8Bits:
@ -5482,7 +5375,7 @@ CheckSimdCtorCall(FunctionValidator& f, ParseNode* call, const ModuleValidator::
MOZ_ASSERT(call->isKind(PNK_CALL));
SimdType simdType = global->simdCtorType();
if (!SwitchPackOp(f, simdType, Expr::I32X4Ctor, Expr::F32X4Ctor, Expr::B32X4Ctor))
if (!f.writeSimdOp(simdType, SimdOperation::Constructor))
return false;
unsigned length = SimdTypeToLength(simdType);

Просмотреть файл

@ -20,6 +20,7 @@
#define wasm_binary_h
#include "asmjs/WasmTypes.h"
#include "builtin/SIMD.h"
namespace js {
@ -41,7 +42,7 @@ static const char EndSection[] = "";
// Subsection names:
static const char FuncSubsection[] = "func";
enum class Expr : uint8_t
enum class Expr : uint16_t
{
// Control opcodes
Nop,
@ -219,53 +220,23 @@ enum class Expr : uint8_t
I32AtomicsBinOp,
// SIMD
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,
#define SIMD_OPCODE(TYPE, OP) TYPE##OP,
#define _(OP) SIMD_OPCODE(I32x4, OP)
FORALL_INT32X4_ASMJS_OP(_)
I32x4Constructor,
I32x4Const,
#undef _
#define _(OP) SIMD_OPCODE(F32x4, OP)
FORALL_FLOAT32X4_ASMJS_OP(_)
F32x4Constructor,
F32x4Const,
#undef _
#define _(OP) SIMD_OPCODE(B32x4, OP)
FORALL_BOOL_SIMD_OP(_)
B32x4Constructor,
B32x4Const,
#undef _
#undef OPCODE
// I32 asm.js opcodes
I32Not,
@ -328,21 +299,21 @@ class Encoder
template <class T>
MOZ_WARN_UNUSED_RESULT
bool writeEnum(T v, size_t* offset) {
// For now, just write a u8 instead of a variable-length integer.
// For now, just write a u16 instead of a variable-length integer.
// Variable-length is somewhat annoying at the moment due to the
// pre-order encoding and back-patching; let's see if we switch to
// post-order first.
static_assert(mozilla::IsEnum<T>::value, "is an enum");
MOZ_ASSERT(uint64_t(v) < UINT8_MAX);
return writeU8(uint8_t(v), offset);
MOZ_ASSERT(uint64_t(v) < UINT16_MAX);
return write<uint16_t>(uint16_t(v), offset);
}
template <class T>
void patchEnum(size_t pc, T v) {
// See writeEnum comment.
static_assert(mozilla::IsEnum<T>::value, "is an enum");
MOZ_ASSERT(uint64_t(v) < UINT8_MAX);
bytecode_[pc] = uint8_t(v);
MOZ_ASSERT(uint64_t(v) < UINT16_MAX);
memcpy(&bytecode_[pc], &v, sizeof(uint16_t));
}
template <class T>
@ -448,7 +419,8 @@ class Encoder
bytecode_[pc] = i;
}
void patchExpr(size_t pc, Expr expr) {
MOZ_ASSERT(pcIsPatchable(pc, sizeof(uint8_t)));
// See comment in writeEnum
MOZ_ASSERT(pcIsPatchable(pc, sizeof(uint16_t)));
patchEnum(pc, expr);
}
template<class T>
@ -482,11 +454,11 @@ class Decoder
readEnum(T* out) {
static_assert(mozilla::IsEnum<T>::value, "is an enum");
// See Encoder::writeEnum.
uint8_t u8;
if (!read(&u8))
uint16_t u16;
if (!read(&u16))
return false;
if (out)
*out = T(u8);
*out = T(u16);
return true;
}
@ -502,7 +474,7 @@ class Decoder
T uncheckedPeekEnum() const {
// See Encoder::writeEnum.
static_assert(mozilla::IsEnum<T>::value, "is an enum");
return (T)uncheckedPeek<uint8_t>();
return (T)uncheckedPeek<uint16_t>();
}
template <class T>
@ -516,7 +488,7 @@ class Decoder
T uncheckedReadEnum() {
// See Encoder::writeEnum.
static_assert(mozilla::IsEnum<T>::value, "is an enum");
return (T)uncheckedReadU8();
return (T)uncheckedRead<uint16_t>();
}
public:

Просмотреть файл

@ -474,7 +474,7 @@ class FunctionCompiler
return;
bool needsBoundsCheck = chk == NEEDS_BOUNDS_CHECK;
MOZ_ASSERT(!Scalar::isSimdType(accessType), "SIMD stores should use loadSimdHeap");
MOZ_ASSERT(!Scalar::isSimdType(accessType), "SIMD stores should use storeSimdHeap");
MAsmJSStoreHeap* store = MAsmJSStoreHeap::New(alloc(), accessType, ptr, v, needsBoundsCheck);
curBlock_->add(store);
}
@ -1175,16 +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(); }
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_++);
@ -1311,7 +1311,7 @@ class MaybeType
};
static bool
EmitLiteral(FunctionCompiler& f, ExprType type, MDefinition**def)
EmitLiteral(FunctionCompiler& f, ExprType type, MDefinition** def)
{
switch (type) {
case ExprType::I32: {
@ -1376,7 +1376,6 @@ 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)
@ -1722,9 +1721,31 @@ EmitF64MathBuiltinCall(FunctionCompiler& f, Expr f64, MDefinition** def)
}
static bool
EmitSimdUnary(FunctionCompiler& f, ExprType type, MDefinition** def)
EmitSimdUnary(FunctionCompiler& f, ExprType type, SimdOperation simdOp, MDefinition** def)
{
MSimdUnaryArith::Operation op = MSimdUnaryArith::Operation(f.readU8());
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");
}
MDefinition* in;
if (!EmitExpr(f, type, &in))
return false;
@ -1734,7 +1755,7 @@ EmitSimdUnary(FunctionCompiler& f, ExprType type, MDefinition** def)
template<class OpKind>
inline bool
EmitBinarySimdGuts(FunctionCompiler& f, ExprType type, OpKind op, MDefinition** def)
EmitSimdBinary(FunctionCompiler& f, ExprType type, OpKind op, MDefinition** def)
{
MDefinition* lhs;
if (!EmitExpr(f, type, &lhs))
@ -1747,23 +1768,9 @@ EmitBinarySimdGuts(FunctionCompiler& f, ExprType type, OpKind op, MDefinition**
}
static bool
EmitSimdBinaryArith(FunctionCompiler& f, ExprType type, MDefinition** def)
EmitSimdBinaryComp(FunctionCompiler& f, ExprType type, MSimdBinaryComp::Operation op,
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;
@ -1775,11 +1782,10 @@ EmitSimdBinaryComp(FunctionCompiler& f, ExprType type, MDefinition** def)
}
static bool
EmitSimdBinaryShift(FunctionCompiler& f, MDefinition** def)
EmitSimdShift(FunctionCompiler& f, ExprType type, MSimdShift::Operation op, MDefinition** def)
{
MSimdShift::Operation op = MSimdShift::Operation(f.readU8());
MDefinition* lhs;
if (!EmitExpr(f, ExprType::I32x4, &lhs))
if (!EmitExpr(f, type, &lhs))
return false;
MDefinition* rhs;
if (!EmitExpr(f, ExprType::I32, &rhs))
@ -1829,6 +1835,19 @@ 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)
{
@ -1906,12 +1925,27 @@ EmitSimdShuffle(FunctionCompiler& f, ExprType type, MDefinition** def)
return true;
}
static bool
EmitSimdLoad(FunctionCompiler& f, MDefinition** def)
static inline Scalar::Type
SimdExprTypeToViewType(ExprType type, unsigned* defaultNumElems)
{
Scalar::Type viewType = Scalar::Type(f.readU8());
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)
{
unsigned defaultNumElems;
Scalar::Type viewType = SimdExprTypeToViewType(type, &defaultNumElems);
if (!numElems)
numElems = defaultNumElems;
NeedsBoundsCheck needsBoundsCheck = NeedsBoundsCheck(f.readU8());
uint8_t numElems = f.readU8();
MDefinition* index;
if (!EmitExpr(f, ExprType::I32, &index))
@ -1922,11 +1956,15 @@ EmitSimdLoad(FunctionCompiler& f, MDefinition** def)
}
static bool
EmitSimdStore(FunctionCompiler& f, ExprType type, MDefinition** def)
EmitSimdStore(FunctionCompiler& f, ExprType type, unsigned numElems, MDefinition** def)
{
Scalar::Type viewType = Scalar::Type(f.readU8());
unsigned defaultNumElems;
Scalar::Type viewType = SimdExprTypeToViewType(type, &defaultNumElems);
if (!numElems)
numElems = defaultNumElems;
NeedsBoundsCheck needsBoundsCheck = NeedsBoundsCheck(f.readU8());
uint8_t numElems = f.readU8();
MDefinition* index;
if (!EmitExpr(f, ExprType::I32, &index))
@ -1981,22 +2019,16 @@ static bool
EmitSimdSplat(FunctionCompiler& f, ExprType type, MDefinition** def)
{
MDefinition* in;
if (!EmitExpr(f, SimdToLaneType(type), &in))
if (IsSimdBoolType(type)) {
if (!EmitSimdBooleanLaneExpr(f, &in))
return false;
} else 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)
{
@ -2273,17 +2305,98 @@ 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
EmitSimdBooleanLaneExpr(FunctionCompiler& f, MDefinition** def)
EmitSimdOp(FunctionCompiler& f, ExprType type, SimdOperation op, 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;
switch (op) {
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");
}
static bool
@ -2723,14 +2836,6 @@ 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);
@ -2767,8 +2872,6 @@ 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);
@ -2817,83 +2920,30 @@ 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);
// 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);
// SIMD
#define CASE(TYPE, OP) \
case Expr::TYPE##OP: \
return EmitSimdOp(f, ExprType::TYPE, SimdOperation::Fn_##OP, def);
#define I32CASE(OP) CASE(I32x4, OP)
#define F32CASE(OP) CASE(F32x4, OP)
#define B32CASE(OP) CASE(B32x4, OP)
#define ENUMERATE(TYPE, FORALL, DO) \
case Expr::TYPE##Const: \
return EmitLiteral(f, ExprType::TYPE, def); \
case Expr::TYPE##Constructor: \
return EmitSimdOp(f, ExprType::TYPE, SimdOperation::Constructor, def); \
FORALL(DO)
ENUMERATE(I32x4, FORALL_INT32X4_ASMJS_OP, I32CASE)
ENUMERATE(F32x4, FORALL_FLOAT32X4_ASMJS_OP, F32CASE)
ENUMERATE(B32x4, FORALL_BOOL_SIMD_OP, B32CASE)
#undef CASE
#undef I32CASE
#undef F32CASE
#undef B32CASE
#undef ENUMERATE
// Future opcodes
case Expr::Loop:
case Expr::Select:
case Expr::Br: