V4 IR: change IR printing to be more readable.
authorErik Verbruggen <erik.verbruggen@digia.com>
Tue, 5 Aug 2014 12:11:16 +0000 (14:11 +0200)
committerErik Verbruggen <erik.verbruggen@digia.com>
Wed, 13 Aug 2014 10:53:19 +0000 (12:53 +0200)
New structure:
- "comments" now start with a semi-colon, and have a list of key: values.
    ; predecessors: L17 L26 L36, loop_header: yes
    ; line: 30, column: 3

- when a temporary has a known type, it is written in front of the
  teporary when it is being assigned, and not repeated.
    var %109 = this
    double %42 = 42

- an expression starts with the operation, followed by the operands that
  are separated by commas. The type of the operands is the type
  mentioned when they are assigned.
    int32 %115 = sub %184, %185
    if gt %27, 0 goto L40 else goto L41

- conversions do mention the operand type in order to make them easier
  to read.
    double %178 = convert var to double %60

- phi node operands are prefixed by the from-label to make it easy to
  match those operands with the from-block.
    double %62 = phi L35: %58, L34: %61

- all names except for "this" and built-ins are prefixed by a dot in
  order to make it clear that a lookup will occur, just like member
  accesses.
    $6 = call .int2char($0)
    %7 = this
    %8 = %7.toString()

Change-Id: I9f626a91f97ca7c3f27e01a5539f3c4fc10a46b4
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
src/qml/compiler/qv4jsir.cpp
src/qml/compiler/qv4jsir_p.h
src/qml/compiler/qv4ssa.cpp
src/qml/jit/qv4regalloc.cpp

index 4b26ff2..36fb66b 100644 (file)
@@ -86,41 +86,41 @@ const char *opname(AluOp op)
     case OpInvalid: return "?";
 
     case OpIfTrue: return "(bool)";
-    case OpNot: return "!";
-    case OpUMinus: return "-";
-    case OpUPlus: return "+";
-    case OpCompl: return "~";
-    case OpIncrement: return "++";
-    case OpDecrement: return "--";
-
-    case OpBitAnd: return "&";
-    case OpBitOr: return "|";
-    case OpBitXor: return "^";
-
-    case OpAdd: return "+";
-    case OpSub: return "-";
-    case OpMul: return "*";
-    case OpDiv: return "/";
-    case OpMod: return "%";
-
-    case OpLShift: return "<<";
-    case OpRShift: return ">>";
-    case OpURShift: return ">>>";
-
-    case OpGt: return ">";
-    case OpLt: return "<";
-    case OpGe: return ">=";
-    case OpLe: return "<=";
-    case OpEqual: return "==";
-    case OpNotEqual: return "!=";
-    case OpStrictEqual: return "===";
-    case OpStrictNotEqual: return "!==";
+    case OpNot: return "not";
+    case OpUMinus: return "neg";
+    case OpUPlus: return "plus";
+    case OpCompl: return "invert";
+    case OpIncrement: return "incr";
+    case OpDecrement: return "decr";
+
+    case OpBitAnd: return "bitand";
+    case OpBitOr: return "bitor";
+    case OpBitXor: return "bitxor";
+
+    case OpAdd: return "add";
+    case OpSub: return "sub";
+    case OpMul: return "mul";
+    case OpDiv: return "div";
+    case OpMod: return "mod";
+
+    case OpLShift: return "shl";
+    case OpRShift: return "shr";
+    case OpURShift: return "asr";
+
+    case OpGt: return "gt";
+    case OpLt: return "lt";
+    case OpGe: return "ge";
+    case OpLe: return "le";
+    case OpEqual: return "eq";
+    case OpNotEqual: return "ne";
+    case OpStrictEqual: return "se";
+    case OpStrictNotEqual: return "sne";
 
     case OpInstanceof: return "instanceof";
     case OpIn: return "in";
 
-    case OpAnd: return "&&";
-    case OpOr: return "||";
+    case OpAnd: return "and";
+    case OpOr: return "or";
 
     default: return "?";
 
@@ -311,7 +311,7 @@ void Name::init(Builtin builtin, quint32 line, quint32 column)
     this->column = column;
 }
 
