From: Erik Verbruggen Date: Tue, 1 Oct 2013 11:12:52 +0000 (+0200) Subject: V4 IR: fix dead-code elimination. X-Git-Tag: upstream/5.2.1~311 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f4b38392898dfac6be8fa6a7874138a5eb49a32c;p=platform%2Fupstream%2Fqtdeclarative.git V4 IR: fix dead-code elimination. Change-Id: If00a108fb107d331478dd36ad7feae4c4521c2ae Reviewed-by: Lars Knoll --- diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index deadf47..0462874 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 _worklist; + QVector _worklist; + const bool _variablesCanEscape; + bool _sideEffect; + QVector _collectedTemps; public: - DeadCodeElimination(DefUsesCalculator &defUses, Function *function) - : variablesCanEscape(function->variablesCanEscape()) - , _defUses(defUses) + EliminateDeadCode(DefUsesCalculator &defUses, QVector worklist, bool variablesCanEscape) + : _defUses(defUses) + , _worklist(worklist) + , _variablesCanEscape(variablesCanEscape) { - _worklist = QVector::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..."<dump(qout); - qout< &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:"<index); - *ref[s] = 0; - continue; - } -#endif - // copy propagation: if (Temp *sourceTemp = unescapableTemp(m->source, variablesCanEscape)) { QVector 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);