mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1241454: Change SIMD opcodes encoding in wasm; r=luke, r=jolesen
This commit is contained in:
parent
b4d84742e4
commit
dd59e56f50
@ -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;
|
||||
@ -2727,6 +2721,16 @@ class MOZ_STACK_CLASS FunctionValidator
|
||||
bool writeOp(Expr op) {
|
||||
return encoder().writeExpr(op);
|
||||
}
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
bool writeExprType(ExprType type) {
|
||||
return encoder().writeExprType(type);
|
||||
}
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
bool writeSimdOp(SimdType simdType, SimdOperation op) {
|
||||
return writeOp(Expr::SimdOp) &&
|
||||
encoder().writeExprType(ToExprType(ToValType(simdType))) &&
|
||||
encoder().writeSimdOp(op);
|
||||
}
|
||||
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
bool writeDebugCheckPoint() {
|
||||
@ -2769,12 +2773,15 @@ 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::SimdConst) && writeExprType(ExprType::I32x4) &&
|
||||
encoder().writeI32X4(lit.simdValue().asInt32x4());
|
||||
case NumLit::Float32x4:
|
||||
return writeOp(Expr::F32X4Const) && encoder().writeF32X4(lit.simdValue().asFloat32x4());
|
||||
return writeOp(Expr::SimdConst) && writeExprType(ExprType::F32x4) &&
|
||||
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::SimdConst) && writeExprType(ExprType::B32x4) &&
|
||||
encoder().writeI32X4(lit.simdValue().asInt32x4());
|
||||
case NumLit::OutOfRangeInt:
|
||||
break;
|
||||
}
|
||||
@ -4941,24 +4948,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 +4959,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 +4971,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 +5012,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 +5020,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 +5060,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 +5091,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 +5118,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 +5132,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 +5154,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 +5190,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 +5201,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 +5212,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 +5223,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 +5244,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 +5260,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 +5283,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 +5303,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 +5325,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 +5345,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);
|
||||
|
@ -25,6 +25,8 @@ namespace js {
|
||||
|
||||
class PropertyName;
|
||||
|
||||
enum class SimdOperation : uint8_t;
|
||||
|
||||
namespace wasm {
|
||||
|
||||
// Module header constants
|
||||
@ -219,53 +221,8 @@ 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,
|
||||
SimdConst,
|
||||
SimdOp,
|
||||
|
||||
// I32 asm.js opcodes
|
||||
I32Not,
|
||||
@ -383,6 +340,8 @@ class Encoder
|
||||
writeValType(ValType type, size_t* offset = nullptr) { return writeEnum(type, offset); }
|
||||
MOZ_WARN_UNUSED_RESULT bool
|
||||
writeExprType(ExprType type, size_t* offset = nullptr) { return writeEnum(type, offset); }
|
||||
MOZ_WARN_UNUSED_RESULT bool
|
||||
writeSimdOp(SimdOperation op, size_t* offset = nullptr) { return writeEnum(op, offset); }
|
||||
|
||||
MOZ_WARN_UNUSED_RESULT bool
|
||||
writeU8(uint8_t i, size_t* offset = nullptr) { return write<uint8_t>(i, offset); }
|
||||
@ -607,6 +566,9 @@ class Decoder
|
||||
MOZ_WARN_UNUSED_RESULT bool readExprType(ExprType* type = nullptr) {
|
||||
return readEnum(type);
|
||||
}
|
||||
MOZ_WARN_UNUSED_RESULT bool readSimdOp(SimdOperation* op = nullptr) {
|
||||
return readEnum(op);
|
||||
}
|
||||
|
||||
MOZ_WARN_UNUSED_RESULT bool readCString(const char** cstr = nullptr) {
|
||||
if (cstr)
|
||||
@ -696,6 +658,12 @@ class Decoder
|
||||
Expr uncheckedReadExpr() {
|
||||
return uncheckedReadEnum<Expr>();
|
||||
}
|
||||
ExprType uncheckedReadExprType() {
|
||||
return uncheckedReadEnum<ExprType>();
|
||||
}
|
||||
SimdOperation uncheckedReadSimdOp() {
|
||||
return uncheckedReadEnum<SimdOperation>();
|
||||
}
|
||||
Expr uncheckedPeekExpr() const {
|
||||
return uncheckedPeekEnum<Expr>();
|
||||
}
|
||||
|
@ -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,18 @@ 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(); }
|
||||
ExprType readExprType() { return decoder_.uncheckedReadExprType(); }
|
||||
SimdOperation readSimdOp() { return decoder_.uncheckedReadSimdOp(); }
|
||||
Expr peekOpcode() { return decoder_.uncheckedPeekExpr(); }
|
||||
|
||||
void readCallLineCol(uint32_t* line, uint32_t* column) {
|
||||
const SourceCoords& sc = func_.sourceCoords(lastReadCallSite_++);
|
||||
@ -1376,7 +1378,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 +1723,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 +1757,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 +1770,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 +1784,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 +1837,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 +1927,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 +1958,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 +2021,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 +2307,99 @@ 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, 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;
|
||||
ExprType type = f.readExprType();
|
||||
switch (SimdOperation op = f.readSimdOp()) {
|
||||
case SimdOperation::Constructor:
|
||||
return EmitSimdCtor(f, type, def);
|
||||
case SimdOperation::Fn_extractLane:
|
||||
return EmitExtractLane(f, type, def);
|
||||
case SimdOperation::Fn_replaceLane:
|
||||
return EmitSimdReplaceLane(f, type, def);
|
||||
case SimdOperation::Fn_check:
|
||||
MOZ_CRASH("only used in asm.js' type system");
|
||||
case SimdOperation::Fn_splat:
|
||||
return EmitSimdSplat(f, type, def);
|
||||
case SimdOperation::Fn_select:
|
||||
return EmitSimdSelect(f, type, def);
|
||||
case SimdOperation::Fn_swizzle:
|
||||
return EmitSimdSwizzle(f, type, def);
|
||||
case SimdOperation::Fn_shuffle:
|
||||
return EmitSimdShuffle(f, type, def);
|
||||
case SimdOperation::Fn_load:
|
||||
return EmitSimdLoad(f, type, 0, def);
|
||||
case SimdOperation::Fn_load1:
|
||||
return EmitSimdLoad(f, type, 1, def);
|
||||
case SimdOperation::Fn_load2:
|
||||
return EmitSimdLoad(f, type, 2, def);
|
||||
case SimdOperation::Fn_load3:
|
||||
return EmitSimdLoad(f, type, 3, def);
|
||||
case SimdOperation::Fn_store:
|
||||
return EmitSimdStore(f, type, 0, def);
|
||||
case SimdOperation::Fn_store1:
|
||||
return EmitSimdStore(f, type, 1, def);
|
||||
case SimdOperation::Fn_store2:
|
||||
return EmitSimdStore(f, type, 2, def);
|
||||
case SimdOperation::Fn_store3:
|
||||
return EmitSimdStore(f, type, 3, def);
|
||||
case SimdOperation::Fn_allTrue:
|
||||
return EmitSimdAllTrue(f, type, def);
|
||||
case SimdOperation::Fn_anyTrue:
|
||||
return EmitSimdAnyTrue(f, type, def);
|
||||
case SimdOperation::Fn_abs:
|
||||
case SimdOperation::Fn_neg:
|
||||
case SimdOperation::Fn_not:
|
||||
case SimdOperation::Fn_sqrt:
|
||||
case SimdOperation::Fn_reciprocalApproximation:
|
||||
case SimdOperation::Fn_reciprocalSqrtApproximation:
|
||||
return EmitSimdUnary(f, type, op, def);
|
||||
case SimdOperation::Fn_shiftLeftByScalar:
|
||||
return EmitSimdShift(f, type, MSimdShift::lsh, def);
|
||||
case SimdOperation::Fn_shiftRightByScalar:
|
||||
return EmitSimdShift(f, type,
|
||||
type == ExprType::I32x4 ? MSimdShift::rsh : MSimdShift::ursh,
|
||||
def);
|
||||
case SimdOperation::Fn_shiftRightArithmeticByScalar:
|
||||
return EmitSimdShift(f, type, MSimdShift::rsh, def);
|
||||
case SimdOperation::Fn_shiftRightLogicalByScalar:
|
||||
return EmitSimdShift(f, type, MSimdShift::ursh, def);
|
||||
#define _CASE(OP) \
|
||||
case SimdOperation::Fn_##OP: \
|
||||
return EmitSimdBinaryComp(f, type, MSimdBinaryComp::OP, def);
|
||||
FOREACH_COMP_SIMD_OP(_CASE)
|
||||
#undef _CASE
|
||||
case SimdOperation::Fn_and:
|
||||
return EmitSimdBinary(f, type, MSimdBinaryBitwise::and_, def);
|
||||
case SimdOperation::Fn_or:
|
||||
return EmitSimdBinary(f, type, MSimdBinaryBitwise::or_, def);
|
||||
case SimdOperation::Fn_xor:
|
||||
return EmitSimdBinary(f, type, MSimdBinaryBitwise::xor_, def);
|
||||
#define _CASE(OP) \
|
||||
case SimdOperation::Fn_##OP: \
|
||||
return EmitSimdBinary(f, type, MSimdBinaryArith::Op_##OP, def);
|
||||
FOREACH_NUMERIC_SIMD_BINOP(_CASE)
|
||||
FOREACH_FLOAT_SIMD_BINOP(_CASE)
|
||||
#undef _CASE
|
||||
case SimdOperation::Fn_fromFloat32x4:
|
||||
return EmitSimdCast<MSimdConvert>(f, ExprType::F32x4, type, def);
|
||||
case SimdOperation::Fn_fromInt32x4:
|
||||
return EmitSimdCast<MSimdConvert>(f, ExprType::I32x4, type, def);
|
||||
case SimdOperation::Fn_fromInt32x4Bits:
|
||||
return EmitSimdCast<MSimdReinterpretCast>(f, ExprType::I32x4, type, def);
|
||||
case SimdOperation::Fn_fromFloat32x4Bits:
|
||||
return EmitSimdCast<MSimdReinterpretCast>(f, ExprType::F32x4, type, def);
|
||||
case SimdOperation::Fn_fromUint32x4:
|
||||
case SimdOperation::Fn_fromInt8x16Bits:
|
||||
case SimdOperation::Fn_fromInt16x8Bits:
|
||||
case SimdOperation::Fn_fromUint8x16Bits:
|
||||
case SimdOperation::Fn_fromUint16x8Bits:
|
||||
case SimdOperation::Fn_fromUint32x4Bits:
|
||||
case SimdOperation::Fn_fromFloat64x2Bits:
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
MOZ_CRASH("unexpected opcode");
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -2723,14 +2839,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 +2875,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 +2923,11 @@ 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
|
||||
case Expr::SimdConst:
|
||||
return EmitLiteral(f, f.readExprType(), def);
|
||||
case Expr::SimdOp:
|
||||
return EmitSimdOp(f, def);
|
||||
case Expr::Loop:
|
||||
case Expr::Select:
|
||||
case Expr::Br:
|
||||
|
Loading…
Reference in New Issue
Block a user