Enabled lowering pass, improved spew if but a little.
authorDavid Anderson <danderson@mozilla.com>
Mon, 23 May 2011 18:22:00 -0700
changeset 104806 faeb5a8fde24557a2a30ec00c329c3153e6ba2fe
parent 104805 7d362a3df2f82eb4284200d36cebac3f91a2f919
child 104807 6a23997d5e65dc0e340572099aaedf54a6a1fd64
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
milestone6.0a1
Enabled lowering pass, improved spew if but a little.
js/src/ion/InlineList.h
js/src/ion/IonBuilder.cpp
js/src/ion/IonLowering.cpp
js/src/ion/IonSpew.cpp
js/src/ion/MIR.cpp
js/src/ion/MIR.h
js/src/ion/MIRGraph.cpp
js/src/ion/MIRGraph.h
--- a/js/src/ion/InlineList.h
+++ b/js/src/ion/InlineList.h
@@ -118,16 +118,30 @@ class InlineList
         iter++;
 
         node->prev->next = node->next;
         node->next->prev = node->prev;
 
         return iter;
     }
 
+    void insertBefore(Node *at, Node *item) {
+        item->next = at;
+        item->prev = at->prev;
+        at->prev->next = item;
+        at->prev = item;
+    }
+
+    void insertAfter(Node *at, Node *item) {
+        item->next = at->next;
+        item->prev = at;
+        at->next->prev = item;
+        at->next = item;
+    }
+
     void insert(Node *t) {
         t->prev = head.prev;
         t->next = &head;
         head.prev->next = t;
         head.prev = t;
     }
 };
 
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -65,18 +65,18 @@ ion::Go(JSContext *cx, JSScript *script,
     spew.enable("/tmp/ion.cfg");
 
     if (!analyzer.analyze())
         return false;
     spew.spew("Build SSA");
 
     if (!ApplyTypeInformation(&analyzer, graph))
         return false;
-    //if (!Lower(&analyzer, graph))
-    //    return false;
+    if (!Lower(&analyzer, graph))
+        return false;
     spew.spew("Lower");
 
     return false;
 }
 
 IonBuilder::IonBuilder(JSContext *cx, JSScript *script, JSFunction *fun, TempAllocator &temp,
                                    MIRGraph &graph)
   : MIRGenerator(cx, temp, script, fun, graph),
--- a/js/src/ion/IonLowering.cpp
+++ b/js/src/ion/IonLowering.cpp
@@ -59,43 +59,22 @@ class LoweringPhase : public MInstructio
     LoweringPhase(MIRGenerator *gen, MIRGraph &graph)
       : gen(gen),
         graph(graph)
     { }
 
     bool lowerBlock(MBasicBlock *block);
     bool lowerInstruction(MInstruction *ins);
     bool analyze();
-    bool insertBox(MInstruction *def, MOperand *operand);
-    bool insertUnbox(MInstruction *def, MOperand *operand, MIRType type);
-    bool insertConversion(MInstruction *def, MOperand *operand, MIRType type);
 
-#define VISITOR(op) bool visit(M##op *ins) { return false; }
+#define VISITOR(op) bool visit(M##op *ins) { return true; }
     MIR_OPCODE_LIST(VISITOR)
 #undef VISITOR
 };
 
-bool
-LoweringPhase::insertBox(MInstruction *def, MOperand *operand)
-{
-    return false;
-}
-
-bool
-LoweringPhase::insertUnbox(MInstruction *def, MOperand *operand, MIRType type)
-{
-    return false;
-}
-
-bool
-LoweringPhase::insertConversion(MInstruction *def, MOperand *operand, MIRType type)
-{
-    return false;
-}
-
 static inline bool
 IsConversionPure(MIRType from, MIRType to)
 {
     return from != MIRType_Object;
 }
 
 bool
 LoweringPhase::lowerInstruction(MInstruction *ins)
