зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
c2d519ab45
Коммит
b433b6eb43
|
@ -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:
|
||||
|
|
Загрузка…
Ссылка в новой задаче