Remove the index magic from the temp.
authorErik Verbruggen <erik.verbruggen@me.com>
Mon, 10 Jun 2013 15:59:41 +0000 (17:59 +0200)
committerSimon Hausmann <simon.hausmann@digia.com>
Tue, 18 Jun 2013 14:57:41 +0000 (16:57 +0200)
Change-Id: If746ebdd6f29d7140781869af6d589cc4c5b8c9e
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
src/qml/qml/v4/moth/qv4isel_moth.cpp
src/qml/qml/v4/moth/qv4isel_moth_p.h
src/qml/qml/v4/qv4codegen.cpp
src/qml/qml/v4/qv4isel_llvm.cpp
src/qml/qml/v4/qv4isel_masm.cpp
src/qml/qml/v4/qv4jsir.cpp
src/qml/qml/v4/qv4jsir_p.h
src/qml/qml/v4/qv4ssa.cpp
src/qml/qml/v4/qv4ssa_p.h

index e4a3738..a15d64e 100644 (file)
@@ -482,17 +482,13 @@ void InstructionSelection::prepareCallArgs(V4IR::ExprList *e, quint32 &argc, qui
 {
     bool singleArgIsTemp = false;
     if (e && e->next == 0 && e->expr->asTemp()) {
-        // ok, only 1 argument in the call...
-        const int idx = e->expr->asTemp()->index;
-        // We can only pass a reference into the stack, which holds temps that
-        // are not arguments (idx >= 0) nor locals (idx >= localCound).
-        singleArgIsTemp = idx >= _function->locals.size() && e->expr->asTemp()->scope == 0;
+        singleArgIsTemp = e->expr->asTemp()->kind == V4IR::Temp::VirtualRegister;
     }
 
     if (singleArgIsTemp) {
         // We pass single arguments as references to the stack, but only if it's not a local or an argument.
         argc = 1;
-        args = e->expr->asTemp()->index - _function->locals.size();
+        args = e->expr->asTemp()->index;
     } else if (e) {
         // We need to move all the temps into the function arg array
         int argLocation = outgoingArgumentTempStart();
index e969e33..a15af6a 100644 (file)
@@ -97,17 +97,15 @@ private:
         if (V4IR::Const *c = e->asConst()) {
             return Param::createValue(convertToValue(c));
         } else if (V4IR::Temp *t = e->asTemp()) {
-            const int index = t->index;
-            if (index < 0) {
-                return Param::createArgument(-index - 1, t->scope);
-            } else if (!t->scope) {
-                const int localCount = _function->locals.size();
-                if (index < localCount)
-                    return Param::createLocal(index);
-                else
-                    return Param::createTemp(index - localCount);
-            } else {
-                return Param::createScopedLocal(t->index, t->scope);
+            switch (t->kind) {
+            case V4IR::Temp::Formal:
+            case V4IR::Temp::ScopedFormal: return Param::createArgument(t->index, t->scope);
+            case V4IR::Temp::Local: return Param::createLocal(t->index);
+            case V4IR::Temp::ScopedLocal: return Param::createScopedLocal(t->index, t->scope);
+            case V4IR::Temp::VirtualRegister: return Param::createTemp(t->index);
+            default:
+                Q_UNIMPLEMENTED();
+                return Param();
             }
         } else {
             Q_UNIMPLEMENTED();
@@ -126,7 +124,7 @@ private:
     void simpleMove(V4IR::Move *);
     void prepareCallArgs(V4IR::ExprList *, quint32 &, quint32 &);
 
-    int outgoingArgumentTempStart() const { return _function->tempCount - _function->locals.size(); }
+    int outgoingArgumentTempStart() const { return _function->tempCount; }
     int scratchTempIndex() const { return outgoingArgumentTempStart() + _function->maxNumberOfArguments; }
     int frameSize() const { return scratchTempIndex() + 1; }
 
index f4482db..164aa97 100644 (file)
@@ -898,7 +898,7 @@ void Codegen::variableDeclaration(VariableDeclaration *ast)
     } else {
         const int index = _env->findMember(ast->name.toString());
         assert(index != -1);
-        move(_block->TEMP(index), initializer);
+        move(_block->LOCAL(index, 0), initializer);
     }
 }
 
@@ -1437,11 +1437,11 @@ V4IR::Expr *Codegen::identifier(const QString &name, int line, int col)
         int index = e->findMember(name);
         assert (index < e->members.size());
         if (index != -1) {
-            return _block->TEMP(index, scope);
+            return _block->LOCAL(index, scope);
         }
         const int argIdx = f->indexOfArgument(&name);
         if (argIdx != -1)
-            return _block->TEMP(-(argIdx + 1), scope);
+            return _block->ARG(argIdx, scope);
         ++scope;
         e = e->parent;
         f = f->outer;
@@ -1841,12 +1841,13 @@ V4IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
 
     // variables in global code are properties of the global context object, not locals as with other functions.
     if (_mode == FunctionCode) {
+        unsigned t = 0;
         for (Environment::MemberMap::iterator it = _env->members.begin(); it != _env->members.end(); ++it) {
             const QString &local = it.key();
             function->LOCAL(local);
-            unsigned t = entryBlock->newTemp();
             (*it).index = t;
-            entryBlock->MOVE(entryBlock->TEMP(t), entryBlock->CONST(V4IR::UndefinedType, 0));
+            entryBlock->MOVE(entryBlock->LOCAL(t, 0), entryBlock->CONST(V4IR::UndefinedType, 0));
+            ++t;
         }
     } else {
         if (!_env->isStrict) {
@@ -1908,7 +1909,7 @@ V4IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
                      _block->CLOSURE(function));
             } else {
                 assert(member.index >= 0);
-                move(_block->TEMP(member.index), _block->CLOSURE(function));
+                move(_block->LOCAL(member.index, 0), _block->CLOSURE(function));
             }
         }
     }
index 96b023e..6b2f6c8 100644 (file)
@@ -928,13 +928,19 @@ llvm::Value *InstructionSelection::getLLVMCondition(V4IR::Expr *expr)
 
 llvm::Value *InstructionSelection::getLLVMTemp(V4IR::Temp *temp)
 {
-    if (temp->index < 0) {
-        const int index = -temp->index -1;
+    // TODO
+    assert(!"TODO!");
+    Q_UNREACHABLE();
+    return 0;
+#if 0
+    if (temp->idx < 0) {
+        const int index = -temp->idx -1;
         return CreateCall2(getRuntimeFunction("__qmljs_llvm_get_argument"),
                            _llvmFunction->arg_begin(), getInt32(index));
     }
 
-    return _tempMap[temp->index];
+    return _tempMap[temp->idx];
+#endif
 }
 
 llvm::Value *InstructionSelection::getStringPtr(const QString &s)
index 867100d..240b162 100644 (file)
@@ -158,19 +158,26 @@ Assembler::Pointer Assembler::loadTempAddress(RegisterID reg, V4IR::Temp *t)
             --scope;
         }
     }