@@ -116,16 +95,22 @@ LoweringPhase::lowerInstruction(MInstruc
             return false;
     }
 
     MUseIterator uses(ins);
     while (uses.more()) {
         MInstruction *use = uses->ins();
         MIRType required = use->requiredInputType(uses->index());
 
+        // Ignore instructions that don't return values, such as guards.
+        if (ins->type() == MIRType_None) {
+            uses.next();
+            continue;
+        }
+
         // An instruction cannot return an abstract type, or if it has inputs,
         // can it accept "none" as a type.
         JS_ASSERT(ins->type() < MIRType_Any);
         JS_ASSERT(required < MIRType_None);
 
         // If the types are compatible, do nothing. Note that even though a
         // narrowed type is compatible with "any", we would like to replace it
         // anyway, to avoid potentially keeping a type tag alive longer that
@@ -136,41 +121,45 @@ LoweringPhase::lowerInstruction(MInstruc
         }
 
         // At this point, the required type is not equal to ins->type(), and
         // usedAs is either Value or a specific type. If required == usedAs,
         // then a narrowed version is available.
         //
         // We also take the more specialized version if the input accepts any
         // type.
-        if (required == usedAs || (required == MIRType_Any && narrowed)) {
+        if ((usedAs != MIRType_Value && required == usedAs) || (required == MIRType_Any && narrowed)) {
             JS_ASSERT(narrowed);
             use->replaceOperand(uses, narrowed);
             continue;
         }
 
         // At this point, if usedAs is not Value, then required == Value. If
         // usedAs is Value, required is anything.
         JS_ASSERT_IF(usedAs != MIRType_Value, required == MIRType_Value);
 
         // If a value is desired, create a box instruction near the use.
         if (required == MIRType_Value) {
             MBox *box = MBox::New(gen, ins);
+            if (!use->block()->insertBefore(use, box))
+                return false;
             use->replaceOperand(uses, box);
             continue;
         }
 
         // At this point, usedAs is definitely Value, and required is not
         // Value. A narrow type is needed here, and this generally means type
         // information is poor or the JS code has messy types. For example, an
         // ADD with a known object input should not trigger an integer
         // specialization, but a boolean input could be okay at the cost of a
         // conversion.
         JS_ASSERT(required < MIRType_Value);
         MConvert *converted = MConvert::New(gen, ins, required);
+        if (!use->block()->insertBefore(use, converted))
+            return false;
         use->replaceOperand(uses, converted);
     }
 
     // Finally, ask the instruction to reserve its register allocation
     // structures.
     return ins->accept(this);
 }
 
