From f6de6160b915b5a35e75746a35c4ef94ceb9b2c2 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 4 Oct 2013 15:38:42 +0200 Subject: Optimise code generation for convertTypeToSInt32 Add 64 bit code patch and avoid some duplicated calculation in 32 bit mode Change-Id: I0e111de8ac4e733aa8802c49b4b15d785688d7ea Reviewed-by: Simon Hausmann --- .../masm/assembler/MacroAssemblerX86Common.h | 4 +- src/3rdparty/masm/assembler/MacroAssemblerX86_64.h | 10 ++++ src/3rdparty/masm/assembler/X86Assembler.h | 23 +++++++++ src/qml/compiler/qv4isel_masm.cpp | 57 ++++++++++++++++++++-- src/qml/jsruntime/qv4value_def_p.h | 3 +- src/qml/jsruntime/qv4value_p.h | 7 +++ 6 files changed, 96 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/3rdparty/masm/assembler/MacroAssemblerX86Common.h b/src/3rdparty/masm/assembler/MacroAssemblerX86Common.h index 53cb80c210..520cf915fa 100644 --- a/src/3rdparty/masm/assembler/MacroAssemblerX86Common.h +++ b/src/3rdparty/masm/assembler/MacroAssemblerX86Common.h @@ -318,7 +318,7 @@ public: { m_assembler.sarl_i8r(imm.m_value, dest); } - + void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest) { if (src != dest) @@ -362,7 +362,7 @@ public: move(src, dest); urshift32(imm, dest); } - + void sub32(RegisterID src, RegisterID dest) { m_assembler.subl_rr(src, dest); diff --git a/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h b/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h index 3aaa0fd1bc..db0e880cb9 100644 --- a/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h +++ b/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h @@ -295,6 +295,16 @@ public: m_assembler.xorq_ir(imm.m_value, srcDest); } + void urshift64(TrustedImm32 imm, RegisterID dest) + { + m_assembler.shrq_i8r(imm.m_value, dest); + } + + void lshift64(TrustedImm32 imm, RegisterID dest) + { + m_assembler.shlq_i8r(imm.m_value, dest); + } + void load64(ImplicitAddress address, RegisterID dest) { m_assembler.movq_mr(address.offset, address.base, dest); diff --git a/src/3rdparty/masm/assembler/X86Assembler.h b/src/3rdparty/masm/assembler/X86Assembler.h index a3a480541c..1875ebaff0 100644 --- a/src/3rdparty/masm/assembler/X86Assembler.h +++ b/src/3rdparty/masm/assembler/X86Assembler.h @@ -683,6 +683,29 @@ public: } } + void shrq_i8r(int imm, RegisterID dst) + { + // ### doesn't work when removing the "0 &&" + if (0 && imm == 1) + m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_SHR, dst); + else { + m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_SHR, dst); + m_formatter.immediate8(imm); + } + } + + void shlq_i8r(int imm, RegisterID dst) + { + // ### doesn't work when removing the "0 &&" + if (0 && imm == 1) + m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_SHL, dst); + else { + m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_SHL, dst); + m_formatter.immediate8(imm); + } + } + + #endif void sarl_i8r(int imm, RegisterID dst) diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp index 574b4e278b..4ca4f82cef 100644 --- a/src/qml/compiler/qv4isel_masm.cpp +++ b/src/qml/compiler/qv4isel_masm.cpp @@ -1590,15 +1590,60 @@ void InstructionSelection::convertTypeToSInt32(V4IR::Temp *source, V4IR::Temp *t { switch (source->type) { case V4IR::VarType: { + +#if QT_POINTER_SIZE == 8 + Assembler::Pointer addr = _as->loadTempAddress(Assembler::ScratchRegister, source); + _as->load64(addr, Assembler::ScratchRegister); + _as->move(Assembler::ScratchRegister, Assembler::ReturnValueRegister); + + // check if it's a number + _as->urshift64(Assembler::TrustedImm32(QV4::Value::IsNumber_Shift), Assembler::ScratchRegister); + Assembler::Jump fallback = _as->branch32(Assembler::Equal, Assembler::ScratchRegister, Assembler::TrustedImm32(0)); + // we have a number + _as->urshift64(Assembler::TrustedImm32(1), Assembler::ScratchRegister); + Assembler::Jump isInt = _as->branch32(Assembler::Equal, Assembler::ScratchRegister, Assembler::TrustedImm32(0)); + + // it's a double + _as->move(Assembler::TrustedImm64(QV4::Value::NaNEncodeMask), Assembler::ScratchRegister); + _as->xor64(Assembler::ScratchRegister, Assembler::ReturnValueRegister); + _as->move64ToDouble(Assembler::ReturnValueRegister, Assembler::FPGpr0); + Assembler::Jump success = + _as->branchTruncateDoubleToInt32(Assembler::FPGpr0, Assembler::ReturnValueRegister, + Assembler::BranchIfTruncateSuccessful); + generateFunctionCall(Assembler::ReturnValueRegister, __qmljs_double_to_int32, + Assembler::PointerToValue(source)); + Assembler::Jump converted = _as->jump(); + + // not an int: + fallback.link(_as); + generateFunctionCall(Assembler::ReturnValueRegister, __qmljs_value_to_int32, + _as->loadTempAddress(Assembler::ScratchRegister, source)); + + isInt.link(_as); + success.link(_as); + converted.link(_as); + if (target->kind == V4IR::Temp::StackSlot) { +// _as->move(Assembler::TrustedImm32(QV4::Value::_Integer_Type), Assembler::ScratchRegister); +// _as->lshift64(Assembler::TrustedImm32(32), Assembler::ScratchRegister); +// _as->or64(Assembler::ScratchRegister, Assembler::ReturnValueRegister, Assembler::ScratchRegister); +// _as->store64(Assembler::ScratchRegister, target); + Assembler::Pointer targetAddr = _as->stackSlotPointer(target); + _as->store32(Assembler::ReturnValueRegister, targetAddr); + targetAddr.offset += 4; + _as->store32(Assembler::TrustedImm32(Value::_Integer_Type), targetAddr); + } else { + _as->storeInt32(Assembler::ReturnValueRegister, target); + } +#else // load the tag: - Assembler::Pointer tagAddr = _as->loadTempAddress(Assembler::ScratchRegister, source); + Assembler::Pointer addr = _as->loadTempAddress(Assembler::ScratchRegister, source); + Assembler::Pointer tagAddr = addr; tagAddr.offset += 4; - _as->load32(tagAddr, Assembler::ScratchRegister); + _as->load32(tagAddr, Assembler::ReturnValueRegister); // check if it's an int32: - Assembler::Jump isNoInt = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister, + Assembler::Jump fallback = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister, Assembler::TrustedImm32(Value::_Integer_Type)); - Assembler::Pointer addr = _as->loadTempAddress(Assembler::ScratchRegister, source); if (target->kind == V4IR::Temp::StackSlot) { _as->load32(addr, Assembler::ScratchRegister); Assembler::Pointer targetAddr = _as->stackSlotPointer(target); @@ -1611,12 +1656,14 @@ void InstructionSelection::convertTypeToSInt32(V4IR::Temp *source, V4IR::Temp *t Assembler::Jump intDone = _as->jump(); // not an int: - isNoInt.link(_as); + fallback.link(_as); generateFunctionCall(Assembler::ReturnValueRegister, __qmljs_value_to_int32, _as->loadTempAddress(Assembler::ScratchRegister, source)); _as->storeInt32(Assembler::ReturnValueRegister, target); intDone.link(_as); +#endif + } break; case V4IR::DoubleType: { Assembler::FPRegisterID reg = _as->toDoubleRegister(source); diff --git a/src/qml/jsruntime/qv4value_def_p.h b/src/qml/jsruntime/qv4value_def_p.h index 82f8d02dfe..163aed9abc 100644 --- a/src/qml/jsruntime/qv4value_def_p.h +++ b/src/qml/jsruntime/qv4value_def_p.h @@ -194,8 +194,8 @@ struct Q_QML_EXPORT Value inline bool isUndefined() const { return tag == Undefined_Type; } inline bool isNull() const { return tag == _Null_Type; } inline bool isBoolean() const { return tag == _Boolean_Type; } - inline bool isInteger() const { return tag == _Integer_Type; } #if QT_POINTER_SIZE == 8 + inline bool isInteger() const { return (val >> IsNumber_Shift) == 1; } inline bool isDouble() const { return (val >> IsDouble_Shift); } inline bool isNumber() const { return (val >> IsNumber_Shift); } inline bool isManaged() const { return !(val >> IsManaged_Shift); } @@ -227,6 +227,7 @@ struct Q_QML_EXPORT Value } bool isNaN() const { return (tag & 0x7fff8000) == 0x00078000; } #else + inline bool isInteger() const { return tag == _Integer_Type; } inline bool isDouble() const { return (tag & NotDouble_Mask) != NotDouble_Mask; } inline bool isNumber() const { return tag == _Integer_Type || (tag & NotDouble_Mask) != NotDouble_Mask; } inline bool isManaged() const { return tag == Managed_Type; } diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 362f41affe..a2137ee849 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -200,10 +200,17 @@ inline bool Value::toBoolean() const inline uint Value::asArrayIndex() const { +#if QT_POINTER_SIZE == 8 + if (!isNumber()) + return UINT_MAX; + if (isInteger()) + return int_32 >= 0 ? (uint)int_32 : UINT_MAX; +#else if (isInteger() && int_32 >= 0) return (uint)int_32; if (!isDouble()) return UINT_MAX; +#endif double d = doubleValue(); uint idx = (uint)d; if (idx != d) -- cgit v1.2.3