From 5efbd7165d6867aa376f23c20edcfe49e80518c6 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 11 May 2017 10:09:12 +0200 Subject: Change temp allocation when generating IR For functions that won't get optimized, it's useful to limit the number of temporaries as much as possible. Change-Id: I6e9be3129c064fdc4c01e1ec6f1617e901c05935 Reviewed-by: Erik Verbruggen Reviewed-by: Simon Hausmann --- src/qml/compiler/qqmlirbuilder.cpp | 3 +- src/qml/compiler/qv4codegen.cpp | 172 ++++++++++++++++++++++++++----------- src/qml/compiler/qv4codegen_p.h | 12 ++- src/qml/compiler/qv4jsir_p.h | 18 +++- src/qml/compiler/qv4ssa.cpp | 6 +- 5 files changed, 155 insertions(+), 56 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 16eee50cf9..57cb4c607c 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1948,7 +1948,8 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int QQmlTypeNameCache::Result r = imports->query(name); if (r.isValid()) { if (r.scriptIndex != -1) { - return subscript(_block->TEMP(_importedScriptsTemp), _block->CONST(QV4::IR::SInt32Type, r.scriptIndex)); + return _block->SUBSCRIPT(_block->TEMP(_importedScriptsTemp), + _block->CONST(QV4::IR::SInt32Type, r.scriptIndex)); } else if (r.type) { QV4::IR::Name *typeName = _block->NAME(name, line, col); // Make sure the run-time loads this through the more efficient singleton getter. diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index fcfbdfa74b..1e98d1167b 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -113,6 +113,18 @@ static inline void setJumpOutLocation(IR::Stmt *s, const Statement *body, } } +static inline bool isSimpleExpr(IR::Expr *e) +{ + switch (e->exprKind) { + case IR::Expr::TempExpr: + case IR::Expr::ArgLocalExpr: + case IR::Expr::ConstExpr: + return true; + default: + return false; + } +} + Codegen::ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode, CompilationMode defaultProgramMode) : _cg(cg) , _sourceCode(sourceCode) @@ -561,28 +573,6 @@ IR::Expr *Codegen::member(IR::Expr *base, const QString *name) } } -IR::Expr *Codegen::subscript(IR::Expr *base, IR::Expr *index) -{ - if (hasError) - return 0; - - if (! base->asTemp() && !base->asArgLocal()) { - const unsigned t = _block->newTemp(); - move(_block->TEMP(t), base); - base = _block->TEMP(t); - } - - if (! index->asTemp() && !index->asArgLocal() && !index->asConst()) { - const unsigned t = _block->newTemp(); - move(_block->TEMP(t), index); - index = _block->TEMP(t); - } - - Q_ASSERT(base->asTemp() || base->asArgLocal()); - Q_ASSERT(index->asTemp() || index->asArgLocal() || index->asConst()); - return _block->SUBSCRIPT(base, index); -} - IR::Expr *Codegen::argument(IR::Expr *expr) { if (expr && !expr->asTemp()) { @@ -635,12 +625,14 @@ IR::Expr *Codegen::unop(IR::AluOp op, IR::Expr *expr, const SourceLocation &loc) } } } - if (!expr->asTemp() && !expr->asArgLocal()) { - const unsigned t = _block->newTemp(); - setLocation(move(_block->TEMP(t), expr), loc); - expr = _block->TEMP(t); - } - Q_ASSERT(expr->asTemp() || expr->asArgLocal()); + + TempScope scope(_function); + if (isSimpleExpr(expr)) + return _block->UNOP(op, expr); + + const unsigned t = _block->newTemp(); + setLocation(move(_block->TEMP(t), expr), loc); + expr = _block->TEMP(t); return _block->UNOP(op, expr); } @@ -649,6 +641,8 @@ IR::Expr *Codegen::binop(IR::AluOp op, IR::Expr *left, IR::Expr *right, const AS if (hasError) return 0; + TempScope scope(_function); + if (IR::Const *c1 = left->asConst()) { if (IR::Const *c2 = right->asConst()) { if ((c1->type & IR::NumberType) && (c2->type & IR::NumberType)) { @@ -736,6 +730,8 @@ IR::Stmt *Codegen::move(IR::Expr *target, IR::Expr *source, IR::AluOp op) return move(target, binop(op, target, source)); } + TempScope scope(_function); + if (!source->asTemp() && !source->asConst() && !target->asTemp() && !source->asArgLocal() && !target->asArgLocal()) { unsigned t = _block->newTemp(); _block->MOVE(_block->TEMP(t), source); @@ -755,6 +751,8 @@ IR::Stmt *Codegen::cjump(IR::Expr *cond, IR::BasicBlock *iftrue, IR::BasicBlock if (hasError) return 0; + TempScope scope(_function); + if (! (cond->asTemp() || (cond->asBinop() && cjumpCanHandle(cond->asBinop()->op)) )) { const unsigned t = _block->newTemp(); move(_block->TEMP(t), cond); @@ -774,12 +772,16 @@ void Codegen::accept(Node *node) void Codegen::statement(Statement *ast) { + TempScope scope(_function); + _block->nextLocation = ast->firstSourceLocation(); accept(ast); } void Codegen::statement(ExpressionNode *ast) { + TempScope scope(_function); + if (! ast) { return; } else { @@ -888,6 +890,7 @@ void Codegen::variableDeclaration(VariableDeclaration *ast) if (lhs->asArgLocal()) { move(lhs, initializer); } else { + TempScope scope(_function); int initialized = _block->newTemp(); move(_block->TEMP(initialized), initializer); move(lhs, _block->TEMP(initialized)); @@ -1091,6 +1094,10 @@ bool Codegen::visit(ArrayLiteral *ast) if (hasError) return false; + const unsigned t = _block->newTemp(); + + TempScope scope(_function); + IR::ExprList *args = 0; IR::ExprList *current = 0; for (ElementList *it = ast->elements; it; it = it->next) { @@ -1136,7 +1143,6 @@ bool Codegen::visit(ArrayLiteral *ast) current->expr = _block->CONST(IR::MissingType, 0); } - const unsigned t = _block->newTemp(); move(_block->TEMP(t), _block->CALL(_block->NAME(IR::Name::builtin_define_array, 0, 0), args)); _expr.code = _block->TEMP(t); return false; @@ -1147,11 +1153,25 @@ bool Codegen::visit(ArrayMemberExpression *ast) if (hasError) return false; - Result base = expression(ast->base); - Result index = expression(ast->expression); + IR::Expr *base = *expression(ast->base); + if (hasError) + return false; + if (!isSimpleExpr(base)) { + const unsigned t = _block->newTemp(); + move(_block->TEMP(t), base); + base = _block->TEMP(t); + } + + IR::Expr *index = *expression(ast->expression); if (hasError) return false; - _expr.code = subscript(*base, *index); + if (!isSimpleExpr(index)) { + const unsigned t = _block->newTemp(); + move(_block->TEMP(t), index); + index = _block->TEMP(t); + } + + _expr.code = _block->SUBSCRIPT(base, index); return false; } @@ -1287,14 +1307,12 @@ bool Codegen::visit(BinaryExpression *ast) return false; } - if (_expr.accept(nx)) { - move(left, *right, baseOp(ast->op)); - } else { - const unsigned t = _block->newTemp(); - move(_block->TEMP(t), *right); - move(left, _block->TEMP(t), baseOp(ast->op)); + TempScope scope(_function); + const unsigned t = _block->newTemp(); + move(_block->TEMP(t), *right); + move(left, _block->TEMP(t), baseOp(ast->op)); + if (!_expr.accept(nx)) _expr.code = left; - } break; } @@ -1308,6 +1326,7 @@ bool Codegen::visit(BinaryExpression *ast) case QSOperator::Lt: case QSOperator::StrictEqual: case QSOperator::StrictNotEqual: { + TempScope scope(_function); if (!left->asTemp() && !left->asArgLocal() && !left->asConst()) { const unsigned t = _block->newTemp(); setLocation(move(_block->TEMP(t), left), ast->operatorToken); @@ -1337,6 +1356,7 @@ bool Codegen::visit(BinaryExpression *ast) case QSOperator::RShift: case QSOperator::Sub: case QSOperator::URShift: { + TempScope scope(_function); if (!left->asTemp() && !left->asArgLocal() && !left->asConst()) { const unsigned t = _block->newTemp(); setLocation(move(_block->TEMP(t), left), ast->operatorToken); @@ -1388,6 +1408,7 @@ bool Codegen::visit(ConditionalExpression *ast) IR::BasicBlock *endif = _function->newBasicBlock(exceptionHandler()); const unsigned t = _block->newTemp(); + TempScope scope(_function); condition(ast->expression, iftrue, iffalse); @@ -1491,6 +1512,8 @@ bool Codegen::visit(FunctionExpression *ast) if (hasError) return false; + TempScope scope(_function); + int function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body ? ast->body->elements : 0); _expr.code = _block->CLOSURE(function); return false; @@ -1571,6 +1594,7 @@ bool Codegen::visit(NewExpression *ast) { if (hasError) return false; + TempScope scope(_function); Result base = expression(ast->expression); if (hasError) @@ -1590,6 +1614,10 @@ bool Codegen::visit(NewMemberExpression *ast) if (hasError) return false; + const unsigned t = _block->newTemp(); + + TempScope scope(_function); + Result base = expression(ast->base); if (hasError) return false; @@ -1610,7 +1638,6 @@ bool Codegen::visit(NewMemberExpression *ast) (*args_it)->init(actual); args_it = &(*args_it)->next; } - const unsigned t = _block->newTemp(); move(_block->TEMP(t), _block->NEW(expr, args)); _expr.code = _block->TEMP(t); return false; @@ -1621,10 +1648,12 @@ bool Codegen::visit(NotExpression *ast) if (hasError) return false; + const unsigned r = _block->newTemp(); + TempScope scope(_function); + Result expr = expression(ast->expression); if (hasError) return false; - const unsigned r = _block->newTemp(); setLocation(move(_block->TEMP(r), unop(IR::OpNot, *expr, ast->notToken)), ast->notToken); _expr.code = _block->TEMP(r); return false; @@ -1677,6 +1706,9 @@ bool Codegen::visit(ObjectLiteral *ast) QMap valueMap; + const unsigned t = _block->newTemp(); + TempScope scope(_function); + for (PropertyAssignmentList *it = ast->properties; it; it = it->next) { QString name = it->assignment->name->asString(); if (PropertyNameAndValue *nv = AST::cast(it->assignment)) { @@ -1690,7 +1722,13 @@ bool Codegen::visit(ObjectLiteral *ast) return false; } - valueMap[name].value = *value; + if (IR::Const *c = (*value)->asConst()) { + valueMap[name].value = c; + } else { + unsigned t = _block->newTemp(); + move(_block->TEMP(t), *value); + valueMap[name].value = _block->TEMP(t); + } } else if (PropertyGetterSetter *gs = AST::cast(it->assignment)) { const int function = defineFunction(name, gs, gs->formals, gs->functionBody ? gs->functionBody->elements : 0); ObjectPropertyValue &v = valueMap[name]; @@ -1761,12 +1799,9 @@ bool Codegen::visit(ObjectLiteral *ast) current = current->next; current->expr = _block->CONST(IR::BoolType, true); - unsigned value = _block->newTemp(); - move(_block->TEMP(value), it->value); - current->next = _function->New(); current = current->next; - current->expr = _block->TEMP(value); + current->expr = it->value; } else { current->next = _function->New(); current = current->next; @@ -1799,7 +1834,6 @@ bool Codegen::visit(ObjectLiteral *ast) args->next = arrayEntries; } - const unsigned t = _block->newTemp(); move(_block->TEMP(t), _block->CALL(_block->NAME(IR::Name::builtin_define_object_literal, ast->firstSourceLocation().startLine, ast->firstSourceLocation().startColumn), args)); @@ -1825,6 +1859,7 @@ bool Codegen::visit(PostDecrementExpression *ast) const unsigned oldValue = _block->newTemp(); setLocation(move(_block->TEMP(oldValue), unop(IR::OpUPlus, *expr, ast->decrementToken)), ast->decrementToken); + TempScope scope(_function); const unsigned newValue = _block->newTemp(); setLocation(move(_block->TEMP(newValue), binop(IR::OpSub, _block->TEMP(oldValue), _block->CONST(IR::NumberType, 1), ast->decrementToken)), ast->decrementToken); setLocation(move(*expr, _block->TEMP(newValue)), ast->decrementToken); @@ -1853,6 +1888,7 @@ bool Codegen::visit(PostIncrementExpression *ast) const unsigned oldValue = _block->newTemp(); setLocation(move(_block->TEMP(oldValue), unop(IR::OpUPlus, *expr, ast->incrementToken)), ast->incrementToken); + TempScope scope(_function); const unsigned newValue = _block->newTemp(); setLocation(move(_block->TEMP(newValue), binop(IR::OpAdd, _block->TEMP(oldValue), _block->CONST(IR::NumberType, 1), ast->incrementToken)), ast->incrementToken); setLocation(move(*expr, _block->TEMP(newValue)), ast->incrementToken); @@ -1949,10 +1985,12 @@ bool Codegen::visit(TildeExpression *ast) if (hasError) return false; + const unsigned t = _block->newTemp(); + TempScope scope(_function); + Result expr = expression(ast->expression); if (hasError) return false; - const unsigned t = _block->newTemp(); setLocation(move(_block->TEMP(t), unop(IR::OpCompl, *expr, ast->tildeToken)), ast->tildeToken); _expr.code = _block->TEMP(t); return false; @@ -1976,6 +2014,8 @@ bool Codegen::visit(TypeOfExpression *ast) if (hasError) return false; + TempScope scope(_function); + Result expr = expression(ast->expression); if (hasError) return false; @@ -2018,6 +2058,8 @@ bool Codegen::visit(VoidExpression *ast) if (hasError) return false; + TempScope scope(_function); + statement(ast->expression); _expr.code = _block->CONST(IR::UndefinedType, 0); return false; @@ -2028,6 +2070,8 @@ bool Codegen::visit(FunctionDeclaration * ast) if (hasError) return false; + TempScope scope(_function); + if (_env->compilationMode == QmlBinding) move(_block->TEMP(_returnAddress), _block->NAME(ast->name.toString(), 0, 0)); _expr.accept(nx); @@ -2190,6 +2234,8 @@ bool Codegen::visit(Block *ast) if (hasError) return false; + TempScope scope(_function); + for (StatementList *it = ast->statements; it; it = it->next) { statement(it->statement); } @@ -2201,6 +2247,8 @@ bool Codegen::visit(BreakStatement *ast) if (hasError) return false; + TempScope scope(_function); + if (!_loop) { throwSyntaxError(ast->lastSourceLocation(), QStringLiteral("Break outside of loop")); return false; @@ -2228,6 +2276,8 @@ bool Codegen::visit(ContinueStatement *ast) if (hasError) return false; + TempScope scope(_function); + Loop *loop = 0; if (ast->label.isEmpty()) { for (loop = _loop; loop; loop = loop->parent) { @@ -2267,6 +2317,8 @@ bool Codegen::visit(DoWhileStatement *ast) if (hasError) return true; + TempScope scope(_function); + IR::BasicBlock *loopbody = _function->newBasicBlock(exceptionHandler()); IR::BasicBlock *loopcond = _function->newBasicBlock(exceptionHandler()); IR::BasicBlock *loopend = _function->newBasicBlock(exceptionHandler()); @@ -2302,6 +2354,8 @@ bool Codegen::visit(ExpressionStatement *ast) if (hasError) return true; + TempScope scope(_function); + if (_env->compilationMode == EvalCode || _env->compilationMode == QmlBinding) { Result e = expression(ast->expression); if (*e) @@ -2317,6 +2371,8 @@ bool Codegen::visit(ForEachStatement *ast) if (hasError) return true; + TempScope scope(_function); + IR::BasicBlock *foreachin = _function->newBasicBlock(exceptionHandler()); IR::BasicBlock *foreachbody = _function->newBasicBlock(exceptionHandler()); IR::BasicBlock *foreachend = _function->newBasicBlock(exceptionHandler()); @@ -2363,6 +2419,8 @@ bool Codegen::visit(ForStatement *ast) if (hasError) return true; + TempScope scope(_function); + IR::BasicBlock *forcond = _function->newBasicBlock(exceptionHandler()); IR::BasicBlock *forbody = _function->newBasicBlock(exceptionHandler()); IR::BasicBlock *forstep = _function->newBasicBlock(exceptionHandler()); @@ -2399,6 +2457,8 @@ bool Codegen::visit(IfStatement *ast) if (hasError) return true; + TempScope scope(_function); + IR::BasicBlock *iftrue = _function->newBasicBlock(exceptionHandler()); IR::BasicBlock *iffalse = ast->ko ? _function->newBasicBlock(exceptionHandler()) : 0; IR::BasicBlock *endif = _function->newBasicBlock(exceptionHandler()); @@ -2425,6 +2485,8 @@ bool Codegen::visit(LabelledStatement *ast) if (hasError) return true; + TempScope scope(_function); + // check that no outer loop contains the label Loop *l = _loop; while (l) { @@ -2462,6 +2524,8 @@ bool Codegen::visit(LocalForEachStatement *ast) if (hasError) return true; + TempScope scope(_function); + IR::BasicBlock *foreachin = _function->newBasicBlock(exceptionHandler()); IR::BasicBlock *foreachbody = _function->newBasicBlock(exceptionHandler()); IR::BasicBlock *foreachend = _function->newBasicBlock(exceptionHandler()); @@ -2502,6 +2566,8 @@ bool Codegen::visit(LocalForStatement *ast) if (hasError) return true; + TempScope scope(_function); + IR::BasicBlock *forcond = _function->newBasicBlock(exceptionHandler()); IR::BasicBlock *forbody = _function->newBasicBlock(exceptionHandler()); IR::BasicBlock *forstep = _function->newBasicBlock(exceptionHandler()); @@ -2564,6 +2630,8 @@ bool Codegen::visit(SwitchStatement *ast) if (hasError) return true; + TempScope scope(_function); + IR::BasicBlock *switchend = _function->newBasicBlock(exceptionHandler()); if (ast->block) { @@ -2659,6 +2727,8 @@ bool Codegen::visit(ThrowStatement *ast) if (hasError) return true; + TempScope scope(_function); + Result expr = expression(ast->expression); move(_block->TEMP(_returnAddress), *expr); IR::ExprList *throwArgs = _function->New(); @@ -2672,6 +2742,8 @@ bool Codegen::visit(TryStatement *ast) if (hasError) return true; + TempScope scope(_function); + _function->hasTry = true; if (_function->isStrict && ast->catchExpression && @@ -2750,6 +2822,8 @@ bool Codegen::visit(TryStatement *ast) _function->addBasicBlock(finallyBody); _block = finallyBody; + TempScope scope(_function); + int hasException = _block->newTemp(); move(_block->TEMP(hasException), _block->CALL(_block->NAME(IR::Name::builtin_unwind_exception, /*line*/0, /*column*/0), 0)); @@ -2834,6 +2908,8 @@ bool Codegen::visit(WithStatement *ast) if (hasError) return true; + TempScope scope(_function); + _function->hasWith = true; const int withObject = _block->newTemp(); diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index 742ee79648..1cbe6949a1 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -231,6 +231,17 @@ protected: } }; + struct TempScope { + TempScope(QV4::IR::Function *f) + : function(f), + tempCountForScope(f->currentTemp) {} + ~TempScope() { + function->currentTemp = tempCountForScope; + } + QV4::IR::Function *function; + int tempCountForScope; + }; + Environment *newEnvironment(AST::Node *node, Environment *parent, CompilationMode compilationMode) { Environment *env = new Environment(parent, compilationMode); @@ -293,7 +304,6 @@ protected: } QV4::IR::Expr *member(QV4::IR::Expr *base, const QString *name); - QV4::IR::Expr *subscript(QV4::IR::Expr *base, QV4::IR::Expr *index); QV4::IR::Expr *argument(QV4::IR::Expr *expr); QV4::IR::Expr *reference(QV4::IR::Expr *expr); QV4::IR::Expr *unop(QV4::IR::AluOp op, QV4::IR::Expr *expr, const AST::SourceLocation &loc = AST::SourceLocation()); diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index caab9c0f9e..6f14e3dfaf 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -1113,7 +1113,11 @@ public: return false; } - unsigned newTemp(); + enum TempForWhom { + NewTempForCodegen, + NewTempForOptimizer + }; + unsigned newTemp(TempForWhom tfw = NewTempForCodegen); Temp *TEMP(unsigned kind); ArgLocal *ARG(unsigned index, unsigned scope); @@ -1278,6 +1282,7 @@ struct Function { Module *module; QQmlJS::MemoryPool *pool; const QString *name; + int currentTemp = 0; int tempCount; int maxNumberOfArguments; QSet strings; @@ -1485,10 +1490,17 @@ protected: BasicBlock *currentBB; }; -inline unsigned BasicBlock::newTemp() +inline unsigned BasicBlock::newTemp(TempForWhom tfw) { Q_ASSERT(!isRemoved()); - return function->tempCount++; + + if (tfw == NewTempForOptimizer) + return function->tempCount++; + + int t = function->currentTemp++; + if (function->tempCount < function->currentTemp) + function->tempCount = function->currentTemp; + return t; } inline Temp *BasicBlock::TEMP(unsigned index) diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index fc136b09ff..8cf5fac760 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -2770,7 +2770,7 @@ public: } else if (Const *c = (*conversion.expr)->asConst()) { convertConst(c, conversion.targetType); } else if (ArgLocal *al = (*conversion.expr)->asArgLocal()) { - Temp *target = bb->TEMP(bb->newTemp()); + Temp *target = bb->TEMP(bb->newTemp(BasicBlock::NewTempForOptimizer)); target->type = conversion.targetType; Expr *convert = bb->CONVERT(al, conversion.targetType); Move *convCall = f->NewStmt(); @@ -2791,7 +2791,7 @@ public: *conversion.expr = source; } else if (Temp *t = (*conversion.expr)->asTemp()) { - Temp *target = bb->TEMP(bb->newTemp()); + Temp *target = bb->TEMP(bb->newTemp(BasicBlock::NewTempForOptimizer)); target->type = conversion.targetType; Expr *convert = bb->CONVERT(t, conversion.targetType); Move *convCall = f->NewStmt(); @@ -2820,7 +2820,7 @@ public: // to: // double{%3} = double{-double{%1}}; // int32{%2} = int32{convert(double{%3})}; - Temp *tmp = bb->TEMP(bb->newTemp()); + Temp *tmp = bb->TEMP(bb->newTemp(BasicBlock::NewTempForOptimizer)); tmp->type = u->type; Move *extraMove = f->NewStmt(); worklist.registerNewStatement(extraMove); -- cgit v1.2.3