aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@digia.com>2014-02-11 09:46:45 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-02-22 18:47:35 +0100
commit7dbb49bdec6e74f9d1eb096d15bdeea0881c3704 (patch)
tree1838e6d68d34823c0626f583a3b43dddb32b24c4
parentc60387d210b03ba4fa42522dec3184e254eb7006 (diff)
Move binops out of the isel
Move the binop handling into qv4binop* to clean up the code and ease maintenance. Change-Id: I0053380be7f326a2100302a63e921698a5b28c2a Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
-rw-r--r--src/qml/jit/jit.pri2
-rw-r--r--src/qml/jit/qv4assembler.cpp96
-rw-r--r--src/qml/jit/qv4assembler_p.h2
-rw-r--r--src/qml/jit/qv4binop.cpp431
-rw-r--r--src/qml/jit/qv4binop_p.h76
-rw-r--r--src/qml/jit/qv4isel_masm.cpp456
-rw-r--r--src/qml/jit/qv4isel_masm_p.h8
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);