зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1244571 - BaldrMonkey: Implement parsing, encoding, and decoding for the conversion operators. r=luke
This commit is contained in:
Родитель
2924fd6106
Коммит
15c58eb3b3
|
@ -4564,15 +4564,15 @@ CheckFloatCoercionArg(FunctionValidator& f, ParseNode* inputNode, Type inputType
|
||||||
size_t opcodeAt)
|
size_t opcodeAt)
|
||||||
{
|
{
|
||||||
if (inputType.isMaybeDouble()) {
|
if (inputType.isMaybeDouble()) {
|
||||||
f.patchOp(opcodeAt, Expr::F32FromF64);
|
f.patchOp(opcodeAt, Expr::F32DemoteF64);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (inputType.isSigned()) {
|
if (inputType.isSigned()) {
|
||||||
f.patchOp(opcodeAt, Expr::F32FromS32);
|
f.patchOp(opcodeAt, Expr::F32ConvertSI32);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (inputType.isUnsigned()) {
|
if (inputType.isUnsigned()) {
|
||||||
f.patchOp(opcodeAt, Expr::F32FromU32);
|
f.patchOp(opcodeAt, Expr::F32ConvertUI32);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (inputType.isFloatish()) {
|
if (inputType.isFloatish()) {
|
||||||
|
@ -4820,7 +4820,7 @@ class CheckSimdScalarArgs
|
||||||
|
|
||||||
// We emitted a double literal and actually want a float32.
|
// We emitted a double literal and actually want a float32.
|
||||||
MOZ_ASSERT(patchAt != size_t(-1));
|
MOZ_ASSERT(patchAt != size_t(-1));
|
||||||
f.patchOp(patchAt, Expr::F32FromF64);
|
f.patchOp(patchAt, Expr::F32DemoteF64);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5411,11 +5411,11 @@ CoerceResult(FunctionValidator& f, ParseNode* expr, ExprType expected, Type actu
|
||||||
if (actual.isMaybeDouble())
|
if (actual.isMaybeDouble())
|
||||||
f.patchOp(patchAt, Expr::Id);
|
f.patchOp(patchAt, Expr::Id);
|
||||||
else if (actual.isMaybeFloat())
|
else if (actual.isMaybeFloat())
|
||||||
f.patchOp(patchAt, Expr::F64FromF32);
|
f.patchOp(patchAt, Expr::F64PromoteF32);
|
||||||
else if (actual.isSigned())
|
else if (actual.isSigned())
|
||||||
f.patchOp(patchAt, Expr::F64FromS32);
|
f.patchOp(patchAt, Expr::F64ConvertSI32);
|
||||||
else if (actual.isUnsigned())
|
else if (actual.isUnsigned())
|
||||||
f.patchOp(patchAt, Expr::F64FromU32);
|
f.patchOp(patchAt, Expr::F64ConvertUI32);
|
||||||
else
|
else
|
||||||
return f.failf(expr, "%s is not a subtype of double?, float?, signed or unsigned", actual.toChars());
|
return f.failf(expr, "%s is not a subtype of double?, float?, signed or unsigned", actual.toChars());
|
||||||
break;
|
break;
|
||||||
|
@ -5631,7 +5631,7 @@ CheckCoerceToInt(FunctionValidator& f, ParseNode* expr, Type* type)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (operandType.isMaybeDouble() || operandType.isMaybeFloat()) {
|
if (operandType.isMaybeDouble() || operandType.isMaybeFloat()) {
|
||||||
Expr opcode = operandType.isMaybeDouble() ? Expr::I32SConvertF64 : Expr::I32SConvertF32;
|
Expr opcode = operandType.isMaybeDouble() ? Expr::I32TruncSF64 : Expr::I32TruncSF32;
|
||||||
f.patchOp(opcodeAt, opcode);
|
f.patchOp(opcodeAt, opcode);
|
||||||
*type = Type::Signed;
|
*type = Type::Signed;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -289,6 +289,14 @@ DecodeComparisonOperator(FunctionDecoder& f, ExprType expected, ExprType type)
|
||||||
DecodeExpr(f, type);
|
DecodeExpr(f, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
DecodeConversionOperator(FunctionDecoder& f, ExprType expected,
|
||||||
|
ExprType dstType, ExprType srcType)
|
||||||
|
{
|
||||||
|
return CheckType(f, dstType, expected) &&
|
||||||
|
DecodeExpr(f, srcType);
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
DecodeExpr(FunctionDecoder& f, ExprType expected)
|
DecodeExpr(FunctionDecoder& f, ExprType expected)
|
||||||
{
|
{
|
||||||
|
@ -386,6 +394,24 @@ DecodeExpr(FunctionDecoder& f, ExprType expected)
|
||||||
case Expr::F64Gt:
|
case Expr::F64Gt:
|
||||||
case Expr::F64Ge:
|
case Expr::F64Ge:
|
||||||
return DecodeComparisonOperator(f, expected, ExprType::F64);
|
return DecodeComparisonOperator(f, expected, ExprType::F64);
|
||||||
|
case Expr::I32TruncSF32:
|
||||||
|
case Expr::I32TruncUF32:
|
||||||
|
case Expr::I32ReinterpretF32:
|
||||||
|
return DecodeConversionOperator(f, expected, ExprType::I32, ExprType::F32);
|
||||||
|
case Expr::I32TruncSF64:
|
||||||
|
case Expr::I32TruncUF64:
|
||||||
|
return DecodeConversionOperator(f, expected, ExprType::I32, ExprType::F64);
|
||||||
|
case Expr::F32ConvertSI32:
|
||||||
|
case Expr::F32ConvertUI32:
|
||||||
|
case Expr::F32ReinterpretI32:
|
||||||
|
return DecodeConversionOperator(f, expected, ExprType::F32, ExprType::I32);
|
||||||
|
case Expr::F32DemoteF64:
|
||||||
|
return DecodeConversionOperator(f, expected, ExprType::F32, ExprType::F64);
|
||||||
|
case Expr::F64ConvertSI32:
|
||||||
|
case Expr::F64ConvertUI32:
|
||||||
|
return DecodeConversionOperator(f, expected, ExprType::F64, ExprType::I32);
|
||||||
|
case Expr::F64PromoteF32:
|
||||||
|
return DecodeConversionOperator(f, expected, ExprType::F64, ExprType::F32);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,17 +154,31 @@ enum class Expr : uint16_t
|
||||||
F64Ge,
|
F64Ge,
|
||||||
|
|
||||||
// Conversions
|
// Conversions
|
||||||
I32SConvertF32,
|
I32WrapI64,
|
||||||
I32SConvertF64,
|
I64ExtendSI32,
|
||||||
I32UConvertF32,
|
I64ExtendUI32,
|
||||||
I32UConvertF64,
|
I32TruncSF32,
|
||||||
I32ConvertI64,
|
I32TruncSF64,
|
||||||
I64SConvertF32,
|
I32TruncUF32,
|
||||||
I64SConvertF64,
|
I32TruncUF64,
|
||||||
I64UConvertF32,
|
I64TruncSF32,
|
||||||
I64UConvertF64,
|
I64TruncSF64,
|
||||||
I64SConvertI32,
|
I64TruncUF32,
|
||||||
I64UConvertI32,
|
I64TruncUF64,
|
||||||
|
F32ConvertSI32,
|
||||||
|
F32ConvertUI32,
|
||||||
|
F64ConvertSI32,
|
||||||
|
F64ConvertUI32,
|
||||||
|
F32ConvertSI64,
|
||||||
|
F32ConvertUI64,
|
||||||
|
F64ConvertSI64,
|
||||||
|
F64ConvertUI64,
|
||||||
|
F32DemoteF64,
|
||||||
|
F64PromoteF32,
|
||||||
|
I32ReinterpretF32,
|
||||||
|
F32ReinterpretI32,
|
||||||
|
I64ReinterpretF64,
|
||||||
|
F64ReinterpretI64,
|
||||||
|
|
||||||
// Load/store operations
|
// Load/store operations
|
||||||
I32LoadMem8S,
|
I32LoadMem8S,
|
||||||
|
@ -251,10 +265,6 @@ enum class Expr : uint16_t
|
||||||
I32Abs,
|
I32Abs,
|
||||||
|
|
||||||
// F32 asm.js opcodes
|
// F32 asm.js opcodes
|
||||||
F32FromF64,
|
|
||||||
F32FromS32,
|
|
||||||
F32FromU32,
|
|
||||||
|
|
||||||
F32StoreMemF64,
|
F32StoreMemF64,
|
||||||
|
|
||||||
// F64 asm.js opcodes
|
// F64 asm.js opcodes
|
||||||
|
@ -271,10 +281,6 @@ enum class Expr : uint16_t
|
||||||
F64Pow,
|
F64Pow,
|
||||||
F64Atan2,
|
F64Atan2,
|
||||||
|
|
||||||
F64FromF32,
|
|
||||||
F64FromS32,
|
|
||||||
F64FromU32,
|
|
||||||
|
|
||||||
F64StoreMemF32,
|
F64StoreMemF32,
|
||||||
|
|
||||||
Limit
|
Limit
|
||||||
|
|
|
@ -2726,9 +2726,11 @@ EmitExpr(FunctionCompiler& f, ExprType type, MDefinition** def, LabelVector* may
|
||||||
return EmitMathMinMax(f, ExprType::I32, IsMax(true), def);
|
return EmitMathMinMax(f, ExprType::I32, IsMax(true), def);
|
||||||
case Expr::I32Not:
|
case Expr::I32Not:
|
||||||
return EmitUnary<MNot>(f, ExprType::I32, def);
|
return EmitUnary<MNot>(f, ExprType::I32, def);
|
||||||
case Expr::I32SConvertF32:
|
case Expr::I32TruncSF32:
|
||||||
|
case Expr::I32TruncUF32:
|
||||||
return EmitUnary<MTruncateToInt32>(f, ExprType::F32, def);
|
return EmitUnary<MTruncateToInt32>(f, ExprType::F32, def);
|
||||||
case Expr::I32SConvertF64:
|
case Expr::I32TruncSF64:
|
||||||
|
case Expr::I32TruncUF64:
|
||||||
return EmitUnary<MTruncateToInt32>(f, ExprType::F64, def);
|
return EmitUnary<MTruncateToInt32>(f, ExprType::F64, def);
|
||||||
case Expr::I32Clz:
|
case Expr::I32Clz:
|
||||||
return EmitUnary<MClz>(f, ExprType::I32, def);
|
return EmitUnary<MClz>(f, ExprType::I32, def);
|
||||||
|
@ -2823,11 +2825,11 @@ EmitExpr(FunctionCompiler& f, ExprType type, MDefinition** def, LabelVector* may
|
||||||
case Expr::F32Ceil:
|
case Expr::F32Ceil:
|
||||||
case Expr::F32Floor:
|
case Expr::F32Floor:
|
||||||
return EmitF32MathBuiltinCall(f, op, def);
|
return EmitF32MathBuiltinCall(f, op, def);
|
||||||
case Expr::F32FromF64:
|
case Expr::F32DemoteF64:
|
||||||
return EmitUnary<MToFloat32>(f, ExprType::F64, def);
|
return EmitUnary<MToFloat32>(f, ExprType::F64, def);
|
||||||
case Expr::F32FromS32:
|
case Expr::F32ConvertSI32:
|
||||||
return EmitUnary<MToFloat32>(f, ExprType::I32, def);
|
return EmitUnary<MToFloat32>(f, ExprType::I32, def);
|
||||||
case Expr::F32FromU32:
|
case Expr::F32ConvertUI32:
|
||||||
return EmitUnary<MAsmJSUnsignedToFloat32>(f, ExprType::I32, def);
|
return EmitUnary<MAsmJSUnsignedToFloat32>(f, ExprType::I32, def);
|
||||||
case Expr::F32LoadMem:
|
case Expr::F32LoadMem:
|
||||||
return EmitLoadArray(f, Scalar::Float32, def);
|
return EmitLoadArray(f, Scalar::Float32, def);
|
||||||
|
@ -2871,11 +2873,11 @@ EmitExpr(FunctionCompiler& f, ExprType type, MDefinition** def, LabelVector* may
|
||||||
case Expr::F64Pow:
|
case Expr::F64Pow:
|
||||||
case Expr::F64Atan2:
|
case Expr::F64Atan2:
|
||||||
return EmitF64MathBuiltinCall(f, op, def);
|
return EmitF64MathBuiltinCall(f, op, def);
|
||||||
case Expr::F64FromF32:
|
case Expr::F64PromoteF32:
|
||||||
return EmitUnary<MToDouble>(f, ExprType::F32, def);
|
return EmitUnary<MToDouble>(f, ExprType::F32, def);
|
||||||
case Expr::F64FromS32:
|
case Expr::F64ConvertSI32:
|
||||||
return EmitUnary<MToDouble>(f, ExprType::I32, def);
|
return EmitUnary<MToDouble>(f, ExprType::I32, def);
|
||||||
case Expr::F64FromU32:
|
case Expr::F64ConvertUI32:
|
||||||
return EmitUnary<MAsmJSUnsignedToDouble>(f, ExprType::I32, def);
|
return EmitUnary<MAsmJSUnsignedToDouble>(f, ExprType::I32, def);
|
||||||
case Expr::F64LoadMem:
|
case Expr::F64LoadMem:
|
||||||
return EmitLoadArray(f, Scalar::Float64, def);
|
return EmitLoadArray(f, Scalar::Float64, def);
|
||||||
|
@ -2920,16 +2922,22 @@ EmitExpr(FunctionCompiler& f, ExprType type, MDefinition** def, LabelVector* may
|
||||||
case Expr::F64CopySign:
|
case Expr::F64CopySign:
|
||||||
case Expr::F64Nearest:
|
case Expr::F64Nearest:
|
||||||
case Expr::F64Trunc:
|
case Expr::F64Trunc:
|
||||||
case Expr::I32UConvertF32:
|
case Expr::I32WrapI64:
|
||||||
case Expr::I32UConvertF64:
|
|
||||||
case Expr::I32ConvertI64:
|
|
||||||
case Expr::I64Const:
|
case Expr::I64Const:
|
||||||
case Expr::I64SConvertI32:
|
case Expr::I64ExtendSI32:
|
||||||
case Expr::I64UConvertI32:
|
case Expr::I64ExtendUI32:
|
||||||
case Expr::I64SConvertF32:
|
case Expr::I64TruncSF32:
|
||||||
case Expr::I64SConvertF64:
|
case Expr::I64TruncSF64:
|
||||||
case Expr::I64UConvertF32:
|
case Expr::I64TruncUF32:
|
||||||
case Expr::I64UConvertF64:
|
case Expr::I64TruncUF64:
|
||||||
|
case Expr::F32ConvertSI64:
|
||||||
|
case Expr::F32ConvertUI64:
|
||||||
|
case Expr::F64ConvertSI64:
|
||||||
|
case Expr::F64ConvertUI64:
|
||||||
|
case Expr::I64ReinterpretF64:
|
||||||
|
case Expr::F64ReinterpretI64:
|
||||||
|
case Expr::I32ReinterpretF32:
|
||||||
|
case Expr::F32ReinterpretI32:
|
||||||
case Expr::I64LoadMem8S:
|
case Expr::I64LoadMem8S:
|
||||||
case Expr::I64LoadMem16S:
|
case Expr::I64LoadMem16S:
|
||||||
case Expr::I64LoadMem32S:
|
case Expr::I64LoadMem32S:
|
||||||
|
|
|
@ -98,6 +98,7 @@ enum class WasmAstExprKind
|
||||||
Call,
|
Call,
|
||||||
ComparisonOperator,
|
ComparisonOperator,
|
||||||
Const,
|
Const,
|
||||||
|
ConversionOperator,
|
||||||
GetLocal,
|
GetLocal,
|
||||||
Nop,
|
Nop,
|
||||||
SetLocal,
|
SetLocal,
|
||||||
|
@ -366,6 +367,22 @@ class WasmAstComparisonOperator final : public WasmAstExpr
|
||||||
WasmAstExpr* rhs() const { return rhs_; }
|
WasmAstExpr* rhs() const { return rhs_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class WasmAstConversionOperator final : public WasmAstExpr
|
||||||
|
{
|
||||||
|
Expr expr_;
|
||||||
|
WasmAstExpr* op_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const WasmAstExprKind Kind = WasmAstExprKind::ConversionOperator;
|
||||||
|
explicit WasmAstConversionOperator(Expr expr, WasmAstExpr* op)
|
||||||
|
: WasmAstExpr(Kind),
|
||||||
|
expr_(expr), op_(op)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Expr expr() const { return expr_; }
|
||||||
|
WasmAstExpr* op() const { return op_; }
|
||||||
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
// wasm text token stream
|
// wasm text token stream
|
||||||
|
|
||||||
|
@ -381,6 +398,7 @@ class WasmToken
|
||||||
CloseParen,
|
CloseParen,
|
||||||
ComparisonOpcode,
|
ComparisonOpcode,
|
||||||
Const,
|
Const,
|
||||||
|
ConversionOpcode,
|
||||||
EndOfFile,
|
EndOfFile,
|
||||||
Error,
|
Error,
|
||||||
Export,
|
Export,
|
||||||
|
@ -442,7 +460,8 @@ class WasmToken
|
||||||
end_(end)
|
end_(end)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(begin != end);
|
MOZ_ASSERT(begin != end);
|
||||||
MOZ_ASSERT(kind_ == UnaryOpcode || kind_ == BinaryOpcode || kind_ == ComparisonOpcode);
|
MOZ_ASSERT(kind_ == UnaryOpcode || kind_ == BinaryOpcode || kind_ == ComparisonOpcode ||
|
||||||
|
kind_ == ConversionOpcode);
|
||||||
u.expr_ = expr;
|
u.expr_ = expr;
|
||||||
}
|
}
|
||||||
explicit WasmToken(const char16_t* begin)
|
explicit WasmToken(const char16_t* begin)
|
||||||
|
@ -475,7 +494,8 @@ class WasmToken
|
||||||
return u.valueType_;
|
return u.valueType_;
|
||||||
}
|
}
|
||||||
Expr expr() const {
|
Expr expr() const {
|
||||||
MOZ_ASSERT(kind_ == UnaryOpcode || kind_ == BinaryOpcode || kind_ == ComparisonOpcode);
|
MOZ_ASSERT(kind_ == UnaryOpcode || kind_ == BinaryOpcode || kind_ == ComparisonOpcode ||
|
||||||
|
kind_ == ConversionOpcode);
|
||||||
return u.expr_;
|
return u.expr_;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -626,10 +646,19 @@ class WasmTokenStream
|
||||||
return WasmToken(WasmToken::UnaryOpcode, Expr::F32Ceil, begin, cur_);
|
return WasmToken(WasmToken::UnaryOpcode, Expr::F32Ceil, begin, cur_);
|
||||||
if (consume(MOZ_UTF16("const")))
|
if (consume(MOZ_UTF16("const")))
|
||||||
return WasmToken(WasmToken::Const, ValType::F32, begin, cur_);
|
return WasmToken(WasmToken::Const, ValType::F32, begin, cur_);
|
||||||
|
if (consume(MOZ_UTF16("convert_s/i32")))
|
||||||
|
return WasmToken(WasmToken::ConversionOpcode, Expr::F32ConvertSI32,
|
||||||
|
begin, cur_);
|
||||||
|
if (consume(MOZ_UTF16("convert_u/i32")))
|
||||||
|
return WasmToken(WasmToken::ConversionOpcode, Expr::F32ConvertUI32,
|
||||||
|
begin, cur_);
|
||||||
if (consume(MOZ_UTF16("copysign")))
|
if (consume(MOZ_UTF16("copysign")))
|
||||||
return WasmToken(WasmToken::BinaryOpcode, Expr::F32CopySign, begin, cur_);
|
return WasmToken(WasmToken::BinaryOpcode, Expr::F32CopySign, begin, cur_);
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
|
if (consume(MOZ_UTF16("demote/f64")))
|
||||||
|
return WasmToken(WasmToken::ConversionOpcode, Expr::F32DemoteF64,
|
||||||
|
begin, cur_);
|
||||||
if (consume(MOZ_UTF16("div")))
|
if (consume(MOZ_UTF16("div")))
|
||||||
return WasmToken(WasmToken::BinaryOpcode, Expr::F32Div, begin, cur_);
|
return WasmToken(WasmToken::BinaryOpcode, Expr::F32Div, begin, cur_);
|
||||||
break;
|
break;
|
||||||
|
@ -669,6 +698,11 @@ class WasmTokenStream
|
||||||
if (consume(MOZ_UTF16("ne")))
|
if (consume(MOZ_UTF16("ne")))
|
||||||
return WasmToken(WasmToken::ComparisonOpcode, Expr::F32Ne, begin, cur_);
|
return WasmToken(WasmToken::ComparisonOpcode, Expr::F32Ne, begin, cur_);
|
||||||
break;
|
break;
|
||||||
|
case 'r':
|
||||||
|
if (consume(MOZ_UTF16("reinterpret/i32")))
|
||||||
|
return WasmToken(WasmToken::ConversionOpcode, Expr::F32ReinterpretI32,
|
||||||
|
begin, cur_);
|
||||||
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
if (consume(MOZ_UTF16("sqrt")))
|
if (consume(MOZ_UTF16("sqrt")))
|
||||||
return WasmToken(WasmToken::UnaryOpcode, Expr::F32Sqrt, begin, cur_);
|
return WasmToken(WasmToken::UnaryOpcode, Expr::F32Sqrt, begin, cur_);
|
||||||
|
@ -698,6 +732,12 @@ class WasmTokenStream
|
||||||
return WasmToken(WasmToken::UnaryOpcode, Expr::F64Ceil, begin, cur_);
|
return WasmToken(WasmToken::UnaryOpcode, Expr::F64Ceil, begin, cur_);
|
||||||
if (consume(MOZ_UTF16("const")))
|
if (consume(MOZ_UTF16("const")))
|
||||||
return WasmToken(WasmToken::Const, ValType::F64, begin, cur_);
|
return WasmToken(WasmToken::Const, ValType::F64, begin, cur_);
|
||||||
|
if (consume(MOZ_UTF16("convert_s/i32")))
|
||||||
|
return WasmToken(WasmToken::ConversionOpcode, Expr::F64ConvertSI32,
|
||||||
|
begin, cur_);
|
||||||
|
if (consume(MOZ_UTF16("convert_u/i32")))
|
||||||
|
return WasmToken(WasmToken::ConversionOpcode, Expr::F64ConvertUI32,
|
||||||
|
begin, cur_);
|
||||||
if (consume(MOZ_UTF16("copysign")))
|
if (consume(MOZ_UTF16("copysign")))
|
||||||
return WasmToken(WasmToken::BinaryOpcode, Expr::F64CopySign, begin, cur_);
|
return WasmToken(WasmToken::BinaryOpcode, Expr::F64CopySign, begin, cur_);
|
||||||
break;
|
break;
|
||||||
|
@ -741,6 +781,11 @@ class WasmTokenStream
|
||||||
if (consume(MOZ_UTF16("ne")))
|
if (consume(MOZ_UTF16("ne")))
|
||||||
return WasmToken(WasmToken::ComparisonOpcode, Expr::F64Ne, begin, cur_);
|
return WasmToken(WasmToken::ComparisonOpcode, Expr::F64Ne, begin, cur_);
|
||||||
break;
|
break;
|
||||||
|
case 'p':
|
||||||
|
if (consume(MOZ_UTF16("promote/f32")))
|
||||||
|
return WasmToken(WasmToken::ConversionOpcode, Expr::F64PromoteF32,
|
||||||
|
begin, cur_);
|
||||||
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
if (consume(MOZ_UTF16("sqrt")))
|
if (consume(MOZ_UTF16("sqrt")))
|
||||||
return WasmToken(WasmToken::UnaryOpcode, Expr::F64Sqrt, begin, cur_);
|
return WasmToken(WasmToken::UnaryOpcode, Expr::F64Sqrt, begin, cur_);
|
||||||
|
@ -822,16 +867,19 @@ class WasmTokenStream
|
||||||
if (consume(MOZ_UTF16("or")))
|
if (consume(MOZ_UTF16("or")))
|
||||||
return WasmToken(WasmToken::BinaryOpcode, Expr::I32Or, begin, cur_);
|
return WasmToken(WasmToken::BinaryOpcode, Expr::I32Or, begin, cur_);
|
||||||
break;
|
break;
|
||||||
|
case 'p':
|
||||||
|
if (consume(MOZ_UTF16("popcnt")))
|
||||||
|
return WasmToken(WasmToken::UnaryOpcode, Expr::I32Popcnt, begin, cur_);
|
||||||
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
|
if (consume(MOZ_UTF16("reinterpret/f32")))
|
||||||
|
return WasmToken(WasmToken::UnaryOpcode, Expr::I32ReinterpretF32,
|
||||||
|
begin, cur_);
|
||||||
if (consume(MOZ_UTF16("rem_s")))
|
if (consume(MOZ_UTF16("rem_s")))
|
||||||
return WasmToken(WasmToken::BinaryOpcode, Expr::I32RemS, begin, cur_);
|
return WasmToken(WasmToken::BinaryOpcode, Expr::I32RemS, begin, cur_);
|
||||||
if (consume(MOZ_UTF16("rem_u")))
|
if (consume(MOZ_UTF16("rem_u")))
|
||||||
return WasmToken(WasmToken::BinaryOpcode, Expr::I32RemU, begin, cur_);
|
return WasmToken(WasmToken::BinaryOpcode, Expr::I32RemU, begin, cur_);
|
||||||
break;
|
break;
|
||||||
case 'p':
|
|
||||||
if (consume(MOZ_UTF16("popcnt")))
|
|
||||||
return WasmToken(WasmToken::UnaryOpcode, Expr::I32Popcnt, begin, cur_);
|
|
||||||
break;
|
|
||||||
case 's':
|
case 's':
|
||||||
if (consume(MOZ_UTF16("sub")))
|
if (consume(MOZ_UTF16("sub")))
|
||||||
return WasmToken(WasmToken::BinaryOpcode, Expr::I32Sub, begin, cur_);
|
return WasmToken(WasmToken::BinaryOpcode, Expr::I32Sub, begin, cur_);
|
||||||
|
@ -842,6 +890,20 @@ class WasmTokenStream
|
||||||
if (consume(MOZ_UTF16("shr_u")))
|
if (consume(MOZ_UTF16("shr_u")))
|
||||||
return WasmToken(WasmToken::BinaryOpcode, Expr::I32ShrU, begin, cur_);
|
return WasmToken(WasmToken::BinaryOpcode, Expr::I32ShrU, begin, cur_);
|
||||||
break;
|
break;
|
||||||
|
case 't':
|
||||||
|
if (consume(MOZ_UTF16("trunc_s/f32")))
|
||||||
|
return WasmToken(WasmToken::ConversionOpcode, Expr::I32TruncSF32,
|
||||||
|
begin, cur_);
|
||||||
|
if (consume(MOZ_UTF16("trunc_s/f64")))
|
||||||
|
return WasmToken(WasmToken::ConversionOpcode, Expr::I32TruncSF64,
|
||||||
|
begin, cur_);
|
||||||
|
if (consume(MOZ_UTF16("trunc_u/f32")))
|
||||||
|
return WasmToken(WasmToken::ConversionOpcode, Expr::I32TruncUF32,
|
||||||
|
begin, cur_);
|
||||||
|
if (consume(MOZ_UTF16("trunc_u/f64")))
|
||||||
|
return WasmToken(WasmToken::ConversionOpcode, Expr::I32TruncUF64,
|
||||||
|
begin, cur_);
|
||||||
|
break;
|
||||||
case 'x':
|
case 'x':
|
||||||
if (consume(MOZ_UTF16("xor")))
|
if (consume(MOZ_UTF16("xor")))
|
||||||
return WasmToken(WasmToken::BinaryOpcode, Expr::I32Xor, begin, cur_);
|
return WasmToken(WasmToken::BinaryOpcode, Expr::I32Xor, begin, cur_);
|
||||||
|
@ -1110,6 +1172,16 @@ ParseComparisonOperator(WasmParseContext& c, Expr expr)
|
||||||
return new(c.lifo) WasmAstComparisonOperator(expr, lhs, rhs);
|
return new(c.lifo) WasmAstComparisonOperator(expr, lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static WasmAstConversionOperator*
|
||||||
|
ParseConversionOperator(WasmParseContext& c, Expr expr)
|
||||||
|
{
|
||||||
|
WasmAstExpr* op = ParseExpr(c);
|
||||||
|
if (!op)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return new(c.lifo) WasmAstConversionOperator(expr, op);
|
||||||
|
}
|
||||||
|
|
||||||
static WasmAstExpr*
|
static WasmAstExpr*
|
||||||
ParseExprInsideParens(WasmParseContext& c)
|
ParseExprInsideParens(WasmParseContext& c)
|
||||||
{
|
{
|
||||||
|
@ -1126,10 +1198,12 @@ ParseExprInsideParens(WasmParseContext& c)
|
||||||
return ParseCall(c, Expr::Call);
|
return ParseCall(c, Expr::Call);
|
||||||
case WasmToken::CallImport:
|
case WasmToken::CallImport:
|
||||||
return ParseCall(c, Expr::CallImport);
|
return ParseCall(c, Expr::CallImport);
|
||||||
case WasmToken::Const:
|
|
||||||
return ParseConst(c, token);
|
|
||||||
case WasmToken::ComparisonOpcode:
|
case WasmToken::ComparisonOpcode:
|
||||||
return ParseComparisonOperator(c, token.expr());
|
return ParseComparisonOperator(c, token.expr());
|
||||||
|
case WasmToken::Const:
|
||||||
|
return ParseConst(c, token);
|
||||||
|
case WasmToken::ConversionOpcode:
|
||||||
|
return ParseConversionOperator(c, token.expr());
|
||||||
case WasmToken::GetLocal:
|
case WasmToken::GetLocal:
|
||||||
return ParseGetLocal(c);
|
return ParseGetLocal(c);
|
||||||
case WasmToken::SetLocal:
|
case WasmToken::SetLocal:
|
||||||
|
@ -1406,6 +1480,13 @@ EncodeComparisonOperator(Encoder& e, WasmAstComparisonOperator& b)
|
||||||
EncodeExpr(e, *b.rhs());
|
EncodeExpr(e, *b.rhs());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
EncodeConversionOperator(Encoder& e, WasmAstConversionOperator& b)
|
||||||
|
{
|
||||||
|
return e.writeExpr(b.expr()) &&
|
||||||
|
EncodeExpr(e, *b.op());
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
EncodeExpr(Encoder& e, WasmAstExpr& expr)
|
EncodeExpr(Encoder& e, WasmAstExpr& expr)
|
||||||
{
|
{
|
||||||
|
@ -1422,6 +1503,8 @@ EncodeExpr(Encoder& e, WasmAstExpr& expr)
|
||||||
return EncodeComparisonOperator(e, expr.as<WasmAstComparisonOperator>());
|
return EncodeComparisonOperator(e, expr.as<WasmAstComparisonOperator>());
|
||||||
case WasmAstExprKind::Const:
|
case WasmAstExprKind::Const:
|
||||||
return EncodeConst(e, expr.as<WasmAstConst>());
|
return EncodeConst(e, expr.as<WasmAstConst>());
|
||||||
|
case WasmAstExprKind::ConversionOperator:
|
||||||
|
return EncodeConversionOperator(e, expr.as<WasmAstConversionOperator>());
|
||||||
case WasmAstExprKind::GetLocal:
|
case WasmAstExprKind::GetLocal:
|
||||||
return EncodeGetLocal(e, expr.as<WasmAstGetLocal>());
|
return EncodeGetLocal(e, expr.as<WasmAstGetLocal>());
|
||||||
case WasmAstExprKind::SetLocal:
|
case WasmAstExprKind::SetLocal:
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
load(libdir + "wasm.js");
|
||||||
|
|
||||||
|
if (!wasmIsSupported())
|
||||||
|
quit();
|
||||||
|
|
||||||
|
function mismatchError(actual, expect) {
|
||||||
|
var str = "type mismatch: expression has type " + actual + " but expected " + expect;
|
||||||
|
return RegExp(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testConversion(resultType, opcode, paramType, op, expect) {
|
||||||
|
assertEq(wasmEvalText('(module (func (param ' + paramType + ') (result ' + resultType + ') (' + resultType + '.' + opcode + '/' + paramType + ' (get_local 0))) (export "" 0))')(op), expect);
|
||||||
|
|
||||||
|
for (var bad of ['i32', 'f32', 'f64']) {
|
||||||
|
if (bad != resultType)
|
||||||
|
assertErrorMessage(() => wasmEvalText('(module (func (param ' + paramType + ') (result ' + bad + ') (' + resultType + '.' + opcode + '/' + paramType + ' (get_local 0))))'),
|
||||||
|
TypeError,
|
||||||
|
mismatchError(resultType, bad)
|
||||||
|
);
|
||||||
|
if (bad != paramType)
|
||||||
|
assertErrorMessage(() => wasmEvalText('(module (func (param ' + bad + ') (result ' + resultType + ') (' + resultType + '.' + opcode + '/' + paramType + ' (get_local 0))))'),
|
||||||
|
TypeError,
|
||||||
|
mismatchError(bad, paramType)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testConversion('i32', 'trunc_s', 'f32', 40.1, 40);
|
||||||
|
testConversion('i32', 'trunc_u', 'f32', 40.1, 40);
|
||||||
|
testConversion('i32', 'trunc_s', 'f64', 40.1, 40);
|
||||||
|
testConversion('i32', 'trunc_u', 'f64', 40.1, 40);
|
||||||
|
//testConversion('i32', 'reinterpret', 'f32', 40.1, 1109419622); // TODO: NYI
|
||||||
|
|
||||||
|
testConversion('f32', 'convert_s', 'i32', 40, 40);
|
||||||
|
testConversion('f32', 'convert_u', 'i32', 40, 40);
|
||||||
|
testConversion('f32', 'demote', 'f64', 40.1, 40.099998474121094);
|
||||||
|
//testConversion('f32', 'reinterpret', 'i32', 40, 5.605193857299268e-44); // TODO: NYI
|
||||||
|
|
||||||
|
testConversion('f64', 'convert_s', 'i32', 40, 40);
|
||||||
|
testConversion('f64', 'convert_u', 'i32', 40, 40);
|
||||||
|
testConversion('f64', 'promote', 'f32', 40.1, 40.099998474121094);
|
Загрузка…
Ссылка в новой задаче