aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jit/qv4regalloc_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jit/qv4regalloc_p.h')
-rw-r--r--src/qml/jit/qv4regalloc_p.h51
1 files changed, 37 insertions, 14 deletions
diff --git a/src/qml/jit/qv4regalloc_p.h b/src/qml/jit/qv4regalloc_p.h
index 030fb4bf50..34ae19dfec 100644
--- a/src/qml/jit/qv4regalloc_p.h
+++ b/src/qml/jit/qv4regalloc_p.h
@@ -44,6 +44,7 @@
#include "qv4global_p.h"
#include "qv4isel_p.h"
#include "qv4ssa_p.h"
+#include "qv4registerinfo_p.h"
#include <config.h>
@@ -54,46 +55,68 @@ namespace JIT {
class RegAllocInfo;
+// This class implements a linear-scan register allocator, with a couple of tweaks:
+// - Second-chance allocation is used when an interval becomes active after a spill, which results
+// in fewer differences between edges, and hence fewer moves before jumps.
+// - Use positions are flagged with either "must have" register or "could have" register. This is
+// used to decide whether a register is really needed when a temporary is used after a spill
+// occurred.
+// - Fixed intervals are used to denotate IR positions where certain registers are needed in order
+// to implement the operation, and cannot be used by a temporary on that position. An example is
+// caller saved registers, where the call will use/clobber those registers.
+// - Hints are used to indicate which registers could be used to generate more compact code. An
+// example is an addition, where one (or both) operands' life-time ends at that instruction. In
+// this case, re-using an operand register for the result will result in an in-place add.
+// - SSA form properties are used:
+// - to simplify life-times (two temporaries will never interfere as long as their intervals
+// are not split), resulting in a slightly faster algorithm;
+// - when a temporary needs to be spilled, it is done directly after calculating it, so that
+// 1 store is generated even if multiple spills/splits happen.
+// - phi-node elimination (SSA form deconstruction) is done when resolving differences between
+// CFG edges
class RegisterAllocator
{
typedef IR::LifeTimeInterval LifeTimeInterval;
- QVector<int> _normalRegisters;
- QVector<int> _fpRegisters;
+ const RegisterInformation &_registerInformation;
+ QVector<const RegisterInfo *> _normalRegisters;
+ QVector<const RegisterInfo *> _fpRegisters;
QScopedPointer<RegAllocInfo> _info;
- QVector<LifeTimeInterval> _fixedRegisterRanges, _fixedFPRegisterRanges;
+ QVector<LifeTimeInterval *> _fixedRegisterRanges, _fixedFPRegisterRanges;
- QVector<LifeTimeInterval> _unhandled, _active, _inactive, _handled;
+ IR::LifeTimeIntervals::Ptr _lifeTimeIntervals;
+ typedef QVector<LifeTimeInterval *> Intervals;
+ Intervals _unhandled, _active, _inactive, _handled;
- QHash<IR::Temp, int> _lastAssignedRegister;
- QHash<IR::Temp, int> _assignedSpillSlots;
+ std::vector<int> _lastAssignedRegister;
+ std::vector<int> _assignedSpillSlots;
QVector<int> _activeSpillSlots;
Q_DISABLE_COPY(RegisterAllocator)
public:
- RegisterAllocator(const QVector<int> &normalRegisters, const QVector<int> &fpRegisters);
+ enum { InvalidSpillSlot = -1 };
+
+ RegisterAllocator(const RegisterInformation &registerInformation);
~RegisterAllocator();
void run(IR::Function *function, const IR::Optimizer &opt);
private:
+ LifeTimeInterval *cloneFixedInterval(int reg, bool isFP, const LifeTimeInterval &original);
void prepareRanges();
void linearScan();
- void tryAllocateFreeReg(LifeTimeInterval &current, const int position);
- void allocateBlockedReg(LifeTimeInterval &current, const int position);
- void longestAvailableReg(const QVector<int> &nextUses, int &reg, int &nextUsePos_reg,
- int lastUse) const;
- int nextIntersection(const LifeTimeInterval &current, const LifeTimeInterval &another,
- const int position) const;
+ void tryAllocateFreeReg(LifeTimeInterval &current);
+ void allocateBlockedReg(LifeTimeInterval &current);
+ int nextIntersection(const LifeTimeInterval &current, const LifeTimeInterval &another) const;
int nextUse(const IR::Temp &t, int startPosition) const;
void split(LifeTimeInterval &current, int beforePosition, bool skipOptionalRegisterUses =false);
void splitInactiveAtEndOfLifetimeHole(int reg, bool isFPReg, int position);
void assignSpillSlot(const IR::Temp &t, int startPos, int endPos);
void resolve(IR::Function *function, const IR::Optimizer &opt);
- void dump() const;
+ void dump(IR::Function *function) const;
};
} // end of namespace JIT