-    if (t->index < 0) {
-        const int arg = -t->index - 1;
+    switch (t->kind) {
+    case V4IR::Temp::Formal:
+    case V4IR::Temp::ScopedFormal: {
         loadPtr(Address(context, offsetof(CallContext, arguments)), reg);
-        offset = arg * sizeof(Value);
-    } else if (t->index < f->locals.size()) {
+        offset = t->index * sizeof(Value);
+    } break;
+    case V4IR::Temp::Local:
+    case V4IR::Temp::ScopedLocal: {
         loadPtr(Address(context, offsetof(CallContext, locals)), reg);
         offset = t->index * sizeof(Value);
-    } else {
+    } break;
+    case V4IR::Temp::VirtualRegister: {
         assert(t->scope == 0);
-        const int arg = _function->maxNumberOfArguments + t->index - _function->locals.size() + 1;
+        const int arg = _function->maxNumberOfArguments + t->index + 1;
         offset = - sizeof(Value) * (arg + 1);
         offset -= sizeof(void*) * calleeSavedRegisterCount;
         reg = LocalsRegister;
+    } break;
+    default:
+        Q_UNIMPLEMENTED();
     }
     return Pointer(reg, offset);
 }
@@ -574,7 +581,7 @@ void InstructionSelection::run(QV4::Function *vmFunction, V4IR::Function *functi
     Assembler* oldAssembler = _as;
     _as = new Assembler(_function, _vmFunction, engine());
 
-    int locals = (_function->tempCount - _function->locals.size() + _function->maxNumberOfArguments) + 1;
+    int locals = (_function->tempCount + _function->maxNumberOfArguments) + 1;
     locals = (locals + 1) & ~1;
     qSwap(_locals, locals);
     _as->enterStandardStackFrame(_locals);
index fd0b866..44e28d1 100644 (file)
@@ -280,7 +280,7 @@ struct RemoveSharedExpressions: V4IR::StmtVisitor, V4IR::ExprVisitor
     }
 };
 
