aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@qt.io>2016-08-12 08:02:37 +0200
committerSimon Hausmann <simon.hausmann@qt.io>2016-08-12 07:51:12 +0000
commitb4327851a4895b28b2c60ca51e77eca3ee0a1b4e (patch)
tree24f386105b659070bfd7c5229ad49db8985a26aa /src/qml
parente0acbde6da2127d9fa75aa6c032682086295ce27 (diff)
Move the moth stack slot allocator into qmldevtools
This way it's accessible to the QML compiler. Change-Id: I3918a796c698fc75e134b29a61eed2ec028bc851 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp163
-rw-r--r--src/qml/compiler/qv4ssa_p.h163
2 files changed, 164 insertions, 162 deletions
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index afb36c5f14..f87cbe3f1b 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -143,167 +143,6 @@ inline bool isBoolType(IR::Expr *e)
return (e->type == IR::BoolType);
}
-/*
- * stack slot allocation:
- *
- * foreach bb do
- * foreach stmt do
- * if the current statement is not a phi-node:
- * purge ranges that end before the current statement
- * check for life ranges to activate, and if they don't have a stackslot associated then allocate one
- * renumber temps to stack
- * for phi nodes: check if all temps (src+dst) are assigned stack slots and marked as allocated
- * if it's a jump:
- * foreach phi node in the successor:
- * allocate slots for each temp (both sources and targets) if they don't have one allocated already
- * insert moves before the jump
- */
-class AllocateStackSlots: protected ConvertTemps
-{
- IR::LifeTimeIntervals::Ptr _intervals;
- QVector<IR::LifeTimeInterval *> _unhandled;
- QVector<IR::LifeTimeInterval *> _live;
- QBitArray _slotIsInUse;
- IR::Function *_function;
-
- int defPosition(IR::Stmt *s) const
- {
- return usePosition(s) + 1;
- }
-
- int usePosition(IR::Stmt *s) const
- {
- return _intervals->positionForStatement(s);
- }
-
-public:
- AllocateStackSlots(const IR::LifeTimeIntervals::Ptr &intervals)
- : _intervals(intervals)
- , _slotIsInUse(intervals->size(), false)
- , _function(0)
- {
- _live.reserve(8);
- _unhandled = _intervals->intervals();
- }
-
- void forFunction(IR::Function *function)
- {
- IR::Optimizer::showMeTheCode(function, "Before stack slot allocation");
- _function = function;
- toStackSlots(function);
- }
-
-protected:
- virtual int allocateFreeSlot()
- {
- for (int i = 0, ei = _slotIsInUse.size(); i != ei; ++i) {
- if (!_slotIsInUse[i]) {
- if (_nextUnusedStackSlot <= i) {
- Q_ASSERT(_nextUnusedStackSlot == i);
- _nextUnusedStackSlot = i + 1;
- }
- _slotIsInUse[i] = true;
- return i;
- }
- }
-
- Q_UNREACHABLE();
- return -1;
- }
-
- virtual void process(IR::Stmt *s)
- {
-// qDebug("L%d statement %d:", _currentBasicBlock->index, s->id);
-
- if (IR::Phi *phi = s->asPhi()) {
- visitPhi(phi);
- } else {
- // purge ranges no longer alive:
- for (int i = 0; i < _live.size(); ) {
- const IR::LifeTimeInterval *lti = _live.at(i);
- if (lti->end() < usePosition(s)) {
-// qDebug() << "\t - moving temp" << lti->temp().index << "to handled, freeing slot" << _stackSlotForTemp[lti->temp().index];
- _live.remove(i);
- Q_ASSERT(_slotIsInUse[_stackSlotForTemp[lti->temp().index]]);
- _slotIsInUse[_stackSlotForTemp[lti->temp().index]] = false;
- continue;
- } else {
- ++i;
- }
- }
-
- // active new ranges:
- while (!_unhandled.isEmpty()) {
- IR::LifeTimeInterval *lti = _unhandled.last();
- if (lti->start() > defPosition(s))
- break; // we're done
- Q_ASSERT(!_stackSlotForTemp.contains(lti->temp().index));
- _stackSlotForTemp[lti->temp().index] = allocateFreeSlot();
-// qDebug() << "\t - activating temp" << lti->temp().index << "on slot" << _stackSlotForTemp[lti->temp().index];
- _live.append(lti);
- _unhandled.removeLast();
- }
-
- s->accept(this);
- }
-
- if (IR::Jump *jump = s->asJump()) {
- IR::MoveMapping moves;
- foreach (IR::Stmt *succStmt, jump->target->statements()) {
- if (IR::Phi *phi = succStmt->asPhi()) {
- forceActivation(*phi->targetTemp);
- for (int i = 0, ei = phi->d->incoming.size(); i != ei; ++i) {
- IR::Expr *e = phi->d->incoming[i];
- if (IR::Temp *t = e->asTemp()) {
- forceActivation(*t);
- }
- if (jump->target->in[i] == _currentBasicBlock)
- moves.add(phi->d->incoming[i], phi->targetTemp);
- }
- } else {
- break;
- }
- }
- moves.order();
- QList<IR::Move *> newMoves = moves.insertMoves(_currentBasicBlock, _function, true);
- foreach (IR::Move *move, newMoves)
- move->accept(this);
- }
- }
-
- void forceActivation(const IR::Temp &t)
- {
- if (_stackSlotForTemp.contains(t.index))
- return;
-
- int i = _unhandled.size() - 1;
- for (; i >= 0; --i) {
- IR::LifeTimeInterval *lti = _unhandled[i];
- if (lti->temp() == t) {
- _live.append(lti);
- _unhandled.remove(i);
- break;
- }
- }
- Q_ASSERT(i >= 0); // check that we always found the entry
-
- _stackSlotForTemp[t.index] = allocateFreeSlot();
-// qDebug() << "\t - force activating temp" << t.index << "on slot" << _stackSlotForTemp[t.index];
- }
-
- virtual void visitPhi(IR::Phi *phi)
- {
- Q_UNUSED(phi);
-#if !defined(QT_NO_DEBUG)
- Q_ASSERT(_stackSlotForTemp.contains(phi->targetTemp->index));
- Q_ASSERT(_slotIsInUse[_stackSlotForTemp[phi->targetTemp->index]]);
- foreach (IR::Expr *e, phi->d->incoming) {
- if (IR::Temp *t = e->asTemp())
- Q_ASSERT(_stackSlotForTemp.contains(t->index));
- }
-#endif // defined(QT_NO_DEBUG)
- }
-};
} // anonymous namespace
InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
@@ -353,7 +192,7 @@ void InstructionSelection::run(int functionIndex)
qEnvironmentVariableIsEmpty("QV4_NO_INTERPRETER_STACK_SLOT_ALLOCATION");
if (doStackSlotAllocation) {
- AllocateStackSlots(opt.lifeTimeIntervals()).forFunction(_function);
+ IR::AllocateStackSlots(opt.lifeTimeIntervals()).forFunction(_function);
} else {
opt.convertOutOfSSA();
ConvertTemps().toStackSlots(_function);
diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h
index d06774e803..c5690a8581 100644
--- a/src/qml/compiler/qv4ssa_p.h
+++ b/src/qml/compiler/qv4ssa_p.h
@@ -46,6 +46,7 @@
//
#include "qv4jsir_p.h"
+#include "qv4isel_util_p.h"
#include <QtCore/QSharedPointer>
QT_BEGIN_NAMESPACE
@@ -271,6 +272,168 @@ private:
QList<Move> &swaps) const;
};
+/*
+ * stack slot allocation:
+ *
+ * foreach bb do
+ * foreach stmt do
+ * if the current statement is not a phi-node:
+ * purge ranges that end before the current statement
+ * check for life ranges to activate, and if they don't have a stackslot associated then allocate one
+ * renumber temps to stack
+ * for phi nodes: check if all temps (src+dst) are assigned stack slots and marked as allocated
+ * if it's a jump:
+ * foreach phi node in the successor:
+ * allocate slots for each temp (both sources and targets) if they don't have one allocated already
+ * insert moves before the jump
+ */
+class AllocateStackSlots: protected ConvertTemps
+{
+ IR::LifeTimeIntervals::Ptr _intervals;
+ QVector<IR::LifeTimeInterval *> _unhandled;
+ QVector<IR::LifeTimeInterval *> _live;
+ QBitArray _slotIsInUse;
+ IR::Function *_function;
+
+ int defPosition(IR::Stmt *s) const
+ {
+ return usePosition(s) + 1;
+ }
+
+ int usePosition(IR::Stmt *s) const
+ {
+ return _intervals->positionForStatement(s);
+ }
+
+public:
+ AllocateStackSlots(const IR::LifeTimeIntervals::Ptr &intervals)
+ : _intervals(intervals)
+ , _slotIsInUse(intervals->size(), false)
+ , _function(0)
+ {
+ _live.reserve(8);
+ _unhandled = _intervals->intervals();
+ }
+
+ void forFunction(IR::Function *function)
+ {
+ IR::Optimizer::showMeTheCode(function, "Before stack slot allocation");
+ _function = function;
+ toStackSlots(function);
+ }
+
+protected:
+ virtual int allocateFreeSlot()
+ {
+ for (int i = 0, ei = _slotIsInUse.size(); i != ei; ++i) {
+ if (!_slotIsInUse[i]) {
+ if (_nextUnusedStackSlot <= i) {
+ Q_ASSERT(_nextUnusedStackSlot == i);
+ _nextUnusedStackSlot = i + 1;
+ }
+ _slotIsInUse[i] = true;
+ return i;
+ }
+ }
+
+ Q_UNREACHABLE();
+ return -1;
+ }
+
+ virtual void process(IR::Stmt *s)
+ {
+// qDebug("L%d statement %d:", _currentBasicBlock->index, s->id);
+
+ if (IR::Phi *phi = s->asPhi()) {
+ visitPhi(phi);
+ } else {
+ // purge ranges no longer alive:
+ for (int i = 0; i < _live.size(); ) {
+ const IR::LifeTimeInterval *lti = _live.at(i);
+ if (lti->end() < usePosition(s)) {
+// qDebug() << "\t - moving temp" << lti->temp().index << "to handled, freeing slot" << _stackSlotForTemp[lti->temp().index];
+ _live.remove(i);
+ Q_ASSERT(_slotIsInUse[_stackSlotForTemp[lti->temp().index]]);
+ _slotIsInUse[_stackSlotForTemp[lti->temp().index]] = false;
+ continue;
+ } else {
+ ++i;
+ }
+ }
+
+ // active new ranges:
+ while (!_unhandled.isEmpty()) {
+ IR::LifeTimeInterval *lti = _unhandled.last();
+ if (lti->start() > defPosition(s))
+ break; // we're done
+ Q_ASSERT(!_stackSlotForTemp.contains(lti->temp().index));
+ _stackSlotForTemp[lti->temp().index] = allocateFreeSlot();
+// qDebug() << "\t - activating temp" << lti->temp().index << "on slot" << _stackSlotForTemp[lti->temp().index];
+ _live.append(lti);
+ _unhandled.removeLast();
+ }
+
+ s->accept(this);
+ }
+
+ if (IR::Jump *jump = s->asJump()) {
+ IR::MoveMapping moves;
+ foreach (IR::Stmt *succStmt, jump->target->statements()) {
+ if (IR::Phi *phi = succStmt->asPhi()) {
+ forceActivation(*phi->targetTemp);
+ for (int i = 0, ei = phi->d->incoming.size(); i != ei; ++i) {
+ IR::Expr *e = phi->d->incoming[i];
+ if (IR::Temp *t = e->asTemp()) {
+ forceActivation(*t);
+ }
+ if (jump->target->in[i] == _currentBasicBlock)
+ moves.add(phi->d->incoming[i], phi->targetTemp);
+ }
+ } else {
+ break;
+ }
+ }
+ moves.order();
+ QList<IR::Move *> newMoves = moves.insertMoves(_currentBasicBlock, _function, true);
+ foreach (IR::Move *move, newMoves)
+ move->accept(this);
+ }
+ }
+
+ void forceActivation(const IR::Temp &t)
+ {
+ if (_stackSlotForTemp.contains(t.index))
+ return;
+
+ int i = _unhandled.size() - 1;
+ for (; i >= 0; --i) {
+ IR::LifeTimeInterval *lti = _unhandled[i];
+ if (lti->temp() == t) {
+ _live.append(lti);
+ _unhandled.remove(i);
+ break;
+ }
+ }
+ Q_ASSERT(i >= 0); // check that we always found the entry
+
+ _stackSlotForTemp[t.index] = allocateFreeSlot();
+// qDebug() << "\t - force activating temp" << t.index << "on slot" << _stackSlotForTemp[t.index];
+ }
+
+ virtual void visitPhi(IR::Phi *phi)
+ {
+ Q_UNUSED(phi);
+#if !defined(QT_NO_DEBUG)
+ Q_ASSERT(_stackSlotForTemp.contains(phi->targetTemp->index));
+ Q_ASSERT(_slotIsInUse[_stackSlotForTemp[phi->targetTemp->index]]);
+ foreach (IR::Expr *e, phi->d->incoming) {
+ if (IR::Temp *t = e->asTemp())
+ Q_ASSERT(_stackSlotForTemp.contains(t->index));
+ }
+#endif // defined(QT_NO_DEBUG)
+ }
+};
+
} // IR namespace
} // QV4 namespace