aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2017-05-31 12:05:26 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2017-05-31 12:05:39 +0200
commitdece229a7c2284598c36fb668de766309a6893cf (patch)
tree6e34cfa52416b2f27d2fa0631cf34f8ffd171be4 /src/qml/compiler
parente2520ff76be49c5aa917741cc6a380fe1549e47d (diff)
parentc158ca8be49a75026e83751dfd825c5bdd63189a (diff)
Merge remote-tracking branch 'origin/dev' into wip/scenegraphng
Diffstat (limited to 'src/qml/compiler')
-rw-r--r--src/qml/compiler/compiler.pri3
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp37
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp45
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h2
-rw-r--r--src/qml/compiler/qv4jsir.cpp4
-rw-r--r--src/qml/compiler/qv4jsir_p.h1
-rw-r--r--src/qml/compiler/qv4ssa.cpp336
7 files changed, 256 insertions, 172 deletions
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index 871f28f2d0..31ee917b39 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -41,7 +41,7 @@ SOURCES += \
unix: SOURCES += $$PWD/qv4compilationunitmapper_unix.cpp
else: SOURCES += $$PWD/qv4compilationunitmapper_win.cpp
-qtConfig(private_tests): LIBS_PRIVATE += $$QMAKE_LIBS_DYNLOAD
+qtConfig(private_tests):unix: QMAKE_USE_PRIVATE += libdl
}
qmldevtools_build|qtConfig(qml-interpreter) {
@@ -52,4 +52,3 @@ qmldevtools_build|qtConfig(qml-interpreter) {
$$PWD/qv4instr_moth.cpp \
$$PWD/qv4isel_moth.cpp
}
-
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 218f5675dc..de04116a6b 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -1687,6 +1687,7 @@ enum MetaObjectResolverFlags {
};
static void initMetaObjectResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject);
+static void initScopedEnumResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlType *qmlType, int index);
static QV4::IR::DiscoveredType resolveQmlType(QQmlEnginePrivate *qmlEngine,
const QV4::IR::MemberExpressionResolver *resolver,
@@ -1702,6 +1703,14 @@ static QV4::IR::DiscoveredType resolveQmlType(QQmlEnginePrivate *qmlEngine,
if (ok) {
member->setEnumValue(value);
return QV4::IR::SInt32Type;
+ } else {
+ int index = type->scopedEnumIndex(qmlEngine, *member->name, &ok);
+ if (ok) {
+ auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>();
+ newResolver->owner = resolver->owner;
+ initScopedEnumResolver(newResolver, type, index);
+ return QV4::IR::DiscoveredType(newResolver);
+ }
}
}
@@ -1885,6 +1894,34 @@ static void initMetaObjectResolver(QV4::IR::MemberExpressionResolver *resolver,
resolver->flags = 0;
}
+static QV4::IR::DiscoveredType resolveScopedEnum(QQmlEnginePrivate *qmlEngine,
+ const QV4::IR::MemberExpressionResolver *resolver,
+ QV4::IR::Member *member)
+{
+ if (!member->name->constData()->isUpper())
+ return QV4::IR::VarType;
+
+ QQmlType *type = static_cast<QQmlType*>(resolver->data);
+ int index = resolver->flags;
+
+ bool ok = false;
+ int value = type->scopedEnumValue(qmlEngine, index, *member->name, &ok);
+ if (!ok)
+ return QV4::IR::VarType;
+ member->setEnumValue(value);
+ return QV4::IR::SInt32Type;
+}
+
+static void initScopedEnumResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlType *qmlType, int index)
+{
+ Q_ASSERT(resolver);
+
+ resolver->resolveMember = &resolveScopedEnum;
+ resolver->data = qmlType;
+ resolver->extraData = 0;
+ resolver->flags = index;
+}
+
#endif // V4_BOOTSTRAP
void JSCodeGen::beginFunctionBodyHook()
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index d1d22be0ac..c09fde86f1 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -591,21 +591,32 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
if (!string.constData()->isUpper())
return true;
+ // we support one or two '.' in the enum phrase:
+ // * <TypeName>.<EnumValue>
+ // * <TypeName>.<ScopedEnumName>.<EnumValue>
+
int dot = string.indexOf(QLatin1Char('.'));
if (dot == -1 || dot == string.length()-1)
return true;
- if (string.indexOf(QLatin1Char('.'), dot+1) != -1)
- return true;
+ int dot2 = string.indexOf(QLatin1Char('.'), dot+1);
+ if (dot2 != -1 && dot2 != string.length()-1) {
+ if (!string.at(dot+1).isUpper())
+ return true;
+ if (string.indexOf(QLatin1Char('.'), dot2+1) != -1)
+ return true;
+ }
QHashedStringRef typeName(string.constData(), dot);
const bool isQtObject = (typeName == QLatin1String("Qt"));
- const QStringRef enumValue = string.midRef(dot + 1);
+ const QStringRef scopedEnumName = (dot2 != -1 ? string.midRef(dot + 1, dot2 - dot - 1) : QStringRef());
+ // ### consider supporting scoped enums in Qt namespace
+ const QStringRef enumValue = string.midRef(!isQtObject && dot2 != -1 ? dot2 + 1 : dot + 1);
- if (isIntProp) {
+ if (isIntProp) { // ### C++11 allows enums to be other integral types. Should we support other integral types here?
// Allow enum assignment to ints.
bool ok;
- int enumval = evaluateEnum(typeName.toString(), enumValue.toUtf8(), &ok);
+ int enumval = evaluateEnum(typeName.toString(), scopedEnumName, enumValue, &ok);
if (ok) {
if (!assignEnumToBinding(binding, enumValue, enumval, isQtObject))
return false;
@@ -623,18 +634,25 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
auto *tr = resolvedTypes->value(obj->inheritedTypeNameIndex);
if (type && tr && tr->type == type) {
+ // When these two match, we can short cut the search
QMetaProperty mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex());
+ QMetaEnum menum = mprop.enumerator();
+ QByteArray enumName = enumValue.toUtf8();
+ if (menum.isScoped() && !scopedEnumName.isEmpty() && enumName != scopedEnumName.toUtf8())
+ return true;
- // When these two match, we can short cut the search
if (mprop.isFlagType()) {
- value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
+ value = menum.keysToValue(enumName.constData(), &ok);
} else {
- value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
+ value = menum.keyToValue(enumName.constData(), &ok);
}
} else {
// Otherwise we have to search the whole type
if (type) {
- value = type->enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue), &ok);
+ if (!scopedEnumName.isEmpty())
+ value = type->scopedEnumValue(compiler->enginePrivate(), scopedEnumName, enumValue, &ok);
+ else
+ value = type->enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue), &ok);
} else {
QByteArray enumName = enumValue.toUtf8();
const QMetaObject *metaObject = StaticQtMetaObject::get();
@@ -651,7 +669,7 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
return assignEnumToBinding(binding, enumValue, value, isQtObject);
}
-int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QByteArray &enumValue, bool *ok) const
+int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QStringRef &enumName, const QStringRef &enumValue, bool *ok) const
{
Q_ASSERT_X(ok, "QQmlEnumTypeResolver::evaluateEnum", "ok must not be a null pointer");
*ok = false;
@@ -661,13 +679,16 @@ int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QByteArray &e
imports->resolveType(scope, &type, 0, 0, 0);
if (!type)
return -1;
- return type->enumValue(compiler->enginePrivate(), QHashedCStringRef(enumValue.constData(), enumValue.length()), ok);
+ if (!enumName.isEmpty())
+ return type->scopedEnumValue(compiler->enginePrivate(), enumName, enumValue, ok);
+ return type->enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue.constData(), enumValue.length()), ok);
}
const QMetaObject *mo = StaticQtMetaObject::get();
int i = mo->enumeratorCount();
+ const QByteArray ba = enumValue.toUtf8();
while (i--) {
- int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok);
+ int v = mo->enumerator(i).keyToValue(ba.constData(), ok);
if (*ok)
return v;
}
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
index 79fc073d8b..76aa422fc5 100644
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ b/src/qml/compiler/qqmltypecompiler_p.h
@@ -209,7 +209,7 @@ private:
bool tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache,
const QQmlPropertyData *prop,
QmlIR::Binding *binding);
- int evaluateEnum(const QString &scope, const QByteArray &enumValue, bool *ok) const;
+ int evaluateEnum(const QString &scope, const QStringRef &enumName, const QStringRef &enumValue, bool *ok) const;
const QVector<QmlIR::Object*> &qmlObjects;
diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp
index cc2f9b7cf2..5a58380005 100644
--- a/src/qml/compiler/qv4jsir.cpp
+++ b/src/qml/compiler/qv4jsir.cpp
@@ -444,10 +444,6 @@ void Function::setScheduledBlocks(const QVector<BasicBlock *> &scheduled)
Q_ASSERT(!_allBasicBlocks);
_allBasicBlocks = new QVector<BasicBlock *>(basicBlocks());
_basicBlocks = scheduled;
-}
-
-void Function::renumberBasicBlocks()
-{
for (int i = 0, ei = basicBlockCount(); i != ei; ++i)
basicBlock(i)->changeIndex(i);
}
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index 35cf0fc174..b534eaa54f 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -1348,7 +1348,6 @@ struct Function {
{ return hasDirectEval || !nestedFunctions.isEmpty() || module->debugMode; }
void setScheduledBlocks(const QVector<BasicBlock *> &scheduled);
- void renumberBasicBlocks();
int getNewStatementId() { return _statementCount++; }
int statementCount() const { return _statementCount; }
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index 62e2833089..731c6ad38f 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -3025,14 +3025,19 @@ void splitCriticalEdges(IR::Function *f, DominatorTree &df, StatementWorklist &w
// add newBB to the correct loop group
if (toBB->isGroupStart()) {
- BasicBlock *container;
- for (container = fromBB->containingGroup(); container; container = container->containingGroup())
- if (container == toBB)
- break;
- if (container == toBB) // if we were already inside the toBB loop
+ if (fromBB == toBB) {
+ // special case: the loop header points back to itself (so it's a small loop).
newBB->setContainingGroup(toBB);
- else
- newBB->setContainingGroup(toBB->containingGroup());
+ } else {
+ BasicBlock *container;
+ for (container = fromBB->containingGroup(); container; container = container->containingGroup())
+ if (container == toBB)
+ break;
+ if (container == toBB) // if we were already inside the toBB loop
+ newBB->setContainingGroup(toBB);
+ else
+ newBB->setContainingGroup(toBB->containingGroup());
+ }
} else {
newBB->setContainingGroup(toBB->containingGroup());
}
@@ -3063,7 +3068,7 @@ void splitCriticalEdges(IR::Function *f, DominatorTree &df, StatementWorklist &w
bool toNeedsNewIdom = true;
for (BasicBlock *bb : toBB->in) {
- if (bb != newBB && !df.dominates(toBB, bb)) {
+ if (bb != newBB && bb != toBB && !df.dominates(toBB, bb)) {
toNeedsNewIdom = false;
break;
}
@@ -3174,7 +3179,7 @@ public:
backedges.clear();
for (BasicBlock *in : bb->in)
- if (dt.dominates(bb, in))
+ if (bb == in || dt.dominates(bb, in))
backedges.push_back(in);
if (!backedges.empty()) {
@@ -3191,6 +3196,7 @@ public:
if (!DebugLoopDetection)
return;
+ qDebug() << "Found" << loopInfos.size() << "loops";
for (const LoopInfo *info : loopInfos) {
qDebug() << "Loop header:" << info->loopHeader->index()
<< "for loop" << quint64(info);
@@ -3224,6 +3230,9 @@ private:
void subLoop(BasicBlock *loopHead, const std::vector<BasicBlock *> &backedges)
{
loopHead->markAsGroupStart();
+ LoopInfo *info = new LoopInfo;
+ info->loopHeader = loopHead;
+ loopInfos.append(info);
std::vector<BasicBlock *> worklist;
worklist.reserve(backedges.size() + 8);
@@ -3293,10 +3302,8 @@ private:
return info;
}
- LoopInfo *info = new LoopInfo;
- info->loopHeader = loopHeader;
- loopInfos.append(info);
- return info;
+ Q_UNREACHABLE();
+ return nullptr;
}
};
@@ -3326,6 +3333,8 @@ private:
// the same reason.
class BlockScheduler
{
+ enum { DebugBlockScheduler = 0 };
+
IR::Function *function;
const DominatorTree &dominatorTree;
@@ -3441,6 +3450,14 @@ class BlockScheduler
Q_UNREACHABLE();
}
+ void dumpLoopStartsEnds() const
+ {
+ qDebug() << "Found" << loopsStartEnd.size() << "loops:";
+ for (auto key : loopsStartEnd.keys())
+ qDebug("Loop starting at L%d ends at L%d.", key->index(),
+ loopsStartEnd.value(key)->index());
+ }
+
public:
BlockScheduler(IR::Function *function, const DominatorTree &dominatorTree)
: function(function)
@@ -3452,11 +3469,15 @@ public:
QHash<BasicBlock *, BasicBlock *> go()
{
showMeTheCode(function, "Before block scheduling");
+ if (DebugBlockScheduler)
+ dominatorTree.dumpImmediateDominators();
+
schedule(function->basicBlock(0));
Q_ASSERT(function->liveBasicBlocksCount() == sequence.size());
function->setScheduledBlocks(sequence);
- function->renumberBasicBlocks();
+ if (DebugBlockScheduler)
+ dumpLoopStartsEnds();
return loopsStartEnd;
}
};
@@ -4592,7 +4613,6 @@ void removeUnreachleBlocks(IR::Function *function)
if (!bb->isRemoved())
newSchedule.append(bb);
function->setScheduledBlocks(newSchedule);
- function->renumberBasicBlocks();
}
class ConvertArgLocals
@@ -4766,6 +4786,137 @@ private:
IR::Stmt *clonedStmt;
};
+static void verifyCFG(IR::Function *function)
+{
+ if (!DoVerification)
+ return;
+
+ for (BasicBlock *bb : function->basicBlocks()) {
+ if (bb->isRemoved()) {
+ Q_ASSERT(bb->in.isEmpty());
+ Q_ASSERT(bb->out.isEmpty());
+ continue;
+ }
+
+ Q_ASSERT(function->basicBlock(bb->index()) == bb);
+
+ // Check the terminators:
+ Stmt *terminator = bb->terminator();
+ if (terminator == nullptr) {
+ Stmt *last = bb->statements().last();
+ Call *call = last->asExp()->expr->asCall();
+ Name *baseName = call->base->asName();
+ Q_ASSERT(baseName->builtin == Name::builtin_rethrow);
+ Q_UNUSED(baseName);
+ } else if (Jump *jump = terminator->asJump()) {
+ Q_UNUSED(jump);
+ Q_ASSERT(jump->target);
+ Q_ASSERT(!jump->target->isRemoved());
+ Q_ASSERT(bb->out.size() == 1);
+ Q_ASSERT(bb->out.first() == jump->target);
+ } else if (CJump *cjump = terminator->asCJump()) {
+ Q_UNUSED(cjump);
+ Q_ASSERT(bb->out.size() == 2);
+ Q_ASSERT(cjump->iftrue);
+ Q_ASSERT(!cjump->iftrue->isRemoved());
+ Q_ASSERT(cjump->iftrue == bb->out[0]);
+ Q_ASSERT(cjump->iffalse);
+ Q_ASSERT(!cjump->iffalse->isRemoved());
+ Q_ASSERT(cjump->iffalse == bb->out[1]);
+ } else if (terminator->asRet()) {
+ Q_ASSERT(bb->out.size() == 0);
+ } else {
+ Q_UNREACHABLE();
+ }
+
+ // Check the outgoing edges:
+ for (BasicBlock *out : bb->out) {
+ Q_UNUSED(out);
+ Q_ASSERT(!out->isRemoved());
+ Q_ASSERT(out->in.contains(bb));
+ }
+
+ // Check the incoming edges:
+ for (BasicBlock *in : bb->in) {
+ Q_UNUSED(in);
+ Q_ASSERT(!in->isRemoved());
+ Q_ASSERT(in->out.contains(bb));
+ }
+ }
+}
+
+static void verifyImmediateDominators(const DominatorTree &dt, IR::Function *function)
+{
+ if (!DoVerification)
+ return;
+
+ cfg2dot(function);
+ dt.dumpImmediateDominators();
+ DominatorTree referenceTree(function);
+
+ for (BasicBlock *bb : function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+
+ BasicBlock *idom = dt.immediateDominator(bb);
+ BasicBlock *referenceIdom = referenceTree.immediateDominator(bb);
+ Q_UNUSED(idom);
+ Q_UNUSED(referenceIdom);
+ Q_ASSERT(idom == referenceIdom);
+ }
+}
+
+static void verifyNoPointerSharing(IR::Function *function)
+{
+ if (!DoVerification)
+ return;
+
+ class {
+ public:
+ void operator()(IR::Function *f)
+ {
+ for (BasicBlock *bb : f->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+
+ for (Stmt *s : bb->statements()) {
+ visit(s);
+ }
+ }
+ }
+
+ private:
+ void visit(Stmt *s)
+ {
+ check(s);
+ STMT_VISIT_ALL_KINDS(s);
+ }
+
+ void visit(Expr *e)
+ {
+ check(e);
+ EXPR_VISIT_ALL_KINDS(e);
+ }
+
+ private:
+ void check(Stmt *s)
+ {
+ Q_ASSERT(!stmts.contains(s));
+ stmts.insert(s);
+ }
+
+ void check(Expr *e)
+ {
+ Q_ASSERT(!exprs.contains(e));
+ exprs.insert(e);
+ }
+
+ QSet<Stmt *> stmts;
+ QSet<Expr *> exprs;
+ } V;
+ V(function);
+}
+
// Loop-peeling is done by unfolding the loop once. The "original" loop basic blocks stay where they
// are, and a copy of the loop is placed after it. Special care is taken while copying the loop body:
// by having the copies of the basic-blocks point to the same nodes as the "original" basic blocks,
@@ -4826,12 +4977,14 @@ private:
void peelLoop(LoopDetection::LoopInfo *loop)
{
+ IR::Function *f = loop->loopHeader->function;
CloneBasicBlock clone;
LoopDetection::LoopInfo unpeeled(*loop);
unpeeled.loopHeader = clone(unpeeled.loopHeader);
unpeeled.loopHeader->setContainingGroup(loop->loopHeader->containingGroup());
unpeeled.loopHeader->markAsGroupStart(true);
+ f->addBasicBlock(unpeeled.loopHeader);
for (int i = 0, ei = unpeeled.loopBody.size(); i != ei; ++i) {
BasicBlock *&bodyBlock = unpeeled.loopBody[i];
bodyBlock = clone(bodyBlock);
@@ -4845,8 +4998,8 @@ private:
BasicBlock::IncomingEdges inCopy = loop->loopHeader->in;
for (BasicBlock *in : inCopy) {
- if (unpeeled.loopHeader != in // this can happen for really tight loops (where there are no body blocks). This is a back-edge in that case.
- && !unpeeled.loopBody.contains(in) // if the edge is not coming from within the copied set, leave it alone
+ if (loop->loopHeader != in // this can happen for really tight loops (where there are no body blocks). This is a back-edge in that case.
+ && unpeeled.loopHeader != in && !unpeeled.loopBody.contains(in) // if the edge is not coming from within the copied set, leave it alone
&& !dt.dominates(loop->loopHeader, in)) // an edge coming from within the loop (so a back-edge): this is handled when rewiring all outgoing edges
continue;
@@ -4876,9 +5029,7 @@ private:
loopExits.reserve(8);
loopExits.append(unpeeled.loopHeader);
- IR::Function *f = unpeeled.loopHeader->function;
rewire(unpeeled.loopHeader, loop->loopBody, unpeeled.loopBody, loopExits);
- f->addBasicBlock(unpeeled.loopHeader);
for (int i = 0, ei = unpeeled.loopBody.size(); i != ei; ++i) {
BasicBlock *bodyBlock = unpeeled.loopBody.at(i);
rewire(bodyBlock, loop->loopBody, unpeeled.loopBody, loopExits);
@@ -4891,6 +5042,9 @@ private:
for (BasicBlock *bb : qAsConst(loop->loopBody))
bb->setContainingGroup(loop->loopHeader->containingGroup());
+ // Set the immediate dominator of the new loop header to the old one. The real immediate
+ // dominator will be calculated later.
+ dt.setImmediateDominator(unpeeled.loopHeader, loop->loopHeader);
// calculate the idoms in a separate loop, because addBasicBlock in the previous loop will
// set the block index, which in turn is used by the dominator tree.
for (int i = 0, ei = unpeeled.loopBody.size(); i != ei; ++i) {
@@ -4909,141 +5063,13 @@ private:
for (BasicBlock *bb : qAsConst(loopExits))
dt.collectSiblings(bb, siblings);
+ siblings.insert(unpeeled.loopHeader);
dt.recalculateIDoms(siblings, loop->loopHeader);
+ dt.dumpImmediateDominators();
+ verifyImmediateDominators(dt, f);
}
};
-static void verifyCFG(IR::Function *function)
-{
- if (!DoVerification)
- return;
-
- for (BasicBlock *bb : function->basicBlocks()) {
- if (bb->isRemoved()) {
- Q_ASSERT(bb->in.isEmpty());
- Q_ASSERT(bb->out.isEmpty());
- continue;
- }
-
- Q_ASSERT(function->basicBlock(bb->index()) == bb);
-
- // Check the terminators:
- Stmt *terminator = bb->terminator();
- if (terminator == nullptr) {
- Stmt *last = bb->statements().last();
- Call *call = last->asExp()->expr->asCall();
- Name *baseName = call->base->asName();
- Q_ASSERT(baseName->builtin == Name::builtin_rethrow);
- Q_UNUSED(baseName);
- } else if (Jump *jump = terminator->asJump()) {
- Q_UNUSED(jump);
- Q_ASSERT(jump->target);
- Q_ASSERT(!jump->target->isRemoved());
- Q_ASSERT(bb->out.size() == 1);
- Q_ASSERT(bb->out.first() == jump->target);
- } else if (CJump *cjump = terminator->asCJump()) {
- Q_UNUSED(cjump);
- Q_ASSERT(bb->out.size() == 2);
- Q_ASSERT(cjump->iftrue);
- Q_ASSERT(!cjump->iftrue->isRemoved());
- Q_ASSERT(cjump->iftrue == bb->out[0]);
- Q_ASSERT(cjump->iffalse);
- Q_ASSERT(!cjump->iffalse->isRemoved());
- Q_ASSERT(cjump->iffalse == bb->out[1]);
- } else if (terminator->asRet()) {
- Q_ASSERT(bb->out.size() == 0);
- } else {
- Q_UNREACHABLE();
- }
-
- // Check the outgoing edges:
- for (BasicBlock *out : bb->out) {
- Q_UNUSED(out);
- Q_ASSERT(!out->isRemoved());
- Q_ASSERT(out->in.contains(bb));
- }
-
- // Check the incoming edges:
- for (BasicBlock *in : bb->in) {
- Q_UNUSED(in);
- Q_ASSERT(!in->isRemoved());
- Q_ASSERT(in->out.contains(bb));
- }
- }
-}
-
-static void verifyImmediateDominators(const DominatorTree &dt, IR::Function *function)
-{
- if (!DoVerification)
- return;
-
- cfg2dot(function);
- dt.dumpImmediateDominators();
- DominatorTree referenceTree(function);
-
- for (BasicBlock *bb : function->basicBlocks()) {
- if (bb->isRemoved())
- continue;
-
- BasicBlock *idom = dt.immediateDominator(bb);
- BasicBlock *referenceIdom = referenceTree.immediateDominator(bb);
- Q_UNUSED(idom);
- Q_UNUSED(referenceIdom);
- Q_ASSERT(idom == referenceIdom);
- }
-}
-
-static void verifyNoPointerSharing(IR::Function *function)
-{
- if (!DoVerification)
- return;
-
- class {
- public:
- void operator()(IR::Function *f)
- {
- for (BasicBlock *bb : f->basicBlocks()) {
- if (bb->isRemoved())
- continue;
-
- for (Stmt *s : bb->statements()) {
- visit(s);
- }
- }
- }
-
- private:
- void visit(Stmt *s)
- {
- check(s);
- STMT_VISIT_ALL_KINDS(s);
- }
-
- void visit(Expr *e)
- {
- check(e);
- EXPR_VISIT_ALL_KINDS(e);
- }
-
- private:
- void check(Stmt *s)
- {
- Q_ASSERT(!stmts.contains(s));
- stmts.insert(s);
- }
-
- void check(Expr *e)
- {
- Q_ASSERT(!exprs.contains(e));
- exprs.insert(e);
- }
-
- QSet<Stmt *> stmts;
- QSet<Expr *> exprs;
- } V;
- V(function);
-}
-
class RemoveLineNumbers: private SideEffectsChecker
{
public:
@@ -5452,6 +5478,9 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine, bool doTypeInference, bool pee
verifyNoPointerSharing(function);
mergeBasicBlocks(function, &defUses, &df);
+ verifyImmediateDominators(df, function);
+ verifyCFG(function);
+
// Basic-block cycles that are unreachable (i.e. for loops in a then-part where the
// condition is calculated to be always false) are not yet removed. This will choke the
// block scheduling, so remove those now.
@@ -5459,10 +5488,13 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine, bool doTypeInference, bool pee
cleanupBasicBlocks(function);
// showMeTheCode(function);
+ verifyImmediateDominators(df, function);
+ verifyCFG(function);
+
// Transform the CFG into edge-split SSA.
-// qout << "Starting edge splitting..." << endl;
+ showMeTheCode(function, "Before edge splitting");
splitCriticalEdges(function, df, worklist, defUses);
-// showMeTheCode(function);
+ showMeTheCode(function, "After edge splitting");
verifyImmediateDominators(df, function);
verifyCFG(function);