diff options
-rw-r--r-- | src/qml/jit/jit.pri | 2 | ||||
-rw-r--r-- | src/qml/jit/qv4assembler.cpp | 96 | ||||
-rw-r--r-- | src/qml/jit/qv4assembler_p.h | 2 | ||||
-rw-r--r-- | src/qml/jit/qv4binop.cpp | 431 | ||||
-rw-r--r-- | src/qml/jit/qv4binop_p.h | 76 | ||||
-rw-r--r-- | src/qml/jit/qv4isel_masm.cpp | 456 | ||||
-rw-r--r-- | src/qml/jit/qv4isel_masm_p.h | 8 |
7 files changed, 612 insertions, 459 deletions
diff --git a/src/qml/jit/jit.pri b/src/qml/jit/jit.pri index 581eadc43a..151ff32df9 100644 --- a/src/qml/jit/jit.pri +++ b/src/qml/jit/jit.pri @@ -7,12 +7,14 @@ HEADERS += \ $$PWD/qv4assembler_p.h \ $$PWD/qv4regalloc_p.h \ $$PWD/qv4isel_masm_p.h \ + $$PWD/qv4binop_p.h \ $$PWD/qv4unop_p.h \ SOURCES += \ $$PWD/qv4assembler.cpp \ $$PWD/qv4regalloc.cpp \ $$PWD/qv4isel_masm.cpp \ + $$PWD/qv4binop.cpp \ $$PWD/qv4unop.cpp \ include(../../3rdparty/masm/masm.pri) diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index 6733d7f2f1..0cf2b79ac8 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -370,4 +370,100 @@ const Assembler::BinaryOperationInfo Assembler::binaryOperations[QQmlJS::V4IR::L NULL_OP // OpOr }; + +// Try to load the source expression into the destination FP register. This assumes that two +// general purpose (integer) registers are available: the ScratchRegister and the +// ReturnValueRegister. It returns a Jump if no conversion can be performed. +Assembler::Jump Assembler::genTryDoubleConversion(V4IR::Expr *src, Assembler::FPRegisterID dest) +{ + switch (src->type) { + case V4IR::DoubleType: + moveDouble(toDoubleRegister(src, dest), dest); + return Assembler::Jump(); + case V4IR::SInt32Type: + convertInt32ToDouble(toInt32Register(src, Assembler::ScratchRegister), + dest); + return Assembler::Jump(); + case V4IR::UInt32Type: + convertUInt32ToDouble(toUInt32Register(src, Assembler::ScratchRegister), + dest, Assembler::ReturnValueRegister); + return Assembler::Jump(); + case V4IR::BoolType: + // TODO? + return jump(); + default: + break; + } + + V4IR::Temp *sourceTemp = src->asTemp(); + Q_ASSERT(sourceTemp); + + // It's not a number type, so it cannot be in a register. + Q_ASSERT(sourceTemp->kind != V4IR::Temp::PhysicalRegister || sourceTemp->type == V4IR::BoolType); + + Assembler::Pointer tagAddr = loadTempAddress(Assembler::ScratchRegister, sourceTemp); + tagAddr.offset += 4; + load32(tagAddr, Assembler::ScratchRegister); + + // check if it's an int32: + Assembler::Jump isNoInt = branch32(Assembler::NotEqual, Assembler::ScratchRegister, + Assembler::TrustedImm32(Value::_Integer_Type)); + convertInt32ToDouble(toInt32Register(src, Assembler::ScratchRegister), dest); + Assembler::Jump intDone = jump(); + + // not an int, check if it's a double: + isNoInt.link(this); +#if QT_POINTER_SIZE == 8 + and32(Assembler::TrustedImm32(Value::IsDouble_Mask), Assembler::ScratchRegister); + Assembler::Jump isNoDbl = branch32(Assembler::Equal, Assembler::ScratchRegister, + Assembler::TrustedImm32(0)); +#else + and32(Assembler::TrustedImm32(Value::NotDouble_Mask), Assembler::ScratchRegister); + Assembler::Jump isNoDbl = branch32(Assembler::Equal, Assembler::ScratchRegister, + Assembler::TrustedImm32(Value::NotDouble_Mask)); +#endif + toDoubleRegister(src, dest); + intDone.link(this); + + return isNoDbl; +} + +#ifndef QT_NO_DEBUG +namespace { +inline bool isPregOrConst(V4IR::Expr *e) +{ + if (V4IR::Temp *t = e->asTemp()) + return t->kind == V4IR::Temp::PhysicalRegister; + return e->asConst() != 0; +} +} // anonymous namespace +#endif + +Assembler::Jump Assembler::branchDouble(bool invertCondition, V4IR::AluOp op, + V4IR::Expr *left, V4IR::Expr *right) +{ + Q_ASSERT(isPregOrConst(left)); + Q_ASSERT(isPregOrConst(right)); + Q_ASSERT(left->asConst() == 0 || right->asConst() == 0); + + Assembler::DoubleCondition cond; + switch (op) { + case V4IR::OpGt: cond = Assembler::DoubleGreaterThan; break; + case V4IR::OpLt: cond = Assembler::DoubleLessThan; break; + case V4IR::OpGe: cond = Assembler::DoubleGreaterThanOrEqual; break; + case V4IR::OpLe: cond = Assembler::DoubleLessThanOrEqual; break; + case V4IR::OpEqual: + case V4IR::OpStrictEqual: cond = Assembler::DoubleEqual; break; + case V4IR::OpNotEqual: + case V4IR::OpStrictNotEqual: cond = Assembler::DoubleNotEqualOrUnordered; break; // No, the inversion of DoubleEqual is NOT DoubleNotEqual. + default: + Q_UNREACHABLE(); + } + if (invertCondition) + cond = JSC::MacroAssembler::invert(cond); + + return JSC::MacroAssembler::branchDouble(cond, toDoubleRegister(left), toDoubleRegister(right)); +} + + #endif diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index ace1aab7b5..daa7816a2d 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -498,6 +498,8 @@ public: void generateCJumpOnCompare(RelationalCondition cond, RegisterID left, RegisterID right, V4IR::BasicBlock *currentBlock, V4IR::BasicBlock *trueBlock, V4IR::BasicBlock *falseBlock); + Jump genTryDoubleConversion(V4IR::Expr *src, Assembler::FPRegisterID dest); + Assembler::Jump branchDouble(bool invertCondition, V4IR::AluOp op, V4IR::Expr *left, V4IR::Expr *right); Pointer loadTempAddress(RegisterID baseReg, V4IR::Temp *t); Pointer loadStringAddress(RegisterID reg, const QString &string); diff --git a/src/qml/jit/qv4binop.cpp b/src/qml/jit/qv4binop.cpp new file mode 100644 index 0000000000..02762db65b --- /dev/null +++ b/src/qml/jit/qv4binop.cpp @@ -0,0 +1,431 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <qv4binop_p.h> +#include <qv4assembler_p.h> + +#if ENABLE(ASSEMBLER) + +using namespace QV4; +using namespace JIT; + +using namespace QQmlJS; +using namespace MASM; + +namespace { +inline bool isPregOrConst(V4IR::Expr *e) +{ + if (V4IR::Temp *t = e->asTemp()) + return t->kind == V4IR::Temp::PhysicalRegister; + return e->asConst() != 0; +} +} // anonymous namespace + +void Binop::generate(V4IR::Expr *lhs, V4IR::Expr *rhs, V4IR::Temp *target) +{ + if (op != V4IR::OpMod + && lhs->type == V4IR::DoubleType && rhs->type == V4IR::DoubleType + && isPregOrConst(lhs) && isPregOrConst(rhs)) { + doubleBinop(lhs, rhs, target); + return; + } + if (lhs->type == V4IR::SInt32Type && rhs->type == V4IR::SInt32Type) { + if (int32Binop(lhs, rhs, target)) + return; + } + + Assembler::Jump done; + if (lhs->type != V4IR::StringType && rhs->type != V4IR::StringType) + done = genInlineBinop(lhs, rhs, target); + + // TODO: inline var===null and var!==null + Assembler::BinaryOperationInfo info = Assembler::binaryOperation(op); + + if (op == V4IR::OpAdd && + (lhs->type == V4IR::StringType || rhs->type == V4IR::StringType)) { + const Assembler::BinaryOperationInfo stringAdd = OPCONTEXT(__qmljs_add_string); + info = stringAdd; + } + + if (info.fallbackImplementation) { + as->generateFunctionCallImp(target, info.name, info.fallbackImplementation, + Assembler::PointerToValue(lhs), + Assembler::PointerToValue(rhs)); + } else if (info.contextImplementation) { + as->generateFunctionCallImp(target, info.name, info.contextImplementation, + Assembler::ContextRegister, + Assembler::PointerToValue(lhs), + Assembler::PointerToValue(rhs)); + } else { + assert(!"unreachable"); + } + + if (done.isSet()) + done.link(as); + +} + +void Binop::doubleBinop(V4IR::Expr *lhs, V4IR::Expr *rhs, V4IR::Temp *target) +{ + Q_ASSERT(lhs->asConst() == 0 || rhs->asConst() == 0); + Q_ASSERT(isPregOrConst(lhs)); + Q_ASSERT(isPregOrConst(rhs)); + Assembler::FPRegisterID targetReg; + if (target->kind == V4IR::Temp::PhysicalRegister) + targetReg = (Assembler::FPRegisterID) target->index; + else + targetReg = Assembler::FPGpr0; + + switch (op) { + case V4IR::OpAdd: + as->addDouble(as->toDoubleRegister(lhs), as->toDoubleRegister(rhs), + targetReg); + break; + case V4IR::OpMul: + as->mulDouble(as->toDoubleRegister(lhs), as->toDoubleRegister(rhs), + targetReg); + break; + case V4IR::OpSub: +#if CPU(X86) || CPU(X86_64) + if (V4IR::Temp *rightTemp = rhs->asTemp()) { + if (rightTemp->kind == V4IR::Temp::PhysicalRegister && rightTemp->index == targetReg) { + as->moveDouble(targetReg, Assembler::FPGpr0); + as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); + as->subDouble(Assembler::FPGpr0, targetReg); + break; + } + } else if (rhs->asConst() && targetReg == Assembler::FPGpr0) { + Q_ASSERT(lhs->asTemp()); + Q_ASSERT(lhs->asTemp()->kind == V4IR::Temp::PhysicalRegister); + as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); + Assembler::FPRegisterID reg = (Assembler::FPRegisterID) lhs->asTemp()->index; + as->moveDouble(as->toDoubleRegister(rhs, reg), reg); + as->subDouble(reg, targetReg); + break; + } +#endif + + as->subDouble(as->toDoubleRegister(lhs), as->toDoubleRegister(rhs), + targetReg); + break; + case V4IR::OpDiv: +#if CPU(X86) || CPU(X86_64) + if (V4IR::Temp *rightTemp = rhs->asTemp()) { + if (rightTemp->kind == V4IR::Temp::PhysicalRegister && rightTemp->index == targetReg) { + as->moveDouble(targetReg, Assembler::FPGpr0); + as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); + as->divDouble(Assembler::FPGpr0, targetReg); + break; + } + } else if (rhs->asConst() && targetReg == Assembler::FPGpr0) { + Q_ASSERT(lhs->asTemp()); + Q_ASSERT(lhs->asTemp()->kind == V4IR::Temp::PhysicalRegister); + as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); + Assembler::FPRegisterID reg = (Assembler::FPRegisterID) lhs->asTemp()->index; + as->moveDouble(as->toDoubleRegister(rhs, reg), reg); + as->divDouble(reg, targetReg); + break; + } +#endif + as->divDouble(as->toDoubleRegister(lhs), as->toDoubleRegister(rhs), + targetReg); + break; + default: { + Q_ASSERT(target->type == V4IR::BoolType); + Assembler::Jump trueCase = as->branchDouble(false, op, lhs, rhs); + as->storeBool(false, target); + Assembler::Jump done = as->jump(); + trueCase.link(as); + as->storeBool(true, target); + done.link(as); + } return; + } + + if (target->kind != V4IR::Temp::PhysicalRegister) + as->storeDouble(Assembler::FPGpr0, target); +} + + +bool Binop::int32Binop(V4IR::Expr *leftSource, V4IR::Expr *rightSource, V4IR::Temp *target) +{ + Q_ASSERT(leftSource->type == V4IR::SInt32Type); + Assembler::RegisterID targetReg; + if (target->kind == V4IR::Temp::PhysicalRegister) + targetReg = (Assembler::RegisterID) target->index; + else + targetReg = Assembler::ReturnValueRegister; + + switch (op) { + case V4IR::OpBitAnd: { + Q_ASSERT(rightSource->type == V4IR::SInt32Type); + if (rightSource->asTemp() && rightSource->asTemp()->kind == V4IR::Temp::PhysicalRegister + && target->kind == V4IR::Temp::PhysicalRegister + && target->index == rightSource->asTemp()->index) { + as->and32(as->toInt32Register(leftSource, Assembler::ScratchRegister), + (Assembler::RegisterID) target->index); + return true; + } + + as->and32(as->toInt32Register(leftSource, targetReg), + as->toInt32Register(rightSource, Assembler::ScratchRegister), + targetReg); + as->storeInt32(targetReg, target); + } return true; + case V4IR::OpBitOr: { + Q_ASSERT(rightSource->type == V4IR::SInt32Type); + if (rightSource->asTemp() && rightSource->asTemp()->kind == V4IR::Temp::PhysicalRegister + && target->kind == V4IR::Temp::PhysicalRegister + && target->index == rightSource->asTemp()->index) { + as->or32(as->toInt32Register(leftSource, Assembler::ScratchRegister), + (Assembler::RegisterID) target->index); + return true; + } + + as->or32(as->toInt32Register(leftSource, targetReg), + as->toInt32Register(rightSource, Assembler::ScratchRegister), + targetReg); + as->storeInt32(targetReg, target); + } return true; + case V4IR::OpBitXor: { + Q_ASSERT(rightSource->type == V4IR::SInt32Type); + if (rightSource->asTemp() && rightSource->asTemp()->kind == V4IR::Temp::PhysicalRegister + && target->kind == V4IR::Temp::PhysicalRegister + && target->index == rightSource->asTemp()->index) { + as->xor32(as->toInt32Register(leftSource, Assembler::ScratchRegister), + (Assembler::RegisterID) target->index); + return true; + } + + as->xor32(as->toInt32Register(leftSource, targetReg), + as->toInt32Register(rightSource, Assembler::ScratchRegister), + targetReg); + as->storeInt32(targetReg, target); + } return true; + case V4IR::OpLShift: { + Q_ASSERT(rightSource->type == V4IR::SInt32Type); + + if (V4IR::Const *c = rightSource->asConst()) { + as->lshift32(as->toInt32Register(leftSource, Assembler::ReturnValueRegister), + Assembler::TrustedImm32(int(c->value) & 0x1f), targetReg); + } else { + as->move(as->toInt32Register(rightSource, Assembler::ScratchRegister), + Assembler::ScratchRegister); + if (!rightSource->asConst()) + as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); + as->lshift32(as->toInt32Register(leftSource, targetReg), Assembler::ScratchRegister, targetReg); + } + as->storeInt32(targetReg, target); + } return true; + case V4IR::OpRShift: { + Q_ASSERT(rightSource->type == V4IR::SInt32Type); + + if (V4IR::Const *c = rightSource->asConst()) { + as->rshift32(as->toInt32Register(leftSource, Assembler::ReturnValueRegister), + Assembler::TrustedImm32(int(c->value) & 0x1f), targetReg); + } else { + as->move(as->toInt32Register(rightSource, Assembler::ScratchRegister), + Assembler::ScratchRegister); + as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); + as->rshift32(as->toInt32Register(leftSource, targetReg), Assembler::ScratchRegister, targetReg); + } + as->storeInt32(targetReg, target); + } return true; + case V4IR::OpURShift: + Q_ASSERT(rightSource->type == V4IR::SInt32Type); + + if (V4IR::Const *c = rightSource->asConst()) { + as->urshift32(as->toInt32Register(leftSource, Assembler::ReturnValueRegister), + Assembler::TrustedImm32(int(c->value) & 0x1f), targetReg); + } else { + as->move(as->toInt32Register(rightSource, Assembler::ScratchRegister), + Assembler::ScratchRegister); + as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); + as->urshift32(as->toInt32Register(leftSource, targetReg), Assembler::ScratchRegister, targetReg); + } + as->storeUInt32(targetReg, target); + return true; + case V4IR::OpAdd: { + Q_ASSERT(rightSource->type == V4IR::SInt32Type); + + Assembler::RegisterID targetReg; + if (target->kind == V4IR::Temp::PhysicalRegister) + targetReg = (Assembler::RegisterID) target->index; + else + targetReg = Assembler::ReturnValueRegister; + + as->add32(as->toInt32Register(leftSource, targetReg), + as->toInt32Register(rightSource, Assembler::ScratchRegister), + targetReg); + as->storeInt32(targetReg, target); + } return true; + case V4IR::OpSub: { + Q_ASSERT(rightSource->type == V4IR::SInt32Type); + + if (rightSource->asTemp() && rightSource->asTemp()->kind == V4IR::Temp::PhysicalRegister + && target->kind == V4IR::Temp::PhysicalRegister + && target->index == rightSource->asTemp()->index) { + Assembler::RegisterID targetReg = (Assembler::RegisterID) target->index; + as->move(targetReg, Assembler::ScratchRegister); + as->move(as->toInt32Register(leftSource, targetReg), targetReg); + as->sub32(Assembler::ScratchRegister, targetReg); + as->storeInt32(targetReg, target); + return true; + } + + Assembler::RegisterID targetReg; + if (target->kind == V4IR::Temp::PhysicalRegister) + targetReg = (Assembler::RegisterID) target->index; + else + targetReg = Assembler::ReturnValueRegister; + + as->move(as->toInt32Register(leftSource, targetReg), targetReg); + as->sub32(as->toInt32Register(rightSource, Assembler::ScratchRegister), targetReg); + as->storeInt32(targetReg, target); + } return true; + case V4IR::OpMul: { + Q_ASSERT(rightSource->type == V4IR::SInt32Type); + + Assembler::RegisterID targetReg; + if (target->kind == V4IR::Temp::PhysicalRegister) + targetReg = (Assembler::RegisterID) target->index; + else + targetReg = Assembler::ReturnValueRegister; + + as->mul32(as->toInt32Register(leftSource, targetReg), + as->toInt32Register(rightSource, Assembler::ScratchRegister), + targetReg); + as->storeInt32(targetReg, target); + } return true; + default: + return false; + } +} + +static inline Assembler::FPRegisterID getFreeFPReg(V4IR::Expr *shouldNotOverlap, unsigned hint) +{ + if (V4IR::Temp *t = shouldNotOverlap->asTemp()) + if (t->type == V4IR::DoubleType) + if (t->kind == V4IR::Temp::PhysicalRegister) + if (t->index == hint) + return Assembler::FPRegisterID(hint + 1); + return Assembler::FPRegisterID(hint); +} + +Assembler::Jump Binop::genInlineBinop(V4IR::Expr *leftSource, V4IR::Expr *rightSource, V4IR::Temp *target) +{ + Assembler::Jump done; + + // Try preventing a call for a few common binary operations. This is used in two cases: + // - no register allocation was performed (not available for the platform, or the IR was + // not transformed into SSA) + // - type inference found that either or both operands can be of non-number type, and the + // register allocator will have prepared for a call (meaning: all registers that do not + // hold operands are spilled to the stack, which makes them available here) + // Note: FPGPr0 can still not be used, because uint32->double conversion uses it as a scratch + // register. + switch (op) { + case V4IR::OpAdd: { + Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2); + Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4); + Assembler::Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg); + Assembler::Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg); + + as->addDouble(rReg, lReg); + as->storeDouble(lReg, target); + done = as->jump(); + + if (leftIsNoDbl.isSet()) + leftIsNoDbl.link(as); + if (rightIsNoDbl.isSet()) + rightIsNoDbl.link(as); + } break; + case V4IR::OpMul: { + Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2); + Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4); + Assembler::Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg); + Assembler::Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg); + + as->mulDouble(rReg, lReg); + as->storeDouble(lReg, target); + done = as->jump(); + + if (leftIsNoDbl.isSet()) + leftIsNoDbl.link(as); + if (rightIsNoDbl.isSet()) + rightIsNoDbl.link(as); + } break; + case V4IR::OpSub: { + Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2); + Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4); + Assembler::Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg); + Assembler::Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg); + + as->subDouble(rReg, lReg); + as->storeDouble(lReg, target); + done = as->jump(); + + if (leftIsNoDbl.isSet()) + leftIsNoDbl.link(as); + if (rightIsNoDbl.isSet()) + rightIsNoDbl.link(as); + } break; + case V4IR::OpDiv: { + Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2); + Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4); + Assembler::Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg); + Assembler::Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg); + + as->divDouble(rReg, lReg); + as->storeDouble(lReg, target); + done = as->jump(); + + if (leftIsNoDbl.isSet()) + leftIsNoDbl.link(as); + if (rightIsNoDbl.isSet()) + rightIsNoDbl.link(as); + } break; + default: + break; + } + + return done; +} + +#endif diff --git a/src/qml/jit/qv4binop_p.h b/src/qml/jit/qv4binop_p.h new file mode 100644 index 0000000000..06e0a8b68a --- /dev/null +++ b/src/qml/jit/qv4binop_p.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QV4BINOP_P_H +#define QV4BINOP_P_H + +#include <qv4jsir_p.h> +#include <qv4isel_masm_p.h> + +QT_BEGIN_NAMESPACE + +#if ENABLE(ASSEMBLER) + +namespace QV4 { +namespace JIT { + +struct Binop { + Binop(QQmlJS::MASM::Assembler *assembler, QQmlJS::V4IR::AluOp operation) + : as(assembler) + , op(operation) + {} + + void generate(QQmlJS::V4IR::Expr *lhs, QQmlJS::V4IR::Expr *rhs, QQmlJS::V4IR::Temp *target); + void doubleBinop(QQmlJS::V4IR::Expr *lhs, QQmlJS::V4IR::Expr *rhs, QQmlJS::V4IR::Temp *target); + bool int32Binop(QQmlJS::V4IR::Expr *leftSource, QQmlJS::V4IR::Expr *rightSource, QQmlJS::V4IR::Temp *target); + QQmlJS::MASM::Assembler::Jump genInlineBinop(QQmlJS::V4IR::Expr *leftSource, QQmlJS::V4IR::Expr *rightSource, QQmlJS::V4IR::Temp *target); + + QQmlJS::MASM::Assembler *as; + QQmlJS::V4IR::AluOp op; +}; + +} +} + +#endif + +QT_END_NAMESPACE + +#endif diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index 4287cee9a3..26ef359b05 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -50,6 +50,7 @@ #include "qv4regalloc_p.h" #include "qv4assembler_p.h" #include "qv4unop_p.h" +#include "qv4binop_p.h" #include <assembler/LinkBuffer.h> #include <WTFStubs.h> @@ -885,137 +886,11 @@ void InstructionSelection::unop(V4IR::AluOp oper, V4IR::Temp *sourceTemp, V4IR:: unop.generate(sourceTemp, targetTemp); } -static inline Assembler::FPRegisterID getFreeFPReg(V4IR::Expr *shouldNotOverlap, unsigned hint) -{ - if (V4IR::Temp *t = shouldNotOverlap->asTemp()) - if (t->type == V4IR::DoubleType) - if (t->kind == V4IR::Temp::PhysicalRegister) - if (t->index == hint) - return Assembler::FPRegisterID(hint + 1); - return Assembler::FPRegisterID(hint); -} - -Assembler::Jump InstructionSelection::genInlineBinop(V4IR::AluOp oper, V4IR::Expr *leftSource, V4IR::Expr *rightSource, V4IR::Temp *target) -{ - Assembler::Jump done; - - // Try preventing a call for a few common binary operations. This is used in two cases: - // - no register allocation was performed (not available for the platform, or the IR was - // not transformed into SSA) - // - type inference found that either or both operands can be of non-number type, and the - // register allocator will have prepared for a call (meaning: all registers that do not - // hold operands are spilled to the stack, which makes them available here) - // Note: FPGPr0 can still not be used, because uint32->double conversion uses it as a scratch - // register. - switch (oper) { - case V4IR::OpAdd: { - Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2); - Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4); - Assembler::Jump leftIsNoDbl = genTryDoubleConversion(leftSource, lReg); - Assembler::Jump rightIsNoDbl = genTryDoubleConversion(rightSource, rReg); - - _as->addDouble(rReg, lReg); - _as->storeDouble(lReg, target); - done = _as->jump(); - - if (leftIsNoDbl.isSet()) - leftIsNoDbl.link(_as); - if (rightIsNoDbl.isSet()) - rightIsNoDbl.link(_as); - } break; - case V4IR::OpMul: { - Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2); - Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4); - Assembler::Jump leftIsNoDbl = genTryDoubleConversion(leftSource, lReg); - Assembler::Jump rightIsNoDbl = genTryDoubleConversion(rightSource, rReg); - - _as->mulDouble(rReg, lReg); - _as->storeDouble(lReg, target); - done = _as->jump(); - - if (leftIsNoDbl.isSet()) - leftIsNoDbl.link(_as); - if (rightIsNoDbl.isSet()) - rightIsNoDbl.link(_as); - } break; - case V4IR::OpSub: { - Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2); - Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4); - Assembler::Jump leftIsNoDbl = genTryDoubleConversion(leftSource, lReg); - Assembler::Jump rightIsNoDbl = genTryDoubleConversion(rightSource, rReg); - - _as->subDouble(rReg, lReg); - _as->storeDouble(lReg, target); - done = _as->jump(); - - if (leftIsNoDbl.isSet()) - leftIsNoDbl.link(_as); - if (rightIsNoDbl.isSet()) - rightIsNoDbl.link(_as); - } break; - case V4IR::OpDiv: { - Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2); - Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4); - Assembler::Jump leftIsNoDbl = genTryDoubleConversion(leftSource, lReg); - Assembler::Jump rightIsNoDbl = genTryDoubleConversion(rightSource, rReg); - - _as->divDouble(rReg, lReg); - _as->storeDouble(lReg, target); - done = _as->jump(); - - if (leftIsNoDbl.isSet()) - leftIsNoDbl.link(_as); - if (rightIsNoDbl.isSet()) - rightIsNoDbl.link(_as); - } break; - default: - break; - } - - return done; -} void InstructionSelection::binop(V4IR::AluOp oper, V4IR::Expr *leftSource, V4IR::Expr *rightSource, V4IR::Temp *target) { - if (oper != V4IR::OpMod - && leftSource->type == V4IR::DoubleType && rightSource->type == V4IR::DoubleType - && isPregOrConst(leftSource) && isPregOrConst(rightSource)) { - doubleBinop(oper, leftSource, rightSource, target); - return; - } - if (leftSource->type == V4IR::SInt32Type && rightSource->type == V4IR::SInt32Type) { - if (int32Binop(oper, leftSource, rightSource, target)) - return; - } - - Assembler::Jump done; - if (leftSource->type != V4IR::StringType && rightSource->type != V4IR::StringType) - done = genInlineBinop(oper, leftSource, rightSource, target); - - // TODO: inline var===null and var!==null - Assembler::BinaryOperationInfo info = Assembler::binaryOperation(oper); - - if (oper == V4IR::OpAdd && - (leftSource->type == V4IR::StringType || rightSource->type == V4IR::StringType)) { - const Assembler::BinaryOperationInfo stringAdd = OPCONTEXT(__qmljs_add_string); - info = stringAdd; - } - - if (info.fallbackImplementation) { - _as->generateFunctionCallImp(target, info.name, info.fallbackImplementation, - Assembler::PointerToValue(leftSource), - Assembler::PointerToValue(rightSource)); - } else if (info.contextImplementation) { - _as->generateFunctionCallImp(target, info.name, info.contextImplementation, - Assembler::ContextRegister, - Assembler::PointerToValue(leftSource), - Assembler::PointerToValue(rightSource)); - } else { - assert(!"unreachable"); - } - - if (done.isSet()) - done.link(_as); + QV4::JIT::Binop binop(_as, oper); + binop.generate(leftSource, rightSource, target); } void InstructionSelection::callProperty(V4IR::Expr *base, const QString &name, V4IR::ExprList *args, @@ -1700,171 +1575,6 @@ void Assembler::ConstantTable::finalize(JSC::LinkBuffer &linkBuffer, Instruction linkBuffer.patch(label, tablePtr); } -// Try to load the source expression into the destination FP register. This assumes that two -// general purpose (integer) registers are available: the ScratchRegister and the -// ReturnValueRegister. It returns a Jump if no conversion can be performed. -Assembler::Jump InstructionSelection::genTryDoubleConversion(V4IR::Expr *src, - Assembler::FPRegisterID dest) -{ - switch (src->type) { - case V4IR::DoubleType: - _as->moveDouble(_as->toDoubleRegister(src, dest), dest); - return Assembler::Jump(); - case V4IR::SInt32Type: - _as->convertInt32ToDouble(_as->toInt32Register(src, Assembler::ScratchRegister), - dest); - return Assembler::Jump(); - case V4IR::UInt32Type: - _as->convertUInt32ToDouble(_as->toUInt32Register(src, Assembler::ScratchRegister), - dest, Assembler::ReturnValueRegister); - return Assembler::Jump(); - case V4IR::BoolType: - // TODO? - return _as->jump(); - default: - break; - } - - V4IR::Temp *sourceTemp = src->asTemp(); - Q_ASSERT(sourceTemp); - - // It's not a number type, so it cannot be in a register. - Q_ASSERT(sourceTemp->kind != V4IR::Temp::PhysicalRegister || sourceTemp->type == V4IR::BoolType); - - Assembler::Pointer tagAddr = _as->loadTempAddress(Assembler::ScratchRegister, sourceTemp); - tagAddr.offset += 4; - _as->load32(tagAddr, Assembler::ScratchRegister); - - // check if it's an int32: - Assembler::Jump isNoInt = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister, - Assembler::TrustedImm32(Value::_Integer_Type)); - _as->convertInt32ToDouble(_as->toInt32Register(src, Assembler::ScratchRegister), dest); - Assembler::Jump intDone = _as->jump(); - - // not an int, check if it's a double: - isNoInt.link(_as); -#if QT_POINTER_SIZE == 8 - _as->and32(Assembler::TrustedImm32(Value::IsDouble_Mask), Assembler::ScratchRegister); - Assembler::Jump isNoDbl = _as->branch32(Assembler::Equal, Assembler::ScratchRegister, - Assembler::TrustedImm32(0)); -#else - _as->and32(Assembler::TrustedImm32(Value::NotDouble_Mask), Assembler::ScratchRegister); - Assembler::Jump isNoDbl = _as->branch32(Assembler::Equal, Assembler::ScratchRegister, - Assembler::TrustedImm32(Value::NotDouble_Mask)); -#endif - _as->toDoubleRegister(src, dest); - intDone.link(_as); - - return isNoDbl; -} - -void InstructionSelection::doubleBinop(V4IR::AluOp oper, V4IR::Expr *leftSource, - V4IR::Expr *rightSource, V4IR::Temp *target) -{ - Q_ASSERT(leftSource->asConst() == 0 || rightSource->asConst() == 0); - Q_ASSERT(isPregOrConst(leftSource)); - Q_ASSERT(isPregOrConst(rightSource)); - Assembler::FPRegisterID targetReg; - if (target->kind == V4IR::Temp::PhysicalRegister) - targetReg = (Assembler::FPRegisterID) target->index; - else - targetReg = Assembler::FPGpr0; - - switch (oper) { - case V4IR::OpAdd: - _as->addDouble(_as->toDoubleRegister(leftSource), _as->toDoubleRegister(rightSource), - targetReg); - break; - case V4IR::OpMul: - _as->mulDouble(_as->toDoubleRegister(leftSource), _as->toDoubleRegister(rightSource), - targetReg); - break; - case V4IR::OpSub: -#if CPU(X86) || CPU(X86_64) - if (V4IR::Temp *rightTemp = rightSource->asTemp()) { - if (rightTemp->kind == V4IR::Temp::PhysicalRegister && rightTemp->index == targetReg) { - _as->moveDouble(targetReg, Assembler::FPGpr0); - _as->moveDouble(_as->toDoubleRegister(leftSource, targetReg), targetReg); - _as->subDouble(Assembler::FPGpr0, targetReg); - break; - } - } else if (rightSource->asConst() && targetReg == Assembler::FPGpr0) { - Q_ASSERT(leftSource->asTemp()); - Q_ASSERT(leftSource->asTemp()->kind == V4IR::Temp::PhysicalRegister); - _as->moveDouble(_as->toDoubleRegister(leftSource, targetReg), targetReg); - Assembler::FPRegisterID reg = (Assembler::FPRegisterID) leftSource->asTemp()->index; - _as->moveDouble(_as->toDoubleRegister(rightSource, reg), reg); - _as->subDouble(reg, targetReg); - break; - } -#endif - - _as->subDouble(_as->toDoubleRegister(leftSource), _as->toDoubleRegister(rightSource), - targetReg); - break; - case V4IR::OpDiv: -#if CPU(X86) || CPU(X86_64) - if (V4IR::Temp *rightTemp = rightSource->asTemp()) { - if (rightTemp->kind == V4IR::Temp::PhysicalRegister && rightTemp->index == targetReg) { - _as->moveDouble(targetReg, Assembler::FPGpr0); - _as->moveDouble(_as->toDoubleRegister(leftSource, targetReg), targetReg); - _as->divDouble(Assembler::FPGpr0, targetReg); - break; - } - } else if (rightSource->asConst() && targetReg == Assembler::FPGpr0) { - Q_ASSERT(leftSource->asTemp()); - Q_ASSERT(leftSource->asTemp()->kind == V4IR::Temp::PhysicalRegister); - _as->moveDouble(_as->toDoubleRegister(leftSource, targetReg), targetReg); - Assembler::FPRegisterID reg = (Assembler::FPRegisterID) leftSource->asTemp()->index; - _as->moveDouble(_as->toDoubleRegister(rightSource, reg), reg); - _as->divDouble(reg, targetReg); - break; - } -#endif - _as->divDouble(_as->toDoubleRegister(leftSource), _as->toDoubleRegister(rightSource), - targetReg); - break; - default: { - Q_ASSERT(target->type == V4IR::BoolType); - Assembler::Jump trueCase = branchDouble(false, oper, leftSource, rightSource); - _as->storeBool(false, target); - Assembler::Jump done = _as->jump(); - trueCase.link(_as); - _as->storeBool(true, target); - done.link(_as); - } return; - } - - if (target->kind != V4IR::Temp::PhysicalRegister) - _as->storeDouble(Assembler::FPGpr0, target); -} - -Assembler::Jump InstructionSelection::branchDouble(bool invertCondition, V4IR::AluOp op, - V4IR::Expr *left, V4IR::Expr *right) -{ - Q_ASSERT(isPregOrConst(left)); - Q_ASSERT(isPregOrConst(right)); - Q_ASSERT(left->asConst() == 0 || right->asConst() == 0); - - Assembler::DoubleCondition cond; - switch (op) { - case V4IR::OpGt: cond = Assembler::DoubleGreaterThan; break; - case V4IR::OpLt: cond = Assembler::DoubleLessThan; break; - case V4IR::OpGe: cond = Assembler::DoubleGreaterThanOrEqual; break; - case V4IR::OpLe: cond = Assembler::DoubleLessThanOrEqual; break; - case V4IR::OpEqual: - case V4IR::OpStrictEqual: cond = Assembler::DoubleEqual; break; - case V4IR::OpNotEqual: - case V4IR::OpStrictNotEqual: cond = Assembler::DoubleNotEqualOrUnordered; break; // No, the inversion of DoubleEqual is NOT DoubleNotEqual. - default: - Q_UNREACHABLE(); - } - if (invertCondition) - cond = JSC::MacroAssembler::invert(cond); - - return _as->branchDouble(cond, _as->toDoubleRegister(left), _as->toDoubleRegister(right)); -} - bool InstructionSelection::visitCJumpDouble(V4IR::AluOp op, V4IR::Expr *left, V4IR::Expr *right, V4IR::BasicBlock *iftrue, V4IR::BasicBlock *iffalse) { @@ -1872,10 +1582,10 @@ bool InstructionSelection::visitCJumpDouble(V4IR::AluOp op, V4IR::Expr *left, V4 return false; if (_as->nextBlock() == iftrue) { - Assembler::Jump target = branchDouble(true, op, left, right); + Assembler::Jump target = _as->branchDouble(true, op, left, right); _as->addPatch(iffalse, target); } else { - Assembler::Jump target = branchDouble(false, op, left, right); + Assembler::Jump target = _as->branchDouble(false, op, left, right); _as->addPatch(iftrue, target); _as->jumpToBlock(_block, iffalse); } @@ -2069,160 +1779,4 @@ void InstructionSelection::visitCJumpEqual(V4IR::Binop *binop, V4IR::BasicBlock } -bool InstructionSelection::int32Binop(V4IR::AluOp oper, V4IR::Expr *leftSource, - V4IR::Expr *rightSource, V4IR::Temp *target) -{ - Q_ASSERT(leftSource->type == V4IR::SInt32Type); - Assembler::RegisterID targetReg; - if (target->kind == V4IR::Temp::PhysicalRegister) - targetReg = (Assembler::RegisterID) target->index; - else - targetReg = Assembler::ReturnValueRegister; - - switch (oper) { - case V4IR::OpBitAnd: { - Q_ASSERT(rightSource->type == V4IR::SInt32Type); - if (rightSource->asTemp() && rightSource->asTemp()->kind == V4IR::Temp::PhysicalRegister - && target->kind == V4IR::Temp::PhysicalRegister - && target->index == rightSource->asTemp()->index) { - _as->and32(_as->toInt32Register(leftSource, Assembler::ScratchRegister), - (Assembler::RegisterID) target->index); - return true; - } - - _as->and32(_as->toInt32Register(leftSource, targetReg), - _as->toInt32Register(rightSource, Assembler::ScratchRegister), - targetReg); - _as->storeInt32(targetReg, target); - } return true; - case V4IR::OpBitOr: { - Q_ASSERT(rightSource->type == V4IR::SInt32Type); - if (rightSource->asTemp() && rightSource->asTemp()->kind == V4IR::Temp::PhysicalRegister - && target->kind == V4IR::Temp::PhysicalRegister - && target->index == rightSource->asTemp()->index) { - _as->or32(_as->toInt32Register(leftSource, Assembler::ScratchRegister), - (Assembler::RegisterID) target->index); - return true; - } - - _as->or32(_as->toInt32Register(leftSource, targetReg), - _as->toInt32Register(rightSource, Assembler::ScratchRegister), - targetReg); - _as->storeInt32(targetReg, target); - } return true; - case V4IR::OpBitXor: { - Q_ASSERT(rightSource->type == V4IR::SInt32Type); - if (rightSource->asTemp() && rightSource->asTemp()->kind == V4IR::Temp::PhysicalRegister - && target->kind == V4IR::Temp::PhysicalRegister - && target->index == rightSource->asTemp()->index) { - _as->xor32(_as->toInt32Register(leftSource, Assembler::ScratchRegister), - (Assembler::RegisterID) target->index); - return true; - } - - _as->xor32(_as->toInt32Register(leftSource, targetReg), - _as->toInt32Register(rightSource, Assembler::ScratchRegister), - targetReg); - _as->storeInt32(targetReg, target); - } return true; - case V4IR::OpLShift: { - Q_ASSERT(rightSource->type == V4IR::SInt32Type); - - if (V4IR::Const *c = rightSource->asConst()) { - _as->lshift32(_as->toInt32Register(leftSource, Assembler::ReturnValueRegister), - Assembler::TrustedImm32(int(c->value) & 0x1f), targetReg); - } else { - _as->move(_as->toInt32Register(rightSource, Assembler::ScratchRegister), - Assembler::ScratchRegister); - if (!rightSource->asConst()) - _as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); - _as->lshift32(_as->toInt32Register(leftSource, targetReg), Assembler::ScratchRegister, targetReg); - } - _as->storeInt32(targetReg, target); - } return true; - case V4IR::OpRShift: { - Q_ASSERT(rightSource->type == V4IR::SInt32Type); - - if (V4IR::Const *c = rightSource->asConst()) { - _as->rshift32(_as->toInt32Register(leftSource, Assembler::ReturnValueRegister), - Assembler::TrustedImm32(int(c->value) & 0x1f), targetReg); - } else { - _as->move(_as->toInt32Register(rightSource, Assembler::ScratchRegister), - Assembler::ScratchRegister); - _as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); - _as->rshift32(_as->toInt32Register(leftSource, targetReg), Assembler::ScratchRegister, targetReg); - } - _as->storeInt32(targetReg, target); - } return true; - case V4IR::OpURShift: - Q_ASSERT(rightSource->type == V4IR::SInt32Type); - - if (V4IR::Const *c = rightSource->asConst()) { - _as->urshift32(_as->toInt32Register(leftSource, Assembler::ReturnValueRegister), - Assembler::TrustedImm32(int(c->value) & 0x1f), targetReg); - } else { - _as->move(_as->toInt32Register(rightSource, Assembler::ScratchRegister), - Assembler::ScratchRegister); - _as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); - _as->urshift32(_as->toInt32Register(leftSource, targetReg), Assembler::ScratchRegister, targetReg); - } - _as->storeUInt32(targetReg, target); - return true; - case V4IR::OpAdd: { - Q_ASSERT(rightSource->type == V4IR::SInt32Type); - - Assembler::RegisterID targetReg; - if (target->kind == V4IR::Temp::PhysicalRegister) - targetReg = (Assembler::RegisterID) target->index; - else - targetReg = Assembler::ReturnValueRegister; - - _as->add32(_as->toInt32Register(leftSource, targetReg), - _as->toInt32Register(rightSource, Assembler::ScratchRegister), - targetReg); - _as->storeInt32(targetReg, target); - } return true; - case V4IR::OpSub: { - Q_ASSERT(rightSource->type == V4IR::SInt32Type); - - if (rightSource->asTemp() && rightSource->asTemp()->kind == V4IR::Temp::PhysicalRegister - && target->kind == V4IR::Temp::PhysicalRegister - && target->index == rightSource->asTemp()->index) { - Assembler::RegisterID targetReg = (Assembler::RegisterID) target->index; - _as->move(targetReg, Assembler::ScratchRegister); - _as->move(_as->toInt32Register(leftSource, targetReg), targetReg); - _as->sub32(Assembler::ScratchRegister, targetReg); - _as->storeInt32(targetReg, target); - return true; - } - - Assembler::RegisterID targetReg; - if (target->kind == V4IR::Temp::PhysicalRegister) - targetReg = (Assembler::RegisterID) target->index; - else - targetReg = Assembler::ReturnValueRegister; - - _as->move(_as->toInt32Register(leftSource, targetReg), targetReg); - _as->sub32(_as->toInt32Register(rightSource, Assembler::ScratchRegister), targetReg); - _as->storeInt32(targetReg, target); - } return true; - case V4IR::OpMul: { - Q_ASSERT(rightSource->type == V4IR::SInt32Type); - - Assembler::RegisterID targetReg; - if (target->kind == V4IR::Temp::PhysicalRegister) - targetReg = (Assembler::RegisterID) target->index; - else - targetReg = Assembler::ReturnValueRegister; - - _as->mul32(_as->toInt32Register(leftSource, targetReg), - _as->toInt32Register(rightSource, Assembler::ScratchRegister), - targetReg); - _as->storeInt32(targetReg, target); - } return true; - default: - return false; - } -} - #endif // ENABLE(ASSEMBLER) diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h index ab8d33e300..b6af385887 100644 --- a/src/qml/jit/qv4isel_masm_p.h +++ b/src/qml/jit/qv4isel_masm_p.h @@ -158,12 +158,6 @@ protected: virtual void visitCJump(V4IR::CJump *); virtual void visitRet(V4IR::Ret *); - Assembler::Jump genTryDoubleConversion(V4IR::Expr *src, Assembler::FPRegisterID dest); - Assembler::Jump genInlineBinop(V4IR::AluOp oper, V4IR::Expr *leftSource, - V4IR::Expr *rightSource, V4IR::Temp *target); - void doubleBinop(V4IR::AluOp oper, V4IR::Expr *leftSource, V4IR::Expr *rightSource, - V4IR::Temp *target); - Assembler::Jump branchDouble(bool invertCondition, V4IR::AluOp op, V4IR::Expr *left, V4IR::Expr *right); bool visitCJumpDouble(V4IR::AluOp op, V4IR::Expr *left, V4IR::Expr *right, V4IR::BasicBlock *iftrue, V4IR::BasicBlock *iffalse); void visitCJumpStrict(V4IR::Binop *binop, V4IR::BasicBlock *trueBlock, V4IR::BasicBlock *falseBlock); @@ -173,8 +167,6 @@ protected: bool visitCJumpNullUndefined(V4IR::Type nullOrUndef, V4IR::Binop *binop, V4IR::BasicBlock *trueBlock, V4IR::BasicBlock *falseBlock); void visitCJumpEqual(V4IR::Binop *binop, V4IR::BasicBlock *trueBlock, V4IR::BasicBlock *falseBlock); - bool int32Binop(V4IR::AluOp oper, V4IR::Expr *leftSource, V4IR::Expr *rightSource, - V4IR::Temp *target); private: void convertTypeSlowPath(V4IR::Temp *source, V4IR::Temp *target); |