From d9f33ccdef985badc56fd8940373748626beffc7 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 12 Aug 2014 09:40:11 +0200 Subject: [PATCH] V4 JIT: parameterize the prologue and epilogue generation ... with the regular (non-FP) registers that need to be saved. This patch shouldn't change any of the JIT generated code, because all regular callee saved registers are passed in. Change-Id: Id11b8f37f06d80e8015ac6f0d0ccefdfa3342cbe Reviewed-by: Simon Hausmann --- src/qml/jit/qv4assembler.cpp | 37 ++++++++++++++++++++++--------------- src/qml/jit/qv4assembler_p.h | 32 +++++++++++++++++--------------- src/qml/jit/qv4isel_masm.cpp | 31 +++++++++++++++++++++++++++---- src/qml/jit/qv4isel_masm_p.h | 3 +++ src/qml/jit/qv4registerinfo_p.h | 26 +++++++++++++++----------- src/qml/jit/qv4targetplatform_p.h | 24 ------------------------ 6 files changed, 84 insertions(+), 69 deletions(-) diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index 3f3fccb..e76d498 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -93,10 +93,8 @@ QV4::ExecutableAllocator::ChunkOfPages *CompilationUnit::chunkForFunction(int fu const Assembler::VoidType Assembler::Void; -Assembler::Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator, - int maxArgCountForBuiltins) - : _stackLayout(function, maxArgCountForBuiltins) - , _constTable(this) +Assembler::Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator) + : _constTable(this) , _function(function) , _nextBlock(0) , _executableAllocator(executableAllocator) @@ -241,7 +239,7 @@ void Assembler::storeValue(QV4::Primitive value, IR::Expr *destination) storeValue(value, addr); } -void Assembler::enterStandardStackFrame() +void Assembler::enterStandardStackFrame(const RegisterInformation ®ularRegistersToSave) { platformEnterStandardStackFrame(this); @@ -250,24 +248,28 @@ void Assembler::enterStandardStackFrame() push(StackFrameRegister); move(StackPointerRegister, StackFrameRegister); - int frameSize = _stackLayout.calculateStackFrameSize(); + int frameSize = _stackLayout->calculateStackFrameSize(); subPtr(TrustedImm32(frameSize), StackPointerRegister); - const RegisterInformation &calleeSavedRegisters = getCalleeSavedRegisters(); - for (int i = 0; i < calleeSavedRegisterCount(); ++i) - storePtr(calleeSavedRegisters[i].reg(), Address(StackFrameRegister, -(i + 1) * sizeof(void*))); - + Address slotAddr(StackFrameRegister, -RegisterSize); + for (int i = 0, ei = regularRegistersToSave.size(); i < ei; ++i) { + storePtr(regularRegistersToSave.at(i).reg(), slotAddr); + slotAddr.offset -= RegisterSize; + } } -void Assembler::leaveStandardStackFrame() +void Assembler::leaveStandardStackFrame(const RegisterInformation ®ularRegistersToSave) { + Address slotAddr(StackFrameRegister, -regularRegistersToSave.size() * RegisterSize); + // restore the callee saved registers - const RegisterInformation &calleeSavedRegisters = getCalleeSavedRegisters(); - for (int i = calleeSavedRegisterCount() - 1; i >= 0; --i) - loadPtr(Address(StackFrameRegister, -(i + 1) * sizeof(void*)), calleeSavedRegisters[i].reg()); + for (int i = regularRegistersToSave.size() - 1; i >= 0; --i) { + loadPtr(slotAddr, regularRegistersToSave.at(i).reg()); + slotAddr.offset += RegisterSize; + } - int frameSize = _stackLayout.calculateStackFrameSize(); + int frameSize = _stackLayout->calculateStackFrameSize(); // Work around bug in ARMv7Assembler.h where add32(imm, sp, sp) doesn't // work well for large immediates. #if CPU(ARM_THUMB2) @@ -388,4 +390,9 @@ Assembler::Jump Assembler::branchInt32(bool invertCondition, IR::AluOp op, IR::E toInt32Register(right, Assembler::ReturnValueRegister)); } +void Assembler::setStackLayout(int maxArgCountForBuiltins, int regularRegistersToSave) +{ + _stackLayout.reset(new StackLayout(_function, maxArgCountForBuiltins, regularRegistersToSave)); +} + #endif diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 5e868c3..7d774f9 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -135,9 +135,10 @@ struct ExceptionCheck { class Assembler : public JSC::MacroAssembler, public TargetPlatform { + Q_DISABLE_COPY(Assembler) + public: - Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator, - int maxArgCountForBuiltins); + Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator); // Explicit type to allow distinguishing between // pushing an address itself or the value it points @@ -181,8 +182,8 @@ public: class StackLayout { public: - StackLayout(IR::Function *function, int maxArgCountForBuiltins) - : calleeSavedRegCount(Assembler::calleeSavedRegisterCount() + 1) + StackLayout(IR::Function *function, int maxArgCountForBuiltins, int normalRegistersToSave) + : normalRegistersToSave(normalRegistersToSave) , maxOutgoingArgumentCount(function->maxNumberOfArguments) , localCount(function->tempCount) , savedRegCount(maxArgCountForBuiltins) @@ -215,7 +216,7 @@ public: + RegisterSize; // saved StackFrameRegister // space for the callee saved registers - int frameSize = RegisterSize * calleeSavedRegisterCount(); + int frameSize = RegisterSize * normalRegistersToSave; frameSize += savedRegCount * sizeof(QV4::Value); // these get written out as Values, not as native registers Q_ASSERT(frameSize + stackSpaceAllocatedOtherwise < INT_MAX); @@ -268,11 +269,11 @@ public: int calleeSavedRegisterSpace() const { // plus 1 for the old FP - return RegisterSize * (calleeSavedRegCount + 1); + return RegisterSize * (normalRegistersToSave + 1); } private: - int calleeSavedRegCount; + int normalRegistersToSave; /// arg count for calls to JS functions int maxOutgoingArgumentCount; @@ -384,7 +385,7 @@ public: { Q_ASSERT(t->kind == IR::Temp::StackSlot); - return Pointer(_stackLayout.stackSlotPointer(t->index)); + return Pointer(_stackLayout->stackSlotPointer(t->index)); } template @@ -394,7 +395,7 @@ public: return; if (IR::Temp *t = arg.value->asTemp()) { if (t->kind == IR::Temp::PhysicalRegister) { - Pointer addr(_stackLayout.savedRegPointer(argumentNumber)); + Pointer addr(_stackLayout->savedRegPointer(argumentNumber)); switch (t->type) { case IR::BoolType: storeBool((RegisterID) t->index, addr); @@ -793,8 +794,8 @@ public: void storeValue(QV4::Primitive value, IR::Expr* temp); - void enterStandardStackFrame(); - void leaveStandardStackFrame(); + void enterStandardStackFrame(const RegisterInformation ®ularRegistersToSave); + void leaveStandardStackFrame(const RegisterInformation ®ularRegistersToSave); void checkException() { loadPtr(Address(ContextRegister, qOffsetOf(QV4::ExecutionContext::Data, engine)), ScratchRegister); @@ -941,7 +942,7 @@ public: Pointer toAddress(RegisterID tmpReg, IR::Expr *e, int offset) { if (IR::Const *c = e->asConst()) { - Address addr = _stackLayout.savedRegPointer(offset); + Address addr = _stackLayout->savedRegPointer(offset); Address tagAddr = addr; tagAddr.offset += 4; @@ -953,7 +954,7 @@ public: if (IR::Temp *t = e->asTemp()) if (t->kind == IR::Temp::PhysicalRegister) - return Pointer(_stackLayout.savedRegPointer(offset)); + return Pointer(_stackLayout->savedRegPointer(offset)); return loadAddress(tmpReg, e); } @@ -1145,14 +1146,15 @@ public: JSC::MacroAssemblerCodeRef link(int *codeSize); - const StackLayout stackLayout() const { return _stackLayout; } + void setStackLayout(int maxArgCountForBuiltins, int regularRegistersToSave); + const StackLayout &stackLayout() const { return *_stackLayout.data(); } ConstantTable &constantTable() { return _constTable; } Label exceptionReturnLabel; IR::BasicBlock * catchBlock; QVector exceptionPropagationJumps; private: - const StackLayout _stackLayout; + QScopedPointer _stackLayout; ConstantTable _constTable; IR::Function *_function; QHash _addrs; diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index f5d112c..5547190 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -226,20 +226,23 @@ void InstructionSelection::run(int functionIndex) static const bool withRegisterAllocator = qgetenv("QV4_NO_REGALLOC").isEmpty(); if (Assembler::RegAllocIsSupported && opt.isInSSA() && withRegisterAllocator) { RegisterAllocator(Assembler::getRegisterInfo()).run(_function, opt); + calculateRegistersToSave(Assembler::getRegisterInfo()); } else { if (opt.isInSSA()) // No register allocator available for this platform, or env. var was set, so: opt.convertOutOfSSA(); ConvertTemps().toStackSlots(_function); IR::Optimizer::showMeTheCode(_function); + calculateRegistersToSave(Assembler::getRegisterInfo()); // FIXME: this saves all registers. We can probably do with a subset: those that are not used by the register allocator. } QSet removableJumps = opt.calculateOptionalJumps(); qSwap(_removableJumps, removableJumps); Assembler* oldAssembler = _as; - _as = new Assembler(this, _function, executableAllocator, 6); // 6 == max argc for calls to built-ins with an argument array - - _as->enterStandardStackFrame(); + _as = new Assembler(this, _function, executableAllocator); + _as->setStackLayout(6, // 6 == max argc for calls to built-ins with an argument array + regularRegistersToSave.size()); + _as->enterStandardStackFrame(regularRegistersToSave); #ifdef ARGUMENTS_IN_REGISTERS _as->move(_as->registerForArgument(0), Assembler::ContextRegister); @@ -1470,7 +1473,7 @@ void InstructionSelection::visitRet(IR::Ret *s) _as->loadPtr(Address(Assembler::ContextRegister, qOffsetOf(ExecutionContext::Data, engine)), Assembler::ScratchRegister); _as->storePtr(Assembler::LocalsRegister, Address(Assembler::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop))); - _as->leaveStandardStackFrame(); + _as->leaveStandardStackFrame(regularRegistersToSave); _as->ret(); } @@ -1525,6 +1528,26 @@ int InstructionSelection::prepareCallData(IR::ExprList* args, IR::Expr *thisObje return argc; } +void InstructionSelection::calculateRegistersToSave(const RegisterInformation &used) +{ + regularRegistersToSave.clear(); + + foreach (const RegisterInfo &ri, Assembler::getRegisterInfo()) { + if (ri.isCallerSaved()) + continue; + + if (ri.isRegularRegister()) { +#if defined(RESTORE_EBX_ON_CALL) + if (ri.isRegularRegister() && ri.reg() == JSC::X86Registers::ebx) { + regularRegistersToSave.append(ri); + continue; + } +#endif // RESTORE_EBX_ON_CALL + if (ri.isPredefined() || used.contains(ri)) + regularRegistersToSave.append(ri); + } + } +} QT_BEGIN_NAMESPACE namespace QV4 { diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h index af518a0..bbe0f05 100644 --- a/src/qml/jit/qv4isel_masm_p.h +++ b/src/qml/jit/qv4isel_masm_p.h @@ -237,6 +237,8 @@ private: int prepareVariableArguments(IR::ExprList* args); int prepareCallData(IR::ExprList* args, IR::Expr *thisObject); + void calculateRegistersToSave(const RegisterInformation &used); + template void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2, Arg3 arg3) { @@ -263,6 +265,7 @@ private: QScopedPointer compilationUnit; QQmlEnginePrivate *qmlEngine; + RegisterInformation regularRegistersToSave; }; class Q_QML_EXPORT ISelFactory: public EvalISelFactory diff --git a/src/qml/jit/qv4registerinfo_p.h b/src/qml/jit/qv4registerinfo_p.h index b8701d7..ed816fd 100644 --- a/src/qml/jit/qv4registerinfo_p.h +++ b/src/qml/jit/qv4registerinfo_p.h @@ -52,27 +52,30 @@ namespace JIT { class RegisterInfo { public: - enum { InvalidRegister = -1 }; + enum { InvalidRegister = (1 << 29) - 1 }; enum SavedBy { CallerSaved, CalleeSaved }; enum RegisterType { RegularRegister, FloatingPointRegister }; enum Usage { Predefined, RegAlloc }; public: RegisterInfo() - : _reg(InvalidRegister) - , _type(RegularRegister) - , _savedBy(CallerSaved) + : _savedBy(CallerSaved) , _usage(Predefined) + , _type(RegularRegister) + , _reg(InvalidRegister) {} RegisterInfo(int reg, const QString &prettyName, RegisterType type, SavedBy savedBy, Usage usage) - : _reg(reg) - , _prettyName(prettyName) - , _type(type) + : _prettyName(prettyName) , _savedBy(savedBy) , _usage(usage) + , _type(type) + , _reg(reg) {} + bool operator==(const RegisterInfo &other) const + { return _type == other._type && _reg == other._reg; } + bool isValid() const { return _reg != InvalidRegister; } template T reg() const { return static_cast(_reg); } QString prettyName() const { return _prettyName; } @@ -81,13 +84,14 @@ public: bool isFloatingPoint() const { return _type == FloatingPointRegister; } bool isRegularRegister() const { return _type == RegularRegister; } bool useForRegAlloc() const { return _usage == RegAlloc; } + bool isPredefined() const { return _usage == Predefined; } private: - int _reg; QString _prettyName; - RegisterType _type; - SavedBy _savedBy; - Usage _usage; + unsigned _savedBy : 1; + unsigned _usage : 1; + unsigned _type : 1; + unsigned _reg : 29; }; typedef QVector RegisterInformation; diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h index 4b384d2..b32fe66 100644 --- a/src/qml/jit/qv4targetplatform_p.h +++ b/src/qml/jit/qv4targetplatform_p.h @@ -354,30 +354,6 @@ public: // utility functions return info; } - - static RegisterInformation &getCalleeSavedRegisters() - { - static RegisterInformation regs; - if (regs.isEmpty()) { - foreach (const RegisterInfo &info, getRegisterInfo()) { -#if defined(RESTORE_EBX_ON_CALL) - if (info.reg() == JSC::X86Registers::ebx) { - regs.append(info); - continue; - } -#endif // RESTORE_EBX_ON_CALL - if (info.isCalleeSaved()) - regs.append(info); - } - } - - return regs; - } - - static int calleeSavedRegisterCount() - { - return getCalleeSavedRegisters().size(); - } }; } // JIT namespace -- 2.7.4