-static QString dumpStart(Expr *e) {
+static QString dumpStart(const Expr *e) {
     if (e->type == UnknownType)
 //        return QStringLiteral("**UNKNOWN**");
         return QString();
@@ -288,14 +288,14 @@ static QString dumpStart(Expr *e) {
         return typeName(e->type) + QStringLiteral("{");
 }
 
-static const char *dumpEnd(Expr *e) {
+static const char *dumpEnd(const Expr *e) {
     if (e->type == UnknownType)
         return "";
     else
         return "}";
 }
 
-void Const::dump(QTextStream &out)
+void Const::dump(QTextStream &out) const
 {
     if (type != UndefinedType && type != NullType)
         out << dumpStart(this);
@@ -320,7 +320,7 @@ void Const::dump(QTextStream &out)
         out << dumpEnd(this);
 }
 
-void String::dump(QTextStream &out)
+void String::dump(QTextStream &out) const
 {
     out << '"' << escape(*value) << '"';
 }
@@ -346,7 +346,7 @@ QString String::escape(const QString &s)
     return r;
 }
 
-void RegExp::dump(QTextStream &out)
+void RegExp::dump(QTextStream &out) const
 {
     char f[3];
     int i = 0;
@@ -427,8 +427,7 @@ static const char *builtin_to_string(Name::Builtin b)
     return "builtin_(###FIXME)";
 };
 
-
-void Name::dump(QTextStream &out)
+void Name::dump(QTextStream &out) const
 {
     if (id)
         out << *id;
@@ -436,20 +435,32 @@ void Name::dump(QTextStream &out)
         out << builtin_to_string(builtin);
 }
 
-void Temp::dump(QTextStream &out)
+void Temp::dump(QTextStream &out) const
 {
     out << dumpStart(this);
-    if (index < 0) {
-        out << '#' << -(index + 1); // negative and 1-based.
-    } else {
-        out << '%' << index; // temp
+    switch (kind) {
+    case Formal:           out << '#' << index; break;
+    case ScopedFormal:     out << '#' << index
+                               << '@' << scope; break;
+    case Local:            out << '$' << index; break;
+    case ScopedLocal:      out << '$' << index
+                               << '@' << scope; break;
+    case VirtualRegister:  out << '%' << index; break;
+    default:               out << "INVALID";
     }
-    if (scope)
-        out << "@" << scope;
     out << dumpEnd(this);
 }
 
-void Closure::dump(QTextStream &out)
+bool operator<(const Temp &t1, const Temp &t2) Q_DECL_NOTHROW
+{
+    if (t1.kind < t2.kind) return true;
+    if (t1.kind > t2.kind) return false;
+    if (t1.index < t2.index) return true;
+    if (t1.index > t2.index) return false;
+    return t1.scope < t2.scope;
+}
+
+void Closure::dump(QTextStream &out) const
 {
     QString name = value->name ? *value->name : QString();
     if (name.isEmpty())
@@ -457,7 +468,7 @@ void Closure::dump(QTextStream &out)
     out << "closure(" << name << ')';
 }
 
-void Convert::dump(QTextStream &out)
+void Convert::dump(QTextStream &out) const
 {
     out << dumpStart(this);
     out << "convert(";
@@ -465,14 +476,14 @@ void Convert::dump(QTextStream &out)
     out << ')' << dumpEnd(this);
 }
 
-void Unop::dump(QTextStream &out)
+void Unop::dump(QTextStream &out) const
 {
     out << dumpStart(this) << opname(op);
     expr->dump(out);
     out << dumpEnd(this);
 }
 
-void Binop::dump(QTextStream &out)
+void Binop::dump(QTextStream &out) const
 {
     out << dumpStart(this);
     left->dump(out);
@@ -481,7 +492,7 @@ void Binop::dump(QTextStream &out)
     out << dumpEnd(this);
 }
 
-void Call::dump(QTextStream &out)
+void Call::dump(QTextStream &out) const
 {
     base->dump(out);
     out << '(';
@@ -493,7 +504,7 @@ void Call::dump(QTextStream &out)
     out << ')';
 }
 
-void New::dump(QTextStream &out)
+void New::dump(QTextStream &out) const
 {
     out << "new ";
     base->dump(out);
@@ -506,7 +517,7 @@ void New::dump(QTextStream &out)
     out << ')';
 }
 
-void Subscript::dump(QTextStream &out)
+void Subscript::dump(QTextStream &out) const
 {
     base->dump(out);
     out << '[';
@@ -514,7 +525,7 @@ void Subscript::dump(QTextStream &out)
     out << ']';
 }
 
-void Member::dump(QTextStream &out)
+void Member::dump(QTextStream &out) const
 {
     base->dump(out);
     out << '.' << *name;
@@ -681,10 +692,24 @@ unsigned BasicBlock::newTemp()
     return function->tempCount++;
 }
 
-Temp *BasicBlock::TEMP(int index, uint scope)
-{ 
+Temp *BasicBlock::TEMP(unsigned index)
+{
+    Temp *e = function->New<Temp>();
+    e->init(Temp::VirtualRegister, index, 0);
+    return e;
+}
+
+Temp *BasicBlock::ARG(unsigned index, unsigned scope)
+{
+    Temp *e = function->New<Temp>();
+    e->init(scope ? Temp::ScopedFormal : Temp::Formal, index, scope);
+    return e;
+}
+
+Temp *BasicBlock::LOCAL(unsigned index, unsigned scope)
+{
     Temp *e = function->New<Temp>();
-    e->init(index, scope);
+    e->init(scope ? Temp::ScopedLocal : Temp::Local, index, scope);
     return e;
 }
 
@@ -993,7 +1018,9 @@ void CloneExpr::visitName(Name *e)
 
 void CloneExpr::visitTemp(Temp *e)
 {
-    cloned = block->TEMP(e->index, e->scope);
+    Temp *t = block->function->New<Temp>();
+    t->init(e->kind, e->index, e->scope);
+    cloned = t;
 }
 
 void CloneExpr::visitClosure(Closure *e)
index c873344..a43a182 100644 (file)
@@ -235,7 +235,7 @@ struct Expr {
     virtual New *asNew() { return 0; }
     virtual Subscript *asSubscript() { return 0; }
     virtual Member *asMember() { return 0; }
-    virtual void dump(QTextStream &out) = 0;
+    virtual void dump(QTextStream &out) const = 0;
 };
 
 struct ExprList {
@@ -261,7 +261,7 @@ struct Const: Expr {
     virtual void accept(ExprVisitor *v) { v->visitConst(this); }
     virtual Const *asConst() { return this; }
 
-    virtual void dump(QTextStream &out);
+    virtual void dump(QTextStream &out) const;
 };
 
 struct String: Expr {
@@ -275,7 +275,7 @@ struct String: Expr {
     virtual void accept(ExprVisitor *v) { v->visitString(this); }
     virtual String *asString() { return this; }
 
-    virtual void dump(QTextStream &out);
+    virtual void dump(QTextStream &out) const;
     static QString escape(const QString &s);
 };
 
@@ -299,7 +299,7 @@ struct RegExp: Expr {
     virtual void accept(ExprVisitor *v) { v->visitRegExp(this); }
     virtual RegExp *asRegExp() { return this; }
 
-    virtual void dump(QTextStream &out);
+    virtual void dump(QTextStream &out) const;
 };
 
 struct Name: Expr {
@@ -336,15 +336,29 @@ struct Name: Expr {
     virtual bool isLValue() { return true; }
     virtual Name *asName() { return this; }
 
-    virtual void dump(QTextStream &out);
+    virtual void dump(QTextStream &out) const;
 };
 
 struct Temp: Expr {
-    int index;
-    int scope; // how many scopes outside the current one?
+    enum Kind {
+        Formal = 0,
+        ScopedFormal,
+        Local,
+        ScopedLocal,
+        VirtualRegister
+    };
 
-    void init(int index, int scope = 0)
+    unsigned index;
+    unsigned scope : 29; // how many scopes outside the current one?
+    unsigned kind  : 3;
+
+    void init(unsigned kind, unsigned index, unsigned scope)
     {
+        Q_ASSERT((kind == ScopedLocal && scope != 0) ||
+                 (kind == ScopedFormal && scope != 0) ||
+                 (scope == 0));
+
+        this->kind = kind;
         this->index = index;
         this->scope = scope;
     }
@@ -353,9 +367,17 @@ struct Temp: Expr {
     virtual bool isLValue() { return true; }
     virtual Temp *asTemp() { return this; }
 
-    virtual void dump(QTextStream &out);
+    virtual void dump(QTextStream &out) const;
 };
 
+inline bool operator==(const Temp &t1, const Temp &t2) Q_DECL_NOTHROW
+{ return t1.index == t2.index && t1.scope == t2.scope && t1.kind == t2.kind; }
+
+inline uint qHash(const Temp &t, uint seed = 0) Q_DECL_NOTHROW
+{ return t.index ^ (t.kind | (t.scope << 3)) ^ seed; }
+
+bool operator<(const Temp &t1, const Temp &t2) Q_DECL_NOTHROW;
+
 struct Closure: Expr {
     Function *value;
 
@@ -367,7 +389,7 @@ struct Closure: Expr {
     virtual void accept(ExprVisitor *v) { v->visitClosure(this); }
     virtual Closure *asClosure() { return this; }
 
-    virtual void dump(QTextStream &out);
+    virtual void dump(QTextStream &out) const;
 };
 
 struct Convert: Expr {
@@ -382,7 +404,7 @@ struct Convert: Expr {
     virtual void accept(ExprVisitor *v) { v->visitConvert(this); }
     virtual Convert *asConvert() { return this; }
 
-    virtual void dump(QTextStream &out);
+    virtual void dump(QTextStream &out) const;
 };
 
 struct Unop: Expr {
@@ -398,7 +420,7 @@ struct Unop: Expr {
     virtual void accept(ExprVisitor *v) { v->visitUnop(this); }
     virtual Unop *asUnop() { return this; }
 
-    virtual void dump(QTextStream &out);
+    virtual void dump(QTextStream &out) const;
 };
 
 struct Binop: Expr {
@@ -416,7 +438,7 @@ struct Binop: Expr {
     virtual void accept(ExprVisitor *v) { v->visitBinop(this); }
     virtual Binop *asBinop() { return this; }
 
-    virtual void dump(QTextStream &out);
+    virtual void dump(QTextStream &out) const;
 };
 
 struct Call: Expr {
@@ -438,7 +460,7 @@ struct Call: Expr {
     virtual void accept(ExprVisitor *v) { v->visitCall(this); }
     virtual Call *asCall() { return this; }
 
-    virtual void dump(QTextStream &out);
+    virtual void dump(QTextStream &out) const;
 };
 
 struct New: Expr {
@@ -460,7 +482,7 @@ struct New: Expr {
     virtual void accept(ExprVisitor *v) { v->visitNew(this); }
     virtual New *asNew() { return this; }
 
-    virtual void dump(QTextStream &out);
+    virtual void dump(QTextStream &out) const;
 };
 
 struct Subscript: Expr {
@@ -477,7 +499,7 @@ struct Subscript: Expr {
     virtual bool isLValue() { return true; }
     virtual Subscript *asSubscript() { return this; }
 
-    virtual void dump(QTextStream &out);
+    virtual void dump(QTextStream &out) const;
 };
 
 struct Member: Expr {
@@ -494,7 +516,7 @@ struct Member: Expr {
     virtual bool isLValue() { return true; }
     virtual Member *asMember() { return this; }
 
-    virtual void dump(QTextStream &out);
+    virtual void dump(QTextStream &out) const;
 };
 
 struct Stmt {
@@ -791,7 +813,9 @@ struct BasicBlock {
 
     unsigned newTemp();
 
-    Temp *TEMP(int index, uint scope = 0);
+    Temp *TEMP(unsigned kind);
+    Temp *ARG(unsigned index, unsigned scope);
+    Temp *LOCAL(unsigned index, unsigned scope);
 
     Expr *CONST(Type type, double value);
     Expr *STRING(const QString *value);
index 4f88ede..294cb7c 100644 (file)
 #define QV4_NO_LIVENESS
 #undef SHOW_SSA
 
+QT_USE_NAMESPACE
+
 using namespace QQmlJS;
 
 namespace {
+using namespace V4IR;
+
 QTextStream qout(stdout, QIODevice::WriteOnly);
 
 void showMeTheCode(V4IR::Function *function)
 {
-    // TODO: maybe we should move this somewhere else?
     static bool showCode = !qgetenv("SHOW_CODE").isNull();
     if (showCode) {
         QVector<V4IR::Stmt *> code;
@@ -194,8 +197,6 @@ void showMeTheCode(V4IR::Function *function)
     }
 }
 
-using namespace V4IR;
-
 class DominatorTree {
     int N;
     QHash<BasicBlock *, int> dfnum;
@@ -386,33 +387,39 @@ public:
 };
 
 class VariableCollector: public StmtVisitor, ExprVisitor {
-    QHash<int, QSet<BasicBlock *> > _defsites;
-    QHash<BasicBlock *, QSet<int> > A_orig;
-    QSet<int> nonLocals;
-    QSet<int> killed;
+    QHash<Temp, QSet<BasicBlock *> > _defsites;
+    QHash<BasicBlock *, QSet<Temp> > A_orig;
+    QSet<Temp> nonLocals;
+    QSet<Temp> killed;
 
     BasicBlock *currentBB;
-    int lastUncollectible;
+    const bool variablesCanEscape;
+    bool isCollectable(Temp *t) const
+    {
+        switch (t->kind) {
+        case Temp::Formal:
+        case Temp::ScopedFormal:
+        case Temp::ScopedLocal:
+            return false;
+        case Temp::Local:
+            return !variablesCanEscape;
+        case Temp::VirtualRegister:
+            return true;
+        default:
+            // PhysicalRegister and StackSlot can only get inserted later.
+            Q_ASSERT(!"Invalid temp kind!");
+            return false;
+        }
+    }
 
 public:
     VariableCollector(Function *function)
-        : lastUncollectible(function->variablesCanEscape() ? function->locals.size() - 1 : -1)
+        : variablesCanEscape(function->variablesCanEscape())
     {
 #ifdef SHOW_SSA
         qout << "Variables collected:" << endl;
 #endif // SHOW_SSA
 
-        if (!function->variablesCanEscape() && false) {
-            BasicBlock *entryBlock = function->basicBlocks.at(0);
-            for (int i = -function->formals.size(); i < 0; ++i) {
-                _defsites[i].insert(entryBlock);
-                A_orig[entryBlock].insert(i);
-#ifdef SHOW_SSA
-                qout << "\t#" << -i << " -> L0" << endl;
-#endif // SHOW_SSA
-            }
-        }
-
         foreach (BasicBlock *bb, function->basicBlocks) {
             currentBB = bb;
             killed.clear();
@@ -424,26 +431,29 @@ public:
 
 #ifdef SHOW_SSA
         qout << "Non-locals:" << endl;
-        foreach (int nonLocal, nonLocals)
-            qout << "\t" << nonLocal << endl;
+        foreach (const Temp &nonLocal, nonLocals) {
+            qout << "\t";
+            nonLocal.dump(qout);
+            qout << endl;
+        }
 
         qout << "end collected variables." << endl;
 #endif // SHOW_SSA
     }
 
-    QList<int> vars() const {
+    QList<Temp> vars() const {
         return _defsites.keys();
     }
 
-    QSet<BasicBlock *> defsite(int n) const {
+    QSet<BasicBlock *> defsite(const Temp &n) const {
         return _defsites[n];
     }
 
-    QSet<int> inBlock(BasicBlock *n) const {
+    QSet<Temp> inBlock(BasicBlock *n) const {
         return A_orig[n];
     }
 
-    bool isNonLocal(int var) const { return nonLocals.contains(var); }
+    bool isNonLocal(const Temp &var) const { return nonLocals.contains(var); }
 
 protected:
     virtual void visitPhi(Phi *) {};
@@ -483,44 +493,46 @@ protected:
         s->source->accept(this);
 
         if (Temp *t = s->target->asTemp()) {
-            if (t->scope == 0 && lastUncollectible < t->index) {
+            if (isCollectable(t)) {
 #ifdef SHOW_SSA
                 qout << '\t';
                 t->dump(qout);
                 qout << " -> L" << currentBB->index << endl;
 #endif // SHOW_SSA
 
-                _defsites[t->index].insert(currentBB);
-                A_orig[currentBB].insert(t->index);
+                _defsites[*t].insert(currentBB);
+                A_orig[currentBB].insert(*t);
 
                 // For semi-pruned SSA:
-                killed.insert(t->index);
+                killed.insert(*t);
             }
         }
     }
 
     virtual void visitTemp(Temp *t)
     {
-        if (t->scope == 0 && lastUncollectible < t->index)
-            if (!killed.contains(t->index))
-                nonLocals.insert(t->index);
+        if (isCollectable(t))
+            if (!killed.contains(*t))
+                nonLocals.insert(*t);
     }
 };
 
-void insertPhiNode(int a, BasicBlock *y, Function *f) {
-#ifdef SHOW_SSA
-    qout << "-> inserted phi node for variable " << a << " in block " << y->index << endl;
+void insertPhiNode(const Temp &a, BasicBlock *y, Function *f) {
+#if defined(SHOW_SSA)
+    qout << "-> inserted phi node for variable ";
+    a.dump(qout);
+    qout << " in block " << y->index << endl;
 #endif
 
     Phi *phiNode = f->New<Phi>();
     phiNode->targetTemp = f->New<Temp>();
-    phiNode->targetTemp->init(a);
+    phiNode->targetTemp->init(a.kind, a.index, 0);
     y->statements.prepend(phiNode);
 
     phiNode->incoming.resize(y->in.size());
     for (int i = 0, ei = y->in.size(); i < ei; ++i) {
         Temp *t = f->New<Temp>();
-        t->init(a);
+        t->init(a.kind, a.index, 0);
         phiNode->incoming[i] = t;
     }
 }
@@ -528,14 +540,28 @@ void insertPhiNode(int a, BasicBlock *y, Function *f) {
 class VariableRenamer: public StmtVisitor, public ExprVisitor
 {
     Function *function;
-    QHash<int, QStack<int> > stack;
+    QHash<Temp, QStack<unsigned> > stack;
     QSet<BasicBlock *> seen;
 
-    QHash<int, unsigned> defCounts;
-    QHash<int, int> tempMapping;
-
-    int lastUncollectible;
+    QHash<Temp, unsigned> defCounts;
 
+    const bool variablesCanEscape;
+    bool isRenamable(Temp *t) const
+    {
+        switch (t->kind) {
+        case Temp::Formal:
+        case Temp::ScopedFormal:
+        case Temp::ScopedLocal:
+            return false;
+        case Temp::Local:
+            return !variablesCanEscape;
+        case Temp::VirtualRegister:
+            return true;
+        default:
+            Q_ASSERT(!"Invalid temp kind!");
+            return false;
+        }
+    }
     int nextFreeTemp() {
         const int next = function->tempCount++;
 //        qDebug()<<"Next free temp:"<<next;
@@ -576,28 +602,36 @@ class VariableRenamer: public StmtVisitor, public ExprVisitor
      */
 
 public:
-    VariableRenamer(Function *f) {
-        function = f;
-
-        int a = f->variablesCanEscape() ? f->locals.size() : a = 0;
-        lastUncollectible = a - 1;
+    VariableRenamer(Function *f)
+        : function(f)
+        , variablesCanEscape(f->variablesCanEscape())
+    {
+        if (!variablesCanEscape) {
+            Temp t;
+            t.init(Temp::Local, 0, 0);
+            for (int i = 0, ei = f->locals.size(); i != ei; ++i) {
+                t.index = i;
+                stack[t].push(nextFreeTemp());
+            }
+        }
 
-        for (; a < f->tempCount; ++a) {
-            stack[a].push(a);
+        Temp t;
+        t.init(Temp::VirtualRegister, 0, 0);
+        for (int i = 0, ei = f->tempCount; i != ei; ++i) {
+            t.index = i;
+            stack[t].push(i);
         }
     }
 
-    QHash<int, int> run() {
+    void run() {
         foreach (BasicBlock *n, function->basicBlocks)
             rename(n);
 
 #ifdef SHOW_SSA
-        qout << "Temp to local mapping:" << endl;
-        foreach (int key, tempMapping.keys())
-            qout << '\t' << key << " -> " << tempMapping[key] << endl;
+//        qout << "Temp to local mapping:" << endl;
+//        foreach (int key, tempMapping.keys())
+//            qout << '\t' << key << " -> " << tempMapping[key] << endl;
 #endif
-
-        return tempMapping;
     }
 
     void rename(BasicBlock *n) {
@@ -610,7 +644,7 @@ public:
         foreach (Stmt *s, n->statements)
             s->accept(this);
 
-        QHash<int, unsigned> dc = defCounts;
+        QHash<Temp, unsigned> dc = defCounts;
         defCounts.clear();
 
         // [2]:
@@ -619,10 +653,11 @@ public:
             Q_ASSERT(j >= 0 && j < Y->in.size());
             foreach (Stmt *s, Y->statements) {
                 if (Phi *phi = s->asPhi()) {
-                    int &a = phi->incoming[j]->asTemp()->index;
-                    int newTmp = stack[a].top();
+                    Temp *t = phi->incoming[j]->asTemp();
+                    unsigned newTmp = stack[*t].top();
 //                    qDebug()<<"I: replacing phi use"<<a<<"with"<<newTmp<<"in L"<<Y->index;
-                    a = newTmp;
+                    t->index = newTmp;
+                    t->kind = Temp::VirtualRegister;
                 } else {
                     break;
                 }
@@ -634,7 +669,7 @@ public:
             rename(X);
 
         // [4]:
-        for (QHash<int, unsigned>::const_iterator i = dc.begin(), ei = dc.end(); i != ei; ++i) {
+        for (QHash<Temp, unsigned>::const_iterator i = dc.begin(), ei = dc.end(); i != ei; ++i) {
 //            qDebug()<<i.key() <<" -> " << i.value();
             for (unsigned j = 0, ej = i.value(); j < ej; ++j)
                 stack[i.key()].pop();
@@ -643,9 +678,10 @@ public:
 
 protected:
     virtual void visitTemp(Temp *e) { // only called for uses, not defs
-        if (e->scope == 0 && lastUncollectible < e->index) {
+        if (isRenamable(e)) {
 //            qDebug()<<"I: replacing use of"<<e->index<<"with"<<stack[e->index].top();
-            e->index = stack[e->index].top();
+            e->index = stack[*e].top();
+            e->kind = Temp::VirtualRegister;
         }
     }
 
@@ -661,29 +697,16 @@ protected:
     }
 
     void renameTemp(Temp *t) {
-        if (t->scope == 0 && lastUncollectible < t->index) {
-            int &a = t->index;
-            defCounts[a] = defCounts.value(a, 0) + 1;
+        if (isRenamable(t)) {
+            defCounts[*t] = defCounts.value(*t, 0) + 1;
             const int newIdx = nextFreeTemp();
-            stack[a].push(newIdx);
-            updateLocalMapping(a, newIdx);
+            stack[*t].push(newIdx);
 //            qDebug()<<"I: replacing def of"<<a<<"with"<<newIdx;
-            a = newIdx;
+            t->kind = Temp::VirtualRegister;
+            t->index = newIdx;
         }
     }
 
-    void updateLocalMapping(int origIdx, int newIdx) {
-        if (origIdx < function->locals.size()) {
-            tempMapping[newIdx] = origIdx;
-            return;
-        }
-
-        int next = tempMapping.value(newIdx, INT32_MIN);
-        if (next == INT32_MIN)
-            return;
-        tempMapping[newIdx] = origIdx;
-    }
-
     virtual void visitConvert(Convert *e) { e->expr->accept(this); }
     virtual void visitPhi(Phi *s) { renameTemp(s->targetTemp); }
 
@@ -725,7 +748,7 @@ protected:
     }
 };
 
-QHash<int, int> convertToSSA(Function *function, const DominatorTree &df)
+void convertToSSA(Function *function, const DominatorTree &df)
 {
 #ifdef SHOW_SSA
     qout << "Converting function ";
@@ -740,8 +763,8 @@ QHash<int, int> convertToSSA(Function *function, const DominatorTree &df)
     VariableCollector variables(function);
 
     // Place phi functions:
-    QHash<BasicBlock *, QSet<int> > A_phi;
-    foreach (int a, variables.vars()) {
+    QHash<BasicBlock *, QSet<Temp> > A_phi;
+    foreach (Temp a, variables.vars()) {
         if (!variables.isNonLocal(a))
             continue; // for semi-pruned SSA
 
@@ -759,9 +782,10 @@ QHash<int, int> convertToSSA(Function *function, const DominatorTree &df)
             }
         }
     }
+    showMeTheCode(function);
 
     // Rename variables:
-    return VariableRenamer(function).run();
+    VariableRenamer(function).run();
 }
 
 class DefUsesCalculator: public StmtVisitor, public ExprVisitor {
@@ -773,40 +797,53 @@ public:
     };
 
 private:
-    int _lastUncollectible;
-    QHash<int, DefUse> _defUses;
-    QHash<Stmt *, QList<int> > _usesPerStatement;
+    const bool _variablesCanEscape;
+    QHash<Temp, DefUse> _defUses;
+    QHash<Stmt *, QList<Temp> > _usesPerStatement;
 
     BasicBlock *_block;
     Stmt *_stmt;
 
+    bool isCollectible(Temp *t) const {
+        switch (t->kind) {
+        case Temp::Formal:
+        case Temp::ScopedFormal:
+        case Temp::ScopedLocal:
+            return false;
+        case Temp::Local:
+            return !_variablesCanEscape;
+        case Temp::VirtualRegister:
+            return true;
+        default:
+            Q_UNREACHABLE();
+            return false;
+        }
+    }
+
     void addUse(Temp *t) {
         Q_ASSERT(t);
-        if (t->scope || t->index <= _lastUncollectible)
+        if (!isCollectible(t))
             return;
 
-        _defUses[t->index].uses.append(_stmt);
-        _usesPerStatement[_stmt].append(t->index);
+        _defUses[*t].uses.append(_stmt);
+        _usesPerStatement[_stmt].append(*t);
     }
 
     void addDef(Temp *t) {
-        if (t->scope || t->index <= _lastUncollectible)
+        if (!isCollectible(t))
             return;
 
-        Q_ASSERT(!_defUses.contains(t->index) || _defUses.value(t->index).defStmt == 0 || _defUses.value(t->index).defStmt == _stmt);
+        Q_ASSERT(!_defUses.contains(*t) || _defUses.value(*t).defStmt == 0 || _defUses.value(*t).defStmt == _stmt);
 
-        DefUse &defUse = _defUses[t->index];
+        DefUse &defUse = _defUses[*t];
         defUse.defStmt = _stmt;
         defUse.blockOfStatement = _block;
     }
 
 public:
-    DefUsesCalculator(Function *function) {
-        if (function->variablesCanEscape())
-            _lastUncollectible = function->locals.size() - 1;
-        else
-            _lastUncollectible = -1;
-
+    DefUsesCalculator(Function *function)
+        : _variablesCanEscape(function->variablesCanEscape())
+    {
         foreach (BasicBlock *bb, function->basicBlocks) {
             _block = bb;
             foreach (Stmt *stmt, bb->statements) {
@@ -815,7 +852,7 @@ public:
             }
         }
 
-        QMutableHashIterator<int, DefUse> it(_defUses);
+        QMutableHashIterator<Temp, DefUse> it(_defUses);
         while (it.hasNext()) {
             it.next();
             if (!it.value().defStmt)
@@ -823,40 +860,41 @@ public:
         }
     }
 
-    QList<int> defs() const {
+    QList<Temp> defs() const {
         return _defUses.keys();
     }
 
-    void removeDef(int var) {
+    void removeDef(const Temp &var) {
         _defUses.remove(var);
     }
 
-    void addUses(int variable, QList<Stmt *>newUses)
+    void addUses(const Temp &variable, const QList<Stmt *> &newUses)
     { _defUses[variable].uses.append(newUses); }
 
-    int useCount(int variable) const
+    int useCount(const Temp &variable) const
     { return _defUses[variable].uses.size(); }
 
-    Stmt *defStmt(int variable) const
+    Stmt *defStmt(const Temp &variable) const
     { return _defUses[variable].defStmt; }
 
-    BasicBlock *defStmtBlock(int variable) const
+    BasicBlock *defStmtBlock(const Temp &variable) const
     { return _defUses[variable].blockOfStatement; }
 
-    void removeUse(Stmt *usingStmt, int var)
+    void removeUse(Stmt *usingStmt, const Temp &var)
     { _defUses[var].uses.removeAll(usingStmt); }
 
-    QList<int> usedVars(Stmt *s) const
+    QList<Temp> usedVars(Stmt *s) const
     { return _usesPerStatement[s]; }
 
-    QList<Stmt *> uses(int var) const
+    QList<Stmt *> uses(const Temp &var) const
     { return _defUses[var].uses; }
 
     void dump() const
     {
-        foreach (int var, _defUses.keys()) {
+        foreach (const Temp &var, _defUses.keys()) {
             const DefUse &du = _defUses[var];
-            qout<<var<<" -> defined in block "<<du.blockOfStatement->index<<", statement: ";
+            var.dump(qout);
+            qout<<" -> defined in block "<<du.blockOfStatement->index<<", statement: ";
             du.defStmt->dump(qout);
             qout<<endl<<"     uses:"<<endl;
             foreach (Stmt *s, du.uses) {
@@ -917,7 +955,7 @@ protected:
 bool hasPhiOnlyUses(Phi *phi, const DefUsesCalculator &defUses, QSet<Phi *> &collectedPhis)
 {
     collectedPhis.insert(phi);
-    foreach (Stmt *use, defUses.uses(phi->targetTemp->index)) {
+    foreach (Stmt *use, defUses.uses(*phi->targetTemp)) {
         if (Phi *dependentPhi = use->asPhi()) {
             if (!collectedPhis.contains(dependentPhi)) {
                 if (!hasPhiOnlyUses(dependentPhi, defUses, collectedPhis))
@@ -933,7 +971,7 @@ bool hasPhiOnlyUses(Phi *phi, const DefUsesCalculator &defUses, QSet<Phi *> &col
 void cleanupPhis(DefUsesCalculator &defUses)
 {
     QLinkedList<Phi *> phis;
-    foreach (int def, defUses.defs())
+    foreach (const Temp &def, defUses.defs())
         if (Phi *phi = defUses.defStmt(def)->asPhi())
             phis.append(phi);
 
@@ -949,38 +987,34 @@ void cleanupPhis(DefUsesCalculator &defUses)
     }
 
     foreach (Phi *phi, toRemove) {
-        int targetVar = phi->targetTemp->index;
+        Temp targetVar = *phi->targetTemp;
 
         BasicBlock *bb = defUses.defStmtBlock(targetVar);
         int idx = bb->statements.indexOf(phi);
         bb->statements.remove(idx);
 
-        foreach (int usedVar, defUses.usedVars(phi))
+        foreach (const Temp &usedVar, defUses.usedVars(phi))
             defUses.removeUse(phi, usedVar);
         defUses.removeDef(targetVar);
     }
 }
 
 class DeadCodeElimination: public ExprVisitor {
-    int _lastUncollectible;
+    const bool variablesCanEscape;
     DefUsesCalculator &_defUses;
-    QVector<int> _worklist;
+    QVector<Temp> _worklist;
 
 public:
     DeadCodeElimination(DefUsesCalculator &defUses, Function *function)
-        : _defUses(defUses)
+        : variablesCanEscape(function->variablesCanEscape())
+        , _defUses(defUses)
     {
-        _worklist = QVector<int>::fromList(_defUses.defs());
-
-        if (function->variablesCanEscape())
-            _lastUncollectible = function->locals.size() - 1;
-        else
-            _lastUncollectible = -1;
+        _worklist = QVector<Temp>::fromList(_defUses.defs());
     }
 
     void run() {
         while (!_worklist.isEmpty()) {
-            const int v = _worklist.first();
+            const Temp v = _worklist.first();
             _worklist.removeFirst();
 
             if (_defUses.useCount(v) == 0) {
@@ -989,12 +1023,16 @@ public:
                 if (!s) {
                     _defUses.removeDef(v);
                 } else if (!hasSideEffect(s)) {
-//                    qDebug()<<"-- defining stmt for"<<v<<"has no side effect";
+#ifdef SHOW_SSA
+                    qout<<"-- defining stmt for";
+                    v.dump(qout);
+                    qout<<"has no side effect"<<endl;
+#endif
                     QVector<Stmt *> &stmts = _defUses.defStmtBlock(v)->statements;
                     int idx = stmts.indexOf(s);
                     if (idx != -1)
                         stmts.remove(idx);
-                    foreach (int usedVar, _defUses.usedVars(s)) {
+                    foreach (const Temp &usedVar, _defUses.usedVars(s)) {
                         _defUses.removeUse(s, usedVar);
                         _worklist.append(usedVar);
                     }
@@ -1016,10 +1054,27 @@ private:
         // TODO: check if this can be moved to IR building.
         _sideEffect = false;
         if (Move *move = s->asMove()) {
-            if (Temp *t = move->target->asTemp())
-                if (t->index <= _lastUncollectible || t->scope)
+            if (Temp *t = move->target->asTemp()) {
+                switch (t->kind) {
+                case Temp::Formal:
+                case Temp::ScopedFormal:
+                case Temp::ScopedLocal:
+                    return true;
+                case Temp::Local:
+                    if (variablesCanEscape)
+                        return true;
+                    else
+                        break;
+                case Temp::VirtualRegister:
+                    break;
+                default:
+                    Q_ASSERT(!"Invalid temp kind!");
                     return true;
-            move->source->accept(this);
+                }
+                move->source->accept(this);
+            } else {
+                return true;
+            }
         }
         return _sideEffect;
     }
@@ -1073,8 +1128,9 @@ protected:
 };
 
 class TypeInference: public StmtVisitor, public ExprVisitor {
+    bool _variablesCanEscape;
     const DefUsesCalculator &_defUses;
-    QHash<int, int> _tempTypes;
+    QHash<Temp, int> _tempTypes;
     QSet<Stmt *> _worklist;
     struct TypingResult {
         int type;
@@ -1084,13 +1140,15 @@ class TypeInference: public StmtVisitor, public ExprVisitor {
         explicit TypingResult(int type = UnknownType): type(type), fullyTyped(type != UnknownType) {}
     };
     TypingResult _ty;
-    int _localCount;
 
 public:
-    TypeInference(const DefUsesCalculator &defUses): _defUses(defUses), _ty(UnknownType) {}
+    TypeInference(const DefUsesCalculator &defUses)
+        : _defUses(defUses)
+        , _ty(UnknownType)
+    {}
 
     void run(Function *function) {
-        _localCount = function->variablesCanEscape() ? function->locals.size() : 0;
+        _variablesCanEscape = function->variablesCanEscape();
 
         // TODO: the worklist handling looks a bit inefficient... check if there is something better
         _worklist.clear();
@@ -1145,28 +1203,41 @@ private:
         return ty;
     }
 
+    bool isAlwaysAnObject(Temp *t) {
+        switch (t->kind) {
+        case Temp::Formal:
+        case Temp::ScopedFormal:
+        case Temp::ScopedLocal:
+            return true;
+        case Temp::Local:
+            return _variablesCanEscape;
+        default:
+            return false;
+        }
+    }
+
     void setType(Expr *e, int ty) {
         if (Temp *t = e->asTemp()) {
 #if defined(SHOW_SSA)
             qout<<"Setting type for "<< (t->scope?"scoped temp ":"temp ") <<t->index<< " to "<<typeName(Type(ty)) << " (" << ty << ")" << endl;
 #endif
-            if (t->scope || t->index < _localCount) {
+            if (isAlwaysAnObject(t)) {
                 e->type = ObjectType;
             } else {
                 e->type = (Type) ty;
 
-                if (_tempTypes[t->index] != ty) {
-                    _tempTypes[t->index] = ty;
+                if (_tempTypes[*t] != ty) {
+                    _tempTypes[*t] = ty;
 
 #if defined(SHOW_SSA)
-                    foreach (Stmt *s, _defUses.uses(t->index)) {
+                    foreach (Stmt *s, _defUses.uses(*t)) {
                         qout << "Pushing back dependent stmt: ";
                         s->dump(qout);
                         qout << endl;
                     }
 #endif
 
-                    _worklist += QSet<Stmt *>::fromList(_defUses.uses(t->index));
+                    _worklist += QSet<Stmt *>::fromList(_defUses.uses(*t));
                 }
             }
         } else {
@@ -1180,12 +1251,10 @@ protected:
     virtual void visitRegExp(RegExp *) { _ty = TypingResult(ObjectType); }
     virtual void visitName(Name *) { _ty = TypingResult(ObjectType); }
     virtual void visitTemp(Temp *e) {
-        if (e->scope)
-            _ty = TypingResult(ObjectType);
-        else if (e->index < _localCount)
+        if (isAlwaysAnObject(e))
             _ty = TypingResult(ObjectType);
         else
-            _ty = TypingResult(_tempTypes.value(e->index, UnknownType));
+            _ty = TypingResult(_tempTypes.value(*e, UnknownType));
         setType(e, _ty.type);
     }
     virtual void visitClosure(Closure *) { _ty = TypingResult(ObjectType); } // TODO: VERIFY THIS!
@@ -1338,7 +1407,7 @@ class TypePropagation: public StmtVisitor, public ExprVisitor {
         if (requestedType != UnknownType)
             if (e->type != requestedType)
                 if (requestedType & NumberType) {
-                    //qDebug()<<"adding conversion from"<<typeName(e->type)<<"to"<<typeName(requestedType);
+//                    qDebug()<<"adding conversion from"<<typeName(e->type)<<"to"<<typeName(requestedType);
                     addConversion(e, requestedType);
                 }
     }
@@ -1628,7 +1697,7 @@ void scheduleBlocks(Function *function, const DominatorTree &df)
  * has to be replaced by a phase in the specific ISel back-ends and do register allocation at the
  * same time. That way the huge number of redundant moves generated by this function are eliminated.
  */
-void convertOutOfSSA(Function *function, const QHash<int, int> &tempMapping) {
+void convertOutOfSSA(Function *function) {
     // We assume that edge-splitting is already done.
     foreach (BasicBlock *bb, function->basicBlocks) {
         QVector<Stmt *> &stmts = bb->statements;
@@ -1725,12 +1794,12 @@ void QQmlJS::linearize(V4IR::Function *function)
     if (!function->hasTry && !function->hasWith) {
 //        qout << "Starting edge splitting..." << endl;
         doEdgeSplitting(function);
-        showMeTheCode(function);
+//        showMeTheCode(function);
 
         // Calculate the dominator tree:
         DominatorTree df(function->basicBlocks);
 
-        QHash<int, int> tempMapping = convertToSSA(function, df);
+        convertToSSA(function, df);
 //        showMeTheCode(function);
 
 //        qout << "Starting def/uses calculation..." << endl;
@@ -1757,7 +1826,7 @@ void QQmlJS::linearize(V4IR::Function *function)
 //        showMeTheCode(function);
 
 //        qout << "Converting out of SSA..." << endl;
-        convertOutOfSSA(function, tempMapping);
+        convertOutOfSSA(function);
 //        showMeTheCode(function);
 
 #ifndef QT_NO_DEBUG
index 6f688f3..d11cbdf 100644 (file)
 
 #include "qv4jsir_p.h"
 
+QT_BEGIN_NAMESPACE
 namespace QQmlJS {
 
 void linearize(V4IR::Function *function);
 
-}
+} // QQmlJS namespace
+QT_END_NAMESPACE
 
 #endif // QV4SSA_P_H