author | Benjamin Bouvier <benj@benj.me> |
Mon, 14 Mar 2016 11:27:42 +0100 | |
changeset 329650 | 32f3f27d070c203f3c4869b9fbb44d9c7857a88d |
parent 329649 | 88a8fe526ba3f7bc7aec06bac5b0e88b968baec1 |
child 329651 | efed456bdb89af3eff3221afc2ac5d47aebfc469 |
push id | 1146 |
push user | Callek@gmail.com |
push date | Mon, 25 Jul 2016 16:35:44 +0000 |
treeherder | mozilla-release@a55778f9cd5a [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | sunfish |
bugs | 1255691 |
milestone | 48.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/asmjs/Wasm.cpp +++ b/js/src/asmjs/Wasm.cpp @@ -445,16 +445,44 @@ DecodeConversionOperator(FunctionDecoder if (!CheckType(f, actual, argType)) return false; *type = ToExprType(to); return true; } static bool +DecodeSelectOperator(FunctionDecoder& f, ExprType* type) +{ + ExprType trueType; + if (!DecodeExpr(f, &trueType)) + return false; + + if (trueType == ExprType::I64 && !f.checkI64Support()) + return false; + + ExprType falseType; + if (!DecodeExpr(f, &falseType)) + return false; + + if (!CheckType(f, falseType, trueType)) + return false; + + ExprType condType; + if (!DecodeExpr(f, &condType)) + return false; + + if (!CheckType(f, condType, ValType::I32)) + return false; + + *type = trueType; + return true; +} + +static bool DecodeIfElse(FunctionDecoder& f, bool hasElse, ExprType* type) { ExprType condType; if (!DecodeExpr(f, &condType)) return false; if (!CheckType(f, condType, ValType::I32)) return false; @@ -638,16 +666,18 @@ DecodeExpr(FunctionDecoder& f, ExprType* case Expr::F32Const: return DecodeConstF32(f, type); case Expr::F64Const: return DecodeConstF64(f, type); case Expr::GetLocal: return DecodeGetLocal(f, type); case Expr::SetLocal: return DecodeSetLocal(f, type); + case Expr::Select: + return DecodeSelectOperator(f, type); case Expr::Block: return DecodeBlock(f, /* isLoop */ false, type); case Expr::Loop: return DecodeBlock(f, /* isLoop */ true, type); case Expr::If: return DecodeIfElse(f, /* hasElse */ false, type); case Expr::IfElse: return DecodeIfElse(f, /* hasElse */ true, type);
--- a/js/src/asmjs/WasmIonCompile.cpp +++ b/js/src/asmjs/WasmIonCompile.cpp @@ -453,16 +453,25 @@ class FunctionCompiler { if (inDeadCode()) return nullptr; T* ins = T::NewAsmJS(alloc(), op); curBlock_->add(ins); return ins; } + MDefinition* select(MDefinition* trueExpr, MDefinition* falseExpr, MDefinition* condExpr) + { + if (inDeadCode()) + return nullptr; + auto* ins = MAsmSelect::New(alloc(), trueExpr, falseExpr, condExpr); + curBlock_->add(ins); + return ins; + } + MDefinition* extendI32(MDefinition* op, bool isUnsigned) { if (inDeadCode()) return nullptr; MExtendInt32ToInt64* ins = MExtendInt32ToInt64::NewAsmJS(alloc(), op, isUnsigned); curBlock_->add(ins); return ins; } @@ -2180,16 +2189,35 @@ EmitMultiply(FunctionCompiler& f, ValTyp MDefinition* rhs; if (!EmitExpr(f, &rhs)) return false; MIRType mirType = ToMIRType(type); *def = f.mul(lhs, rhs, mirType, mirType == MIRType_Int32 ? MMul::Integer : MMul::Normal); return true; } +static bool +EmitSelect(FunctionCompiler& f, MDefinition** def) +{ + MDefinition* trueExpr; + if (!EmitExpr(f, &trueExpr)) + return false; + + MDefinition* falseExpr; + if (!EmitExpr(f, &falseExpr)) + return false; + + MDefinition* condExpr; + if (!EmitExpr(f, &condExpr)) + return false; + + *def = f.select(trueExpr, falseExpr, condExpr); + return true; +} + typedef bool IsAdd; static bool EmitAddOrSub(FunctionCompiler& f, ValType type, bool isAdd, MDefinition** def) { MDefinition* lhs; if (!EmitExpr(f, &lhs)) return false; @@ -2747,16 +2775,20 @@ EmitExpr(FunctionCompiler& f, MDefinitio return EmitGetLocal(f, def); case Expr::SetLocal: return EmitSetLocal(f, def); case Expr::LoadGlobal: return EmitLoadGlobal(f, def); case Expr::StoreGlobal: return EmitStoreGlobal(f, def); + // Select + case Expr::Select: + return EmitSelect(f, def); + // I32 case Expr::I32Const: return EmitLiteral(f, ValType::I32, def); case Expr::I32Add: return EmitAddOrSub(f, ValType::I32, IsAdd(true), def); case Expr::I32Sub: return EmitAddOrSub(f, ValType::I32, IsAdd(false), def); case Expr::I32Mul: @@ -3042,17 +3074,16 @@ EmitExpr(FunctionCompiler& f, MDefinitio case Expr::I32AtomicsLoad: return EmitAtomicsLoad(f, def); case Expr::I32AtomicsStore: return EmitAtomicsStore(f, def); case Expr::I32AtomicsBinOp: return EmitAtomicsBinOp(f, def); // Future opcodes - case Expr::Select: case Expr::F32CopySign: case Expr::F32Trunc: case Expr::F32Nearest: case Expr::F64CopySign: case Expr::F64Nearest: case Expr::F64Trunc: case Expr::I64ReinterpretF64: case Expr::F64ReinterpretI64:
--- a/js/src/asmjs/WasmTextToBinary.cpp +++ b/js/src/asmjs/WasmTextToBinary.cpp @@ -205,16 +205,17 @@ enum class WasmAstExprKind ConversionOperator, GetLocal, If, Load, Nop, Return, SetLocal, Store, + TernaryOperator, Trap, UnaryOperator, }; class WasmAstExpr : public WasmAstNode { const WasmAstExprKind kind_; @@ -703,16 +704,36 @@ class WasmAstBinaryOperator final : publ expr_(expr), lhs_(lhs), rhs_(rhs) {} Expr expr() const { return expr_; } WasmAstExpr* lhs() const { return lhs_; } WasmAstExpr* rhs() const { return rhs_; } }; +class WasmAstTernaryOperator : public WasmAstExpr +{ + Expr expr_; + WasmAstExpr* op0_; + WasmAstExpr* op1_; + WasmAstExpr* op2_; + + public: + static const WasmAstExprKind Kind = WasmAstExprKind::TernaryOperator; + WasmAstTernaryOperator(Expr expr, WasmAstExpr* op0, WasmAstExpr* op1, WasmAstExpr* op2) + : WasmAstExpr(Kind), + expr_(expr), op0_(op0), op1_(op1), op2_(op2) + {} + + Expr expr() const { return expr_; } + WasmAstExpr* op0() const { return op0_; } + WasmAstExpr* op1() const { return op1_; } + WasmAstExpr* op2() const { return op2_; } +}; + class WasmAstComparisonOperator final : public WasmAstExpr { Expr expr_; WasmAstExpr* lhs_; WasmAstExpr* rhs_; public: static const WasmAstExprKind Kind = WasmAstExprKind::ComparisonOperator; @@ -799,16 +820,17 @@ class WasmToken OpenParen, Param, Result, Return, Segment, SetLocal, Store, Table, + TernaryOpcode, Text, Trap, Type, UnaryOpcode, ValueType }; private: Kind kind_; @@ -875,18 +897,19 @@ class WasmToken u.valueType_ = valueType; } explicit WasmToken(Kind kind, Expr expr, const char16_t* begin, const char16_t* end) : kind_(kind), begin_(begin), end_(end) { MOZ_ASSERT(begin != end); - MOZ_ASSERT(kind_ == UnaryOpcode || kind_ == BinaryOpcode || kind_ == ComparisonOpcode || - kind_ == ConversionOpcode || kind_ == Load || kind_ == Store); + MOZ_ASSERT(kind_ == UnaryOpcode || kind_ == BinaryOpcode || kind_ == TernaryOpcode || + kind_ == ComparisonOpcode || kind_ == ConversionOpcode || + kind_ == Load || kind_ == Store); u.expr_ = expr; } explicit WasmToken(const char16_t* begin) : kind_(Error), begin_(begin), end_(begin) {} Kind kind() const { @@ -924,18 +947,19 @@ class WasmToken MOZ_ASSERT(kind_ == Float); return u.floatLiteralKind_; } ValType valueType() const { MOZ_ASSERT(kind_ == ValueType || kind_ == Const); return u.valueType_; } Expr expr() const { - MOZ_ASSERT(kind_ == UnaryOpcode || kind_ == BinaryOpcode || kind_ == ComparisonOpcode || - kind_ == ConversionOpcode || kind_ == Load || kind_ == Store); + MOZ_ASSERT(kind_ == UnaryOpcode || kind_ == BinaryOpcode || kind_ == TernaryOpcode || + kind_ == ComparisonOpcode || kind_ == ConversionOpcode || + kind_ == Load || kind_ == Store); return u.expr_; } }; } // end anonymous namespace static bool IsWasmNewLine(char16_t c) @@ -1945,16 +1969,18 @@ WasmTokenStream::next() case 'r': if (consume(MOZ_UTF16("result"))) return WasmToken(WasmToken::Result, begin, cur_); if (consume(MOZ_UTF16("return"))) return WasmToken(WasmToken::Return, begin, cur_); break; case 's': + if (consume(MOZ_UTF16("select"))) + return WasmToken(WasmToken::TernaryOpcode, Expr::Select, begin, cur_); if (consume(MOZ_UTF16("set_local"))) return WasmToken(WasmToken::SetLocal, begin, cur_); if (consume(MOZ_UTF16("segment"))) return WasmToken(WasmToken::Segment, begin, cur_); break; case 't': if (consume(MOZ_UTF16("table"))) @@ -2503,16 +2529,34 @@ ParseComparisonOperator(WasmParseContext WasmAstExpr* rhs = ParseExpr(c); if (!rhs) return nullptr; return new(c.lifo) WasmAstComparisonOperator(expr, lhs, rhs); } +static WasmAstTernaryOperator* +ParseTernaryOperator(WasmParseContext& c, Expr expr) +{ + WasmAstExpr* op0 = ParseExpr(c); + if (!op0) + return nullptr; + + WasmAstExpr* op1 = ParseExpr(c); + if (!op1) + return nullptr; + + WasmAstExpr* op2 = ParseExpr(c); + if (!op2) + return nullptr; + + return new(c.lifo) WasmAstTernaryOperator(expr, op0, op1, op2); +} + static WasmAstConversionOperator* ParseConversionOperator(WasmParseContext& c, Expr expr) { WasmAstExpr* op = ParseExpr(c); if (!op) return nullptr; return new(c.lifo) WasmAstConversionOperator(expr, op); @@ -2736,16 +2780,18 @@ ParseExprInsideParens(WasmParseContext& case WasmToken::Loop: return ParseBlock(c, Expr::Loop); case WasmToken::Return: return ParseReturn(c); case WasmToken::SetLocal: return ParseSetLocal(c); case WasmToken::Store: return ParseStore(c, token.expr()); + case WasmToken::TernaryOpcode: + return ParseTernaryOperator(c, token.expr()); case WasmToken::UnaryOpcode: return ParseUnaryOperator(c, token.expr()); default: c.ts.generateError(token, c.error); return nullptr; } } @@ -3340,16 +3386,24 @@ ResolveUnaryOperator(Resolver& r, WasmAs static bool ResolveBinaryOperator(Resolver& r, WasmAstBinaryOperator& b) { return ResolveExpr(r, *b.lhs()) && ResolveExpr(r, *b.rhs()); } static bool +ResolveTernaryOperator(Resolver& r, WasmAstTernaryOperator& b) +{ + return ResolveExpr(r, *b.op0()) && + ResolveExpr(r, *b.op1()) && + ResolveExpr(r, *b.op2()); +} + +static bool ResolveComparisonOperator(Resolver& r, WasmAstComparisonOperator& b) { return ResolveExpr(r, *b.lhs()) && ResolveExpr(r, *b.rhs()); } static bool ResolveConversionOperator(Resolver& r, WasmAstConversionOperator& b) @@ -3436,16 +3490,18 @@ ResolveExpr(Resolver& r, WasmAstExpr& ex case WasmAstExprKind::Return: return ResolveReturn(r, expr.as<WasmAstReturn>()); case WasmAstExprKind::SetLocal: return ResolveSetLocal(r, expr.as<WasmAstSetLocal>()); case WasmAstExprKind::Store: return ResolveStore(r, expr.as<WasmAstStore>()); case WasmAstExprKind::BranchTable: return ResolveBranchTable(r, expr.as<WasmAstBranchTable>()); + case WasmAstExprKind::TernaryOperator: + return ResolveTernaryOperator(r, expr.as<WasmAstTernaryOperator>()); case WasmAstExprKind::UnaryOperator: return ResolveUnaryOperator(r, expr.as<WasmAstUnaryOperator>()); } MOZ_CRASH("Bad expr kind"); } static bool ResolveFunc(Resolver& r, WasmAstFunc& func) @@ -3656,16 +3712,25 @@ static bool EncodeBinaryOperator(Encoder& e, WasmAstBinaryOperator& b) { return e.writeExpr(b.expr()) && EncodeExpr(e, *b.lhs()) && EncodeExpr(e, *b.rhs()); } static bool +EncodeTernaryOperator(Encoder& e, WasmAstTernaryOperator& b) +{ + return e.writeExpr(b.expr()) && + EncodeExpr(e, *b.op0()) && + EncodeExpr(e, *b.op1()) && + EncodeExpr(e, *b.op2()); +} + +static bool EncodeComparisonOperator(Encoder& e, WasmAstComparisonOperator& b) { return e.writeExpr(b.expr()) && EncodeExpr(e, *b.lhs()) && EncodeExpr(e, *b.rhs()); } static bool @@ -3767,16 +3832,18 @@ EncodeExpr(Encoder& e, WasmAstExpr& expr case WasmAstExprKind::Return: return EncodeReturn(e, expr.as<WasmAstReturn>()); case WasmAstExprKind::SetLocal: return EncodeSetLocal(e, expr.as<WasmAstSetLocal>()); case WasmAstExprKind::Store: return EncodeStore(e, expr.as<WasmAstStore>()); case WasmAstExprKind::BranchTable: return EncodeBranchTable(e, expr.as<WasmAstBranchTable>()); + case WasmAstExprKind::TernaryOperator: + return EncodeTernaryOperator(e, expr.as<WasmAstTernaryOperator>()); case WasmAstExprKind::UnaryOperator: return EncodeUnaryOperator(e, expr.as<WasmAstUnaryOperator>()); } MOZ_CRASH("Bad expr kind"); } /*****************************************************************************/ // wasm AST binary serialization
--- a/js/src/jit-test/tests/wasm/basic-control-flow.js +++ b/js/src/jit-test/tests/wasm/basic-control-flow.js @@ -410,9 +410,8 @@ assertEq(f(3), -1); // unreachable const UNREACHABLE = /unreachable/; assertErrorMessage(wasmEvalText(`(module (func (trap)) (export "" 0))`), Error, UNREACHABLE); assertErrorMessage(wasmEvalText(`(module (func (if (trap) (i32.const 0))) (export "" 0))`), Error, UNREACHABLE); assertErrorMessage(wasmEvalText(`(module (func (block (br_if 0 (trap)))) (export "" 0))`), Error, UNREACHABLE); assertErrorMessage(wasmEvalText(`(module (func (block (br_table 0 (trap)))) (export "" 0))`), Error, UNREACHABLE); assertErrorMessage(wasmEvalText(`(module (func (result i32) (i32.add (i32.const 0) (trap))) (export "" 0))`), Error, UNREACHABLE); -
--- a/js/src/jit-test/tests/wasm/basic.js +++ b/js/src/jit-test/tests/wasm/basic.js @@ -432,8 +432,170 @@ var {v2i, i2i, i2v} = wasmEvalText(`(mod (export "i2i" 7) (export "i2v" 8) )`); wasmEvalText('(module (func $foo (nop)) (func (call $foo)))'); wasmEvalText('(module (func (call $foo)) (func $foo (nop)))'); wasmEvalText('(module (import $bar "a" "") (func (call_import $bar)) (func $foo (nop)))', {a:()=>{}}); + +// ---------------------------------------------------------------------------- +// select + +assertErrorMessage(() => wasmEvalText('(module (func (select (i32.const 0) (f32.const 0) (i32.const 0))))'), TypeError, mismatchError("f32", "i32")); +assertErrorMessage(() => wasmEvalText('(module (func (select (i32.const 0) (i32.const 0) (f32.const 0))))'), TypeError, mismatchError("f32", "i32")); + +(function testSideEffects() { + +var numT = 0; +var numF = 0; + +var imports = { + ifTrue: () => 1 + numT++, + ifFalse: () => -1 + numF++, +} + +// Test that side-effects are applied on both branches. +var f = wasmEvalText(` +(module + (import "ifTrue" "" (result i32)) + (import "ifFalse" "" (result i32)) + (func (result i32) (param i32) + (select + (call_import 0) + (call_import 1) + (get_local 0) + ) + ) + (export "" 0) +) +`, imports); + +assertEq(f(-1), numT); +assertEq(numT, 1); +assertEq(numF, 1); + +assertEq(f(0), numF - 2); +assertEq(numT, 2); +assertEq(numF, 2); + +assertEq(f(1), numT); +assertEq(numT, 3); +assertEq(numF, 3); + +assertEq(f(0), numF - 2); +assertEq(numT, 4); +assertEq(numF, 4); + +assertEq(f(0), numF - 2); +assertEq(numT, 5); +assertEq(numF, 5); + +assertEq(f(1), numT); +assertEq(numT, 6); +assertEq(numF, 6); + +})(); + +function testSelect(type, trueVal, falseVal) { + + function toJS(val) { + switch (val) { + case "infinity": return Infinity; + case "nan": return NaN; + case "-0": return -0; + default: return val; + } + } + + var trueJS = toJS(trueVal); + var falseJS = toJS(falseVal); + + // Always true condition + var alwaysTrue = wasmEvalText(` + (module + (func (result ${type}) (param i32) + (select + (${type}.const ${trueVal}) + (${type}.const ${falseVal}) + (i32.const 1) + ) + ) + (export "" 0) + ) + `, imports); + + assertEq(alwaysTrue(0), trueJS); + assertEq(alwaysTrue(1), trueJS); + assertEq(alwaysTrue(-1), trueJS); + + // Always false condition + var alwaysFalse = wasmEvalText(` + (module + (func (result ${type}) (param i32) + (select + (${type}.const ${trueVal}) + (${type}.const ${falseVal}) + (i32.const 0) + ) + ) + (export "" 0) + ) + `, imports); + + assertEq(alwaysFalse(0), falseJS); + assertEq(alwaysFalse(1), falseJS); + assertEq(alwaysFalse(-1), falseJS); + + // Variable condition + var f = wasmEvalText(` + (module + (func (result ${type}) (param i32) + (select + (${type}.const ${trueVal}) + (${type}.const ${falseVal}) + (get_local 0) + ) + ) + (export "" 0) + ) + `, imports); + + assertEq(f(0), falseJS); + assertEq(f(1), trueJS); + assertEq(f(-1), trueJS); +} + +testSelect('i32', 13, 37); +testSelect('i32', Math.pow(2, 31) - 1, -Math.pow(2, 31)); + +testSelect('f32', Math.fround(13.37), Math.fround(19.89)); +testSelect('f32', 'infinity', '-0'); +testSelect('f32', 'nan', Math.pow(2, -31)); + +testSelect('f64', 13.37, 19.89); +testSelect('f64', 'infinity', '-0'); +testSelect('f64', 'nan', Math.pow(2, -31)); + +if (!hasI64) { + assertErrorMessage(() => wasmEvalText('(module (func (select (i64.const 0) (i64.const 1) (i32.const 0))))'), TypeError, /NYI/); +} else { + var f = wasmEvalText(` + (module + (func (result i32) (param i32) + (i64.gt_s + (select + (i64.const ${Math.pow(2, 31) + 1}) + (i64.const ${-Math.pow(2, 31) - 1}) + (get_local 0) + ) + (i64.const ${Math.pow(2, 31)}) + ) + ) + (export "" 0) + ) + `, imports); + + assertEq(f(0), 0); + assertEq(f(1), 1); + assertEq(f(-1), 1); +}
--- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -14478,16 +14478,59 @@ class MAsmJSCall final return spIncrement_; } bool possiblyCalls() const override { return true; } }; +class MAsmSelect + : public MTernaryInstruction, + public NoTypePolicy::Data +{ + MAsmSelect(MDefinition* trueExpr, MDefinition* falseExpr, MDefinition *condExpr) + : MTernaryInstruction(trueExpr, falseExpr, condExpr) + { + MOZ_ASSERT(condExpr->type() == MIRType_Int32); + MOZ_ASSERT(trueExpr->type() == falseExpr->type()); + setResultType(trueExpr->type()); + setMovable(); + } + + public: + INSTRUCTION_HEADER(AsmSelect) + + static MAsmSelect* New(TempAllocator& alloc, MDefinition* trueExpr, MDefinition* falseExpr, + MDefinition* condExpr) + { + return new(alloc) MAsmSelect(trueExpr, falseExpr, condExpr); + } + + MDefinition* trueExpr() const { + return getOperand(0); + } + MDefinition* falseExpr() const { + return getOperand(1); + } + MDefinition* condExpr() const { + return getOperand(2); + } + + AliasSet getAliasSet() const override { + return AliasSet::None(); + } + + bool congruentTo(const MDefinition* ins) const override { + return congruentIfOperandsEqual(ins); + } + + ALLOW_CLONE(MAsmSelect) +}; + class MUnknownValue : public MNullaryInstruction { protected: MUnknownValue() { setResultType(MIRType_Value); } public:
--- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -271,16 +271,17 @@ namespace jit { _(AsmJSStoreGlobalVar) \ _(AsmJSLoadFuncPtr) \ _(AsmJSLoadFFIFunc) \ _(AsmJSReturn) \ _(AsmJSParameter) \ _(AsmJSVoidReturn) \ _(AsmJSPassStackArg) \ _(AsmJSCall) \ + _(AsmSelect) \ _(NewDerivedTypedObject) \ _(RecompileCheck) \ _(MemoryBarrier) \ _(AsmJSCompareExchangeHeap) \ _(AsmJSAtomicExchangeHeap) \ _(AsmJSAtomicBinopHeap) \ _(UnknownValue) \ _(LexicalCheck) \
--- a/js/src/jit/arm/CodeGenerator-arm.cpp +++ b/js/src/jit/arm/CodeGenerator-arm.cpp @@ -2096,16 +2096,45 @@ CodeGeneratorARM::visitAtomicTypedArrayE AtomicBinopToTypedArray(this, lir->mir()->operation(), arrayType, value, mem, flagTemp); } else { BaseIndex mem(elements, ToRegister(lir->index()), ScaleFromElemWidth(width)); AtomicBinopToTypedArray(this, lir->mir()->operation(), arrayType, value, mem, flagTemp); } } void +CodeGeneratorARM::visitAsmSelect(LAsmSelect* ins) +{ + MIRType mirType = ins->mir()->type(); + + Register cond = ToRegister(ins->condExpr()); + masm.ma_cmp(cond, Imm32(0)); + + if (mirType == MIRType_Int32) { + Register falseExpr = ToRegister(ins->falseExpr()); + Register out = ToRegister(ins->output()); + MOZ_ASSERT(ToRegister(ins->trueExpr()) == out, "true expr input is reused for output"); + masm.ma_mov(falseExpr, out, LeaveCC, Assembler::Zero); + return; + } + + FloatRegister out = ToFloatRegister(ins->output()); + MOZ_ASSERT(ToFloatRegister(ins->trueExpr()) == out, "true expr input is reused for output"); + + FloatRegister falseExpr = ToFloatRegister(ins->falseExpr()); + + if (mirType == MIRType_Double) + masm.moveDouble(falseExpr, out, Assembler::Zero); + else if (mirType == MIRType_Float32) + masm.moveFloat32(falseExpr, out, Assembler::Zero); + else + MOZ_CRASH("unhandled type in visitAsmSelect!"); +} + +void CodeGeneratorARM::visitAsmJSCall(LAsmJSCall* ins) { MAsmJSCall* mir = ins->mir(); if (UseHardFpABI() || mir->callee().which() != MAsmJSCall::Callee::Builtin) { emitAsmJSCall(ins); return; }
--- a/js/src/jit/arm/CodeGenerator-arm.h +++ b/js/src/jit/arm/CodeGenerator-arm.h @@ -195,16 +195,17 @@ class CodeGeneratorARM : public CodeGene void visitNegD(LNegD* lir); void visitNegF(LNegF* lir); void visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins); void visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins); void visitAtomicTypedArrayElementBinop(LAtomicTypedArrayElementBinop* lir); void visitAtomicTypedArrayElementBinopForEffect(LAtomicTypedArrayElementBinopForEffect* lir); void visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir); void visitAtomicExchangeTypedArrayElement(LAtomicExchangeTypedArrayElement* lir); + void visitAsmSelect(LAsmSelect* ins); void visitAsmJSCall(LAsmJSCall* ins); void visitAsmJSLoadHeap(LAsmJSLoadHeap* ins); void visitAsmJSStoreHeap(LAsmJSStoreHeap* ins); void visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap* ins); void visitAsmJSCompareExchangeCallout(LAsmJSCompareExchangeCallout* ins); void visitAsmJSAtomicExchangeHeap(LAsmJSAtomicExchangeHeap* ins); void visitAsmJSAtomicExchangeCallout(LAsmJSAtomicExchangeCallout* ins); void visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins);
--- a/js/src/jit/arm/Lowering-arm.cpp +++ b/js/src/jit/arm/Lowering-arm.cpp @@ -406,16 +406,29 @@ LIRGeneratorARM::lowerUrshD(MUrsh* mir) MOZ_ASSERT(lhs->type() == MIRType_Int32); MOZ_ASSERT(rhs->type() == MIRType_Int32); LUrshD* lir = new(alloc()) LUrshD(useRegister(lhs), useRegisterOrConstant(rhs), temp()); define(lir, mir); } void +LIRGeneratorARM::visitAsmSelect(MAsmSelect* ins) +{ + MOZ_ASSERT(ins->type() != MIRType_Int64); + + auto* lir = new(alloc()) LAsmSelect(useRegisterAtStart(ins->trueExpr()), + useRegister(ins->falseExpr()), + useRegister(ins->condExpr()) + ); + + defineReuseInput(lir, ins, LAsmSelect::TrueExprIndex); +} + +void LIRGeneratorARM::visitAsmJSNeg(MAsmJSNeg* ins) { if (ins->type() == MIRType_Int32) { define(new(alloc()) LNegI(useRegisterAtStart(ins->input())), ins); } else if (ins->type() == MIRType_Float32) { define(new(alloc()) LNegF(useRegisterAtStart(ins->input())), ins); } else { MOZ_ASSERT(ins->type() == MIRType_Double);
--- a/js/src/jit/arm/Lowering-arm.h +++ b/js/src/jit/arm/Lowering-arm.h @@ -89,16 +89,17 @@ class LIRGeneratorARM : public LIRGenera public: void visitBox(MBox* box); void visitUnbox(MUnbox* unbox); void visitReturn(MReturn* ret); void lowerPhi(MPhi* phi); void visitGuardShape(MGuardShape* ins); void visitGuardObjectGroup(MGuardObjectGroup* ins); + void visitAsmSelect(MAsmSelect* ins); void visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble* ins); void visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32* ins); void visitAsmJSLoadHeap(MAsmJSLoadHeap* ins); void visitAsmJSStoreHeap(MAsmJSStoreHeap* ins); void visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr* ins); void visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap* ins); void visitAsmJSAtomicExchangeHeap(MAsmJSAtomicExchangeHeap* ins); void visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap* ins);
--- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -998,18 +998,18 @@ class MacroAssemblerARMCompat : public M void storePtr(Register src, AbsoluteAddress dest); void storeDouble(FloatRegister src, Address addr) { ma_vstr(src, addr); } void storeDouble(FloatRegister src, BaseIndex addr) { uint32_t scale = Imm32::ShiftOf(addr.scale).value; ma_vstr(src, addr.base, addr.index, scale, addr.offset); } - void moveDouble(FloatRegister src, FloatRegister dest) { - ma_vmov(src, dest); + void moveDouble(FloatRegister src, FloatRegister dest, Condition cc = Always) { + ma_vmov(src, dest, cc); } void storeFloat32(FloatRegister src, const Address& addr) { ma_vstr(VFPRegister(src).singleOverlay(), addr); } void storeFloat32(FloatRegister src, const BaseIndex& addr) { uint32_t scale = Imm32::ShiftOf(addr.scale).value; ma_vstr(VFPRegister(src).singleOverlay(), addr.base, addr.index, scale, addr.offset); @@ -1436,18 +1436,18 @@ class MacroAssemblerARMCompat : public M void ma_storeImm(Imm32 c, const Address& dest) { ma_mov(c, lr); ma_str(lr, dest); } BufferOffset ma_BoundsCheck(Register bounded) { return as_cmp(bounded, Imm8(0)); } - void moveFloat32(FloatRegister src, FloatRegister dest) { - as_vmov(VFPRegister(dest).singleOverlay(), VFPRegister(src).singleOverlay()); + void moveFloat32(FloatRegister src, FloatRegister dest, Condition cc = Always) { + as_vmov(VFPRegister(dest).singleOverlay(), VFPRegister(src).singleOverlay(), cc); } void loadWasmActivation(Register dest) { loadPtr(Address(GlobalReg, wasm::ActivationGlobalDataOffset - AsmJSGlobalRegBias), dest); } void loadAsmJSHeapRegisterFromGlobalData() { loadPtr(Address(GlobalReg, wasm::HeapGlobalDataOffset - AsmJSGlobalRegBias), HeapReg); }
--- a/js/src/jit/arm64/Lowering-arm64.cpp +++ b/js/src/jit/arm64/Lowering-arm64.cpp @@ -197,16 +197,22 @@ LIRGeneratorARM64::lowerUrshD(MUrsh* mir void LIRGeneratorARM64::visitAsmJSNeg(MAsmJSNeg* ins) { MOZ_CRASH("visitAsmJSNeg"); } void +LIRGeneratorARM64::visitAsmSelect(MAsmSelect* ins) +{ + MOZ_CRASH("visitAsmSelect"); +} + +void LIRGeneratorARM64::lowerUDiv(MDiv* div) { MOZ_CRASH("lowerUDiv"); } void LIRGeneratorARM64::lowerUMod(MMod* mod) {
--- a/js/src/jit/arm64/Lowering-arm64.h +++ b/js/src/jit/arm64/Lowering-arm64.h @@ -79,16 +79,17 @@ class LIRGeneratorARM64 : public LIRGene void lowerModI(MMod* mod); void lowerDivI64(MDiv* div); void lowerModI64(MMod* mod); void lowerMulI(MMul* mul, MDefinition* lhs, MDefinition* rhs); void lowerUDiv(MDiv* div); void lowerUMod(MMod* mod); void visitPowHalf(MPowHalf* ins); void visitAsmJSNeg(MAsmJSNeg* ins); + void visitAsmSelect(MAsmSelect* ins); LTableSwitchV* newLTableSwitchV(MTableSwitch* ins); LTableSwitch* newLTableSwitch(const LAllocation& in, const LDefinition& inputCopy, MTableSwitch* ins); public: void visitBox(MBox* box);
--- a/js/src/jit/none/Lowering-none.h +++ b/js/src/jit/none/Lowering-none.h @@ -80,16 +80,17 @@ class LIRGeneratorNone : public LIRGener void visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr* ins) { MOZ_CRASH(); } void visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic* ins) { MOZ_CRASH(); } void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins) { MOZ_CRASH(); } void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins) { MOZ_CRASH(); } void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins) { MOZ_CRASH(); } void visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap* ins) { MOZ_CRASH(); } void visitAsmJSAtomicExchangeHeap(MAsmJSAtomicExchangeHeap* ins) { MOZ_CRASH(); } void visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap* ins) { MOZ_CRASH(); } + void visitAsmSelect(MAsmSelect*) { MOZ_CRASH(); } LTableSwitch* newLTableSwitch(LAllocation, LDefinition, MTableSwitch*) { MOZ_CRASH(); } LTableSwitchV* newLTableSwitchV(MTableSwitch*) { MOZ_CRASH(); } void visitSimdSelect(MSimdSelect* ins) { MOZ_CRASH(); } void visitSimdSplatX4(MSimdSplatX4* ins) { MOZ_CRASH(); } void visitSimdValueX4(MSimdValueX4* lir) { MOZ_CRASH(); } void visitSubstr(MSubstr*) { MOZ_CRASH(); } void visitSimdBinaryArith(js::jit::MSimdBinaryArith*) { MOZ_CRASH(); }
--- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -7250,16 +7250,67 @@ class LHasClass : public LInstructionHel const LAllocation* lhs() { return getOperand(0); } MHasClass* mir() const { return mir_->toHasClass(); } }; +template<size_t Defs, size_t Ops> +class LAsmSelectBase : public LInstructionHelper<Defs, Ops, 0> +{ + typedef LInstructionHelper<Defs, Ops, 0> Base; + public: + static const size_t TrueExprIndex = 0; + + const LAllocation* trueExpr() { + static_assert(TrueExprIndex == 0, "trueExprIndex kept in sync"); + return Base::getOperand(0); + } + const LAllocation* falseExpr() { + return Base::getOperand(1); + } + const LAllocation* condExpr() { + return Base::getOperand(2); + } + + MAsmSelect* mir() const { + return Base::mir_->toAsmSelect(); + } +}; + +class LAsmSelect : public LAsmSelectBase<1, 3> +{ + public: + LIR_HEADER(AsmSelect); + + LAsmSelect(const LAllocation& trueExpr, const LAllocation& falseExpr, const LAllocation& cond) { + static_assert(TrueExprIndex == 0, "trueExprIndex kept in sync"); + setOperand(0, trueExpr); + setOperand(1, falseExpr); + setOperand(2, cond); + } +}; + +class LAsmSelectI64 : public LAsmSelectBase<INT64_PIECES, 2 * INT64_PIECES + 1> +{ + public: + LIR_HEADER(AsmSelectI64); + + LAsmSelectI64(const LInt64Allocation& trueExpr, const LInt64Allocation& falseExpr, + const LAllocation& cond) + { + static_assert(TrueExprIndex == 0, "trueExprIndex kept in sync"); + setInt64Operand(0, trueExpr); + setInt64Operand(1, falseExpr); + setOperand(2, cond); + } +}; + class LAsmJSLoadHeap : public LInstructionHelper<1, 1, 0> { public: LIR_HEADER(AsmJSLoadHeap); explicit LAsmJSLoadHeap(const LAllocation& ptr) { setOperand(0, ptr); } MAsmJSLoadHeap* mir() const {
--- a/js/src/jit/shared/LOpcodes-shared.h +++ b/js/src/jit/shared/LOpcodes-shared.h @@ -350,16 +350,18 @@ _(GetDOMMemberV) \ _(GetDOMMemberT) \ _(SetDOMProperty) \ _(CallDOMNative) \ _(IsCallable) \ _(IsObject) \ _(IsObjectAndBranch) \ _(HasClass) \ + _(AsmSelect) \ + _(AsmSelectI64) \ _(AsmJSLoadHeap) \ _(AsmJSStoreHeap) \ _(AsmJSLoadFuncPtr) \ _(AsmJSLoadGlobalVar) \ _(AsmJSStoreGlobalVar) \ _(AsmJSLoadFFIFunc) \ _(AsmJSParameter) \ _(AsmJSReturn) \
--- a/js/src/jit/x64/Assembler-x64.h +++ b/js/src/jit/x64/Assembler-x64.h @@ -433,16 +433,32 @@ class Assembler : public AssemblerX86Sha } void vmovq(FloatRegister src, Register dest) { masm.vmovq_rr(src.encoding(), dest.encoding()); } void movq(Register src, Register dest) { masm.movq_rr(src.encoding(), dest.encoding()); } + void cmovzq(const Operand& src, Register dest) { + switch (src.kind()) { + case Operand::REG: + masm.cmovzq_rr(src.reg(), dest.encoding()); + break; + case Operand::MEM_REG_DISP: + masm.cmovzq_mr(src.disp(), src.base(), dest.encoding()); + break; + case Operand::MEM_SCALE: + masm.cmovzq_mr(src.disp(), src.base(), src.index(), src.scale(), dest.encoding()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + } + } + void xchgq(Register src, Register dest) { masm.xchgq_rr(src.encoding(), dest.encoding()); } void movslq(Register src, Register dest) { masm.movslq_rr(src.encoding(), dest.encoding()); } void movslq(const Operand& src, Register dest) {
--- a/js/src/jit/x64/BaseAssembler-x64.h +++ b/js/src/jit/x64/BaseAssembler-x64.h @@ -430,16 +430,32 @@ class BaseAssemblerX64 : public BaseAsse { spew("testq $0x%4x, " MEM_obs, rhs, ADDR_obs(offset, base, index, scale)); m_formatter.oneByteOp64(OP_GROUP3_EvIz, offset, base, index, scale, GROUP3_OP_TEST); m_formatter.immediate32(rhs); } // Various move ops: + void cmovzq_rr(RegisterID src, RegisterID dst) + { + spew("cmovz %s, %s", GPReg16Name(src), GPReg32Name(dst)); + m_formatter.twoByteOp64(OP2_CMOVZ_GvqpEvqp, src, dst); + } + void cmovzq_mr(int32_t offset, RegisterID base, RegisterID dst) + { + spew("cmovz " MEM_ob ", %s", ADDR_ob(offset, base), GPReg32Name(dst)); + m_formatter.twoByteOp64(OP2_CMOVZ_GvqpEvqp, offset, base, dst); + } + void cmovzq_mr(int32_t offset, RegisterID base, RegisterID index, int scale, RegisterID dst) + { + spew("cmovz " MEM_obs ", %s", ADDR_obs(offset, base, index, scale), GPReg32Name(dst)); + m_formatter.twoByteOp64(OP2_CMOVZ_GvqpEvqp, offset, base, index, scale, dst); + } + void xchgq_rr(RegisterID src, RegisterID dst) { spew("xchgq %s, %s", GPReg64Name(src), GPReg64Name(dst)); m_formatter.oneByteOp64(OP_XCHG_GvEv, src, dst); } void xchgq_rm(RegisterID src, int32_t offset, RegisterID base) { spew("xchgq %s, " MEM_ob, GPReg64Name(src), ADDR_ob(offset, base));
--- a/js/src/jit/x64/CodeGenerator-x64.cpp +++ b/js/src/jit/x64/CodeGenerator-x64.cpp @@ -473,16 +473,31 @@ CodeGeneratorX64::visitUDivOrMod64(LUDiv // Zero extend the lhs into rdx to make (rdx:rax). masm.xorl(rdx, rdx); masm.udivq(rhs); masm.bind(&done); } void +CodeGeneratorX64::visitAsmSelectI64(LAsmSelectI64* lir) +{ + MOZ_ASSERT(lir->mir()->type() == MIRType_Int64); + + Register cond = ToRegister(lir->condExpr()); + Operand falseExpr = ToOperand(lir->falseExpr()); + + Register out = ToRegister(lir->output()); + MOZ_ASSERT(ToRegister(lir->trueExpr()) == out, "true expr is reused for input"); + + masm.test32(cond, cond); + masm.cmovzq(falseExpr, out); +} + +void CodeGeneratorX64::visitAsmJSUInt32ToDouble(LAsmJSUInt32ToDouble* lir) { masm.convertUInt32ToDouble(ToRegister(lir->input()), ToFloatRegister(lir->output())); } void CodeGeneratorX64::visitAsmJSUInt32ToFloat32(LAsmJSUInt32ToFloat32* lir) {
--- a/js/src/jit/x64/CodeGenerator-x64.h +++ b/js/src/jit/x64/CodeGenerator-x64.h @@ -54,16 +54,17 @@ class CodeGeneratorX64 : public CodeGene void visitTruncateDToInt32(LTruncateDToInt32* ins); void visitTruncateFToInt32(LTruncateFToInt32* ins); void visitWrapInt64ToInt32(LWrapInt64ToInt32* lir); void visitExtendInt32ToInt64(LExtendInt32ToInt64* lir); void visitTruncateToInt64(LTruncateToInt64* lir); void visitInt64ToFloatingPoint(LInt64ToFloatingPoint* lir); void visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins); void visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins); + void visitAsmSelectI64(LAsmSelectI64* ins); void visitAsmJSCall(LAsmJSCall* ins); void visitAsmJSLoadHeap(LAsmJSLoadHeap* ins); void visitAsmJSStoreHeap(LAsmJSStoreHeap* ins); void visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap* ins); void visitAsmJSAtomicExchangeHeap(LAsmJSAtomicExchangeHeap* ins); void visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins); void visitAsmJSAtomicBinopHeapForEffect(LAsmJSAtomicBinopHeapForEffect* ins); void visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar* ins);
--- a/js/src/jit/x86-shared/Assembler-x86-shared.h +++ b/js/src/jit/x86-shared/Assembler-x86-shared.h @@ -440,16 +440,31 @@ class AssemblerX86Shared : public Assemb void nopAlign(int alignment) { masm.nopAlign(alignment); } void writeCodePointer(CodeOffset* label) { // A CodeOffset only has one use, bake in the "end of list" value. masm.jumpTablePointer(LabelBase::INVALID_OFFSET); label->bind(masm.size()); } + void cmovz(const Operand& src, Register dest) { + switch (src.kind()) { + case Operand::REG: + masm.cmovz_rr(src.reg(), dest.encoding()); + break; + case Operand::MEM_REG_DISP: + masm.cmovz_mr(src.disp(), src.base(), dest.encoding()); + break; + case Operand::MEM_SCALE: + masm.cmovz_mr(src.disp(), src.base(), src.index(), src.scale(), dest.encoding()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + } + } void movl(Imm32 imm32, Register dest) { masm.movl_i32r(imm32.value, dest.encoding()); } void movl(Register src, Register dest) { masm.movl_rr(src.encoding(), dest.encoding()); } void movl(const Operand& src, Register dest) { switch (src.kind()) {
--- a/js/src/jit/x86-shared/BaseAssembler-x86-shared.h +++ b/js/src/jit/x86-shared/BaseAssembler-x86-shared.h @@ -1766,16 +1766,32 @@ public: m_formatter.oneByteOp(OP_XCHG_GvEv, offset, base, src); } void xchgl_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale) { spew("xchgl %s, " MEM_obs, GPReg32Name(src), ADDR_obs(offset, base, index, scale)); m_formatter.oneByteOp(OP_XCHG_GvEv, offset, base, index, scale, src); } + void cmovz_rr(RegisterID src, RegisterID dst) + { + spew("cmovz %s, %s", GPReg16Name(src), GPReg32Name(dst)); + m_formatter.twoByteOp(OP2_CMOVZ_GvqpEvqp, src, dst); + } + void cmovz_mr(int32_t offset, RegisterID base, RegisterID dst) + { + spew("cmovz " MEM_ob ", %s", ADDR_ob(offset, base), GPReg32Name(dst)); + m_formatter.twoByteOp(OP2_CMOVZ_GvqpEvqp, offset, base, dst); + } + void cmovz_mr(int32_t offset, RegisterID base, RegisterID index, int scale, RegisterID dst) + { + spew("cmovz " MEM_obs ", %s", ADDR_obs(offset, base, index, scale), GPReg32Name(dst)); + m_formatter.twoByteOp(OP2_CMOVZ_GvqpEvqp, offset, base, index, scale, dst); + } + void movl_rr(RegisterID src, RegisterID dst) { spew("movl %s, %s", GPReg32Name(src), GPReg32Name(dst)); m_formatter.oneByteOp(OP_MOV_GvEv, src, dst); } void movw_rm(RegisterID src, int32_t offset, RegisterID base) {
--- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp @@ -296,16 +296,57 @@ CodeGeneratorX86Shared::visitAsmJSPassSt default: break; } MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected mir type in AsmJSPassStackArg"); } } } void +CodeGeneratorX86Shared::visitAsmSelect(LAsmSelect* ins) +{ + MIRType mirType = ins->mir()->type(); + + Register cond = ToRegister(ins->condExpr()); + Operand falseExpr = ToOperand(ins->falseExpr()); + + masm.test32(cond, cond); + + if (mirType == MIRType_Int32) { + Register out = ToRegister(ins->output()); + MOZ_ASSERT(ToRegister(ins->trueExpr()) == out, "true expr input is reused for output"); + masm.cmovz(falseExpr, out); + return; + } + + FloatRegister out = ToFloatRegister(ins->output()); + MOZ_ASSERT(ToFloatRegister(ins->trueExpr()) == out, "true expr input is reused for output"); + + Label done; + masm.j(Assembler::NonZero, &done); + + if (mirType == MIRType_Float32) { + if (falseExpr.kind() == Operand::FPREG) + masm.moveFloat32(ToFloatRegister(ins->falseExpr()), out); + else + masm.loadFloat32(falseExpr, out); + } else if (mirType == MIRType_Double) { + if (falseExpr.kind() == Operand::FPREG) + masm.moveDouble(ToFloatRegister(ins->falseExpr()), out); + else + masm.loadDouble(falseExpr, out); + } else { + MOZ_CRASH("unhandled type in visitAsmSelect!"); + } + + masm.bind(&done); + return; +} + +void CodeGeneratorX86Shared::visitOutOfLineLoadTypedArrayOutOfBounds(OutOfLineLoadTypedArrayOutOfBounds* ool) { switch (ool->viewType()) { case Scalar::Float32x4: case Scalar::Int32x4: case Scalar::MaxTypedArrayViewType: MOZ_CRASH("unexpected array type"); case Scalar::Float32:
--- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.h +++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.h @@ -256,16 +256,17 @@ class CodeGeneratorX86Shared : public Co virtual void visitRoundF(LRoundF* lir); virtual void visitGuardShape(LGuardShape* guard); virtual void visitGuardObjectGroup(LGuardObjectGroup* guard); virtual void visitGuardClass(LGuardClass* guard); virtual void visitEffectiveAddress(LEffectiveAddress* ins); virtual void visitUDivOrMod(LUDivOrMod* ins); virtual void visitUDivOrModConstant(LUDivOrModConstant *ins); virtual void visitAsmJSPassStackArg(LAsmJSPassStackArg* ins); + virtual void visitAsmSelect(LAsmSelect* ins); virtual void visitMemoryBarrier(LMemoryBarrier* ins); virtual void visitAtomicTypedArrayElementBinop(LAtomicTypedArrayElementBinop* lir); virtual void visitAtomicTypedArrayElementBinopForEffect(LAtomicTypedArrayElementBinopForEffect* lir); virtual void visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir); virtual void visitAtomicExchangeTypedArrayElement(LAtomicExchangeTypedArrayElement* lir); void visitOutOfLineLoadTypedArrayOutOfBounds(OutOfLineLoadTypedArrayOutOfBounds* ool); void visitOffsetBoundsCheck(OffsetBoundsCheck* oolCheck);
--- a/js/src/jit/x86-shared/Encoding-x86-shared.h +++ b/js/src/jit/x86-shared/Encoding-x86-shared.h @@ -141,16 +141,17 @@ enum TwoByteOpcodeID { OP2_MOVLHPS_VqUq = 0x16, OP2_MOVSHDUP_VpsWps = 0x16, OP2_MOVAPD_VsdWsd = 0x28, OP2_MOVAPS_VsdWsd = 0x28, OP2_MOVAPS_WsdVsd = 0x29, OP2_CVTSI2SD_VsdEd = 0x2A, OP2_CVTTSD2SI_GdWsd = 0x2C, OP2_UCOMISD_VsdWsd = 0x2E, + OP2_CMOVZ_GvqpEvqp = 0x44, OP2_MOVMSKPD_EdVd = 0x50, OP2_ANDPS_VpsWps = 0x54, OP2_ANDNPS_VpsWps = 0x55, OP2_ORPS_VpsWps = 0x56, OP2_XORPS_VpsWps = 0x57, OP2_ADDSD_VsdWsd = 0x58, OP2_ADDPS_VpsWps = 0x58, OP2_MULSD_VsdWsd = 0x59,
--- a/js/src/jit/x86-shared/Lowering-x86-shared.cpp +++ b/js/src/jit/x86-shared/Lowering-x86-shared.cpp @@ -284,16 +284,37 @@ LIRGeneratorX86Shared::lowerModI(MMod* m useRegister(mod->rhs()), tempFixed(eax)); if (mod->fallible()) assignSnapshot(lir, Bailout_DoubleOutput); defineFixed(lir, mod, LAllocation(AnyRegister(edx))); } void +LIRGeneratorX86Shared::visitAsmSelect(MAsmSelect* ins) +{ + if (ins->type() == MIRType_Int64) { + auto* lir = new(alloc()) LAsmSelectI64(useInt64RegisterAtStart(ins->trueExpr()), + useInt64(ins->falseExpr()), + useRegister(ins->condExpr()) + ); + + defineInt64ReuseInput(lir, ins, LAsmSelectI64::TrueExprIndex); + return; + } + + auto* lir = new(alloc()) LAsmSelect(useRegisterAtStart(ins->trueExpr()), + use(ins->falseExpr()), + useRegister(ins->condExpr()) + ); + + defineReuseInput(lir, ins, LAsmSelect::TrueExprIndex); +} + +void LIRGeneratorX86Shared::visitAsmJSNeg(MAsmJSNeg* ins) { switch (ins->type()) { case MIRType_Int32: defineReuseInput(new(alloc()) LNegI(useRegisterAtStart(ins->input())), ins, 0); break; case MIRType_Float32: defineReuseInput(new(alloc()) LNegF(useRegisterAtStart(ins->input())), ins, 0);
--- a/js/src/jit/x86-shared/Lowering-x86-shared.h +++ b/js/src/jit/x86-shared/Lowering-x86-shared.h @@ -42,16 +42,17 @@ class LIRGeneratorX86Shared : public LIR MDefinition* rhs); void lowerForCompIx4(LSimdBinaryCompIx4* ins, MSimdBinaryComp* mir, MDefinition* lhs, MDefinition* rhs); void lowerForCompFx4(LSimdBinaryCompFx4* ins, MSimdBinaryComp* mir, MDefinition* lhs, MDefinition* rhs); void lowerForBitAndAndBranch(LBitAndAndBranch* baab, MInstruction* mir, MDefinition* lhs, MDefinition* rhs); void visitAsmJSNeg(MAsmJSNeg* ins); + void visitAsmSelect(MAsmSelect* ins); void lowerMulI(MMul* mul, MDefinition* lhs, MDefinition* rhs); void lowerDivI(MDiv* div); void lowerModI(MMod* mod); void lowerUDiv(MDiv* div); void lowerUMod(MMod* mod); void lowerUrshD(MUrsh* mir); void lowerTruncateDToInt32(MTruncateToInt32* ins); void lowerTruncateFToInt32(MTruncateToInt32* ins);