diff options
-rw-r--r-- | src/qml/compiler/qqmltypecompiler.cpp | 10 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 10 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen_p.h | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth.cpp | 11 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_util_p.h | 6 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir.cpp | 169 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir_p.h | 302 | ||||
-rw-r--r-- | src/qml/compiler/qv4ssa.cpp | 513 | ||||
-rw-r--r-- | src/qml/compiler/qv4ssa_p.h | 7 | ||||
-rw-r--r-- | src/qml/jit/qv4isel_masm.cpp | 10 | ||||
-rw-r--r-- | src/qml/jit/qv4regalloc.cpp | 31 |
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 |