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 "?";
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:
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)
void BasicBlock::appendStatement(Stmt *statement)
{
Q_ASSERT(!isRemoved());
- if (nextLocation.isValid())
+ if (nextLocation.startLine)
statement->location = nextLocation;
_statements.append(statement);
}
IRPrinter::IRPrinter(QTextStream *out)
: out(out)
- , printElse(true)
+ , positionSize(Stmt::InvalidId)
+ , currentBB(0)
{
}
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);
<< '{' << 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);
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)
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)
*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";
}
break;
}
- if (e->type != UndefinedType && e->type != NullType)
- *out << dumpEnd(e);
}
void IRPrinter::visitString(String *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")
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
<< '@' << e->scope; break;
default: *out << "INVALID";
}
- *out << dumpEnd(e);
}
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) {
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;
}