Bug 1244571 - BaldrMonkey: Implement parsing, encoding, and decoding for the conversion operators. r=luke

This commit is contained in:
Dan Gohman 2016-02-02 12:30:55 -08:00
Родитель 2924fd6106
Коммит 15c58eb3b3
6 изменённых файлов: 216 добавлений и 52 удалений

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

@ -4564,15 +4564,15 @@ CheckFloatCoercionArg(FunctionValidator& f, ParseNode* inputNode, Type inputType
size_t opcodeAt)
{
if (inputType.isMaybeDouble()) {
f.patchOp(opcodeAt, Expr::F32FromF64);
f.patchOp(opcodeAt, Expr::F32DemoteF64);
return true;
}
if (inputType.isSigned()) {
f.patchOp(opcodeAt, Expr::F32FromS32);
f.patchOp(opcodeAt, Expr::F32ConvertSI32);
return true;
}
if (inputType.isUnsigned()) {
f.patchOp(opcodeAt, Expr::F32FromU32);
f.patchOp(opcodeAt, Expr::F32ConvertUI32);
return true;
}
if (inputType.isFloatish()) {
@ -4820,7 +4820,7 @@ class CheckSimdScalarArgs
// We emitted a double literal and actually want a float32.
MOZ_ASSERT(patchAt != size_t(-1));
f.patchOp(patchAt, Expr::F32FromF64);
f.patchOp(patchAt, Expr::F32DemoteF64);
return true;
}
@ -5411,11 +5411,11 @@ CoerceResult(FunctionValidator& f, ParseNode* expr, ExprType expected, Type actu
if (actual.isMaybeDouble())
f.patchOp(patchAt, Expr::Id);
else if (actual.isMaybeFloat())
f.patchOp(patchAt, Expr::F64FromF32);
f.patchOp(patchAt, Expr::F64PromoteF32);
else if (actual.isSigned())
f.patchOp(patchAt, Expr::F64FromS32);
f.patchOp(patchAt, Expr::F64ConvertSI32);
else if (actual.isUnsigned())
f.patchOp(patchAt, Expr::F64FromU32);
f.patchOp(patchAt, Expr::F64ConvertUI32);
else
return f.failf(expr, "%s is not a subtype of double?, float?, signed or unsigned", actual.toChars());
break;
@ -5631,7 +5631,7 @@ CheckCoerceToInt(FunctionValidator& f, ParseNode* expr, Type* type)
return false;
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);
*type = Type::Signed;
return true;

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

@ -289,6 +289,14 @@ DecodeComparisonOperator(FunctionDecoder& f, ExprType expected, ExprType 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
DecodeExpr(FunctionDecoder& f, ExprType expected)
{
@ -386,6 +394,24 @@ DecodeExpr(FunctionDecoder& f, ExprType expected)
case Expr::F64Gt:
case Expr::F64Ge:
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:
break;
}

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

@ -154,17 +154,31 @@ enum class Expr : uint16_t
F64Ge,
// Conversions
I32SConvertF32,
I32SConvertF64,
I32UConvertF32,
I32UConvertF64,
I32ConvertI64,
I64SConvertF32,
I64SConvertF64,
I64UConvertF32,
I64UConvertF64,
I64SConvertI32,
I64UConvertI32,
I32WrapI64,
I64ExtendSI32,
I64ExtendUI32,
I32TruncSF32,
I32TruncSF64,
I32TruncUF32,
I32TruncUF64,
I64TruncSF32,
I64TruncSF64,
I64TruncUF32,
I64TruncUF64,
F32ConvertSI32,
F32ConvertUI32,
F64ConvertSI32,
F64ConvertUI32,
F32ConvertSI64,
F32ConvertUI64,
F64ConvertSI64,
F64ConvertUI64,
F32DemoteF64,
F64PromoteF32,
I32ReinterpretF32,
F32ReinterpretI32,
I64ReinterpretF64,
F64ReinterpretI64,
// Load/store operations
I32LoadMem8S,
@ -251,10 +265,6 @@ enum class Expr : uint16_t
I32Abs,
// F32 asm.js opcodes
F32FromF64,
F32FromS32,
F32FromU32,
F32StoreMemF64,
// F64 asm.js opcodes
@ -271,10 +281,6 @@ enum class Expr : uint16_t
F64Pow,
F64Atan2,
F64FromF32,
F64FromS32,
F64FromU32,
F64StoreMemF32,
Limit

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

@ -2726,9 +2726,11 @@ EmitExpr(FunctionCompiler& f, ExprType type, MDefinition** def, LabelVector* may
return EmitMathMinMax(f, ExprType::I32, IsMax(true), def);
case Expr::I32Not:
return EmitUnary<MNot>(f, ExprType::I32, def);
case Expr::I32SConvertF32:
case Expr::I32TruncSF32:
case Expr::I32TruncUF32:
return EmitUnary<MTruncateToInt32>(f, ExprType::F32, def);
case Expr::I32SConvertF64:
case Expr::I32TruncSF64:
case Expr::I32TruncUF64:
return EmitUnary<MTruncateToInt32>(f, ExprType::F64, def);
case Expr::I32Clz:
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::F32Floor:
return EmitF32MathBuiltinCall(f, op, def);
case Expr::F32FromF64:
case Expr::F32DemoteF64:
return EmitUnary<MToFloat32>(f, ExprType::F64, def);
case Expr::F32FromS32:
case Expr::F32ConvertSI32:
return EmitUnary<MToFloat32>(f, ExprType::I32, def);
case Expr::F32FromU32:
case Expr::F32ConvertUI32:
return EmitUnary<MAsmJSUnsignedToFloat32>(f, ExprType::I32, def);
case Expr::F32LoadMem:
return EmitLoadArray(f, Scalar::Float32, def);
@ -2871,11 +2873,11 @@ EmitExpr(FunctionCompiler& f, ExprType type, MDefinition** def, LabelVector* may
case Expr::F64Pow:
case Expr::F64Atan2:
return EmitF64MathBuiltinCall(f, op, def);
case Expr::F64FromF32:
case Expr::F64PromoteF32:
return EmitUnary<MToDouble>(f, ExprType::F32, def);
case Expr::F64FromS32:
case Expr::F64ConvertSI32:
return EmitUnary<MToDouble>(f, ExprType::I32, def);
case Expr::F64FromU32:
case Expr::F64ConvertUI32:
return EmitUnary<MAsmJSUnsignedToDouble>(f, ExprType::I32, def);
case Expr::F64LoadMem:
return EmitLoadArray(f, Scalar::Float64, def);
@ -2920,16 +2922,22 @@ EmitExpr(FunctionCompiler& f, ExprType type, MDefinition** def, LabelVector* may
case Expr::F64CopySign:
case Expr::F64Nearest:
case Expr::F64Trunc:
case Expr::I32UConvertF32:
case Expr::I32UConvertF64:
case Expr::I32ConvertI64:
case Expr::I32WrapI64:
case Expr::I64Const:
case Expr::I64SConvertI32:
case Expr::I64UConvertI32:
case Expr::I64SConvertF32:
case Expr::I64SConvertF64:
case Expr::I64UConvertF32:
case Expr::I64UConvertF64:
case Expr::I64ExtendSI32:
case Expr::I64ExtendUI32:
case Expr::I64TruncSF32:
case Expr::I64TruncSF64:
case Expr::I64TruncUF32:
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::I64LoadMem16S:
case Expr::I64LoadMem32S:

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

@ -98,6 +98,7 @@ enum class WasmAstExprKind
Call,
ComparisonOperator,
Const,
ConversionOperator,
GetLocal,
Nop,
SetLocal,
@ -366,6 +367,22 @@ class WasmAstComparisonOperator final : public WasmAstExpr
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
@ -381,6 +398,7 @@ class WasmToken
CloseParen,
ComparisonOpcode,
Const,
ConversionOpcode,
EndOfFile,
Error,
Export,
@ -442,7 +460,8 @@ class WasmToken
end_(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;
}
explicit WasmToken(const char16_t* begin)
@ -475,7 +494,8 @@ class WasmToken
return u.valueType_;
}
Expr expr() const {
MOZ_ASSERT(kind_ == UnaryOpcode || kind_ == BinaryOpcode || kind_ == ComparisonOpcode);
MOZ_ASSERT(kind_ == UnaryOpcode || kind_ == BinaryOpcode || kind_ == ComparisonOpcode ||
kind_ == ConversionOpcode);
return u.expr_;
}
};
@ -626,10 +646,19 @@ class WasmTokenStream
return WasmToken(WasmToken::UnaryOpcode, Expr::F32Ceil, begin, cur_);
if (consume(MOZ_UTF16("const")))
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")))
return WasmToken(WasmToken::BinaryOpcode, Expr::F32CopySign, begin, cur_);
break;
case 'd':
if (consume(MOZ_UTF16("demote/f64")))
return WasmToken(WasmToken::ConversionOpcode, Expr::F32DemoteF64,
begin, cur_);
if (consume(MOZ_UTF16("div")))
return WasmToken(WasmToken::BinaryOpcode, Expr::F32Div, begin, cur_);
break;
@ -669,6 +698,11 @@ class WasmTokenStream
if (consume(MOZ_UTF16("ne")))
return WasmToken(WasmToken::ComparisonOpcode, Expr::F32Ne, begin, cur_);
break;
case 'r':
if (consume(MOZ_UTF16("reinterpret/i32")))
return WasmToken(WasmToken::ConversionOpcode, Expr::F32ReinterpretI32,
begin, cur_);
break;
case 's':
if (consume(MOZ_UTF16("sqrt")))
return WasmToken(WasmToken::UnaryOpcode, Expr::F32Sqrt, begin, cur_);
@ -698,6 +732,12 @@ class WasmTokenStream
return WasmToken(WasmToken::UnaryOpcode, Expr::F64Ceil, begin, cur_);
if (consume(MOZ_UTF16("const")))
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")))
return WasmToken(WasmToken::BinaryOpcode, Expr::F64CopySign, begin, cur_);
break;
@ -741,6 +781,11 @@ class WasmTokenStream
if (consume(MOZ_UTF16("ne")))
return WasmToken(WasmToken::ComparisonOpcode, Expr::F64Ne, begin, cur_);
break;
case 'p':
if (consume(MOZ_UTF16("promote/f32")))
return WasmToken(WasmToken::ConversionOpcode, Expr::F64PromoteF32,
begin, cur_);
break;
case 's':
if (consume(MOZ_UTF16("sqrt")))
return WasmToken(WasmToken::UnaryOpcode, Expr::F64Sqrt, begin, cur_);
@ -822,16 +867,19 @@ class WasmTokenStream
if (consume(MOZ_UTF16("or")))
return WasmToken(WasmToken::BinaryOpcode, Expr::I32Or, begin, cur_);
break;
case 'p':
if (consume(MOZ_UTF16("popcnt")))
return WasmToken(WasmToken::UnaryOpcode, Expr::I32Popcnt, begin, cur_);
break;
case 'r':
if (consume(MOZ_UTF16("reinterpret/f32")))
return WasmToken(WasmToken::UnaryOpcode, Expr::I32ReinterpretF32,
begin, cur_);
if (consume(MOZ_UTF16("rem_s")))
return WasmToken(WasmToken::BinaryOpcode, Expr::I32RemS, begin, cur_);
if (consume(MOZ_UTF16("rem_u")))
return WasmToken(WasmToken::BinaryOpcode, Expr::I32RemU, begin, cur_);
break;
case 'p':
if (consume(MOZ_UTF16("popcnt")))
return WasmToken(WasmToken::UnaryOpcode, Expr::I32Popcnt, begin, cur_);
break;
case 's':
if (consume(MOZ_UTF16("sub")))
return WasmToken(WasmToken::BinaryOpcode, Expr::I32Sub, begin, cur_);
@ -842,6 +890,20 @@ class WasmTokenStream
if (consume(MOZ_UTF16("shr_u")))
return WasmToken(WasmToken::BinaryOpcode, Expr::I32ShrU, begin, cur_);
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':
if (consume(MOZ_UTF16("xor")))
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);
}
static WasmAstConversionOperator*
ParseConversionOperator(WasmParseContext& c, Expr expr)
{
WasmAstExpr* op = ParseExpr(c);
if (!op)
return nullptr;
return new(c.lifo) WasmAstConversionOperator(expr, op);
}
static WasmAstExpr*
ParseExprInsideParens(WasmParseContext& c)
{
@ -1126,10 +1198,12 @@ ParseExprInsideParens(WasmParseContext& c)
return ParseCall(c, Expr::Call);
case WasmToken::CallImport:
return ParseCall(c, Expr::CallImport);
case WasmToken::Const:
return ParseConst(c, token);
case WasmToken::ComparisonOpcode:
return ParseComparisonOperator(c, token.expr());
case WasmToken::Const:
return ParseConst(c, token);
case WasmToken::ConversionOpcode:
return ParseConversionOperator(c, token.expr());
case WasmToken::GetLocal:
return ParseGetLocal(c);
case WasmToken::SetLocal:
@ -1406,6 +1480,13 @@ EncodeComparisonOperator(Encoder& e, WasmAstComparisonOperator& b)
EncodeExpr(e, *b.rhs());
}
static bool
EncodeConversionOperator(Encoder& e, WasmAstConversionOperator& b)
{
return e.writeExpr(b.expr()) &&
EncodeExpr(e, *b.op());
}
static bool
EncodeExpr(Encoder& e, WasmAstExpr& expr)
{
@ -1422,6 +1503,8 @@ EncodeExpr(Encoder& e, WasmAstExpr& expr)
return EncodeComparisonOperator(e, expr.as<WasmAstComparisonOperator>());
case WasmAstExprKind::Const:
return EncodeConst(e, expr.as<WasmAstConst>());
case WasmAstExprKind::ConversionOperator:
return EncodeConversionOperator(e, expr.as<WasmAstConversionOperator>());
case WasmAstExprKind::GetLocal:
return EncodeGetLocal(e, expr.as<WasmAstGetLocal>());
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);