aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler
diff options
context:
space:
mode:
authorErik Verbruggen <erik.verbruggen@me.com>2013-10-01 13:12:52 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-10-03 07:06:42 +0200
commitf4b38392898dfac6be8fa6a7874138a5eb49a32c (patch)
tree3c6455dae761a2755f17ccedb7d10a95b799e562 /src/qml/compiler
parentf9305f9ffaf8dd443369a156f7f7650de6372265 (diff)
V4 IR: fix dead-code elimination.
Change-Id: If00a108fb107d331478dd36ad7feae4c4521c2ae Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/qml/compiler')
-rw-r--r--src/qml/compiler/qv4ssa.cpp202
1 files changed, 109 insertions, 93 deletions
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index deadf471ea..04628743c7 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -1049,130 +1049,152 @@ void cleanupPhis(DefUsesCalculator &defUses)
}
}
-class DeadCodeElimination: public ExprVisitor {
- const bool variablesCanEscape;
+class EliminateDeadCode: public ExprVisitor {
DefUsesCalculator &_defUses;
- QVector<Temp> _worklist;
+ QVector<Stmt *> _worklist;
+ const bool _variablesCanEscape;
+ bool _sideEffect;
+ QVector<Temp *> _collectedTemps;
public:
- DeadCodeElimination(DefUsesCalculator &defUses, Function *function)
- : variablesCanEscape(function->variablesCanEscape())
- , _defUses(defUses)
+ EliminateDeadCode(DefUsesCalculator &defUses, QVector<Stmt *> worklist, bool variablesCanEscape)
+ : _defUses(defUses)
+ , _worklist(worklist)
+ , _variablesCanEscape(variablesCanEscape)
{
- _worklist = QVector<Temp>::fromList(_defUses.defs());
+ _collectedTemps.reserve(8);
}
- void run() {
- while (!_worklist.isEmpty()) {
- const Temp v = _worklist.first();
- _worklist.removeFirst();
-
- if (_defUses.useCount(v) == 0) {
-#if defined(SHOW_SSA)
- qout<<"- ";v.dump(qout);qout<<" has no uses..."<<endl;
-#endif
- Stmt *s = _defUses.defStmt(v);
- if (!s) {
- _defUses.removeDef(v);
- } else if (!hasSideEffect(s)) {
-#if defined(SHOW_SSA)
- qout<<"-- defining stmt for ";
- v.dump(qout);
- qout<<" has no side effect: ";
- s->dump(qout);
- qout<<endl;
-#endif
- QVector<Stmt *> &stmts = _defUses.defStmtBlock(v)->statements;
- int idx = stmts.indexOf(s);
- if (idx != -1)
- stmts.remove(idx);
- foreach (const Temp &usedVar, _defUses.usedVars(s)) {
- _defUses.removeUse(s, usedVar);
- _worklist.append(usedVar);
- }
- _defUses.removeDef(v);
- }
+ void run(Expr *&expr, Stmt *stmt) {
+ if (!checkForSideEffects(expr)) {
+ expr = 0;
+ foreach (Temp *t, _collectedTemps) {
+ _defUses.removeUse(stmt, *t);
+ _worklist += _defUses.defStmt(*t);
}
}
}
private:
- bool _sideEffect;
+ bool checkForSideEffects(Expr *expr)
+ {
+ bool sideEffect = false;
+ qSwap(_sideEffect, sideEffect);
+ expr->accept(this);
+ qSwap(_sideEffect, sideEffect);
+ return sideEffect;
+ }
- bool hasSideEffect(Stmt *s) {
- // TODO: check if this can be moved to IR building.
- _sideEffect = false;
- if (Move *move = s->asMove()) {
- if (Temp *t = move->target->asTemp()) {
- switch (t->kind) {
- case Temp::Formal:
- case Temp::ScopedFormal:
- case Temp::ScopedLocal:
- return true;
- case Temp::Local:
- if (variablesCanEscape)
- return true;
- else
- break;
- case Temp::VirtualRegister:
- break;
- default:
- Q_ASSERT(!"Invalid temp kind!");
- return true;
- }
- move->source->accept(this);
- } else {
- return true;
- }
+ void markAsSideEffect()
+ {
+ _sideEffect = true;
+ _collectedTemps.clear();
+ }
+
+ bool isCollectable(Temp *t) const
+ {
+ switch (t->kind) {
+ case Temp::Formal:
+ case Temp::ScopedFormal:
+ case Temp::ScopedLocal:
+ return false;
+ case Temp::Local:
+ return !_variablesCanEscape;
+ default:
+ return true;
}
- return _sideEffect;
}
protected:
virtual void visitConst(Const *) {}
virtual void visitString(String *) {}
virtual void visitRegExp(RegExp *) {}
- virtual void visitName(Name *e) {
+
+ virtual void visitName(Name *e)
+ {
// TODO: maybe we can distinguish between built-ins of which we know that they do not have
// a side-effect.
if (e->builtin == Name::builtin_invalid || (e->id && *e->id != QStringLiteral("this")))
- _sideEffect = true;
+ markAsSideEffect();
}
- virtual void visitTemp(Temp *e) {
+
+ virtual void visitTemp(Temp *e)
+ {
+ if (isCollectable(e))
+ _collectedTemps.append(e);
}
- virtual void visitClosure(Closure *) {}
+
+ virtual void visitClosure(Closure *)
+ {
+ markAsSideEffect();
+ }
+
virtual void visitConvert(Convert *e) {
- // we do not have type information yet, so:
- _sideEffect = true;
+ e->expr->accept(this);
+
+ switch (e->expr->type) {
+ case StringType:
+ case VarType:
+ markAsSideEffect();
+ break;
+ default:
+ break;
+ }
}
virtual void visitUnop(Unop *e) {
+ e->expr->accept(this);
+
switch (e->op) {
+ case OpUPlus:
+ case OpUMinus:
+ case OpNot:
case OpIncrement:
case OpDecrement:
- _sideEffect = true;
+ if (e->expr->type == VarType || e->expr->type == StringType)
+ markAsSideEffect();
break;
default:
break;
}
+ }
- if (!_sideEffect) e->expr->accept(this);
+ virtual void visitBinop(Binop *e) {
+ // TODO: prune parts that don't have a side-effect. For example, in:
+ // function f(x) { +x+1; return 0; }
+ // we can prune the binop and leave the unop/conversion.
+ _sideEffect = checkForSideEffects(e->left);
+ _sideEffect |= checkForSideEffects(e->right);
+
+ if (e->left->type == VarType || e->left->type == StringType
+ || e->right->type == VarType || e->right->type == StringType)
+ markAsSideEffect();
}
- virtual void visitBinop(Binop *e) { if (!_sideEffect) e->left->accept(this); if (!_sideEffect) e->right->accept(this); }
+
virtual void visitSubscript(Subscript *e) {
- // TODO: see if we can have subscript accesses without side effect
- _sideEffect = true;
+ e->base->accept(this);
+ e->index->accept(this);
+ markAsSideEffect();
}
+
virtual void visitMember(Member *e) {
- // TODO: see if we can have member accesses without side effect
- _sideEffect = true;
+ e->base->accept(this);
+ markAsSideEffect();
}
+
virtual void visitCall(Call *e) {
- _sideEffect = true; // TODO: there are built-in functions that have no side effect.
+ e->base->accept(this);
+ for (ExprList *args = e->args; args; args = args->next)
+ args->expr->accept(this);
+ markAsSideEffect(); // TODO: there are built-in functions that have no side effect.
}
+
virtual void visitNew(New *e) {
- _sideEffect = true; // TODO: there are built-in types that have no side effect.
+ e->base->accept(this);
+ for (ExprList *args = e->args; args; args = args->next)
+ args->expr->accept(this);
+ markAsSideEffect(); // TODO: there are built-in types that have no side effect.
}
};
@@ -2336,6 +2358,14 @@ void optimizeSSA(Function *function, DefUsesCalculator &defUses)
}
if (Temp *targetTemp = unescapableTemp(m->target, variablesCanEscape)) {
+ // dead code elimination:
+ if (defUses.useCount(*targetTemp) == 0) {
+ EliminateDeadCode(defUses, W, variablesCanEscape).run(m->source, s);
+ if (!m->source)
+ *ref[s] = 0;
+ continue;
+ }
+
// constant propagation:
if (Const *sourceConst = m->source->asConst()) {
if (sourceConst->type & NumberType || sourceConst->type == BoolType) {
@@ -2348,16 +2378,6 @@ void optimizeSSA(Function *function, DefUsesCalculator &defUses)
continue;
}
-#if defined(PROPAGATE_THIS)
- if (Name *n = m->source->asName()) {
- qout<<"propagating constant from ";s->dump(qout);qout<<" info:"<<endl;
- W += replaceUses(t, n);
- defUses.removeDef(t->index);
- *ref[s] = 0;
- continue;
- }
-#endif
-
// copy propagation:
if (Temp *sourceTemp = unescapableTemp(m->source, variablesCanEscape)) {
QVector<Stmt *> newT2Uses = replaceUses(targetTemp, sourceTemp);
@@ -2862,10 +2882,6 @@ void Optimizer::run()
cleanupPhis(defUses);
// showMeTheCode(function);
-// qout << "Starting dead-code elimination..." << endl;
- DeadCodeElimination(defUses, function).run();
-// showMeTheCode(function);
-
// qout << "Running type inference..." << endl;
TypeInference(defUses).run(function);
// showMeTheCode(function);