aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorErik Verbruggen <erik.verbruggen@digia.com>2014-03-21 10:56:52 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-04-15 15:31:23 +0200
commit377aeea46cb90f84e5a0e867e5f68cd9f89f56b1 (patch)
tree6e5990fe8b64024c9e943693897d58877f9e5888 /src
parent63f757faea7008e478e0a1edea4f0ae79aaba5f7 (diff)
V4 IR: clean up basic-block management and statement access.
BasicBlocks have an index property which points to the index of that basic block in the container array in Function. This property can be used to store calculated information about basic blocks in a vector, where the vector index corresponds to the basic block index. This is a lot cheaper than storing any information in a QHash<BasicBlock *, ....>. However, this numbering requires that no re-ordering or deletion of blocks happens. This change cleans up all that handling which was scattered over a number of places. Change-Id: I337abd39c030b9d30c82b7bbcf2ba89e50a08e63 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp10
-rw-r--r--src/qml/compiler/qv4codegen.cpp10
-rw-r--r--src/qml/compiler/qv4codegen_p.h2
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp11
-rw-r--r--src/qml/compiler/qv4isel_util_p.h6
-rw-r--r--src/qml/compiler/qv4jsir.cpp169
-rw-r--r--src/qml/compiler/qv4jsir_p.h302
-rw-r--r--src/qml/compiler/qv4ssa.cpp513
-rw-r--r--src/qml/compiler/qv4ssa_p.h7
-rw-r--r--src/qml/jit/qv4isel_masm.cpp10
-rw-r--r--src/qml/jit/qv4regalloc.cpp31
11 files changed, 662 insertions, 409 deletions
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index b5ddf3bc59..9260aba98c 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -2693,11 +2693,11 @@ bool QQmlJavaScriptBindingExpressionSimplificationPass::simplifyBinding(QV4::IR:
// It would seem unlikely that function with some many basic blocks (after optimization)
// consists merely of a qsTr call or a constant value return ;-)
- if (function->basicBlocks.count() > 10)
+ if (function->basicBlockCount() > 10)
return false;
- foreach (QV4::IR::BasicBlock *bb, function->basicBlocks) {
- foreach (QV4::IR::Stmt *s, bb->statements) {
+ foreach (QV4::IR::BasicBlock *bb, function->basicBlocks()) {
+ foreach (QV4::IR::Stmt *s, bb->statements()) {
s->accept(this);
if (!_canSimplify)
return false;
@@ -2866,8 +2866,8 @@ void QQmlIRFunctionCleanser::clean()
module->functions = newFunctions;
foreach (QV4::IR::Function *function, module->functions) {
- foreach (QV4::IR::BasicBlock *block, function->basicBlocks) {
- foreach (QV4::IR::Stmt *s, block->statements) {
+ foreach (QV4::IR::BasicBlock *block, function->basicBlocks()) {
+ foreach (QV4::IR::Stmt *s, block->statements()) {
s->accept(this);
}
}
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 504edfcd36..d1450f051c 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -2041,7 +2041,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
sourceElements(body);
- _function->insertBasicBlock(_exitBlock);
+ _function->addBasicBlock(_exitBlock);
_block->JUMP(_exitBlock);
@@ -2597,7 +2597,7 @@ bool Codegen::visit(TryStatement *ast)
if (ast->catchExpression) {
pushExceptionHandler(catchExceptionHandler);
- _function->insertBasicBlock(catchBody);
+ _function->addBasicBlock(catchBody);
_block = catchBody;
++_function->insideWithOrCatch;
@@ -2615,7 +2615,7 @@ bool Codegen::visit(TryStatement *ast)
_block->JUMP(finallyBody ? finallyBody : end);
popExceptionHandler();
- _function->insertBasicBlock(catchExceptionHandler);
+ _function->addBasicBlock(catchExceptionHandler);
catchExceptionHandler->EXP(catchExceptionHandler->CALL(catchExceptionHandler->NAME(IR::Name::builtin_pop_scope, 0, 0), 0));
if (finallyBody || surroundingExceptionHandler)
catchExceptionHandler->JUMP(finallyBody ? finallyBody : surroundingExceptionHandler);
@@ -2626,7 +2626,7 @@ bool Codegen::visit(TryStatement *ast)
_scopeAndFinally = tcf.parent;
if (finallyBody) {
- _function->insertBasicBlock(finallyBody);
+ _function->addBasicBlock(finallyBody);
_block = finallyBody;
int hasException = _block->newTemp();
@@ -2641,7 +2641,7 @@ bool Codegen::visit(TryStatement *ast)
_block->JUMP(end);
}
- _function->insertBasicBlock(end);
+ _function->addBasicBlock(end);
_block = end;
return false;
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index c495437622..cb87846a3b 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -283,7 +283,7 @@ protected:
}
void pushExceptionHandler(QV4::IR::BasicBlock *handler)
{
- handler->isExceptionHandler = true;
+ handler->setExceptionHandler(true);
_exceptionHandlers.push(handler);
}
void popExceptionHandler()
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index df0625b48e..c7ce7c929a 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -257,7 +257,7 @@ protected:
if (IR::Jump *jump = s->asJump()) {
IR::MoveMapping moves;
- foreach (IR::Stmt *succStmt, jump->target->statements) {
+ 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) {
@@ -386,10 +386,11 @@ void InstructionSelection::run(int functionIndex)
addInstruction(push);
currentLine = 0;
- for (int i = 0, ei = _function->basicBlocks.size(); i != ei; ++i) {
+ QVector<IR::BasicBlock *> basicBlocks = _function->basicBlocks();
+ for (int i = 0, ei = basicBlocks.size(); i != ei; ++i) {
blockNeedsDebugInstruction = irModule->debugMode;
- _block = _function->basicBlocks[i];
- _nextBlock = (i < ei - 1) ? _function->basicBlocks[i + 1] : 0;
+ _block = basicBlocks[i];
+ _nextBlock = (i < ei - 1) ? basicBlocks[i + 1] : 0;
_addrs.insert(_block, _codeNext - _codeStart);
if (_block->catchBlock != exceptionHandler) {
@@ -404,7 +405,7 @@ void InstructionSelection::run(int functionIndex)
exceptionHandler = _block->catchBlock;
}
- foreach (IR::Stmt *s, _block->statements) {
+ foreach (IR::Stmt *s, _block->statements()) {
_currentStatement = s;
if (s->location.isValid()) {
diff --git a/src/qml/compiler/qv4isel_util_p.h b/src/qml/compiler/qv4isel_util_p.h
index be1714f2de..09b98a18d1 100644
--- a/src/qml/compiler/qv4isel_util_p.h
+++ b/src/qml/compiler/qv4isel_util_p.h
@@ -136,9 +136,11 @@ public:
{
_stackSlotForTemp.reserve(function->tempCount);
- foreach (IR::BasicBlock *bb, function->basicBlocks) {
+ foreach (IR::BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
_currentBasicBlock = bb;
- foreach (IR::Stmt *s, bb->statements)
+ foreach (IR::Stmt *s, bb->statements())
process(s);
}
diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp
index efce64bf7a..a067a95104 100644
--- a/src/qml/compiler/qv4jsir.cpp
+++ b/src/qml/compiler/qv4jsir.cpp
@@ -165,10 +165,12 @@ struct RemoveSharedExpressions: IR::StmtVisitor, IR::ExprVisitor
{
subexpressions.clear();
- foreach (BasicBlock *block, function->basicBlocks) {
+ foreach (BasicBlock *block, function->basicBlocks()) {
+ if (block->isRemoved())
+ continue;
clone.setBasicBlock(block);
- foreach (Stmt *s, block->statements) {
+ foreach (Stmt *s, block->statements()) {
s->accept(this);
}
}
@@ -586,7 +588,7 @@ void Move::dump(QTextStream &out, Mode mode)
void Jump::dump(QTextStream &out, Mode mode)
{
Q_UNUSED(mode);
- out << "goto " << 'L' << target->index << ';';
+ out << "goto " << 'L' << target->index() << ';';
}
void CJump::dump(QTextStream &out, Mode mode)
@@ -595,9 +597,9 @@ void CJump::dump(QTextStream &out, Mode mode)
out << "if (";
cond->dump(out);
if (mode == HIR)
- out << ") goto " << 'L' << iftrue->index << "; else goto " << 'L' << iffalse->index << ';';
+ out << ") goto " << 'L' << iftrue->index() << "; else goto " << 'L' << iffalse->index() << ';';
else
- out << ") goto " << 'L' << iftrue->index << ";";
+ out << ") goto " << 'L' << iftrue->index() << ";";
}
void Ret::dump(QTextStream &out, Mode)
@@ -654,15 +656,37 @@ void Module::setFileName(const QString &name)
}
}
+Function::Function(Module *module, Function *outer, const QString &name)
+ : module(module)
+ , pool(&module->pool)
+ , tempCount(0)
+ , maxNumberOfArguments(0)
+ , outer(outer)
+ , insideWithOrCatch(0)
+ , hasDirectEval(false)
+ , usesArgumentsObject(false)
+ , isStrict(false)
+ , isNamedExpression(false)
+ , hasTry(false)
+ , hasWith(false)
+ , unused(0)
+ , line(-1)
+ , column(-1)
+ , _allBasicBlocks(0)
+{
+ this->name = newString(name);
+ _basicBlocks.reserve(8);
+}
+
Function::~Function()
{
- // destroy the Stmt::Data blocks manually, because memory pool cleanup won't
- // call the Stmt destructors.
- foreach (IR::BasicBlock *b, basicBlocks)
- foreach (IR::Stmt *s, b->statements)
- s->destroyData();
+ if (_allBasicBlocks) {
+ qDeleteAll(*_allBasicBlocks);
+ delete _allBasicBlocks;
+ } else {
+ qDeleteAll(_basicBlocks);
+ }
- qDeleteAll(basicBlocks);
pool = 0;
module = 0;
}
@@ -676,7 +700,24 @@ const QString *Function::newString(const QString &text)
BasicBlock *Function::newBasicBlock(BasicBlock *containingLoop, BasicBlock *catchBlock, BasicBlockInsertMode mode)
{
BasicBlock *block = new BasicBlock(this, containingLoop, catchBlock);
- return mode == InsertBlock ? insertBasicBlock(block) : block;
+ return mode == InsertBlock ? addBasicBlock(block) : block;
+}
+
+BasicBlock *Function::addBasicBlock(BasicBlock *block)
+{
+ Q_ASSERT(block->index() < 0);
+ block->setIndex(_basicBlocks.size());
+ _basicBlocks.append(block);
+ return block;
+}
+
+int Function::liveBasicBlocksCount() const
+{
+ int count = 0;
+ foreach (BasicBlock *bb, basicBlocks())
+ if (!bb->isRemoved())
+ ++count;
+ return count;
}
void Function::dump(QTextStream &out, Stmt::Mode mode)
@@ -689,7 +730,7 @@ void Function::dump(QTextStream &out, Stmt::Mode mode)
out << "\treceive " << *formal << ';' << endl;
foreach (const QString *local, locals)
out << "\tlocal " << *local << ';' << endl;
- foreach (BasicBlock *bb, basicBlocks)
+ foreach (BasicBlock *bb, basicBlocks())
bb->dump(out, mode);
out << '}' << endl;
}
@@ -708,13 +749,35 @@ int Function::indexOfArgument(const QStringRef &string) const
}
return -1;
}
+
+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);
+}
+
+BasicBlock::~BasicBlock()
+{
+ foreach (Stmt *s, _statements)
+ s->destroyData();
+}
+
unsigned BasicBlock::newTemp()
{
+ Q_ASSERT(!isRemoved());
return function->tempCount++;
}
Temp *BasicBlock::TEMP(unsigned index)
{
+ Q_ASSERT(!isRemoved());
Temp *e = function->New<Temp>();
e->init(Temp::VirtualRegister, index, 0);
return e;
@@ -722,6 +785,7 @@ Temp *BasicBlock::TEMP(unsigned index)
Temp *BasicBlock::ARG(unsigned index, unsigned scope)
{
+ Q_ASSERT(!isRemoved());
Temp *e = function->New<Temp>();
e->init(scope ? Temp::ScopedFormal : Temp::Formal, index, scope);
return e;
@@ -729,6 +793,7 @@ Temp *BasicBlock::ARG(unsigned index, unsigned scope)
Temp *BasicBlock::LOCAL(unsigned index, unsigned scope)
{
+ Q_ASSERT(!isRemoved());
Temp *e = function->New<Temp>();
e->init(scope ? Temp::ScopedLocal : Temp::Local, index, scope);
return e;
@@ -736,6 +801,7 @@ Temp *BasicBlock::LOCAL(unsigned index, unsigned scope)
Expr *BasicBlock::CONST(Type type, double value)
{
+ Q_ASSERT(!isRemoved());
Const *e = function->New<Const>();
if (type == NumberType) {
int ival = (int)value;
@@ -756,6 +822,7 @@ Expr *BasicBlock::CONST(Type type, double value)
Expr *BasicBlock::STRING(const QString *value)
{
+ Q_ASSERT(!isRemoved());
String *e = function->New<String>();
e->init(value);
return e;
@@ -763,6 +830,7 @@ Expr *BasicBlock::STRING(const QString *value)
Expr *BasicBlock::REGEXP(const QString *value, int flags)
{
+ Q_ASSERT(!isRemoved());
RegExp *e = function->New<RegExp>();
e->init(value, flags);
return e;
@@ -770,6 +838,7 @@ Expr *BasicBlock::REGEXP(const QString *value, int flags)
Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column)
{
+ Q_ASSERT(!isRemoved());
Name *e = function->New<Name>();
e->init(function->newString(id), line, column);
return e;
@@ -777,6 +846,7 @@ Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column)
Name *BasicBlock::GLOBALNAME(const QString &id, quint32 line, quint32 column)
{
+ Q_ASSERT(!isRemoved());
Name *e = function->New<Name>();
e->initGlobal(function->newString(id), line, column);
return e;
@@ -785,6 +855,7 @@ Name *BasicBlock::GLOBALNAME(const QString &id, quint32 line, quint32 column)
Name *BasicBlock::NAME(Name::Builtin builtin, quint32 line, quint32 column)
{
+ Q_ASSERT(!isRemoved());
Name *e = function->New<Name>();
e->init(builtin, line, column);
return e;
@@ -792,6 +863,7 @@ Name *BasicBlock::NAME(Name::Builtin builtin, quint32 line, quint32 column)
Closure *BasicBlock::CLOSURE(int functionInModule)
{
+ Q_ASSERT(!isRemoved());
Closure *clos = function->New<Closure>();
clos->init(functionInModule, function->module->functions.at(functionInModule)->name);
return clos;
@@ -799,6 +871,7 @@ Closure *BasicBlock::CLOSURE(int functionInModule)
Expr *BasicBlock::CONVERT(Expr *expr, Type type)
{
+ Q_ASSERT(!isRemoved());
Convert *e = function->New<Convert>();
e->init(expr, type);
return e;
@@ -806,6 +879,7 @@ Expr *BasicBlock::CONVERT(Expr *expr, Type type)
Expr *BasicBlock::UNOP(AluOp op, Expr *expr)
{
+ Q_ASSERT(!isRemoved());
Unop *e = function->New<Unop>();
e->init(op, expr);
return e;
@@ -813,6 +887,7 @@ Expr *BasicBlock::UNOP(AluOp op, Expr *expr)
Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right)
{
+ Q_ASSERT(!isRemoved());
Binop *e = function->New<Binop>();
e->init(op, left, right);
return e;
@@ -820,6 +895,7 @@ Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right)
Expr *BasicBlock::CALL(Expr *base, ExprList *args)
{
+ Q_ASSERT(!isRemoved());
Call *e = function->New<Call>();
e->init(base, args);
int argc = 0;
@@ -831,6 +907,7 @@ Expr *BasicBlock::CALL(Expr *base, ExprList *args)
Expr *BasicBlock::NEW(Expr *base, ExprList *args)
{
+ Q_ASSERT(!isRemoved());
New *e = function->New<New>();
e->init(base, args);
return e;
@@ -838,6 +915,7 @@ Expr *BasicBlock::NEW(Expr *base, ExprList *args)
Expr *BasicBlock::SUBSCRIPT(Expr *base, Expr *index)
{
+ Q_ASSERT(!isRemoved());
Subscript *e = function->New<Subscript>();
e->init(base, index);
return e;
@@ -845,6 +923,7 @@ Expr *BasicBlock::SUBSCRIPT(Expr *base, Expr *index)
Expr *BasicBlock::MEMBER(Expr *base, const QString *name, QQmlPropertyData *property, uchar kind, int attachedPropertiesIdOrEnumValue)
{
+ Q_ASSERT(!isRemoved());
Member*e = function->New<Member>();
e->init(base, name, property, kind, attachedPropertiesIdOrEnumValue);
return e;
@@ -852,6 +931,7 @@ Expr *BasicBlock::MEMBER(Expr *base, const QString *name, QQmlPropertyData *prop
Stmt *BasicBlock::EXP(Expr *expr)
{
+ Q_ASSERT(!isRemoved());
if (isTerminated())
return 0;
@@ -863,6 +943,7 @@ Stmt *BasicBlock::EXP(Expr *expr)
Stmt *BasicBlock::MOVE(Expr *target, Expr *source)
{
+ Q_ASSERT(!isRemoved());
if (isTerminated())
return 0;
@@ -874,6 +955,7 @@ Stmt *BasicBlock::MOVE(Expr *target, Expr *source)
Stmt *BasicBlock::JUMP(BasicBlock *target)
{
+ Q_ASSERT(!isRemoved());
if (isTerminated())
return 0;
@@ -892,6 +974,7 @@ Stmt *BasicBlock::JUMP(BasicBlock *target)
Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
{
+ Q_ASSERT(!isRemoved());
if (isTerminated())
return 0;
@@ -921,6 +1004,7 @@ Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
Stmt *BasicBlock::RET(Temp *expr)
{
+ Q_ASSERT(!isRemoved());
if (isTerminated())
return 0;
@@ -932,11 +1016,11 @@ Stmt *BasicBlock::RET(Temp *expr)
void BasicBlock::dump(QTextStream &out, Stmt::Mode mode)
{
- out << 'L' << index << ':';
+ out << 'L' << index() << ':';
if (catchBlock)
- out << " (catchBlock L" << catchBlock->index << ")";
+ out << " (catchBlock L" << catchBlock->index() << ")";
out << endl;
- foreach (Stmt *s, statements) {
+ foreach (Stmt *s, statements()) {
out << '\t';
s->dump(out, mode);
@@ -947,11 +1031,62 @@ void BasicBlock::dump(QTextStream &out, Stmt::Mode mode)
}
}
+void BasicBlock::setStatements(const QVector<Stmt *> &newStatements)
+{
+ Q_ASSERT(!isRemoved());
+ Q_ASSERT(newStatements.size() >= _statements.size());
+ _statements = newStatements;
+}
+
void BasicBlock::appendStatement(Stmt *statement)
{
+ Q_ASSERT(!isRemoved());
if (nextLocation.isValid())
statement->location = nextLocation;
- statements.append(statement);
+ _statements.append(statement);
+}
+
+void BasicBlock::prependStatement(Stmt *stmt)
+{
+ Q_ASSERT(!isRemoved());
+ _statements.prepend(stmt);
+}
+
+void BasicBlock::insertStatementBefore(Stmt *before, Stmt *newStmt)
+{
+ int idx = _statements.indexOf(before);
+ Q_ASSERT(idx >= 0);
+ _statements.insert(idx, newStmt);
+}
+
+void BasicBlock::insertStatementBefore(int index, Stmt *newStmt)
+{
+ Q_ASSERT(index >= 0);
+ _statements.insert(index, newStmt);
+}
+
+void BasicBlock::insertStatementBeforeTerminator(Stmt *stmt)
+{
+ Q_ASSERT(!isRemoved());
+ _statements.insert(_statements.size() - 1, stmt);
+}
+
+void BasicBlock::replaceStatement(int index, Stmt *newStmt)
+{
+ Q_ASSERT(!isRemoved());
+ _statements[index] = newStmt;
+}
+
+void BasicBlock::removeStatement(Stmt *stmt)
+{
+ Q_ASSERT(!isRemoved());
+ _statements.remove(_statements.indexOf(stmt));
+}
+
+void BasicBlock::removeStatement(int idx)
+{
+ Q_ASSERT(!isRemoved());
+ _statements.remove(idx);
}
CloneExpr::CloneExpr(BasicBlock *block)
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index a333214a8b..43e7bc0a67 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -643,6 +643,8 @@ struct Stmt {
virtual Phi *asPhi() { return 0; }
virtual void dump(QTextStream &out, Mode mode = HIR) = 0;
+private: // For memory management in BasicBlock
+ friend struct BasicBlock;
void destroyData() {
delete d;
d = 0;
@@ -762,122 +764,74 @@ struct Q_QML_EXPORT Module {
void setFileName(const QString &name);
};
-// Map from meta property index (existence implies dependency) to notify signal index
-typedef QHash<int, int> PropertyDependencyMap;
-
-struct Function {
- Module *module;
- QQmlJS::MemoryPool *pool;
- const QString *name;
- QVector<BasicBlock *> basicBlocks;
- int tempCount;
- int maxNumberOfArguments;
- QSet<QString> strings;
- QList<const QString *> formals;
- QList<const QString *> locals;
- QVector<Function *> nestedFunctions;
- Function *outer;
-
- int insideWithOrCatch;
-
- uint hasDirectEval: 1;
- uint usesArgumentsObject : 1;
- uint usesThis : 1;
- uint isStrict: 1;
- uint isNamedExpression : 1;
- uint hasTry: 1;
- uint hasWith: 1;
- uint unused : 25;
-
- // Location of declaration in source code (-1 if not specified)
- int line;
- int column;
-
- // Qml extension:
- QSet<int> idObjectDependencies;
- PropertyDependencyMap contextObjectPropertyDependencies;
- PropertyDependencyMap scopeObjectPropertyDependencies;
-
- template <typename _Tp> _Tp *New() { return new (pool->allocate(sizeof(_Tp))) _Tp(); }
-
- Function(Module *module, Function *outer, const QString &name)
- : module(module)
- , pool(&module->pool)
- , tempCount(0)
- , maxNumberOfArguments(0)
- , outer(outer)
- , insideWithOrCatch(0)
- , hasDirectEval(false)
- , usesArgumentsObject(false)
- , isStrict(false)
- , isNamedExpression(false)
- , hasTry(false)
- , hasWith(false)
- , unused(0)
- , line(-1)
- , column(-1)
- { this->name = newString(name); }
-
- ~Function();
-
- enum BasicBlockInsertMode {
- InsertBlock,
- DontInsertBlock
- };
-
- BasicBlock *newBasicBlock(BasicBlock *containingLoop, BasicBlock *catchBlock, BasicBlockInsertMode mode = InsertBlock);
- const QString *newString(const QString &text);
-
- void RECEIVE(const QString &name) { formals.append(newString(name)); }
- void LOCAL(const QString &name) { locals.append(newString(name)); }
-
- inline BasicBlock *insertBasicBlock(BasicBlock *block) { basicBlocks.append(block); return block; }
-
- void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR);
-
- void removeSharedExpressions();
-
- int indexOfArgument(const QStringRef &string) const;
-
- bool variablesCanEscape() const
- { return hasDirectEval || !nestedFunctions.isEmpty() || module->debugMode; }
-};
-
struct BasicBlock {
+private:
+ Q_DISABLE_COPY(BasicBlock)
+
+public:
Function *function;
BasicBlock *catchBlock;
- QVector<Stmt *> statements;
QVector<BasicBlock *> in;
QVector<BasicBlock *> out;
QBitArray liveIn;
QBitArray liveOut;
- int index;
- bool isExceptionHandler;
QQmlJS::AST::SourceLocation nextLocation;
BasicBlock(Function *function, BasicBlock *containingLoop, BasicBlock *catcher)
: function(function)
, catchBlock(catcher)
- , index(-1)
- , isExceptionHandler(false)
, _containingGroup(containingLoop)
+ , _index(-1)
+ , _isExceptionHandler(false)
, _groupStart(false)
+ , _isRemoved(false)
{}
- ~BasicBlock() {}
+ ~BasicBlock();
- template <typename Instr> inline Instr i(Instr i) { statements.append(i); return i; }
+ const QVector<Stmt *> &statements() const
+ {
+ Q_ASSERT(!isRemoved());
+ return _statements;
+ }
+
+ int statementCount() const
+ {
+ Q_ASSERT(!isRemoved());
+ return _statements.size();
+ }
+
+ void setStatements(const QVector<Stmt *> &newStatements);
+
+ template <typename Instr> inline Instr i(Instr i)
+ {
+ Q_ASSERT(!isRemoved());
+ appendStatement(i);
+ return i;
+ }
+
+ void appendStatement(Stmt *statement);
+ void prependStatement(Stmt *stmt);
+ void insertStatementBefore(Stmt *before, Stmt *newStmt);
+ void insertStatementBefore(int index, Stmt *newStmt);
+ void insertStatementBeforeTerminator(Stmt *stmt);
+ void replaceStatement(int index, Stmt *newStmt);
+ void removeStatement(Stmt *stmt);
+ void removeStatement(int idx);
inline bool isEmpty() const {
- return statements.isEmpty();
+ Q_ASSERT(!isRemoved());
+ return _statements.isEmpty();
}
inline Stmt *terminator() const {
- if (! statements.isEmpty() && statements.at(statements.size() - 1)->asTerminator() != 0)
- return statements.at(statements.size() - 1);
+ Q_ASSERT(!isRemoved());
+ if (! _statements.isEmpty() && _statements.last()->asTerminator() != 0)
+ return _statements.last();
return 0;
}
inline bool isTerminated() const {
+ Q_ASSERT(!isRemoved());
if (terminator() != 0)
return true;
return false;
@@ -918,20 +872,174 @@ struct BasicBlock {
void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR);
- void appendStatement(Stmt *statement);
-
BasicBlock *containingGroup() const
- { return _containingGroup; }
+ {
+ Q_ASSERT(!isRemoved());
+ return _containingGroup;
+ }
+
+ void setContainingGroup(BasicBlock *loopHeader)
+ {
+ Q_ASSERT(!isRemoved());
+ _containingGroup = loopHeader;
+ }
bool isGroupStart() const
- { return _groupStart; }
+ {
+ Q_ASSERT(!isRemoved());
+ return _groupStart;
+ }
void markAsGroupStart()
- { _groupStart = true; }
+ {
+ Q_ASSERT(!isRemoved());
+ _groupStart = true;
+ }
+
+ // Returns the index of the basic-block.
+ // See Function for the full description.
+ int index() const
+ {
+ Q_ASSERT(!isRemoved());
+ return _index;
+ }
+
+ bool isExceptionHandler() const
+ { return _isExceptionHandler; }
+
+ void setExceptionHandler(bool onoff)
+ { _isExceptionHandler = onoff; }
+
+ bool isRemoved() const
+ { return _isRemoved; }
+
+private: // For Function's eyes only.
+ friend struct Function;
+ void setIndex(int index)
+ {
+ Q_ASSERT(_index < 0);
+ changeIndex(index);
+ }
+
+ void changeIndex(int index)
+ {
+ Q_ASSERT(index >= 0);
+ _index = index;
+ }
+
+ void markAsRemoved()
+ {
+ _isRemoved = true;
+ _index = -1;
+ }
private:
+ QVector<Stmt *> _statements;
BasicBlock *_containingGroup;
- bool _groupStart;
+ int _index;
+ unsigned _isExceptionHandler : 1;
+ unsigned _groupStart : 1;
+ unsigned _isRemoved : 1;
+};
+
+// Map from meta property index (existence implies dependency) to notify signal index
+typedef QHash<int, int> PropertyDependencyMap;
+
+// The Function owns (manages), among things, a list of basic-blocks. All the blocks have an index,
+// which corresponds to the index in the entry/index in the vector in which they are stored. This
+// means that algorithms/classes can also store any information about a basic block in an array,
+// where the index corresponds to the index of the basic block, which can then be used to query
+// the function for a pointer to a basic block. This also means that basic-blocks cannot be removed
+// or renumbered.
+//
+// Note that currently there is one exception: after optimization and block scheduling, the
+// method setScheduledBlocks can be called once, to register a newly ordered list. For debugging
+// purposes, these blocks are not immediately renumbered, so renumberBasicBlocks should be called
+// immediately after changing the order. That will restore the property of having a corresponding
+// block-index and block-position-in-basicBlocks-vector.
+//
+// In order for optimization/transformation passes to skip uninteresting basic blocks that will be
+// removed, the block can be marked as such. After doing so, any access will result in a failing
+// assertion.
+struct Function {
+ Module *module;
+ QQmlJS::MemoryPool *pool;
+ const QString *name;
+ int tempCount;
+ int maxNumberOfArguments;
+ QSet<QString> strings;
+ QList<const QString *> formals;
+ QList<const QString *> locals;
+ QVector<Function *> nestedFunctions;
+ Function *outer;
+
+ int insideWithOrCatch;
+
+ uint hasDirectEval: 1;
+ uint usesArgumentsObject : 1;
+ uint usesThis : 1;
+ uint isStrict: 1;
+ uint isNamedExpression : 1;
+ uint hasTry: 1;
+ uint hasWith: 1;
+ uint unused : 25;
+
+ // Location of declaration in source code (-1 if not specified)
+ int line;
+ int column;
+
+ // Qml extension:
+ QSet<int> idObjectDependencies;
+ PropertyDependencyMap contextObjectPropertyDependencies;
+ PropertyDependencyMap scopeObjectPropertyDependencies;
+
+ template <typename _Tp> _Tp *New() { return new (pool->allocate(sizeof(_Tp))) _Tp(); }
+
+ Function(Module *module, Function *outer, const QString &name);
+ ~Function();
+
+ enum BasicBlockInsertMode {
+ InsertBlock,
+ DontInsertBlock
+ };
+
+ BasicBlock *newBasicBlock(BasicBlock *containingLoop, BasicBlock *catchBlock, BasicBlockInsertMode mode = InsertBlock);
+ const QString *newString(const QString &text);
+
+ void RECEIVE(const QString &name) { formals.append(newString(name)); }
+ void LOCAL(const QString &name) { locals.append(newString(name)); }
+
+ BasicBlock *addBasicBlock(BasicBlock *block);
+
+ void removeBasicBlock(BasicBlock *block)
+ { block->markAsRemoved(); }
+
+ const QVector<BasicBlock *> &basicBlocks() const
+ { return _basicBlocks; }
+
+ BasicBlock *basicBlock(int idx) const
+ { return _basicBlocks.at(idx); }
+
+ int basicBlockCount() const
+ { return _basicBlocks.size(); }
+
+ int liveBasicBlocksCount() const;
+
+ void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR);
+
+ void removeSharedExpressions();
+
+ int indexOfArgument(const QStringRef &string) const;
+
+ bool variablesCanEscape() const
+ { return hasDirectEval || !nestedFunctions.isEmpty() || module->debugMode; }
+
+ void setScheduledBlocks(const QVector<BasicBlock *> &scheduled);
+ void renumberBasicBlocks();
+
+private:
+ QVector<BasicBlock *> _basicBlocks;
+ QVector<BasicBlock *> *_allBasicBlocks;
};
class CloneExpr: protected IR::ExprVisitor
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index 338041ad5d..fd6b7b537e 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -82,11 +82,11 @@ void showMeTheCode(IR::Function *function)
QVector<Stmt *> code;
QHash<Stmt *, BasicBlock *> leader;
- foreach (BasicBlock *block, function->basicBlocks) {
- if (block->statements.isEmpty())
+ foreach (BasicBlock *block, function->basicBlocks()) {
+ if (block->isRemoved() || block->isEmpty())
continue;
- leader.insert(block->statements.first(), block);
- foreach (Stmt *s, block->statements) {
+ leader.insert(block->statements().first(), block);
+ foreach (Stmt *s, block->statements()) {
code.append(s);
}
}
@@ -118,11 +118,11 @@ void showMeTheCode(IR::Function *function)
qout << endl;
QByteArray str;
str.append('L');
- str.append(QByteArray::number(bb->index));
+ str.append(QByteArray::number(bb->index()));
str.append(':');
if (bb->catchBlock) {
str.append(" (exception handler L");
- str.append(QByteArray::number(bb->catchBlock->index));
+ str.append(QByteArray::number(bb->catchBlock->index()));
str.append(')');
}
for (int i = 66 - str.length(); i; --i)
@@ -130,11 +130,11 @@ void showMeTheCode(IR::Function *function)
qout << str;
qout << "// predecessor blocks:";
foreach (BasicBlock *in, bb->in)
- qout << " L" << in->index;
+ qout << " L" << in->index();
if (bb->in.isEmpty())
qout << "(none)";
if (BasicBlock *container = bb->containingGroup())
- qout << "; container block: L" << container->index;
+ qout << "; container block: L" << container->index();
if (bb->isGroupStart())
qout << "; group start";
qout << endl;
@@ -161,7 +161,7 @@ void showMeTheCode(IR::Function *function)
qout << endl;
if (n && s->asCJump()) {
- qout << " else goto L" << s->asCJump()->iffalse->index << ";" << endl;
+ qout << " else goto L" << s->asCJump()->iffalse->index() << ";" << endl;
}
}
@@ -175,24 +175,21 @@ class ProcessedBlocks
QBitArray processed;
public:
- ProcessedBlocks(const QVector<BasicBlock *> allBlocks)
+ ProcessedBlocks(IR::Function *function)
{
- int maxBB = 0;
- foreach (BasicBlock *bb, allBlocks)
- maxBB = qMax(maxBB, bb->index);
- processed = QBitArray(maxBB + 1, false);
+ processed = QBitArray(function->basicBlockCount(), false);
}
bool alreadyProcessed(BasicBlock *bb) const
{
Q_ASSERT(bb);
- return processed.at(bb->index);
+ return processed.at(bb->index());
}
void markAsProcessed(BasicBlock *bb)
{
- processed.setBit(bb->index);
+ processed.setBit(bb->index());
}
};
@@ -226,7 +223,7 @@ class BasicBlockSet
Numbers *blockNumbers;
Flags *blockFlags;
- QVector<BasicBlock *> allBlocks;
+ IR::Function *function;
enum { MaxVectorCapacity = 8 };
// Q_DISABLE_COPY(BasicBlockSet); disabled because MSVC wants assignment operator for std::vector
@@ -268,10 +265,10 @@ public:
BasicBlock *operator*() const
{
if (set.blockNumbers) {
- return set.allBlocks.at(*numberIt);
+ return set.function->basicBlock(*numberIt);
} else {
Q_ASSERT(flagIt <= INT_MAX);
- return set.allBlocks.at(static_cast<int>(flagIt));
+ return set.function->basicBlock(static_cast<int>(flagIt));
}
}
@@ -308,22 +305,23 @@ public:
friend class const_iterator;
public:
- BasicBlockSet(): blockNumbers(0), blockFlags(0) {}
+ BasicBlockSet(): blockNumbers(0), blockFlags(0), function(0) {}
#ifdef Q_COMPILER_RVALUE_REFS
BasicBlockSet(BasicBlockSet &&other): blockNumbers(0), blockFlags(0)
{
std::swap(blockNumbers, other.blockNumbers);
std::swap(blockFlags, other.blockFlags);
- std::swap(allBlocks, other.allBlocks);
+ std::swap(function, other.function);
}
#endif // Q_COMPILER_RVALUE_REFS
~BasicBlockSet() { delete blockNumbers; delete blockFlags; }
- void init(const QVector<BasicBlock *> &nodes)
+ void init(IR::Function *f)
{
- Q_ASSERT(allBlocks.isEmpty());
- allBlocks = nodes;
+ Q_ASSERT(!function);
+ Q_ASSERT(f);
+ function = f;
blockNumbers = new Numbers;
blockNumbers->reserve(MaxVectorCapacity);
}
@@ -331,25 +329,25 @@ public:
void insert(BasicBlock *bb)
{
if (blockFlags) {
- (*blockFlags)[bb->index] = true;
+ (*blockFlags)[bb->index()] = true;
return;
}
for (std::vector<int>::const_iterator i = blockNumbers->begin(), ei = blockNumbers->end();
i != ei; ++i)
- if (*i == bb->index)
+ if (*i == bb->index())
return;
if (blockNumbers->size() == MaxVectorCapacity) {
- blockFlags = new Flags(allBlocks.size(), false);
+ blockFlags = new Flags(function->basicBlockCount(), false);
for (std::vector<int>::const_iterator i = blockNumbers->begin(), ei = blockNumbers->end();
i != ei; ++i)
blockFlags->operator[](*i) = true;
delete blockNumbers;
blockNumbers = 0;
- blockFlags->operator[](bb->index) = true;
+ blockFlags->operator[](bb->index()) = true;
} else {
- blockNumbers->push_back(bb->index);
+ blockNumbers->push_back(bb->index());
}
}
@@ -371,7 +369,7 @@ class DominatorTree {
typedef int BasicBlockIndex;
enum { InvalidBasicBlockIndex = -1 };
- QVector<BasicBlock *> nodes;
+ IR::Function *function;
int N;
std::vector<int> dfnum; // BasicBlock index -> dfnum
std::vector<int> vertex;
@@ -410,12 +408,12 @@ class DominatorTree {
vertex[N] = n;
parent[n] = todo.parent;
++N;
- const QVector<BasicBlock *> &out = nodes[n]->out;
+ const QVector<BasicBlock *> &out = function->basicBlock(n)->out;
for (int i = out.size() - 1; i > 0; --i)
- worklist.push_back(DFSTodo(out[i]->index, n));
+ worklist.push_back(DFSTodo(out[i]->index(), n));
if (out.size() > 0) {
- todo.node = out.first()->index;
+ todo.node = out.first()->index();
todo.parent = n;
continue;
}
@@ -463,21 +461,21 @@ class DominatorTree {
}
void calculateIDoms() {
- Q_ASSERT(nodes.first()->in.isEmpty());
+ Q_ASSERT(function->basicBlock(0)->in.isEmpty());
- vertex = std::vector<int>(nodes.size(), InvalidBasicBlockIndex);
- parent = std::vector<int>(nodes.size(), InvalidBasicBlockIndex);
- dfnum = std::vector<int>(nodes.size(), 0);
- semi = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex);
- ancestor = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex);
- idom = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex);
- samedom = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex);
- best = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex);
+ vertex = std::vector<int>(function->basicBlockCount(), InvalidBasicBlockIndex);
+ parent = std::vector<int>(function->basicBlockCount(), InvalidBasicBlockIndex);
+ dfnum = std::vector<int>(function->basicBlockCount(), 0);
+ semi = std::vector<BasicBlockIndex>(function->basicBlockCount(), InvalidBasicBlockIndex);
+ ancestor = std::vector<BasicBlockIndex>(function->basicBlockCount(), InvalidBasicBlockIndex);
+ idom = std::vector<BasicBlockIndex>(function->basicBlockCount(), InvalidBasicBlockIndex);
+ samedom = std::vector<BasicBlockIndex>(function->basicBlockCount(), InvalidBasicBlockIndex);
+ best = std::vector<BasicBlockIndex>(function->basicBlockCount(), InvalidBasicBlockIndex);
QHash<BasicBlockIndex, std::vector<BasicBlockIndex> > bucket;
- DFS(nodes.first()->index);
- Q_ASSERT(N == nodes.size()); // fails with unreachable nodes, but those should have been removed before.
+ DFS(function->basicBlock(0)->index());
+ Q_ASSERT(N == function->liveBasicBlocksCount());
std::vector<BasicBlockIndex> worklist;
worklist.reserve(vertex.capacity() / 2);
@@ -487,12 +485,12 @@ class DominatorTree {
BasicBlockIndex p = parent[n];
BasicBlockIndex s = p;
- foreach (BasicBlock *v, nodes.at(n)->in) {
+ foreach (BasicBlock *v, function->basicBlock(n)->in) {
BasicBlockIndex ss = InvalidBasicBlockIndex;
- if (dfnum[v->index] <= dfnum[n])
- ss = v->index;
+ if (dfnum[v->index()] <= dfnum[n])
+ ss = v->index();
else
- ss = semi[ancestorWithLowestSemi(v->index, worklist)];
+ ss = semi[ancestorWithLowestSemi(v->index(), worklist)];
if (dfnum[ss] < dfnum[s])
s = ss;
}
@@ -540,6 +538,7 @@ class DominatorTree {
qout << "(none)";
qout << " -> " << to->index << endl;
}
+ qout << "N = " << N << endl;
#endif // SHOW_SSA
}
@@ -551,10 +550,12 @@ class DominatorTree {
void computeDF() {
// compute children of each node in the dominator tree
std::vector<std::vector<BasicBlockIndex> > children; // BasicBlock index -> children
- children.resize(nodes.size());
- foreach (BasicBlock *n, nodes) {
- const BasicBlockIndex nodeIndex = n->index;
- Q_ASSERT(nodes.at(nodeIndex) == n);
+ children.resize(function->basicBlockCount());
+ foreach (BasicBlock *n, function->basicBlocks()) {
+ if (n->isRemoved())
+ continue;
+ const BasicBlockIndex nodeIndex = n->index();
+ Q_ASSERT(function->basicBlock(nodeIndex) == n);
const BasicBlockIndex nodeDominator = idom[nodeIndex];
if (nodeDominator == InvalidBasicBlockIndex)
continue; // there is no dominator to add this node to as a child (e.g. the start node)
@@ -563,18 +564,20 @@ class DominatorTree {
// Fill the worklist and initialize the node status for each basic-block
QHash<BasicBlockIndex, NodeProgress> nodeStatus;
- nodeStatus.reserve(nodes.size());
+ nodeStatus.reserve(function->basicBlockCount());
std::vector<BasicBlockIndex> worklist;
- worklist.reserve(nodes.size() * 2);
- for (int i = 0, ei = nodes.size(); i != ei; ++i) {
- BasicBlockIndex nodeIndex = nodes.at(i)->index;
+ worklist.reserve(function->basicBlockCount() * 2);
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+ BasicBlockIndex nodeIndex = bb->index();
worklist.push_back(nodeIndex);
NodeProgress &np = nodeStatus[nodeIndex];
np.children = children[nodeIndex];
np.todo = children[nodeIndex];
}
- std::vector<bool> DF_done(nodes.size(), false);
+ std::vector<bool> DF_done(function->basicBlockCount(), false);
while (!worklist.empty()) {
BasicBlockIndex node = worklist.back();
@@ -597,16 +600,16 @@ class DominatorTree {
if (np.todo.empty()) {
BasicBlockSet &S = DF[node];
- S.init(nodes);
- foreach (BasicBlock *y, nodes.at(node)->out)
- if (idom[y->index] != node)
+ S.init(function);
+ foreach (BasicBlock *y, function->basicBlock(node)->out)
+ if (idom[y->index()] != node)
S.insert(y);
foreach (BasicBlockIndex child, np.children) {
const BasicBlockSet &ws = DF[child];
for (BasicBlockSet::const_iterator it = ws.begin(), eit = ws.end(); it != eit; ++it) {
BasicBlock *w = *it;
- const BasicBlockIndex wIndex = w->index;
- if (node == wIndex || !dominates(node, w->index))
+ const BasicBlockIndex wIndex = w->index();
+ if (node == wIndex || !dominates(node, w->index()))
S.insert(w);
}
}
@@ -651,21 +654,21 @@ class DominatorTree {
}
public:
- DominatorTree(const QVector<BasicBlock *> &nodes)
- : nodes(nodes)
+ DominatorTree(IR::Function *function)
+ : function(function)
, N(0)
{
- DF.resize(nodes.size());
+ DF.resize(function->basicBlockCount());
calculateIDoms();
computeDF();
}
const BasicBlockSet &dominatorFrontier(BasicBlock *n) const {
- return DF[n->index];
+ return DF[n->index()];
}
BasicBlock *immediateDominator(BasicBlock *bb) const {
- return nodes[idom[bb->index]];
+ return function->basicBlock(idom[bb->index()]);
}
void dumpImmediateDominators() const
@@ -680,46 +683,30 @@ public:
void updateImmediateDominator(BasicBlock *bb, BasicBlock *newDominator)
{
- Q_ASSERT(bb->index >= 0);
+ Q_ASSERT(bb->index() >= 0);
- int blockIndex;
- if (static_cast<std::vector<BasicBlockIndex>::size_type>(bb->index) >= idom.size()) {
+ if (static_cast<std::vector<BasicBlockIndex>::size_type>(bb->index()) >= idom.size()) {
// This is a new block, probably introduced by edge splitting. So, we'll have to grow
// the array before inserting the immediate dominator.
- nodes.append(bb);
- idom.resize(nodes.size(), InvalidBasicBlockIndex);
- blockIndex = nodes.size() - 1;
- } else {
- blockIndex = getBlockIndex(bb);
+ idom.resize(function->basicBlockCount(), InvalidBasicBlockIndex);
}
- idom[blockIndex] = getBlockIndex(newDominator);
+ idom[bb->index()] = newDominator->index();
}
bool dominates(BasicBlock *dominator, BasicBlock *dominated) const {
- // The index of the basic blocks might have changed, or the nodes array might have changed,
- // so get the index from our copy of the array.
- return dominates(getBlockIndex(dominator), getBlockIndex(dominated));
+ return dominates(dominator->index(), dominated->index());
}
private:
- int getBlockIndex(BasicBlock *bb) const {
- if (!bb)
- return InvalidBasicBlockIndex;
-
- if (bb->index >= 0 && bb->index < nodes.size()) {
- if (nodes.at(bb->index) == bb)
- return bb->index;
- }
-
- return nodes.indexOf(bb);
- }
-
bool dominates(BasicBlockIndex dominator, BasicBlockIndex dominated) const {
// dominator can be Invalid when the dominated block has no dominator (i.e. the start node)
Q_ASSERT(dominated != InvalidBasicBlockIndex);
- for (BasicBlockIndex it = dominated; it != InvalidBasicBlockIndex; it = idom[it]) {
+ if (dominator == dominated)
+ return false;
+
+ for (BasicBlockIndex it = idom[dominated]; it != InvalidBasicBlockIndex; it = idom[it]) {
if (it == dominator)
return true;
}
@@ -752,11 +739,14 @@ public:
qout << "Variables collected:" << endl;
#endif // SHOW_SSA
- foreach (BasicBlock *bb, function->basicBlocks) {
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+
currentBB = bb;
killed.clear();
- killed.reserve(bb->statements.size() / 2);
- foreach (Stmt *s, bb->statements) {
+ killed.reserve(bb->statements().size() / 2);
+ foreach (Stmt *s, bb->statements()) {
s->accept(this);
}
}
@@ -858,7 +848,7 @@ void insertPhiNode(const Temp &a, BasicBlock *y, IR::Function *f) {
phiNode->d = new Stmt::Data;
phiNode->targetTemp = f->New<Temp>();
phiNode->targetTemp->init(a.kind, a.index, 0);
- y->statements.prepend(phiNode);
+ y->prependStatement(phiNode);
phiNode->d->incoming.resize(y->in.size());
for (int i = 0, ei = y->in.size(); i < ei; ++i) {
@@ -997,15 +987,15 @@ public:
VariableRenamer(IR::Function *f)
: function(f)
, tempCount(0)
- , processed(f->basicBlocks)
+ , processed(f)
{
localMapping.reserve(f->tempCount);
vregMapping.reserve(f->tempCount);
- todo.reserve(f->basicBlocks.size());
+ todo.reserve(f->basicBlockCount());
}
void run() {
- todo.append(TodoAction(function->basicBlocks.first()));
+ todo.append(TodoAction(function->basicBlock(0)));
while (!todo.isEmpty()) {
TodoAction todoAction = todo.back();
@@ -1060,13 +1050,13 @@ private:
void renameStatementsAndPhis(BasicBlock *bb)
{
- foreach (Stmt *s, bb->statements)
+ foreach (Stmt *s, bb->statements())
s->accept(this);
foreach (BasicBlock *Y, bb->out) {
const int j = Y->in.indexOf(bb);
Q_ASSERT(j >= 0 && j < Y->in.size());
- foreach (Stmt *s, Y->statements) {
+ foreach (Stmt *s, Y->statements()) {
if (Phi *phi = s->asPhi()) {
Temp *t = phi->d->incoming[j]->asTemp();
unsigned newTmp = currentNumber(*t);
@@ -1201,7 +1191,7 @@ protected:
void convertToSSA(IR::Function *function, const DominatorTree &df)
{
-#ifdef SHOW_SSA
+#if defined(SHOW_SSA)
qout << "Converting function ";
if (function->name)
qout << *function->name;
@@ -1302,9 +1292,12 @@ public:
DefUsesCalculator(IR::Function *function)
: function(function)
{
- foreach (BasicBlock *bb, function->basicBlocks) {
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+
_block = bb;
- foreach (Stmt *stmt, bb->statements) {
+ foreach (Stmt *stmt, bb->statements()) {
_stmt = stmt;
stmt->accept(this);
}
@@ -1386,7 +1379,7 @@ public:
foreach (const UntypedTemp &var, _defUses.keys()) {
const DefUse &du = _defUses[var];
var.temp.dump(qout);
- qout<<" -> defined in block "<<du.blockOfStatement->index<<", statement: ";
+ qout<<" -> defined in block "<<du.blockOfStatement->index()<<", statement: ";
du.defStmt->dump(qout);
qout<<endl<<" uses:"<<endl;
foreach (Stmt *s, du.uses) {
@@ -1478,10 +1471,7 @@ void cleanupPhis(DefUsesCalculator &defUses)
foreach (Phi *phi, toRemove) {
Temp targetVar = *phi->targetTemp;
- BasicBlock *bb = defUses.defStmtBlock(targetVar);
- int idx = bb->statements.indexOf(phi);
- bb->statements[idx]->destroyData();
- bb->statements.remove(idx);
+ defUses.defStmtBlock(targetVar)->removeStatement(phi);
foreach (const Temp &usedVar, defUses.usedVars(phi))
defUses.removeUse(phi, usedVar);
@@ -1493,7 +1483,8 @@ class StatementWorklist
{
QVector<Stmt *> worklist;
QBitArray inWorklist;
- QHash<Stmt*,Stmt**> ref;
+ QSet<Stmt *> removed;
+ QHash<Stmt*,Stmt*> replaced;
public:
StatementWorklist(IR::Function *function)
@@ -1503,12 +1494,13 @@ public:
// Put in all statements, and number them on the fly. The numbering is used to index the
// bit array.
- foreach (BasicBlock *bb, function->basicBlocks) {
- for (int i = 0, ei = bb->statements.size(); i != ei; ++i) {
- Stmt **s = &bb->statements[i];
- (*s)->id = stmtCount++;
- w.append(*s);
- ref.insert(*s, s);
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+
+ foreach (Stmt *s, bb->statements()) {
+ s->id = stmtCount++;
+ w.append(s);
}
}
@@ -1527,29 +1519,40 @@ public:
void clear(Stmt *stmt)
{
Q_ASSERT(!inWorklist.at(stmt->id));
- *ref[stmt] = 0;
+ removed.insert(stmt);
}
void replace(Stmt *oldStmt, Stmt *newStmt)
{
Q_ASSERT(oldStmt);
Q_ASSERT(newStmt);
+ Q_ASSERT(!removed.contains(oldStmt));
if (newStmt->id == -1)
newStmt->id = oldStmt->id;
- *ref[oldStmt] = newStmt;
+ QHash<Stmt *, Stmt *>::const_iterator it = replaced.find(oldStmt);
+ if (it != replaced.end())
+ oldStmt = it.key();
+ replaced[oldStmt] = newStmt;
}
void cleanup(IR::Function *function)
{
- foreach (BasicBlock *bb, function->basicBlocks) {
- for (int i = 0; i < bb->statements.size();) {
- if (bb->statements[i]) {
- bb->statements[i]->id = -1;
- ++i;
- } else {
- bb->statements.remove(i);
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+
+ for (int i = 0; i < bb->statementCount();) {
+ Stmt *stmt = bb->statements()[i];
+ QHash<Stmt *, Stmt *>::const_iterator it = replaced.find(stmt);
+ if (it != replaced.end() && !removed.contains(it.value())) {
+ bb->replaceStatement(i, it.value());
+ } else if (removed.contains(stmt)) {
+ bb->removeStatement(i);
+ continue;
}
+
+ ++i;
}
}
}
@@ -1872,10 +1875,12 @@ public:
// TODO: the worklist handling looks a bit inefficient... check if there is something better
_worklist.clear();
- for (int i = 0, ei = function->basicBlocks.size(); i != ei; ++i) {
- BasicBlock *bb = function->basicBlocks[i];
+ for (int i = 0, ei = function->basicBlockCount(); i != ei; ++i) {
+ BasicBlock *bb = function->basicBlock(i);
+ if (bb->isRemoved())
+ continue;
if (i == 0 || !bb->in.isEmpty())
- foreach (Stmt *s, bb->statements)
+ foreach (Stmt *s, bb->statements())
if (!s->asJump())
_worklist.insert(s);
}
@@ -2373,10 +2378,12 @@ public:
void run(IR::Function *f) {
_f = f;
- foreach (BasicBlock *bb, f->basicBlocks) {
+ foreach (BasicBlock *bb, f->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
_conversions.clear();
- foreach (Stmt *s, bb->statements) {
+ foreach (Stmt *s, bb->statements()) {
_currStmt = s;
s->accept(this);
}
@@ -2407,11 +2414,9 @@ public:
if (Phi *phi = conversion.stmt->asPhi()) {
int idx = phi->d->incoming.indexOf(t);
Q_ASSERT(idx != -1);
- QVector<Stmt *> &stmts = bb->in[idx]->statements;
- stmts.insert(stmts.size() - 1, convCall);
+ bb->in[idx]->insertStatementBeforeTerminator(convCall);
} else {
- int idx = bb->statements.indexOf(conversion.stmt);
- bb->statements.insert(idx, convCall);
+ bb->insertStatementBefore(conversion.stmt, convCall);
}
*conversion.expr = source;
@@ -2432,9 +2437,7 @@ public:
_defUses.removeUse(move, *unopOperand);
}
- int idx = bb->statements.indexOf(conversion.stmt);
- Q_ASSERT(idx != -1);
- bb->statements.insert(idx, extraMove);
+ bb->insertStatementBefore(conversion.stmt, extraMove);
*conversion.expr = bb->CONVERT(tmp, conversion.targetType);
_defUses.addUse(*tmp, move);
@@ -2566,56 +2569,55 @@ protected:
void splitCriticalEdges(IR::Function *f, DominatorTree &df)
{
- for (int i = 0, ei = f->basicBlocks.size(); i != ei; ++i) {
- BasicBlock *bb = f->basicBlocks[i];
- if (bb->in.size() > 1) {
- for (int inIdx = 0, eInIdx = bb->in.size(); inIdx != eInIdx; ++inIdx) {
- BasicBlock *inBB = bb->in[inIdx];
- if (inBB->out.size() > 1) { // this should have been split!
- int newIndex = f->basicBlocks.last()->index + 1;
-#if defined(SHOW_SSA)
- qDebug() << "Splitting edge from block" << inBB->index << "to block" << bb->index << "by introducing block" << newIndex;
-#endif
+ foreach (BasicBlock *bb, f->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+ if (bb->in.size() < 2)
+ continue;
- BasicBlock *containingGroup = inBB->isGroupStart() ? inBB : inBB->containingGroup();
-
- // create the basic block:
- BasicBlock *newBB = new BasicBlock(f, containingGroup, bb->catchBlock);
- newBB->index = newIndex;
- f->basicBlocks.append(newBB);
- Jump *s = f->New<Jump>();
- s->init(bb);
- newBB->statements.append(s);
-
- // rewire the old outgoing edge
- int outIdx = inBB->out.indexOf(bb);
- inBB->out[outIdx] = newBB;
- newBB->in.append(inBB);
-
- // rewire the old incoming edge
- bb->in[inIdx] = newBB;
- newBB->out.append(bb);
-
- // patch the terminator
- Stmt *terminator = inBB->terminator();
- if (Jump *j = terminator->asJump()) {
- Q_ASSERT(outIdx == 0);
- j->target = newBB;
- } else if (CJump *j = terminator->asCJump()) {
- if (outIdx == 0)
- j->iftrue = newBB;
- else if (outIdx == 1)
- j->iffalse = newBB;
- else
- Q_ASSERT(!"Invalid out edge index for CJUMP!");
- } else {
- Q_ASSERT(!"Unknown terminator!");
- }
+ for (int inIdx = 0, eInIdx = bb->in.size(); inIdx != eInIdx; ++inIdx) {
+ BasicBlock *inBB = bb->in[inIdx];
+ if (inBB->out.size() < 2)
+ continue;
- // Set the immediate dominator of the new block to inBB
- df.updateImmediateDominator(newBB, inBB);
- }
+ // We found a critical edge.
+ BasicBlock *containingGroup = inBB->isGroupStart() ? inBB : inBB->containingGroup();
+
+ // create the basic block:
+ BasicBlock *newBB = f->newBasicBlock(containingGroup, bb->catchBlock);
+ Jump *s = f->New<Jump>();
+ s->init(bb);
+ newBB->appendStatement(s);
+
+ // rewire the old outgoing edge
+ int outIdx = inBB->out.indexOf(bb);
+ inBB->out[outIdx] = newBB;
+ newBB->in.append(inBB);
+
+ // rewire the old incoming edge
+ bb->in[inIdx] = newBB;
+ newBB->out.append(bb);
+
+ // patch the terminator
+ Stmt *terminator = inBB->terminator();
+ if (Jump *j = terminator->asJump()) {
+ Q_ASSERT(outIdx == 0);
+ j->target = newBB;
+ } else if (CJump *j = terminator->asCJump()) {
+ if (outIdx == 0)
+ j->iftrue = newBB;
+ else if (outIdx == 1)
+ j->iffalse = newBB;
+ else
+ Q_ASSERT(!"Invalid out edge index for CJUMP!");
+ } else if (terminator->asRet()) {
+ Q_ASSERT(!"A block with a RET at the end cannot have outgoing edges.");
+ } else {
+ Q_ASSERT(!"Unknown terminator!");
}
+
+ // Set the immediate dominator of the new block to inBB
+ df.updateImmediateDominator(newBB, inBB);
}
}
}
@@ -2708,6 +2710,7 @@ class BlockScheduler
void emitBlock(BasicBlock *bb)
{
+ Q_ASSERT(!bb->isRemoved());
if (emitted.alreadyProcessed(bb))
return;
@@ -2755,22 +2758,24 @@ public:
BlockScheduler(IR::Function *function, const DominatorTree &dominatorTree)
: function(function)
, dominatorTree(dominatorTree)
- , emitted(function->basicBlocks)
+ , sequence(0)
+ , emitted(function)
{}
QHash<BasicBlock *, BasicBlock *> go()
{
showMeTheCode(function);
- schedule(function->basicBlocks.first());
+ schedule(function->basicBlock(0));
#if defined(SHOW_SSA)
qDebug() << "Block sequence:";
foreach (BasicBlock *bb, sequence)
- qDebug("\tL%d", bb->index);
+ qDebug("\tL%d", bb->index());
#endif // SHOW_SSA
- Q_ASSERT(function->basicBlocks.size() == sequence.size());
- function->basicBlocks = sequence;
+ Q_ASSERT(function->liveBasicBlocksCount() == sequence.size());
+ function->setScheduledBlocks(sequence);
+ function->renumberBasicBlocks();
return loopsStartEnd;
}
};
@@ -2782,7 +2787,7 @@ void checkCriticalEdges(QVector<BasicBlock *> basicBlocks) {
foreach (BasicBlock *bb2, bb->out) {
if (bb2 && bb2->in.size() > 1) {
qout << "found critical edge between block "
- << bb->index << " and block " << bb2->index;
+ << bb->index() << " and block " << bb2->index();
Q_ASSERT(false);
}
}
@@ -2791,7 +2796,7 @@ void checkCriticalEdges(QVector<BasicBlock *> basicBlocks) {
}
#endif
-void cleanupBasicBlocks(IR::Function *function, bool renumber)
+void cleanupBasicBlocks(IR::Function *function)
{
showMeTheCode(function);
@@ -2800,12 +2805,12 @@ void cleanupBasicBlocks(IR::Function *function, bool renumber)
// blocks.
QSet<BasicBlock *> postponed, done;
QSet<BasicBlock *> toRemove;
- toRemove.reserve(function->basicBlocks.size());
- done.reserve(function->basicBlocks.size());
+ toRemove.reserve(function->basicBlockCount());
+ done.reserve(function->basicBlockCount());
postponed.reserve(8);
- for (int i = 0, ei = function->basicBlocks.size(); i != ei; ++i) {
- BasicBlock *bb = function->basicBlocks[i];
- if (i == 0 || bb->isExceptionHandler)
+ for (int i = 0, ei = function->basicBlockCount(); i != ei; ++i) {
+ BasicBlock *bb = function->basicBlock(i);
+ if (i == 0 || bb->isExceptionHandler())
postponed.insert(bb);
else
toRemove.insert(bb);
@@ -2835,7 +2840,7 @@ void cleanupBasicBlocks(IR::Function *function, bool renumber)
int idx = outBB->in.indexOf(bb);
if (idx != -1) {
outBB->in.remove(idx);
- foreach (Stmt *s, outBB->statements) {
+ foreach (Stmt *s, outBB->statements()) {
if (Phi *phi = s->asPhi())
phi->d->incoming.remove(idx);
else
@@ -2844,18 +2849,9 @@ void cleanupBasicBlocks(IR::Function *function, bool renumber)
}
}
- foreach (Stmt *s, bb->statements)
- s->destroyData();
- int idx = function->basicBlocks.indexOf(bb);
- if (idx != -1)
- function->basicBlocks.remove(idx);
- delete bb;
+ function->removeBasicBlock(bb);
}
- if (renumber)
- for (int i = 0; i < function->basicBlocks.size(); ++i)
- function->basicBlocks[i]->index = i;
-
showMeTheCode(function);
}
@@ -3012,28 +3008,24 @@ namespace {
void purgeBB(BasicBlock *bb, IR::Function *func, DefUsesCalculator &defUses, StatementWorklist &W,
DominatorTree &df)
{
- // TODO: change this to mark the block as deleted, but leave it alone so that other references
- // won't be dangling pointers.
// TODO: after the change above: if we keep on detaching the block from predecessors or
// successors, update the DominatorTree too.
// don't purge blocks that are entry points for catch statements. They might not be directly
// connected, but are required anyway
- if (bb->isExceptionHandler)
+ if (bb->isExceptionHandler())
return;
QVector<BasicBlock *> toPurge;
+ toPurge.reserve(8);
toPurge.append(bb);
while (!toPurge.isEmpty()) {
bb = toPurge.first();
toPurge.removeFirst();
- int bbIdx = func->basicBlocks.indexOf(bb);
- if (bbIdx == -1)
+ if (bb->isRemoved())
continue;
- else
- func->basicBlocks.remove(bbIdx);
// unlink all incoming edges
foreach (BasicBlock *in, bb->in) {
@@ -3047,7 +3039,7 @@ void purgeBB(BasicBlock *bb, IR::Function *func, DefUsesCalculator &defUses, Sta
int idx = out->in.indexOf(bb);
if (idx != -1) {
out->in.remove(idx);
- foreach (Stmt *outStmt, out->statements) {
+ foreach (Stmt *outStmt, out->statements()) {
if (!outStmt)
continue;
if (Phi *phi = outStmt->asPhi()) {
@@ -3072,19 +3064,15 @@ void purgeBB(BasicBlock *bb, IR::Function *func, DefUsesCalculator &defUses, Sta
}
// unlink all defs/uses from the statements in the basic block
- foreach (Stmt *s, bb->statements) {
+ foreach (Stmt *s, bb->statements()) {
if (!s)
continue;
W += defUses.removeDefUses(s);
W -= s;
-
- // clean-up the statement's data
- s->destroyData();
}
- bb->statements.clear();
- delete bb;
+ func->removeBasicBlock(bb);
}
}
@@ -3529,8 +3517,8 @@ public:
LifeRanges(IR::Function *function, const QHash<BasicBlock *, BasicBlock *> &startEndLoops)
{
int id = 0;
- foreach (BasicBlock *bb, function->basicBlocks) {
- foreach (Stmt *s, bb->statements) {
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ foreach (Stmt *s, bb->statements()) {
if (s->asPhi())
s->id = id + 1;
else
@@ -3538,8 +3526,8 @@ public:
}
}
- for (int i = function->basicBlocks.size() - 1; i >= 0; --i) {
- BasicBlock *bb = function->basicBlocks[i];
+ for (int i = function->basicBlockCount() - 1; i >= 0; --i) {
+ BasicBlock *bb = function->basicBlock(i);
buildIntervals(bb, startEndLoops.value(bb, 0), function);
}
@@ -3564,7 +3552,7 @@ public:
}
foreach (BasicBlock *bb, _liveIn.keys()) {
- qout << "L" << bb->index <<" live-in: ";
+ qout << "L" << bb->index() <<" live-in: ";
QList<Temp> live = QList<Temp>::fromSet(_liveIn.value(bb));
std::sort(live.begin(), live.end());
for (int i = 0; i < live.size(); ++i) {
@@ -3584,7 +3572,7 @@ private:
const int bbIndex = successor->in.indexOf(bb);
Q_ASSERT(bbIndex >= 0);
- foreach (Stmt *s, successor->statements) {
+ foreach (Stmt *s, successor->statements()) {
if (Phi *phi = s->asPhi()) {
if (Temp *t = phi->d->incoming[bbIndex]->asTemp())
live.insert(*t);
@@ -3594,12 +3582,14 @@ private:
}
}
+ QVector<Stmt *> statements = bb->statements();
+
foreach (const Temp &opd, live)
- _intervals[opd].addRange(bb->statements.first()->id, bb->statements.last()->id);
+ _intervals[opd].addRange(statements.first()->id, statements.last()->id);
InputOutputCollector collector(function);
- for (int i = bb->statements.size() - 1; i >= 0; --i) {
- Stmt *s = bb->statements[i];
+ for (int i = statements.size() - 1; i >= 0; --i) {
+ Stmt *s = statements[i];
if (Phi *phi = s->asPhi()) {
LiveRegs::iterator it = live.find(*phi->targetTemp);
if (it == live.end()) {
@@ -3616,19 +3606,30 @@ private:
live.remove(opd);
}
foreach (const Temp &opd, collector.inputs) {
- _intervals[opd].addRange(bb->statements.first()->id, s->id);
+ _intervals[opd].addRange(statements.first()->id, s->id);
live.insert(opd);
}
}
if (loopEnd) { // Meaning: bb is a loop header, because loopEnd is set to non-null.
foreach (const Temp &opd, live)
- _intervals[opd].addRange(bb->statements.first()->id, loopEnd->statements.last()->id);
+ _intervals[opd].addRange(statements.first()->id, loopEnd->terminator()->id);
}
_liveIn[bb] = live;
}
};
+
+void removeUnreachleBlocks(IR::Function *function)
+{
+ QVector<BasicBlock *> newSchedule;
+ newSchedule.reserve(function->basicBlockCount());
+ foreach (BasicBlock *bb, function->basicBlocks())
+ if (!bb->isRemoved())
+ newSchedule.append(bb);
+ function->setScheduledBlocks(newSchedule);
+ function->renumberBasicBlocks();
+}
} // anonymous namespace
void LifeTimeInterval::setFrom(Stmt *from) {
@@ -3774,6 +3775,11 @@ bool LifeTimeInterval::lessThanForTemp(const LifeTimeInterval &r1, const LifeTim
return r1.temp() < r2.temp();
}
+Optimizer::Optimizer(IR::Function *function)
+ : function(function)
+ , inSSA(false)
+{}
+
void Optimizer::run(QQmlEnginePrivate *qmlEngine)
{
#if defined(SHOW_SSA)
@@ -3781,12 +3787,9 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine)
<< " with " << function->basicBlocks.size() << " basic blocks." << endl << flush;
#endif
- // Number all basic blocks, so we have nice numbers in the dumps:
- for (int i = 0; i < function->basicBlocks.size(); ++i)
- function->basicBlocks[i]->index = i;
// showMeTheCode(function);
- cleanupBasicBlocks(function, true);
+ cleanupBasicBlocks(function);
function->removeSharedExpressions();
@@ -3798,7 +3801,7 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine)
// qout << "SSA for " << (function->name ? qPrintable(*function->name) : "<anonymous>") << endl;
// Calculate the dominator tree:
- DominatorTree df(function->basicBlocks);
+ DominatorTree df(function);
// qout << "Converting to SSA..." << endl;
convertToSSA(function, df);
@@ -3843,21 +3846,22 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine)
// condition is calculated to be always false) are not yet removed. This will choke the
// block scheduling, so remove those now.
// qout << "Cleaning up unreachable basic blocks..." << endl;
- cleanupBasicBlocks(function, false);
+ cleanupBasicBlocks(function);
// showMeTheCode(function);
// qout << "Doing block scheduling..." << endl;
// df.dumpImmediateDominators();
startEndLoops = BlockScheduler(function, df).go();
-// showMeTheCode(function);
+ showMeTheCode(function);
#ifndef QT_NO_DEBUG
- checkCriticalEdges(function->basicBlocks);
+ checkCriticalEdges(function->basicBlocks());
#endif
// qout << "Finished SSA." << endl;
inSSA = true;
} else {
+ removeUnreachleBlocks(function);
inSSA = false;
}
}
@@ -3868,13 +3872,13 @@ void Optimizer::convertOutOfSSA() {
// There should be no critical edges at this point.
- foreach (BasicBlock *bb, function->basicBlocks) {
+ foreach (BasicBlock *bb, function->basicBlocks()) {
MoveMapping moves;
foreach (BasicBlock *successor, bb->out) {
const int inIdx = successor->in.indexOf(bb);
Q_ASSERT(inIdx >= 0);
- foreach (Stmt *s, successor->statements) {
+ foreach (Stmt *s, successor->statements()) {
if (Phi *phi = s->asPhi()) {
moves.add(clone(phi->d->incoming[inIdx], function),
clone(phi->targetTemp, function)->asTemp());
@@ -3900,11 +3904,10 @@ void Optimizer::convertOutOfSSA() {
moves.insertMoves(bb, function, true);
}
- foreach (BasicBlock *bb, function->basicBlocks) {
- while (!bb->statements.isEmpty()) {
- if (Phi *phi = bb->statements.first()->asPhi()) {
- phi->destroyData();
- bb->statements.removeFirst();
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ while (!bb->isEmpty()) {
+ if (bb->statements().first()->asPhi()) {
+ bb->removeStatement(0);
} else {
break;
}
@@ -3927,16 +3930,18 @@ QSet<Jump *> Optimizer::calculateOptionalJumps()
QSet<Jump *> optional;
QSet<BasicBlock *> reachableWithoutJump;
- const int maxSize = function->basicBlocks.size();
+ const int maxSize = function->basicBlockCount();
optional.reserve(maxSize);
reachableWithoutJump.reserve(maxSize);
- for (int i = function->basicBlocks.size() - 1; i >= 0; --i) {
- BasicBlock *bb = function->basicBlocks[i];
+ for (int i = maxSize - 1; i >= 0; --i) {
+ BasicBlock *bb = function->basicBlock(i);
+ if (bb->isRemoved())
+ continue;
- if (Jump *jump = bb->statements.last()->asJump()) {
+ if (Jump *jump = bb->statements().last()->asJump()) {
if (reachableWithoutJump.contains(jump->target)) {
- if (bb->statements.size() > 1)
+ if (bb->statements().size() > 1)
reachableWithoutJump.clear();
optional.insert(jump);
reachableWithoutJump.insert(bb);
@@ -4051,12 +4056,12 @@ QList<IR::Move *> MoveMapping::insertMoves(BasicBlock *bb, IR::Function *functio
QList<IR::Move *> newMoves;
newMoves.reserve(_moves.size());
- int insertionPoint = atEnd ? bb->statements.size() - 1 : 0;
+ int insertionPoint = atEnd ? bb->statements().size() - 1 : 0;
foreach (const Move &m, _moves) {
IR::Move *move = function->New<IR::Move>();
move->init(clone(m.to, function), clone(m.from, function));
move->swap = m.needsSwap;
- bb->statements.insert(insertionPoint++, move);
+ bb->insertStatementBefore(insertionPoint++, move);
newMoves.append(move);
}
diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h
index 87f28d0eb2..9bbe92dfa6 100644
--- a/src/qml/compiler/qv4ssa_p.h
+++ b/src/qml/compiler/qv4ssa_p.h
@@ -139,11 +139,10 @@ public:
class Q_QML_EXPORT Optimizer
{
+ Q_DISABLE_COPY(Optimizer)
+
public:
- Optimizer(Function *function)
- : function(function)
- , inSSA(false)
- {}
+ Optimizer(Function *function);
void run(QQmlEnginePrivate *qmlEngine);
void convertOutOfSSA();
diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp
index 0692fe31c2..57ca940731 100644
--- a/src/qml/jit/qv4isel_masm.cpp
+++ b/src/qml/jit/qv4isel_masm.cpp
@@ -342,12 +342,14 @@ void InstructionSelection::run(int functionIndex)
_as->storePtr(Assembler::LocalsRegister, Address(Assembler::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
int lastLine = 0;
- for (int i = 0, ei = _function->basicBlocks.size(); i != ei; ++i) {
- IR::BasicBlock *nextBlock = (i < ei - 1) ? _function->basicBlocks[i + 1] : 0;
- _block = _function->basicBlocks[i];
+ for (int i = 0, ei = _function->basicBlockCount(); i != ei; ++i) {
+ IR::BasicBlock *nextBlock = (i < ei - 1) ? _function->basicBlock(i + 1) : 0;
+ _block = _function->basicBlock(i);
+ if (_block->isRemoved())
+ continue;
_as->registerBlock(_block, nextBlock);
- foreach (IR::Stmt *s, _block->statements) {
+ foreach (IR::Stmt *s, _block->statements()) {
if (s->location.isValid()) {
if (int(s->location.startLine) != lastLine) {
Assembler::Address lineAddr(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext, lineNumber));
diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp
index 506fd8df6d..a42408890b 100644
--- a/src/qml/jit/qv4regalloc.cpp
+++ b/src/qml/jit/qv4regalloc.cpp
@@ -97,8 +97,8 @@ public:
void collect(IR::Function *function)
{
- foreach (BasicBlock *bb, function->basicBlocks) {
- foreach (Stmt *s, bb->statements) {
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ foreach (Stmt *s, bb->statements()) {
Q_ASSERT(s->id > 0);
_currentStmt = s;
s->accept(this);
@@ -705,8 +705,8 @@ public:
for (int i = 0, ei = _intervals.size(); i != ei; ++i)
_unprocessed[i] = &_intervals[i];
- _liveAtStart.reserve(function->basicBlocks.size());
- _liveAtEnd.reserve(function->basicBlocks.size());
+ _liveAtStart.reserve(function->basicBlockCount());
+ _liveAtEnd.reserve(function->basicBlockCount());
}
void run() {
@@ -718,13 +718,14 @@ public:
private:
void renumber()
{
- foreach (BasicBlock *bb, _function->basicBlocks) {
+ foreach (BasicBlock *bb, _function->basicBlocks()) {
+ QVector<Stmt *> statements = bb->statements();
QVector<Stmt *> newStatements;
- newStatements.reserve(bb->statements.size() + 7);
+ newStatements.reserve(bb->statements().size() + 7);
bool seenFirstNonPhiStmt = false;
- for (int i = 0, ei = bb->statements.size(); i != ei; ++i) {
- _currentStmt = bb->statements[i];
+ for (int i = 0, ei = statements.size(); i != ei; ++i) {
+ _currentStmt = statements[i];
_loads.clear();
_stores.clear();
addNewIntervals();
@@ -766,7 +767,7 @@ private:
}
#endif
- bb->statements = newStatements;
+ bb->setStatements(newStatements);
}
}
@@ -833,7 +834,7 @@ private:
void resolve()
{
- foreach (BasicBlock *bb, _function->basicBlocks) {
+ foreach (BasicBlock *bb, _function->basicBlocks()) {
foreach (BasicBlock *bbOut, bb->out)
resolveEdge(bb, bbOut);
}
@@ -848,11 +849,11 @@ private:
MoveMapping mapping;
- const int predecessorEnd = predecessor->statements.last()->id; // the terminator is always last and always has an id set...
+ const int predecessorEnd = predecessor->terminator()->id; // the terminator is always last and always has an id set...
Q_ASSERT(predecessorEnd > 0); // ... but we verify it anyway for good measure.
int successorStart = -1;
- foreach (Stmt *s, successor->statements) {
+ foreach (Stmt *s, successor->statements()) {
if (s && s->id > 0) {
successorStart = s->id;
break;
@@ -869,7 +870,7 @@ private:
Expr *moveFrom = 0;
if (it->start() == successorStart) {
- foreach (Stmt *s, successor->statements) {
+ foreach (Stmt *s, successor->statements()) {
if (!s || s->id < 1)
continue;
if (Phi *phi = s->asPhi()) {
@@ -925,14 +926,14 @@ private:
Q_ASSERT(!_info->isPhiTarget(it->temp()) || it->isSplitFromInterval() || lifeTimeHole);
if (_info->def(it->temp()) != successorStart && !it->isSplitFromInterval()) {
- const int successorEnd = successor->statements.last()->id;
+ const int successorEnd = successor->terminator()->id;
const int idx = successor->in.indexOf(predecessor);
foreach (const Use &use, _info->uses(it->temp())) {
if (use.pos == static_cast<unsigned>(successorStart)) {
// only check the current edge, not all other possible ones. This is
// important for phi nodes: they have uses that are only valid when
// coming in over a specific edge.
- foreach (Stmt *s, successor->statements) {
+ foreach (Stmt *s, successor->statements()) {
if (Phi *phi = s->asPhi()) {
Q_ASSERT(it->temp().index != phi->targetTemp->index);
Q_ASSERT(phi->d->incoming[idx]->asTemp() == 0