--- a/js/src/ion/IonSpew.cpp
+++ b/js/src/ion/IonSpew.cpp
@@ -96,22 +96,16 @@ C1Spewer::spew(FILE *fp, const char *pas
 static void
 DumpInstruction(FILE *fp, MInstruction *ins)
 {
     fprintf(fp, "      ");
     fprintf(fp, "0 %d ", ins->useCount());
     ins->printName(fp);
     fprintf(fp, " ");
     ins->printOpcode(fp);
-    fprintf(fp, " ");
-    for (size_t j = 0; j < ins->numOperands(); j++) {
-        ins->getOperand(j)->ins()->printName(fp);
-        if (j != ins->numOperands() - 1)
-            fprintf(fp, " ");
-    }
     fprintf(fp, " <|@\n");
 }
 
 void
 C1Spewer::spew(FILE *fp, MBasicBlock *block)
 {
     fprintf(fp, "  begin_block\n");
     fprintf(fp, "    name \"B%d\"\n", block->id());
--- a/js/src/ion/MIR.cpp
+++ b/js/src/ion/MIR.cpp
@@ -68,25 +68,45 @@ PrintOpcodeName(FILE *fp, MInstruction::
     size_t len = strlen(name);
     for (size_t i = 0; i < len; i++)
         fprintf(fp, "%c", tolower(name[i]));
 }
 
 void
 MInstruction::printName(FILE *fp)
 {
-    printOpcode(fp);
+    PrintOpcodeName(fp, op());
     fprintf(fp, "%u", id());
-    fprintf(fp, ":v");
 }
 
+static const char *MirTypeNames[] =
+{
+    "",
+    "v",
+    "n",
+    "b",
+    "i",
+    "s",
+    "d",
+    "x",
+    "a"
+};
+
 void
 MInstruction::printOpcode(FILE *fp)
 {
+    if (assumedType() != MIRType_None)
+        fprintf(fp, "%s:", MirTypeNames[assumedType()]);
     PrintOpcodeName(fp, op());
+    fprintf(fp, " ");
+    for (size_t j = 0; j < numOperands(); j++) {
+        getInput(j)->printName(fp);
+        if (j != numOperands() - 1)
+            fprintf(fp, " ");
+    }
 }
 
 size_t
 MInstruction::useCount() const
 {
     MUse *use = uses();
     size_t count = 0;
     while (use) {
@@ -167,16 +187,50 @@ MConstant::New(MIRGenerator *gen, const 
 }
 
 MConstant::MConstant(const js::Value &vp)
   : value_(vp)
 {
     setResultType(MIRTypeFromValue(vp));
 }
 
+void
+MConstant::printOpcode(FILE *fp)
+{
+    PrintOpcodeName(fp, op());
+    fprintf(fp, " ");
+    switch (type()) {
+      case MIRType_Undefined:
+        fprintf(fp, "undefined");
+        break;
+      case MIRType_Null:
+        fprintf(fp, "null");
+        break;
+      case MIRType_Boolean:
+        fprintf(fp, value().toBoolean() ? "true" : "false");
+        break;
+      case MIRType_Int32:
+        fprintf(fp, "%x", value().toInt32());
+        break;
+      case MIRType_Double:
+        fprintf(fp, "%f", value().toDouble());
+        break;
+      case MIRType_Object:
+        fprintf(fp, "object %p (%s)", (void *)&value().toObject(),
+                value().toObject().getClass()->name);
+        break;
+      case MIRType_String:
+        fprintf(fp, "string %p", (void *)value().toString());
+        break;
+      default:
+        JS_NOT_REACHED("unexpected type");
+        break;
+    }
+}
+
 MParameter *
 MParameter::New(MIRGenerator *gen, int32 index)
 {
     JS_ASSERT(index >= CALLEE_SLOT && index < int32(gen->fun()->nargs));
     return new (gen->temp()) MParameter(index);
 }
 
 MCopy *
--- a/js/src/ion/MIR.h
+++ b/js/src/ion/MIR.h
@@ -307,25 +307,25 @@ class MInstruction
         block_ = block;
     }
 
   public:
     MInstruction()
       : block_(NULL),
         uses_(NULL),
         id_(0),
-        assumedType_(MIRType_Value),
+        assumedType_(MIRType_None),
         resultType_(MIRType_None),
         usedTypes_(0),
         inWorklist_(0)
     { }
 
     virtual Opcode op() const = 0;
     void printName(FILE *fp);
-    void printOpcode(FILE *fp);
+    virtual void printOpcode(FILE *fp);
 
     uint32 id() const {
         JS_ASSERT(block_);
         return id_;
     }
     void setId(uint32 id) {
         id_ = id;
     }
@@ -515,16 +515,17 @@ class MConstant : public MAryInstruction
 
   public:
     INSTRUCTION_HEADER(Constant);
     static MConstant *New(MIRGenerator *gen, const Value &v);
 
     const js::Value &value() const {
         return value_;
     }
+    void printOpcode(FILE *fp);
 };
 
 class MParameter : public MAryInstruction<0>
 {
     int32 index_;
 
   public:
     static const int32 CALLEE_SLOT = -2;
@@ -671,17 +672,17 @@ class MCopy : public MUnaryInstruction
 
 class MBox : public MUnaryInstruction
 {
   public:
     INSTRUCTION_HEADER(Box);
     static MBox *New(MIRGenerator *gen, MInstruction *ins)
     {
         // Cannot box a box.
-        JS_ASSERT(!ins->type() == MIRType_Value);
+        JS_ASSERT(ins->type() != MIRType_Value);
 
         MBox *box = new (gen->temp()) MBox();
         if (!box || !box->init(gen, ins))
             return NULL;
         return box;
     }
 
     MIRType requiredInputType(size_t index) const {
--- a/js/src/ion/MIRGraph.cpp
+++ b/js/src/ion/MIRGraph.cpp
@@ -328,16 +328,38 @@ MInstruction *
 MBasicBlock::peek(int32 depth)
 {
     JS_ASSERT(depth < 0);
     JS_ASSERT(stackPosition_ + depth >= gen->firstStackSlot());
     return getSlot(stackPosition_ + depth);
 }
 
 bool
+MBasicBlock::insertBefore(MInstruction *at, MInstruction *ins)
+{
+    if (!ins)
+        return false;
+    ins->setBlock(this);
+    ins->setId(gen->graph().allocInstructionId());
+    instructions_.insertBefore(at, ins);
+    return true;
+}
+
+bool
+MBasicBlock::insertAfter(MInstruction *at, MInstruction *ins)
+{
+    if (!ins)
+        return false;
+    ins->setBlock(this);
+    ins->setId(gen->graph().allocInstructionId());
+    instructions_.insertAfter(at, ins);
+    return true;
+}
+
+bool
 MBasicBlock::add(MInstruction *ins)
 {
     JS_ASSERT(!lastIns_);
     if (!ins)
         return false;
     ins->setBlock(this);
     ins->setId(gen->graph().allocInstructionId());
     instructions_.insert(ins);
--- a/js/src/ion/MIRGraph.h
+++ b/js/src/ion/MIRGraph.h
@@ -178,16 +178,19 @@ class MBasicBlock : public TempObject
     // automatically creates phi nodes and rewrites uses as needed.
     bool addPredecessor(MBasicBlock *pred);
 
     // Sets a back edge. This places phi nodes and rewrites instructions within
     // the current loop as necessary, and corrects the successor block's initial
     // state at the same time. There may be only one backedge per block.
     bool setBackedge(MBasicBlock *block, MBasicBlock *successor);
 
+    bool insertBefore(MInstruction *at, MInstruction *ins);
+    bool insertAfter(MInstruction *at, MInstruction *ins);
+
     ///////////////////////////////////////////////////////
     /////////// END GRAPH BUILDING INSTRUCTIONS ///////////
     ///////////////////////////////////////////////////////
 
     jsbytecode *pc() const {
         return pc_;
     }
     uint32 id() const {