-static const char *builtin_to_string(Name::Builtin b)
+const char *builtin_to_string(Name::Builtin b)
 {
     switch (b) {
     case Name::builtin_invalid:
@@ -494,6 +494,26 @@ void Function::renumberBasicBlocks()
         basicBlock(i)->changeIndex(i);
 }
 
+BasicBlock *Function::getOrCreateBasicBlock(int index)
+{
+    if (_basicBlocks.size() <= index) {
+        const int oldSize = _basicBlocks.size();
+        _basicBlocks.resize(index + 1);
+        for (int i = oldSize; i <= index; ++i) {
+            BasicBlock *block = new BasicBlock(this, 0);
+            block->setIndex(i);
+            _basicBlocks[i] = block;
+        }
+    }
+
+    return _basicBlocks.at(index);
+}
+
+void Function::setStatementCount(int cnt)
+{
+    _statementCount = cnt;
+}
+
 BasicBlock::~BasicBlock()
 {
     foreach (Stmt *s, _statements)
@@ -760,7 +780,7 @@ void BasicBlock::setStatements(const QVector<Stmt *> &newStatements)
 void BasicBlock::appendStatement(Stmt *statement)
 {
     Q_ASSERT(!isRemoved());
-    if (nextLocation.isValid())
+    if (nextLocation.startLine)
         statement->location = nextLocation;
     _statements.append(statement);
 }
@@ -912,7 +932,8 @@ void CloneExpr::visitMember(Member *e)
 
 IRPrinter::IRPrinter(QTextStream *out)
     : out(out)
-    , printElse(true)
+    , positionSize(Stmt::InvalidId)
+    , currentBB(0)
 {
 }
 
@@ -937,6 +958,9 @@ void IRPrinter::print(Expr *e)
 
 void IRPrinter::print(Function *f)
 {
+    if (positionSize == Stmt::InvalidId)
+        positionSize = QString::number(f->statementCount()).size();
+
     QString n = f->name ? *f->name : QString();
     if (n.isEmpty())
         n.sprintf("%p", f);
@@ -951,21 +975,28 @@ void IRPrinter::print(Function *f)
         << '{' << endl;
 
     foreach (const QString *local, f->locals)
-        *out << "    var " << *local << ';' << endl;
+        *out << "    local var " << *local << endl;
 
-    foreach (BasicBlock *bb, f->basicBlocks())
-        if (!bb->isRemoved())
-            print(bb);
+    bool needsSeperator = !f->locals.isEmpty();
+    foreach (BasicBlock *bb, f->basicBlocks()) {
+        if (bb->isRemoved())
+            continue;
+
+        if (needsSeperator)
+            *out << endl;
+        else
+            needsSeperator = true;
+        print(bb);
+    }
     *out << '}' << endl;
 }
 
 void IRPrinter::print(BasicBlock *bb)
 {
-    bool prevPrintElse = false;
-    std::swap(printElse, prevPrintElse);
-    printBlockStart(bb);
+    std::swap(currentBB, bb);
+    printBlockStart();
 
-    foreach (Stmt *s, bb->statements()) {
+    foreach (Stmt *s, currentBB->statements()) {
         QByteArray str;
         QBuffer buf(&str);
         buf.open(QIODevice::WriteOnly);
@@ -974,36 +1005,34 @@ void IRPrinter::print(BasicBlock *bb)
         std::swap(out, prevOut);
         addStmtNr(s);
         s->accept(this);
-        if (s->location.isValid()) {
+        if (s->location.startLine) {
             out->flush();
             for (int i = 58 - str.length(); i > 0; --i)
                 *out << ' ';
-            *out << "    // line: " << s->location.startLine << " column: " << s->location.startColumn;
+            *out << "    ; line: " << s->location.startLine << ", column: " << s->location.startColumn;
         }
 
         out->flush();
         std::swap(out, prevOut);
 
-        *out << "    " << str;
-        *out << endl;
-
-        if (s->asCJump()) {
-            *out << "    else goto L" << s->asCJump()->iffalse->index() << ";" << endl;
-        }
+        *out << "    " << str << endl;
     }
 
-    std::swap(printElse, prevPrintElse);
+    std::swap(currentBB, bb);
 }
 
 void IRPrinter::visitExp(Exp *s)
 {
-    *out << "(void) ";
+    *out << "void ";
     s->expr->accept(this);
-    *out << ';';
 }
 
 void IRPrinter::visitMove(Move *s)
 {
+    if (Temp *targetTemp = s->target->asTemp())
+        if (!s->swap && targetTemp->type != UnknownType)
+            *out << typeName(targetTemp->type) << ' ';
+
     s->target->accept(this);
     *out << ' ';
     if (s->swap)
@@ -1011,21 +1040,19 @@ void IRPrinter::visitMove(Move *s)
     else
         *out << "= ";
     s->source->accept(this);
-    *out << ';';
 }
 
 void IRPrinter::visitJump(Jump *s)
 {
-    *out << "goto L" << s->target->index() << ';';
+    *out << "goto L" << s->target->index();
 }
 
 void IRPrinter::visitCJump(CJump *s)
 {
-    *out << "if (";
+    *out << "if ";
     s->cond->accept(this);
-    *out << ") goto L" << s->iftrue->index() << ';';
-    if (printElse)
-        *out << " else goto L" << s->iffalse->index() << ';';
+    *out << " goto L" << s->iftrue->index()
+         << " else goto L" << s->iffalse->index();
 }
 
 void IRPrinter::visitRet(Ret *s)
@@ -1035,26 +1062,27 @@ void IRPrinter::visitRet(Ret *s)
         *out << ' ';
         s->expr->accept(this);
     }
-    *out << ';';
 }
 
 void IRPrinter::visitPhi(Phi *s)
 {
+    if (s->targetTemp->type != UnknownType)
+        *out << typeName(s->targetTemp->type) << ' ';
+
     s->targetTemp->accept(this);
-    *out << " = phi(";
+    *out << " = phi ";
     for (int i = 0, ei = s->d->incoming.size(); i < ei; ++i) {
         if (i > 0)
             *out << ", ";
+        if (currentBB)
+            *out << 'L' << currentBB->in.at(i)->index() << ": ";
         if (s->d->incoming[i])
             s->d->incoming[i]->accept(this);
     }
-    *out << ");";
 }
 
 void IRPrinter::visitConst(Const *e)
 {
-    if (e->type != UndefinedType && e->type != NullType)
-        *out << dumpStart(e);
     switch (e->type) {
     case QV4::IR::UndefinedType:
         *out << "undefined";
@@ -1079,8 +1107,6 @@ void IRPrinter::visitConst(Const *e)
         }
         break;
     }
-    if (e->type != UndefinedType && e->type != NullType)
-        *out << dumpEnd(e);
 }
 
 void IRPrinter::visitString(String *e)
@@ -1105,15 +1131,17 @@ void IRPrinter::visitRegExp(RegExp *e)
 
 void IRPrinter::visitName(Name *e)
 {
-    if (e->id)
+    if (e->id) {
+        if (*e->id != QStringLiteral("this"))
+            *out << '.';
         *out << *e->id;
-    else
+    } else {
         *out << builtin_to_string(e->builtin);
+    }
 }
 
 void IRPrinter::visitTemp(Temp *e)
 {
-    *out << dumpStart(e);
     switch (e->kind) {
     case Temp::VirtualRegister:  *out << '%' << e->index; break;
     case Temp::PhysicalRegister: *out << (e->type == DoubleType ? "fp" : "r")
@@ -1121,12 +1149,10 @@ void IRPrinter::visitTemp(Temp *e)
     case Temp::StackSlot:        *out << '&' << e->index; break;
     default:                     *out << "INVALID";
     }
-    *out << dumpEnd(e);
 }
 
 void IRPrinter::visitArgLocal(ArgLocal *e)
 {
-    *out << dumpStart(e);
     switch (e->kind) {
     case ArgLocal::Formal:           *out << '#' << e->index; break;
     case ArgLocal::ScopedFormal:     *out << '#' << e->index
@@ -1136,7 +1162,6 @@ void IRPrinter::visitArgLocal(ArgLocal *e)
                                      << '@' << e->scope; break;
     default:                     *out << "INVALID";
     }
-    *out << dumpEnd(e);
 }
 
 void IRPrinter::visitClosure(Closure *e)
@@ -1144,35 +1169,32 @@ void IRPrinter::visitClosure(Closure *e)
     QString name = e->functionName ? *e->functionName : QString();
     if (name.isEmpty())
         name.sprintf("%x", e->value);
-    *out << "closure(" << name << ')';
+    *out << "closure " << name;
 }
 
 void IRPrinter::visitConvert(Convert *e)
 {
-    *out << dumpStart(e);
-    *out << "convert(";
+    *out << "convert " << typeName(e->expr->type) << " to " << typeName(e->type) << ' ';
     e->expr->accept(this);
-    *out << ')' << dumpEnd(e);
 }
 
 void IRPrinter::visitUnop(Unop *e)
 {
-    *out << dumpStart(e) << opname(e->op);
+    *out << opname(e->op) << ' ';
     e->expr->accept(this);
-    *out << dumpEnd(e);
 }
 
 void IRPrinter::visitBinop(Binop *e)
 {
-    *out << dumpStart(e);
+    *out << opname(e->op) << ' ';
     e->left->accept(this);
-    *out << ' ' << opname(e->op) << ' ';
+    *out << ", ";
     e->right->accept(this);
-    *out << dumpEnd(e);
 }
 
 void IRPrinter::visitCall(Call *e)
 {
+    *out << "call ";
     e->base->accept(this);
     *out << '(';
     for (ExprList *it = e->args; it; it = it->next) {
@@ -1244,64 +1266,54 @@ QString IRPrinter::escape(const QString &s)
 void IRPrinter::addStmtNr(Stmt *s)
 {
     if (s->id() >= 0)
-        *out << s->id() << ": ";
+        addJustifiedNr(s->id());
 }
 
-QString IRPrinter::dumpStart(const Expr *e)
+void IRPrinter::addJustifiedNr(int pos)
 {
-    if (e->type == UnknownType)
-        return QString();
-
-    QString result = typeName(e->type);
-#ifndef V4_BOOTSTRAP
-    const Temp *temp = const_cast<Expr*>(e)->asTemp();
-    if (e->type == QObjectType && temp && temp->memberResolver.isQObjectResolver) {
-        result += QLatin1Char('<');
-        result += QString::fromUtf8(static_cast<QQmlPropertyCache*>(temp->memberResolver.data)->className());
-        result += QLatin1Char('>');
+    if (positionSize == Stmt::InvalidId) {
+        *out << pos << ": ";
+    } else {
+        QString posStr;
+        if (pos != Stmt::InvalidId)
+            posStr = QString::number(pos);
+        *out << posStr.rightJustified(positionSize);
+        if (pos == Stmt::InvalidId)
+            *out << "  ";
+        else
+            *out << ": ";
     }
-#endif
-    result += QLatin1Char('{');
-    return result;
-}
-
-const char *IRPrinter::dumpEnd(const Expr *e)
-{
-    if (e->type == UnknownType)
-        return "";
-    else
-        return "}";
 }
 
-void IRPrinter::printBlockStart(BasicBlock *bb)
+void IRPrinter::printBlockStart()
 {
-    if (bb->isRemoved()) {
+    if (currentBB->isRemoved()) {
         *out << "(block has been removed)";
         return;
     }
 
     QByteArray str;
     str.append('L');
-    str.append(QByteArray::number(bb->index()));
+    str.append(QByteArray::number(currentBB->index()));
     str.append(':');
-    if (bb->catchBlock) {
+    if (currentBB->catchBlock) {
         str.append(" (exception handler L");
-        str.append(QByteArray::number(bb->catchBlock->index()));
+        str.append(QByteArray::number(currentBB->catchBlock->index()));
         str.append(')');
     }
     for (int i = 66 - str.length(); i; --i)
         str.append(' ');
     *out << str;
 
-    *out << "// predecessor blocks:";
-    foreach (BasicBlock *in, bb->in)
+    *out << "; predecessors:";
+    foreach (BasicBlock *in, currentBB->in)
         *out << " L" << in->index();
-    if (bb->in.isEmpty())
-        *out << " (none)";
-    if (BasicBlock *container = bb->containingGroup())
-        *out << "; container block: L" << container->index();
-    if (bb->isGroupStart())
-        *out << "; group start";
+    if (currentBB->in.isEmpty())
+        *out << " none";
+    if (BasicBlock *container = currentBB->containingGroup())
+        *out << ", container: L" << container->index();
+    if (currentBB->isGroupStart())
+        *out << ", loop_header: yes";
     *out << endl;
 }
 
index fcdcdf9..6f42a50 100644 (file)
@@ -1043,13 +1043,17 @@ struct Function {
     void setScheduledBlocks(const QVector<BasicBlock *> &scheduled);
     void renumberBasicBlocks();
 
-    unsigned getNewStatementId() { return _statementCount++; }
-    unsigned statementCount() const { return _statementCount; }
+    int getNewStatementId() { return _statementCount++; }
+    int statementCount() const { return _statementCount; }
+
+private:
+    BasicBlock *getOrCreateBasicBlock(int index);
+    void setStatementCount(int cnt);
 
 private:
     QVector<BasicBlock *> _basicBlocks;
     QVector<BasicBlock *> *_allBasicBlocks;
-    unsigned _statementCount;
+    int _statementCount;
 };
 
 class CloneExpr: protected IR::ExprVisitor
@@ -1136,7 +1140,7 @@ private:
     IR::Expr *cloned;
 };
 
-class IRPrinter: public StmtVisitor, public ExprVisitor
+class Q_AUTOTEST_EXPORT IRPrinter: public StmtVisitor, public ExprVisitor
 {
 public:
     IRPrinter(QTextStream *out);
@@ -1175,13 +1179,13 @@ public:
 
 protected:
     virtual void addStmtNr(Stmt *s);
-    QString dumpStart(const Expr *e);
-    const char *dumpEnd(const Expr *e);
-    void printBlockStart(BasicBlock *bb);
+    void addJustifiedNr(int pos);
+    void printBlockStart();
 
 protected:
     QTextStream *out;
-    bool printElse;
+    int positionSize;
+    BasicBlock *currentBB;
 };
 
 } // end of namespace IR
index 8c5f2e3..9a59795 100644 (file)
@@ -81,8 +81,10 @@ Q_GLOBAL_STATIC_WITH_ARGS(QTextStream, qout, (stderr, QIODevice::WriteOnly));
 void showMeTheCode(IR::Function *function)
 {
     static bool showCode = !qgetenv("QV4_SHOW_IR").isNull();
-    if (showCode)
+    if (showCode) {
         IRPrinter(&qout).print(function);
+        qout << endl;
+    }
 }
 
 class ProcessedBlocks
@@ -1659,7 +1661,7 @@ class StatementWorklist
 public:
     StatementWorklist(IR::Function *function)
         : theFunction(function)
-        , stmts(function->statementCount(), 0)
+        , stmts(function->statementCount(), static_cast<Stmt *>(0))
         , worklist(function->statementCount(), false)
         , worklistSize(0)
         , replaced(function->statementCount(), Stmt::InvalidId)
index 588b6d9..0639c53 100644 (file)
@@ -85,15 +85,7 @@ public:
 protected:
     void addStmtNr(Stmt *s)
     {
-        QString posStr;
-        int pos = intervals->positionForStatement(s);
-        if (pos != Stmt::InvalidId)
-            posStr = QString::number(pos);
-        *out << posStr.rightJustified(positionSize);
-        if (pos == Stmt::InvalidId)
-            *out << "  ";
-        else
-            *out << ": ";
+        addJustifiedNr(intervals->positionForStatement(s));
     }
 };
 
@@ -126,9 +118,7 @@ protected:
             const RegisterInfo *ri = e->type == DoubleType ? _infoForFPRegister.value(e->index, 0)
                                                            : _infoForRegularRegister.value(e->index, 0);
             if (ri) {
-                *out << dumpStart(e);
                 *out << ri->prettyName();
-                *out << dumpEnd(e);
                 break;
             }
         }