aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler
diff options
context:
space:
mode:
authorErik Verbruggen <erik.verbruggen@me.com>2013-09-27 18:44:09 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-30 15:05:01 +0200
commit2b6dfcf23b8e9d672dff0a083ed4e7adc28115eb (patch)
tree340a4df1e473cfe20158ea0cd0b77911c1f86946 /src/qml/compiler
parent7c3f891c454971ed0150e66c2261e6e5c36664a3 (diff)
V4 IR: do type inference/propagation before optimization.
This gives slightly better results for inplace increment/decrement, where the operand has to be converted to a number. When that operand is known to be a number, this conversion can be removed. By doing the optimizations after typing, these conversions will not only turn into assignments, but they will be propagated through the IR. That saves a copy/move, which, in turn, will lighten the work for the register allocator and the instruction selection. Change-Id: If76575a71fbcb2d810b94060e61b4364bdaaa065 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/qml/compiler')
-rw-r--r--src/qml/compiler/qv4ssa.cpp130
1 files changed, 90 insertions, 40 deletions
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index c79f19ecf7..a058ed51da 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -795,6 +795,15 @@ void convertToSSA(Function *function, const DominatorTree &df)
VariableRenamer(function).run();
}
+struct UntypedTemp {
+ Temp temp;
+ UntypedTemp(const Temp &t): temp(t) {}
+};
+inline uint qHash(const UntypedTemp &t, uint seed = 0) Q_DECL_NOTHROW
+{ return t.temp.index ^ (t.temp.kind | (t.temp.scope << 3)) ^ seed; }
+inline bool operator==(const UntypedTemp &t1, const UntypedTemp &t2) Q_DECL_NOTHROW
+{ return t1.temp.index == t2.temp.index && t1.temp.scope == t2.temp.scope && t1.temp.kind == t2.temp.kind; }
+
class DefUsesCalculator: public StmtVisitor, public ExprVisitor {
public:
struct DefUse {
@@ -809,7 +818,7 @@ public:
private:
const bool _variablesCanEscape;
- QHash<Temp, DefUse> _defUses;
+ QHash<UntypedTemp, DefUse> _defUses;
QHash<Stmt *, QList<Temp> > _usesPerStatement;
BasicBlock *_block;
@@ -863,7 +872,7 @@ public:
}
}
- QMutableHashIterator<Temp, DefUse> it(_defUses);
+ QMutableHashIterator<UntypedTemp, DefUse> it(_defUses);
while (it.hasNext()) {
it.next();
if (!it.value().defStmt)
@@ -871,8 +880,19 @@ public:
}
}
+ void addTemp(Temp *newTemp, Stmt *defStmt, BasicBlock *defBlock)
+ {
+ DefUse &defUse = _defUses[*newTemp];
+ defUse.defStmt = defStmt;
+ defUse.blockOfStatement = defBlock;
+ }
+
QList<Temp> defs() const {
- return _defUses.keys();
+ QList<Temp> res;
+ res.reserve(_defUses.size());
+ foreach (const UntypedTemp &t, _defUses.keys())
+ res.append(t.temp);
+ return res;
}
void removeDef(const Temp &var) {
@@ -882,6 +902,9 @@ public:
void addUses(const Temp &variable, const QList<Stmt *> &newUses)
{ _defUses[variable].uses.append(newUses); }
+ void addUse(const Temp &variable, Stmt * newUse)
+ { _defUses[variable].uses.append(newUse); }
+
int useCount(const Temp &variable) const
{ return _defUses[variable].uses.size(); }
@@ -919,9 +942,9 @@ public:
void dump() const
{
- foreach (const Temp &var, _defUses.keys()) {
+ foreach (const UntypedTemp &var, _defUses.keys()) {
const DefUse &du = _defUses[var];
- var.dump(qout);
+ var.temp.dump(qout);
qout<<" -> defined in block "<<du.blockOfStatement->index<<", statement: ";
du.defStmt->dump(qout);
qout<<endl<<" uses:"<<endl;
@@ -1511,7 +1534,30 @@ protected:
}
};
+void convertConst(Const *c, Type targetType)
+{
+ switch (targetType) {
+ case DoubleType:
+ break;
+ case SInt32Type:
+ c->value = QV4::Primitive::toInt32(c->value);
+ break;
+ case UInt32Type:
+ c->value = QV4::Primitive::toUInt32(c->value);
+ break;
+ case BoolType:
+ c->value = !(c->value == 0 || std::isnan(c->value));
+ break;
+ default:
+ Q_UNIMPLEMENTED();
+ Q_ASSERT(!"Unimplemented!");
+ break;
+ }
+ c->type = targetType;
+}
+
class TypePropagation: public StmtVisitor, public ExprVisitor {
+ DefUsesCalculator &_defUses;
Type _ty;
Function *_f;
@@ -1562,7 +1608,7 @@ class TypePropagation: public StmtVisitor, public ExprVisitor {
}
public:
- TypePropagation() : _ty(UnknownType) {}
+ TypePropagation(DefUsesCalculator &defUses) : _defUses(defUses), _ty(UnknownType) {}
void run(Function *f) {
_f = f;
@@ -1578,37 +1624,23 @@ public:
if (conversion.stmt->asMove() && conversion.stmt->asMove()->source->asTemp()) {
*conversion.expr = bb->CONVERT(*conversion.expr, conversion.targetType);
} else if (Const *c = (*conversion.expr)->asConst()) {
- switch (conversion.targetType) {
- case DoubleType:
- break;
- case SInt32Type:
- c->value = QV4::Primitive::toInt32(c->value);
- break;
- case UInt32Type:
- c->value = QV4::Primitive::toUInt32(c->value);
- break;
- case BoolType:
- c->value = !(c->value == 0 || std::isnan(c->value));
- break;
- default:
- Q_UNIMPLEMENTED();
- Q_ASSERT(!"Unimplemented!");
- break;
- }
- c->type = conversion.targetType;
- } else {
+ convertConst(c, conversion.targetType);
+ } else if (Temp *t = (*conversion.expr)->asTemp()) {
Temp *target = bb->TEMP(bb->newTemp());
target->type = conversion.targetType;
- Expr *convert = bb->CONVERT(*conversion.expr, conversion.targetType);
+ Expr *convert = bb->CONVERT(t, conversion.targetType);
Move *convCall = f->New<Move>();
convCall->init(target, convert);
+ _defUses.addTemp(target, convCall, bb);
+ _defUses.addUse(*t, convCall);
Temp *source = bb->TEMP(target->index);
source->type = conversion.targetType;
- *conversion.expr = source;
+ _defUses.removeUse(conversion.stmt, *t);
+ _defUses.addUse(*source, conversion.stmt);
if (Phi *phi = conversion.stmt->asPhi()) {
- int idx = phi->d->incoming.indexOf(*conversion.expr);
+ int idx = phi->d->incoming.indexOf(t);
Q_ASSERT(idx != -1);
QVector<Stmt *> &stmts = bb->in[idx]->statements;
stmts.insert(stmts.size() - 1, convCall);
@@ -1616,6 +1648,10 @@ public:
int idx = bb->statements.indexOf(conversion.stmt);
bb->statements.insert(idx, convCall);
}
+
+ *conversion.expr = source;
+ } else {
+ Q_UNREACHABLE();
}
}
}
@@ -1999,6 +2035,7 @@ public:
qSwap(_replacement, replacement);
QList<Stmt *> uses = _defUses.uses(*_toReplace);
+// qout << " " << uses.size() << " uses:"<<endl;
QVector<Stmt *> result;
result.reserve(uses.size());
foreach (Stmt *use, uses) {
@@ -2275,6 +2312,21 @@ void optimizeSSA(Function *function, DefUsesCalculator &defUses)
continue;
}
} else if (Move *m = s->asMove()) {
+ if (Convert *convert = m->source->asConvert()) {
+ if (Const *sourceConst = convert->expr->asConst()) {
+ convertConst(sourceConst, convert->type);
+ m->source = sourceConst;
+ W += m;
+ continue;
+ } else if (Temp *sourceTemp = convert->expr->asTemp()) {
+ if (sourceTemp->type == convert->type) {
+ m->source = sourceTemp;
+ W += m;
+ continue;
+ }
+ }
+ }
+
if (Temp *targetTemp = unescapableTemp(m->target, variablesCanEscape)) {
// constant propagation:
if (Const *sourceConst = m->source->asConst()) {
@@ -2333,12 +2385,6 @@ void optimizeSSA(Function *function, DefUsesCalculator &defUses)
}
constOperand->value = -constOperand->value;
- if (canConvertToSignedInteger(constOperand->value))
- constOperand->type = SInt32Type;
- else if (canConvertToUnsignedInteger(constOperand->value))
- constOperand->type = UInt32Type;
- else
- constOperand->type = DoubleType;
doneSomething = true;
break;
case OpUPlus:
@@ -2812,18 +2858,22 @@ void Optimizer::run()
DeadCodeElimination(defUses, function).run();
// showMeTheCode(function);
+// qout << "Running type inference..." << endl;
+ TypeInference(defUses).run(function);
+// showMeTheCode(function);
+
+// qout << "Doing type propagation..." << endl;
+ TypePropagation(defUses).run(function);
+// showMeTheCode(function);
+
if (doOpt) {
// qout << "Running SSA optimization..." << endl;
optimizeSSA(function, defUses);
// showMeTheCode(function);
}
-// qout << "Running type inference..." << endl;
- TypeInference(defUses).run(function);
-// showMeTheCode(function);
-
-// qout << "Doing type propagation..." << endl;
- TypePropagation().run(function);
+// qout << "Doing block merging..." << endl;
+// mergeBasicBlocks(function);
// showMeTheCode(function);
// qout << "Doing block scheduling..." << endl;