diff options
-rw-r--r-- | src/qml/jit/jit.pri | 2 | ||||
-rw-r--r-- | src/qml/jit/qv4assembler.cpp | 68 | ||||
-rw-r--r-- | src/qml/jit/qv4assembler_p.h | 161 | ||||
-rw-r--r-- | src/qml/jit/qv4isel_masm.cpp | 96 | ||||
-rw-r--r-- | src/qml/jit/qv4registerinfo_p.h | 98 | ||||
-rw-r--r-- | src/qml/jit/qv4targetplatform_p.h | 397 |
6 files changed, 517 insertions, 305 deletions
diff --git a/src/qml/jit/jit.pri b/src/qml/jit/jit.pri index 151ff32df9..7ea4e951d5 100644 --- a/src/qml/jit/jit.pri +++ b/src/qml/jit/jit.pri @@ -6,9 +6,11 @@ INCLUDEPATH += $$OUT_PWD HEADERS += \ $$PWD/qv4assembler_p.h \ $$PWD/qv4regalloc_p.h \ + $$PWD/qv4targetplatform_p.h \ $$PWD/qv4isel_masm_p.h \ $$PWD/qv4binop_p.h \ $$PWD/qv4unop_p.h \ + $$PWD/qv4registerinfo_p.h SOURCES += \ $$PWD/qv4assembler.cpp \ diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index f090e7d506..7ce682490d 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -91,58 +91,6 @@ QV4::ExecutableAllocator::ChunkOfPages *CompilationUnit::chunkForFunction(int fu return handle->chunk(); } - - -/* Platform/Calling convention/Architecture specific section */ - -#if CPU(X86_64) -# if OS(LINUX) || OS(MAC_OS_X) -static const Assembler::RegisterID calleeSavedRegisters[] = { - JSC::X86Registers::ebx, - JSC::X86Registers::r12, // LocalsRegister - JSC::X86Registers::r13, - JSC::X86Registers::r14, // ContextRegister - JSC::X86Registers::r15 -}; -# elif OS(WINDOWS) -static const Assembler::RegisterID calleeSavedRegisters[] = { - JSC::X86Registers::ebx, - JSC::X86Registers::esi, - JSC::X86Registers::edi, - JSC::X86Registers::r12, // LocalsRegister - JSC::X86Registers::r13, - JSC::X86Registers::r14, // ContextRegister - JSC::X86Registers::r15 -}; -# endif -#endif - -#if CPU(X86) -static const Assembler::RegisterID calleeSavedRegisters[] = { - JSC::X86Registers::ebx, // temporary register - JSC::X86Registers::esi, // ContextRegister - JSC::X86Registers::edi // LocalsRegister -}; -#endif - -#if CPU(ARM) -static const Assembler::RegisterID calleeSavedRegisters[] = { - JSC::ARMRegisters::r11, - JSC::ARMRegisters::r10, - JSC::ARMRegisters::r9, - JSC::ARMRegisters::r8, - JSC::ARMRegisters::r7, - JSC::ARMRegisters::r6, - JSC::ARMRegisters::r5, - JSC::ARMRegisters::r4 -}; -#endif - -const int Assembler::calleeSavedRegisterCount = sizeof(calleeSavedRegisters) / sizeof(calleeSavedRegisters[0]); - -/* End of platform/calling convention/architecture specific section */ - - const Assembler::VoidType Assembler::Void; Assembler::Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator, @@ -295,7 +243,7 @@ void Assembler::storeValue(QV4::Primitive value, IR::Expr *destination) void Assembler::enterStandardStackFrame() { - platformEnterStandardStackFrame(); + platformEnterStandardStackFrame(this); // ### FIXME: Handle through calleeSavedRegisters mechanism // or eliminate StackFrameRegister altogether. @@ -306,16 +254,18 @@ void Assembler::enterStandardStackFrame() subPtr(TrustedImm32(frameSize), StackPointerRegister); - for (int i = 0; i < calleeSavedRegisterCount; ++i) - storePtr(calleeSavedRegisters[i], Address(StackFrameRegister, -(i + 1) * sizeof(void*))); + const RegisterInformation &calleeSavedRegisters = getCalleeSavedRegisters(); + for (int i = 0; i < calleeSavedRegisterCount(); ++i) + storePtr(calleeSavedRegisters[i].reg<RegisterID>(), Address(StackFrameRegister, -(i + 1) * sizeof(void*))); } void Assembler::leaveStandardStackFrame() { // restore the callee saved registers - for (int i = calleeSavedRegisterCount - 1; i >= 0; --i) - loadPtr(Address(StackFrameRegister, -(i + 1) * sizeof(void*)), calleeSavedRegisters[i]); + const RegisterInformation &calleeSavedRegisters = getCalleeSavedRegisters(); + for (int i = calleeSavedRegisterCount() - 1; i >= 0; --i) + loadPtr(Address(StackFrameRegister, -(i + 1) * sizeof(void*)), calleeSavedRegisters[i].reg<RegisterID>()); int frameSize = _stackLayout.calculateStackFrameSize(); // Work around bug in ARMv7Assembler.h where add32(imm, sp, sp) doesn't @@ -328,7 +278,7 @@ void Assembler::leaveStandardStackFrame() #endif pop(StackFrameRegister); - platformLeaveStandardStackFrame(); + platformLeaveStandardStackFrame(this); } diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 90387dcf79..faef4fd168 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -47,6 +47,7 @@ #include "private/qv4isel_util_p.h" #include "private/qv4value_p.h" #include "private/qv4lookup_p.h" +#include "qv4targetplatform_p.h" #include <QtCore/QHash> #include <QtCore/QStack> @@ -123,158 +124,12 @@ struct ExceptionCheck<void (*)(QV4::NoThrowContext *, A, B, C)> { enum { NeedsCheck = 0 }; }; -class Assembler : public JSC::MacroAssembler +class Assembler : public JSC::MacroAssembler, public TargetPlatform { public: Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator, int maxArgCountForBuiltins); -#if CPU(X86) - -#undef VALUE_FITS_IN_REGISTER -#undef ARGUMENTS_IN_REGISTERS - -#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1 - - static const RegisterID StackFrameRegister = JSC::X86Registers::ebp; - static const RegisterID StackPointerRegister = JSC::X86Registers::esp; - static const RegisterID LocalsRegister = JSC::X86Registers::edi; - static const RegisterID ContextRegister = JSC::X86Registers::esi; - static const RegisterID ReturnValueRegister = JSC::X86Registers::eax; - static const RegisterID ScratchRegister = JSC::X86Registers::ecx; - static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0; - static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1; - - static const int RegisterSize = 4; - - static const int RegisterArgumentCount = 0; - static RegisterID registerForArgument(int) - { - Q_ASSERT(false); - // Not reached. - return JSC::X86Registers::eax; - } - - // Return address is pushed onto stack by the CPU. - static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; - static const int StackShadowSpace = 0; - inline void platformEnterStandardStackFrame() {} - inline void platformLeaveStandardStackFrame() {} -#elif CPU(X86_64) - -#define VALUE_FITS_IN_REGISTER -#define ARGUMENTS_IN_REGISTERS -#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1 - - static const RegisterID StackFrameRegister = JSC::X86Registers::ebp; - static const RegisterID StackPointerRegister = JSC::X86Registers::esp; - static const RegisterID LocalsRegister = JSC::X86Registers::r12; - static const RegisterID ContextRegister = JSC::X86Registers::r14; - static const RegisterID ReturnValueRegister = JSC::X86Registers::eax; - static const RegisterID ScratchRegister = JSC::X86Registers::r10; - static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0; - static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1; - - static const int RegisterSize = 8; - -#if OS(WINDOWS) - static const int RegisterArgumentCount = 4; - static RegisterID registerForArgument(int index) - { - static RegisterID regs[RegisterArgumentCount] = { - JSC::X86Registers::ecx, - JSC::X86Registers::edx, - JSC::X86Registers::r8, - JSC::X86Registers::r9 - }; - Q_ASSERT(index >= 0 && index < RegisterArgumentCount); - return regs[index]; - }; - static const int StackShadowSpace = 32; -#else // Unix - static const int RegisterArgumentCount = 6; - static RegisterID registerForArgument(int index) - { - static RegisterID regs[RegisterArgumentCount] = { - JSC::X86Registers::edi, - JSC::X86Registers::esi, - JSC::X86Registers::edx, - JSC::X86Registers::ecx, - JSC::X86Registers::r8, - JSC::X86Registers::r9 - }; - Q_ASSERT(index >= 0 && index < RegisterArgumentCount); - return regs[index]; - }; - static const int StackShadowSpace = 0; -#endif - - // Return address is pushed onto stack by the CPU. - static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; - inline void platformEnterStandardStackFrame() {} - inline void platformLeaveStandardStackFrame() {} -#elif CPU(ARM) - -#undef VALUE_FITS_IN_REGISTER -#define ARGUMENTS_IN_REGISTERS -#undef HAVE_ALU_OPS_WITH_MEM_OPERAND - - static const RegisterID StackPointerRegister = JSC::ARMRegisters::sp; // r13 - static const RegisterID StackFrameRegister = JSC::ARMRegisters::fp; // r11 - static const RegisterID LocalsRegister = JSC::ARMRegisters::r7; - static const RegisterID ScratchRegister = JSC::ARMRegisters::r6; - static const RegisterID ContextRegister = JSC::ARMRegisters::r5; - static const RegisterID ReturnValueRegister = JSC::ARMRegisters::r0; - static const FPRegisterID FPGpr0 = JSC::ARMRegisters::d0; - static const FPRegisterID FPGpr1 = JSC::ARMRegisters::d1; - - static const int RegisterSize = 4; - - static const RegisterID RegisterArgument1 = JSC::ARMRegisters::r0; - static const RegisterID RegisterArgument2 = JSC::ARMRegisters::r1; - static const RegisterID RegisterArgument3 = JSC::ARMRegisters::r2; - static const RegisterID RegisterArgument4 = JSC::ARMRegisters::r3; - - static const int RegisterArgumentCount = 4; - static RegisterID registerForArgument(int index) - { - Q_ASSERT(index >= 0 && index < RegisterArgumentCount); - return static_cast<RegisterID>(JSC::ARMRegisters::r0 + index); - }; - - // Registers saved in platformEnterStandardStackFrame below. - static const int StackSpaceAllocatedUponFunctionEntry = 5 * RegisterSize; - static const int StackShadowSpace = 0; - inline void platformEnterStandardStackFrame() - { - // Move the register arguments onto the stack as if they were - // pushed by the caller, just like on ia32. This gives us consistent - // access to the parameters if we need to. - push(JSC::ARMRegisters::r3); - push(JSC::ARMRegisters::r2); - push(JSC::ARMRegisters::r1); - push(JSC::ARMRegisters::r0); - push(JSC::ARMRegisters::lr); - } - inline void platformLeaveStandardStackFrame() - { - pop(JSC::ARMRegisters::lr); - addPtr(TrustedImm32(4 * RegisterSize), StackPointerRegister); - } -#else -#error The JIT needs to be ported to this platform. -#endif - static const int calleeSavedRegisterCount; - -#if CPU(X86) || CPU(X86_64) - static const int StackAlignment = 16; -#elif CPU(ARM) - // Per AAPCS - static const int StackAlignment = 8; -#else -#error Stack alignment unknown for this platform. -#endif - // Explicit type to allow distinguishing between // pushing an address itself or the value it points // to onto the stack when calling functions. @@ -318,7 +173,7 @@ public: { public: StackLayout(IR::Function *function, int maxArgCountForBuiltins) - : calleeSavedRegCount(Assembler::calleeSavedRegisterCount + 1) + : calleeSavedRegCount(Assembler::calleeSavedRegisterCount() + 1) , maxOutgoingArgumentCount(function->maxNumberOfArguments) , localCount(function->tempCount) , savedRegCount(maxArgCountForBuiltins) @@ -351,7 +206,7 @@ public: + RegisterSize; // saved StackFrameRegister // space for the callee saved registers - int frameSize = RegisterSize * calleeSavedRegisterCount; + int frameSize = RegisterSize * calleeSavedRegisterCount(); frameSize += savedRegCount * sizeof(QV4::Value); // these get written out as Values, not as native registers Q_ASSERT(frameSize + stackSpaceAllocatedOtherwise < INT_MAX); @@ -1014,10 +869,8 @@ public: prepareRelativeCall(function, this); loadArgumentOnStackOrRegister<0>(arg1); -#if (OS(LINUX) && CPU(X86) && (defined(__PIC__) || defined(__PIE__))) || \ - (OS(WINDOWS) && CPU(X86)) - load32(Address(StackFrameRegister, -int(sizeof(void*))), - JSC::X86Registers::ebx); // restore the GOT ptr +#ifdef RESTORE_EBX_ON_CALL + load32(ebxAddressOnStack(), JSC::X86Registers::ebx); // restore the GOT ptr #endif callAbsolute(functionName, function); diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index d82fa990f4..8d732ce657 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -214,91 +214,6 @@ InstructionSelection::~InstructionSelection() delete _as; } -#if (CPU(X86_64) && (OS(MAC_OS_X) || OS(LINUX))) || (CPU(X86) && OS(LINUX)) -# define REGALLOC_IS_SUPPORTED -static QVector<int> getIntRegisters() -{ -# if CPU(X86) && OS(LINUX) // x86 with linux - static const QVector<int> intRegisters = QVector<int>() - << JSC::X86Registers::edx - << JSC::X86Registers::ebx; -# else // x86_64 with linux or with macos - static const QVector<int> intRegisters = QVector<int>() - << JSC::X86Registers::ebx - << JSC::X86Registers::edi - << JSC::X86Registers::esi - << JSC::X86Registers::edx - << JSC::X86Registers::r9 - << JSC::X86Registers::r8 - << JSC::X86Registers::r13 - << JSC::X86Registers::r15; -# endif - return intRegisters; -} - -static QVector<int> getFpRegisters() -{ -// linux/x86_64, linux/x86, and macos/x86_64: - static const QVector<int> fpRegisters = QVector<int>() - << JSC::X86Registers::xmm2 - << JSC::X86Registers::xmm3 - << JSC::X86Registers::xmm4 - << JSC::X86Registers::xmm5 - << JSC::X86Registers::xmm6 - << JSC::X86Registers::xmm7; - return fpRegisters; -} - -#elif CPU(ARM) && OS(LINUX) - // Note: this is not generic for all ARM platforms. Specifically, r9 is platform dependent - // (e.g. iOS reserves it). See the ARM GNU Linux abi for details. -# define REGALLOC_IS_SUPPORTED -static QVector<int> getIntRegisters() -{ - static const QVector<int> intRegisters = QVector<int>() - << JSC::ARMRegisters::r1 - << JSC::ARMRegisters::r2 - << JSC::ARMRegisters::r3 - << JSC::ARMRegisters::r4 - << JSC::ARMRegisters::r8 - << JSC::ARMRegisters::r9; - return intRegisters; -} - -static QVector<int> getFpRegisters() -{ - static const QVector<int> fpRegisters = QVector<int>() - << JSC::ARMRegisters::d1 - << JSC::ARMRegisters::d2 - << JSC::ARMRegisters::d3 - << JSC::ARMRegisters::d4 - << JSC::ARMRegisters::d5 - << JSC::ARMRegisters::d6; - return fpRegisters; -} -#elif CPU(X86) && OS(WINDOWS) -# define REGALLOC_IS_SUPPORTED -static QVector<int> getIntRegisters() -{ - static const QVector<int> intRegisters = QVector<int>() - << JSC::X86Registers::edx - << JSC::X86Registers::ebx; - return intRegisters; -} - -static QVector<int> getFpRegisters() -{ - static const QVector<int> fpRegisters = QVector<int>() - << JSC::X86Registers::xmm2 - << JSC::X86Registers::xmm3 - << JSC::X86Registers::xmm4 - << JSC::X86Registers::xmm5 - << JSC::X86Registers::xmm6 - << JSC::X86Registers::xmm7; - return fpRegisters; -} -#endif - void InstructionSelection::run(int functionIndex) { IR::Function *function = irModule->functions[functionIndex]; @@ -308,13 +223,10 @@ void InstructionSelection::run(int functionIndex) IR::Optimizer opt(_function); opt.run(qmlEngine); -#ifdef REGALLOC_IS_SUPPORTED static const bool withRegisterAllocator = qgetenv("QV4_NO_REGALLOC").isEmpty(); - if (opt.isInSSA() && withRegisterAllocator) { - RegisterAllocator(getIntRegisters(), getFpRegisters()).run(_function, opt); - } else -#endif // REGALLOC_IS_SUPPORTED - { + if (Assembler::RegAllocIsSupported && opt.isInSSA() && withRegisterAllocator) { + RegisterAllocator(Assembler::getIntRegisters(), Assembler::getFpRegisters()).run(_function, opt); + } else { if (opt.isInSSA()) // No register allocator available for this platform, or env. var was set, so: opt.convertOutOfSSA(); diff --git a/src/qml/jit/qv4registerinfo_p.h b/src/qml/jit/qv4registerinfo_p.h new file mode 100644 index 0000000000..b9bef678a3 --- /dev/null +++ b/src/qml/jit/qv4registerinfo_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 QV4REGISTERINFO_P_H +#define QV4REGISTERINFO_P_H + +#include <QtCore/QString> + +QT_BEGIN_NAMESPACE + +namespace QV4 { +namespace JIT { + +class RegisterInfo +{ +public: + enum { InvalidRegister = -1 }; + enum SavedBy { CallerSaved, CalleeSaved }; + enum RegisterType { RegularRegister, FloatingPointRegister }; + enum Usage { Predefined, RegAlloc }; + +public: + RegisterInfo() + : _reg(InvalidRegister) + , _type(RegularRegister) + , _savedBy(CallerSaved) + , _usage(Predefined) + {} + + RegisterInfo(int reg, const QString &prettyName, RegisterType type, SavedBy savedBy, Usage usage) + : _reg(reg) + , _prettyName(prettyName) + , _type(type) + , _savedBy(savedBy) + , _usage(usage) + {} + + bool isValid() const { return _reg != InvalidRegister; } + template <typename T> T reg() const { return static_cast<T>(_reg); } + bool isCallerSaved() const { return _savedBy == CallerSaved; } + bool isCalleeSaved() const { return _savedBy == CalleeSaved; } + bool isFloatingPoint() const { return _type == FloatingPointRegister; } + bool isRegularRegister() const { return _type == RegularRegister; } + bool useForRegAlloc() const { return _usage == RegAlloc; } + +private: + int _reg; + QString _prettyName; + RegisterType _type; + SavedBy _savedBy; + Usage _usage; +}; +typedef QVector<RegisterInfo> RegisterInformation; + +} // JIT namespace +} // QV4 namespace + +QT_END_NAMESPACE + +#endif // QV4REGISTERINFO_P_H diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h new file mode 100644 index 0000000000..654d2f3f52 --- /dev/null +++ b/src/qml/jit/qv4targetplatform_p.h @@ -0,0 +1,397 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 QV4TARGETPLATFORM_P_H +#define QV4TARGETPLATFORM_P_H + +#include <config.h> + +#if ENABLE(ASSEMBLER) + +#include "qv4registerinfo_p.h" +#include <assembler/MacroAssembler.h> + +QT_BEGIN_NAMESPACE + +namespace QV4 { +namespace JIT { + +// The TargetPlatform class describes how the stack and the registers work on a CPU+ABI combination. +// +// All combinations have a separate definition, guarded by #ifdefs. The exceptions are: +// - Linux/x86 and win32, which are the same, except that linux non-PIC/PIE code does not need to +// restore ebx (which holds the GOT ptr) before a call +// - All (supported) ARM platforms, where the only variety is the platform specific usage of r9, +// and the frame-pointer in Thumb/Thumb2 v.s. ARM mode. +class TargetPlatform +{ +public: +#if CPU(X86) && (OS(LINUX) || OS(WINDOWS)) + enum { RegAllocIsSupported = 1 }; + + static const JSC::MacroAssembler::RegisterID StackFrameRegister = JSC::X86Registers::ebp; + static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::X86Registers::esp; + static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::X86Registers::edi; + static const JSC::MacroAssembler::RegisterID ContextRegister = JSC::X86Registers::esi; + static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::X86Registers::eax; + static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::X86Registers::ecx; + static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::X86Registers::xmm0; + static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::X86Registers::xmm1; + + static RegisterInformation getPlatformRegisterInfo() + { + typedef RegisterInfo RI; + return RegisterInformation() + << RI(JSC::X86Registers::edx, QStringLiteral("edx"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::ebx, QStringLiteral("ebx"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) + << RI(JSC::X86Registers::edi, QStringLiteral("edi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::X86Registers::esi, QStringLiteral("esi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::X86Registers::xmm2, QStringLiteral("xmm2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::xmm3, QStringLiteral("xmm3"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::xmm4, QStringLiteral("xmm4"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::xmm5, QStringLiteral("xmm5"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::xmm6, QStringLiteral("xmm6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::xmm7, QStringLiteral("xmm7"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + ; + } + +# undef VALUE_FITS_IN_REGISTER + static const int RegisterSize = 4; + +# undef ARGUMENTS_IN_REGISTERS + static const int RegisterArgumentCount = 0; + static JSC::MacroAssembler::RegisterID registerForArgument(int) { Q_UNREACHABLE(); } + + static const int StackAlignment = 16; + static const int StackShadowSpace = 0; + static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU. + static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); } + static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); } + +#if OS(WINDOWS) || \ + (OS(LINUX) && (defined(__PIC__) || defined(__PIE__))) + +#define RESTORE_EBX_ON_CALL + static JSC::MacroAssembler::Address ebxAddressOnStack() + { + static int ebxIdx = -1; + if (ebxIdx == -1) { + int calleeSaves = 0; + foreach (const RegisterInfo &info, getRegisterInfo()) { + if (info.reg<JSC::X86Registers::RegisterID>() == JSC::X86Registers::ebx) { + ebxIdx = calleeSaves; + break; + } else if (info.isCalleeSaved()) { + ++calleeSaves; + } + } + Q_ASSERT(ebxIdx >= 0); + ebxIdx += 1; + } + return JSC::MacroAssembler::Address(StackFrameRegister, ebxIdx * -int(sizeof(void*))); + } +#endif + +#endif // Windows on x86 + +#if CPU(X86_64) && (OS(LINUX) || OS(MAC_OS_X)) + enum { RegAllocIsSupported = 1 }; + + static const JSC::MacroAssembler::RegisterID StackFrameRegister = JSC::X86Registers::ebp; + static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::X86Registers::esp; + static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::X86Registers::r12; + static const JSC::MacroAssembler::RegisterID ContextRegister = JSC::X86Registers::r14; + static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::X86Registers::eax; + static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::X86Registers::r10; + static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::X86Registers::xmm0; + static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::X86Registers::xmm1; + + static RegisterInformation getPlatformRegisterInfo() + { + typedef RegisterInfo RI; + return RegisterInformation() + << RI(JSC::X86Registers::ebx, QStringLiteral("rbx"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) + << RI(JSC::X86Registers::edi, QStringLiteral("rdi"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::esi, QStringLiteral("rsi"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::edx, QStringLiteral("rdx"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::r12, QStringLiteral("r12"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::X86Registers::r13, QStringLiteral("r13"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) + << RI(JSC::X86Registers::r14, QStringLiteral("r14"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::X86Registers::r15, QStringLiteral("r15"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) + << RI(JSC::X86Registers::xmm2, QStringLiteral("xmm2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::xmm3, QStringLiteral("xmm3"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::xmm4, QStringLiteral("xmm4"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::xmm5, QStringLiteral("xmm5"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::xmm6, QStringLiteral("xmm6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::xmm7, QStringLiteral("xmm7"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + ; + } + +#define VALUE_FITS_IN_REGISTER + static const int RegisterSize = 8; + +#define ARGUMENTS_IN_REGISTERS + static const int RegisterArgumentCount = 6; + static JSC::MacroAssembler::RegisterID registerForArgument(int index) + { + static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = { + JSC::X86Registers::edi, + JSC::X86Registers::esi, + JSC::X86Registers::edx, + JSC::X86Registers::ecx, + JSC::X86Registers::r8, + JSC::X86Registers::r9 + }; + Q_ASSERT(index >= 0 && index < RegisterArgumentCount); + return regs[index]; + }; + + static const int StackAlignment = 16; + static const int StackShadowSpace = 0; + static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU. + static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); } + static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); } +#endif // Linux/MacOS on x86_64 + +#if CPU(X86_64) && OS(WINDOWS) + // Register allocation is not (yet) supported on win64, because the ABI related stack handling + // is not completely implemented. Specifically, the saving of xmm registers, and the saving of + // incoming function parameters to the shadow space is missing. + enum { RegAllocIsSupported = 0 }; + + static const JSC::MacroAssembler::RegisterID StackFrameRegister = JSC::X86Registers::ebp; + static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::X86Registers::esp; + static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::X86Registers::r12; + static const JSC::MacroAssembler::RegisterID ContextRegister = JSC::X86Registers::r14; + static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::X86Registers::eax; + static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::X86Registers::r10; + static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::X86Registers::xmm0; + static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::X86Registers::xmm1; + + static RegisterInformation getPlatformRegisterInfo() + { + typedef RegisterInfo RI; + return RegisterInformation() + << RI(JSC::X86Registers::ebx, QStringLiteral("rbx"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::X86Registers::edi, QStringLiteral("rdi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::X86Registers::esi, QStringLiteral("rsi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::X86Registers::edx, QStringLiteral("rdx"), RI::RegularRegister, RI::CallerSaved, RI::Predefined) + << RI(JSC::X86Registers::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CallerSaved, RI::Predefined) + << RI(JSC::X86Registers::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CallerSaved, RI::Predefined) + << RI(JSC::X86Registers::r12, QStringLiteral("r12"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::X86Registers::r13, QStringLiteral("r13"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::X86Registers::r14, QStringLiteral("r14"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::X86Registers::r15, QStringLiteral("r15"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + ; + } + +#define VALUE_FITS_IN_REGISTER + static const int RegisterSize = 8; + +#define ARGUMENTS_IN_REGISTERS + static const int RegisterArgumentCount = 4; + static JSC::MacroAssembler::RegisterID registerForArgument(int index) + { + static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = { + JSC::X86Registers::ecx, + JSC::X86Registers::edx, + JSC::X86Registers::r8, + JSC::X86Registers::r9 + }; + Q_ASSERT(index >= 0 && index < RegisterArgumentCount); + return regs[index]; + }; + + static const int StackAlignment = 16; + static const int StackShadowSpace = 32; + static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU. + static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); } + static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); } +#endif // Windows on x86_64 + +#if CPU(ARM) + enum { RegAllocIsSupported = 1 }; + + // The AAPCS specifies that the platform ABI has to define the usage of r9. Known are: + // - The GNU/Linux ABI defines it as an additional callee-saved variable register (v6). + // - iOS (for which we cannot JIT, but still...) defines it as having a special use, so we do + // not touch it, nor use it. + // - Any other platform has not been verified, so we conservatively assume we cannot use it. +#if OS(LINUX) +#define CAN_USE_R9 +#endif + + // There are two designated frame-pointer registers on ARM, depending on which instruction set + // is used for the subroutine: r7 for Thumb or Thumb2, and r11 for ARM. We assign the constants + // accordingly, and assign the locals-register to the "other" register. +#if CPU(ARM_THUMB2) + static const JSC::MacroAssembler::RegisterID StackFrameRegister = JSC::ARMRegisters::r7; + static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::ARMRegisters::r11; +#else // Thumbs down + static const JSC::MacroAssembler::RegisterID StackFrameRegister = JSC::ARMRegisters::r11; + static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::ARMRegisters::r7; +#endif + static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::ARMRegisters::r13; + static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::ARMRegisters::r6; + static const JSC::MacroAssembler::RegisterID ContextRegister = JSC::ARMRegisters::r5; + static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::ARMRegisters::r0; + static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::ARMRegisters::d0; + static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::ARMRegisters::d1; + + static RegisterInformation getPlatformRegisterInfo() + { + typedef RegisterInfo RI; + return RegisterInformation() + << RI(JSC::ARMRegisters::r0, QStringLiteral("r0"), RI::RegularRegister, RI::CallerSaved, RI::Predefined) + << RI(JSC::ARMRegisters::r1, QStringLiteral("r1"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::ARMRegisters::r2, QStringLiteral("r2"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::ARMRegisters::r3, QStringLiteral("r3"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::ARMRegisters::r4, QStringLiteral("r4"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) + << RI(JSC::ARMRegisters::r5, QStringLiteral("r5"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::ARMRegisters::r6, QStringLiteral("r6"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) +#if !CPU(ARM_THUMB2) + << RI(JSC::ARMRegisters::r7, QStringLiteral("r7"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) +#endif + << RI(JSC::ARMRegisters::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) +#ifdef CAN_USE_R9 + << RI(JSC::ARMRegisters::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) +#endif + << RI(JSC::ARMRegisters::r10, QStringLiteral("r10"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) +#if CPU(ARM_THUMB2) + << RI(JSC::ARMRegisters::r11, QStringLiteral("r11"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) +#endif + << RI(JSC::ARMRegisters::d2, QStringLiteral("d2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::ARMRegisters::d3, QStringLiteral("d3"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::ARMRegisters::d4, QStringLiteral("d4"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::ARMRegisters::d5, QStringLiteral("d5"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::ARMRegisters::d6, QStringLiteral("d6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + ; + // TODO: someone should check what's up with d8-d15: are they alway available, and are they caller or callee saved? + } + +#undef VALUE_FITS_IN_REGISTER + static const int RegisterSize = 4; + +#define ARGUMENTS_IN_REGISTERS + static const int RegisterArgumentCount = 4; + static JSC::MacroAssembler::RegisterID registerForArgument(int index) + { + static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = { + JSC::ARMRegisters::r0, + JSC::ARMRegisters::r1, + JSC::ARMRegisters::r2, + JSC::ARMRegisters::r3 + }; + + Q_ASSERT(index >= 0 && index < RegisterArgumentCount); + return regs[index]; + }; + + static const int StackAlignment = 8; // Per AAPCS + static const int StackShadowSpace = 0; + static const int StackSpaceAllocatedUponFunctionEntry = 1 * RegisterSize; // Registers saved in platformEnterStandardStackFrame below. + static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { as->push(JSC::ARMRegisters::lr); } + static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { as->pop(JSC::ARMRegisters::lr); } +#endif // Linux on ARM (32 bit) + +public: // utility functions + static RegisterInformation getRegisterInfo() + { + static const RegisterInformation info = getPlatformRegisterInfo(); + + return info; + } + + static RegisterInformation &getCalleeSavedRegisters() + { + static RegisterInformation regs; + if (regs.isEmpty()) { + foreach (const RegisterInfo &info, getRegisterInfo()) { + if (info.isCalleeSaved()) + regs.append(info); + } + } + + return regs; + } + + static int calleeSavedRegisterCount() + { + return getCalleeSavedRegisters().size(); + } + + static QVector<int> getIntRegisters() + { + // TODO: change the register allocator to cope with caller/callee saved registers + static QVector<int> intRegs; + if (intRegs.isEmpty()) { + foreach (const RegisterInfo &info, getRegisterInfo()) + if (info.isRegularRegister() && info.useForRegAlloc()) + intRegs.append(info.reg<int>()); + } + + return intRegs; + } + + static QVector<int> getFpRegisters() + { + // TODO: change the register allocator to cope with caller/callee saved registers + static QVector<int> fpRegs; + if (fpRegs.isEmpty()) { + foreach (const RegisterInfo &info, getRegisterInfo()) + if (info.isFloatingPoint() && info.useForRegAlloc()) + fpRegs.append(info.reg<int>()); + } + + return fpRegs; + } +}; + +} // JIT namespace +} // QV4 namespace + +QT_END_NAMESPACE + +#endif // ENABLE(ASSEMBLER) + +#endif // QV4TARGETPLATFORM_P_H |