Home | History | Annotate | Download | only in compiler
      1 // Copyright 2014 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/compiler/simplified-lowering.h"
      6 
      7 #include "src/base/bits.h"
      8 #include "src/code-factory.h"
      9 #include "src/compiler/common-operator.h"
     10 #include "src/compiler/graph-inl.h"
     11 #include "src/compiler/node-properties-inl.h"
     12 #include "src/compiler/representation-change.h"
     13 #include "src/compiler/simplified-lowering.h"
     14 #include "src/compiler/simplified-operator.h"
     15 #include "src/objects.h"
     16 
     17 namespace v8 {
     18 namespace internal {
     19 namespace compiler {
     20 
     21 // Macro for outputting trace information from representation inference.
     22 #define TRACE(x) \
     23   if (FLAG_trace_representation) PrintF x
     24 
     25 // Representation selection and lowering of {Simplified} operators to machine
     26 // operators are interwined. We use a fixpoint calculation to compute both the
     27 // output representation and the best possible lowering for {Simplified} nodes.
     28 // Representation change insertion ensures that all values are in the correct
     29 // machine representation after this phase, as dictated by the machine
     30 // operators themselves.
     31 enum Phase {
     32   // 1.) PROPAGATE: Traverse the graph from the end, pushing usage information
     33   //     backwards from uses to definitions, around cycles in phis, according
     34   //     to local rules for each operator.
     35   //     During this phase, the usage information for a node determines the best
     36   //     possible lowering for each operator so far, and that in turn determines
     37   //     the output representation.
     38   //     Therefore, to be correct, this phase must iterate to a fixpoint before
     39   //     the next phase can begin.
     40   PROPAGATE,
     41 
     42   // 2.) LOWER: perform lowering for all {Simplified} nodes by replacing some
     43   //     operators for some nodes, expanding some nodes to multiple nodes, or
     44   //     removing some (redundant) nodes.
     45   //     During this phase, use the {RepresentationChanger} to insert
     46   //     representation changes between uses that demand a particular
     47   //     representation and nodes that produce a different representation.
     48   LOWER
     49 };
     50 
     51 
     52 class RepresentationSelector {
     53  public:
     54   // Information for each node tracked during the fixpoint.
     55   struct NodeInfo {
     56     MachineTypeUnion use : 15;     // Union of all usages for the node.
     57     bool queued : 1;           // Bookkeeping for the traversal.
     58     bool visited : 1;          // Bookkeeping for the traversal.
     59     MachineTypeUnion output : 15;  // Output type of the node.
     60   };
     61 
     62   RepresentationSelector(JSGraph* jsgraph, Zone* zone,
     63                          RepresentationChanger* changer)
     64       : jsgraph_(jsgraph),
     65         count_(jsgraph->graph()->NodeCount()),
     66         info_(zone->NewArray<NodeInfo>(count_)),
     67         nodes_(zone),
     68         replacements_(zone),
     69         contains_js_nodes_(false),
     70         phase_(PROPAGATE),
     71         changer_(changer),
     72         queue_(zone) {
     73     memset(info_, 0, sizeof(NodeInfo) * count_);
     74   }
     75 
     76   void Run(SimplifiedLowering* lowering) {
     77     // Run propagation phase to a fixpoint.
     78     TRACE(("--{Propagation phase}--\n"));
     79     phase_ = PROPAGATE;
     80     Enqueue(jsgraph_->graph()->end());
     81     // Process nodes from the queue until it is empty.
     82     while (!queue_.empty()) {
     83       Node* node = queue_.front();
     84       NodeInfo* info = GetInfo(node);
     85       queue_.pop();
     86       info->queued = false;
     87       TRACE((" visit #%d: %s\n", node->id(), node->op()->mnemonic()));
     88       VisitNode(node, info->use, NULL);
     89       TRACE(("  ==> output "));
     90       PrintInfo(info->output);
     91       TRACE(("\n"));
     92     }
     93 
     94     // Run lowering and change insertion phase.
     95     TRACE(("--{Simplified lowering phase}--\n"));
     96     phase_ = LOWER;
     97     // Process nodes from the collected {nodes_} vector.
     98     for (NodeVector::iterator i = nodes_.begin(); i != nodes_.end(); ++i) {
     99       Node* node = *i;
    100       TRACE((" visit #%d: %s\n", node->id(), node->op()->mnemonic()));
    101       // Reuse {VisitNode()} so the representation rules are in one place.
    102       VisitNode(node, GetUseInfo(node), lowering);
    103     }
    104 
    105     // Perform the final replacements.
    106     for (NodeVector::iterator i = replacements_.begin();
    107          i != replacements_.end(); ++i) {
    108       Node* node = *i;
    109       Node* replacement = *(++i);
    110       node->ReplaceUses(replacement);
    111     }
    112   }
    113 
    114   // Enqueue {node} if the {use} contains new information for that node.
    115   // Add {node} to {nodes_} if this is the first time it's been visited.
    116   void Enqueue(Node* node, MachineTypeUnion use = 0) {
    117     if (phase_ != PROPAGATE) return;
    118     NodeInfo* info = GetInfo(node);
    119     if (!info->visited) {
    120       // First visit of this node.
    121       info->visited = true;
    122       info->queued = true;
    123       nodes_.push_back(node);
    124       queue_.push(node);
    125       TRACE(("  initial: "));
    126       info->use |= use;
    127       PrintUseInfo(node);
    128       return;
    129     }
    130     TRACE(("   queue?: "));
    131     PrintUseInfo(node);
    132     if ((info->use & use) != use) {
    133       // New usage information for the node is available.
    134       if (!info->queued) {
    135         queue_.push(node);
    136         info->queued = true;
    137         TRACE(("   added: "));
    138       } else {
    139         TRACE((" inqueue: "));
    140       }
    141       info->use |= use;
    142       PrintUseInfo(node);
    143     }
    144   }
    145 
    146   bool lower() { return phase_ == LOWER; }
    147 
    148   void Enqueue(Node* node, MachineType use) {
    149     Enqueue(node, static_cast<MachineTypeUnion>(use));
    150   }
    151 
    152   void SetOutput(Node* node, MachineTypeUnion output) {
    153     // Every node should have at most one output representation. Note that
    154     // phis can have 0, if they have not been used in a representation-inducing
    155     // instruction.
    156     DCHECK((output & kRepMask) == 0 ||
    157            base::bits::IsPowerOfTwo32(output & kRepMask));
    158     GetInfo(node)->output = output;
    159   }
    160 
    161   bool BothInputsAre(Node* node, Type* type) {
    162     DCHECK_EQ(2, node->InputCount());
    163     return NodeProperties::GetBounds(node->InputAt(0)).upper->Is(type) &&
    164            NodeProperties::GetBounds(node->InputAt(1)).upper->Is(type);
    165   }
    166 
    167   void ProcessInput(Node* node, int index, MachineTypeUnion use) {
    168     Node* input = node->InputAt(index);
    169     if (phase_ == PROPAGATE) {
    170       // In the propagate phase, propagate the usage information backward.
    171       Enqueue(input, use);
    172     } else {
    173       // In the change phase, insert a change before the use if necessary.
    174       if ((use & kRepMask) == 0) return;  // No input requirement on the use.
    175       MachineTypeUnion output = GetInfo(input)->output;
    176       if ((output & kRepMask & use) == 0) {
    177         // Output representation doesn't match usage.
    178         TRACE(("  change: #%d:%s(@%d #%d:%s) ", node->id(),
    179                node->op()->mnemonic(), index, input->id(),
    180                input->op()->mnemonic()));
    181         TRACE((" from "));
    182         PrintInfo(output);
    183         TRACE((" to "));
    184         PrintInfo(use);
    185         TRACE(("\n"));
    186         Node* n = changer_->GetRepresentationFor(input, output, use);
    187         node->ReplaceInput(index, n);
    188       }
    189     }
    190   }
    191 
    192   void ProcessRemainingInputs(Node* node, int index) {
    193     DCHECK_GE(index, NodeProperties::PastValueIndex(node));
    194     DCHECK_GE(index, NodeProperties::PastContextIndex(node));
    195     for (int i = std::max(index, NodeProperties::FirstEffectIndex(node));
    196          i < NodeProperties::PastEffectIndex(node); ++i) {
    197       Enqueue(node->InputAt(i));  // Effect inputs: just visit
    198     }
    199     for (int i = std::max(index, NodeProperties::FirstControlIndex(node));
    200          i < NodeProperties::PastControlIndex(node); ++i) {
    201       Enqueue(node->InputAt(i));  // Control inputs: just visit
    202     }
    203   }
    204 
    205   // The default, most general visitation case. For {node}, process all value,
    206   // context, effect, and control inputs, assuming that value inputs should have
    207   // {kRepTagged} representation and can observe all output values {kTypeAny}.
    208   void VisitInputs(Node* node) {
    209     InputIter i = node->inputs().begin();
    210     for (int j = OperatorProperties::GetValueInputCount(node->op()); j > 0;
    211          ++i, j--) {
    212       ProcessInput(node, i.index(), kMachAnyTagged);  // Value inputs
    213     }
    214     for (int j = OperatorProperties::GetContextInputCount(node->op()); j > 0;
    215          ++i, j--) {
    216       ProcessInput(node, i.index(), kMachAnyTagged);  // Context inputs
    217     }
    218     for (int j = OperatorProperties::GetEffectInputCount(node->op()); j > 0;
    219          ++i, j--) {
    220       Enqueue(*i);  // Effect inputs: just visit
    221     }
    222     for (int j = OperatorProperties::GetControlInputCount(node->op()); j > 0;
    223          ++i, j--) {
    224       Enqueue(*i);  // Control inputs: just visit
    225     }
    226     SetOutput(node, kMachAnyTagged);
    227   }
    228 
    229   // Helper for binops of the I x I -> O variety.
    230   void VisitBinop(Node* node, MachineTypeUnion input_use,
    231                   MachineTypeUnion output) {
    232     DCHECK_EQ(2, node->InputCount());
    233     ProcessInput(node, 0, input_use);
    234     ProcessInput(node, 1, input_use);
    235     SetOutput(node, output);
    236   }
    237 
    238   // Helper for unops of the I -> O variety.
    239   void VisitUnop(Node* node, MachineTypeUnion input_use,
    240                  MachineTypeUnion output) {
    241     DCHECK_EQ(1, node->InputCount());
    242     ProcessInput(node, 0, input_use);
    243     SetOutput(node, output);
    244   }
    245 
    246   // Helper for leaf nodes.
    247   void VisitLeaf(Node* node, MachineTypeUnion output) {
    248     DCHECK_EQ(0, node->InputCount());
    249     SetOutput(node, output);
    250   }
    251 
    252   // Helpers for specific types of binops.
    253   void VisitFloat64Binop(Node* node) {
    254     VisitBinop(node, kMachFloat64, kMachFloat64);
    255   }
    256   void VisitInt32Binop(Node* node) { VisitBinop(node, kMachInt32, kMachInt32); }
    257   void VisitUint32Binop(Node* node) {
    258     VisitBinop(node, kMachUint32, kMachUint32);
    259   }
    260   void VisitInt64Binop(Node* node) { VisitBinop(node, kMachInt64, kMachInt64); }
    261   void VisitUint64Binop(Node* node) {
    262     VisitBinop(node, kMachUint64, kMachUint64);
    263   }
    264   void VisitFloat64Cmp(Node* node) { VisitBinop(node, kMachFloat64, kRepBit); }
    265   void VisitInt32Cmp(Node* node) { VisitBinop(node, kMachInt32, kRepBit); }
    266   void VisitUint32Cmp(Node* node) { VisitBinop(node, kMachUint32, kRepBit); }
    267   void VisitInt64Cmp(Node* node) { VisitBinop(node, kMachInt64, kRepBit); }
    268   void VisitUint64Cmp(Node* node) { VisitBinop(node, kMachUint64, kRepBit); }
    269 
    270   // Helper for handling phis.
    271   void VisitPhi(Node* node, MachineTypeUnion use,
    272                 SimplifiedLowering* lowering) {
    273     // First, propagate the usage information to inputs of the phi.
    274     if (!lower()) {
    275       int values = OperatorProperties::GetValueInputCount(node->op());
    276       // Propagate {use} of the phi to value inputs, and 0 to control.
    277       Node::Inputs inputs = node->inputs();
    278       for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end();
    279            ++iter, --values) {
    280         // TODO(titzer): it'd be nice to have distinguished edge kinds here.
    281         ProcessInput(node, iter.index(), values > 0 ? use : 0);
    282       }
    283     }
    284     // Phis adapt to whatever output representation their uses demand,
    285     // pushing representation changes to their inputs.
    286     MachineTypeUnion use_rep = GetUseInfo(node) & kRepMask;
    287     MachineTypeUnion use_type = GetUseInfo(node) & kTypeMask;
    288     MachineTypeUnion rep = 0;
    289     if (use_rep & kRepTagged) {
    290       rep = kRepTagged;  // Tagged overrides everything.
    291     } else if (use_rep & kRepFloat64) {
    292       rep = kRepFloat64;
    293     } else if (use_rep & kRepWord64) {
    294       rep = kRepWord64;
    295     } else if (use_rep & kRepWord32) {
    296       rep = kRepWord32;
    297     } else if (use_rep & kRepBit) {
    298       rep = kRepBit;
    299     } else {
    300       // There was no representation associated with any of the uses.
    301       // TODO(titzer): Select the best rep using phi's type, not the usage type?
    302       if (use_type & kTypeAny) {
    303         rep = kRepTagged;
    304       } else if (use_type & kTypeNumber) {
    305         rep = kRepFloat64;
    306       } else if (use_type & kTypeInt64 || use_type & kTypeUint64) {
    307         rep = kRepWord64;
    308       } else if (use_type & kTypeInt32 || use_type & kTypeUint32) {
    309         rep = kRepWord32;
    310       } else if (use_type & kTypeBool) {
    311         rep = kRepBit;
    312       } else {
    313         UNREACHABLE();  // should have at least a usage type!
    314       }
    315     }
    316     // Preserve the usage type, but set the representation.
    317     Type* upper = NodeProperties::GetBounds(node).upper;
    318     MachineTypeUnion output_type = rep | changer_->TypeFromUpperBound(upper);
    319     SetOutput(node, output_type);
    320 
    321     if (lower()) {
    322       int values = OperatorProperties::GetValueInputCount(node->op());
    323 
    324       // Update the phi operator.
    325       MachineType type = static_cast<MachineType>(output_type);
    326       if (type != OpParameter<MachineType>(node)) {
    327         node->set_op(lowering->common()->Phi(type, values));
    328       }
    329 
    330       // Convert inputs to the output representation of this phi.
    331       Node::Inputs inputs = node->inputs();
    332       for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end();
    333            ++iter, --values) {
    334         // TODO(titzer): it'd be nice to have distinguished edge kinds here.
    335         ProcessInput(node, iter.index(), values > 0 ? output_type : 0);
    336       }
    337     }
    338   }
    339 
    340   const Operator* Int32Op(Node* node) {
    341     return changer_->Int32OperatorFor(node->opcode());
    342   }
    343 
    344   const Operator* Uint32Op(Node* node) {
    345     return changer_->Uint32OperatorFor(node->opcode());
    346   }
    347 
    348   const Operator* Float64Op(Node* node) {
    349     return changer_->Float64OperatorFor(node->opcode());
    350   }
    351 
    352   static MachineType AssumeImplicitFloat32Change(MachineType type) {
    353     // TODO(titzer): Assume loads of float32 change representation to float64.
    354     // Fix this with full support for float32 representations.
    355     if (type & kRepFloat32) {
    356       return static_cast<MachineType>((type & ~kRepFloat32) | kRepFloat64);
    357     }
    358     return type;
    359   }
    360 
    361   // Dispatching routine for visiting the node {node} with the usage {use}.
    362   // Depending on the operator, propagate new usage info to the inputs.
    363   void VisitNode(Node* node, MachineTypeUnion use,
    364                  SimplifiedLowering* lowering) {
    365     switch (node->opcode()) {
    366       //------------------------------------------------------------------
    367       // Common operators.
    368       //------------------------------------------------------------------
    369       case IrOpcode::kStart:
    370       case IrOpcode::kDead:
    371         return VisitLeaf(node, 0);
    372       case IrOpcode::kParameter: {
    373         // TODO(titzer): use representation from linkage.
    374         Type* upper = NodeProperties::GetBounds(node).upper;
    375         ProcessInput(node, 0, 0);
    376         SetOutput(node, kRepTagged | changer_->TypeFromUpperBound(upper));
    377         return;
    378       }
    379       case IrOpcode::kInt32Constant:
    380         return VisitLeaf(node, kRepWord32);
    381       case IrOpcode::kInt64Constant:
    382         return VisitLeaf(node, kRepWord64);
    383       case IrOpcode::kFloat64Constant:
    384         return VisitLeaf(node, kRepFloat64);
    385       case IrOpcode::kExternalConstant:
    386         return VisitLeaf(node, kMachPtr);
    387       case IrOpcode::kNumberConstant:
    388         return VisitLeaf(node, kRepTagged);
    389       case IrOpcode::kHeapConstant:
    390         return VisitLeaf(node, kRepTagged);
    391 
    392       case IrOpcode::kEnd:
    393       case IrOpcode::kIfTrue:
    394       case IrOpcode::kIfFalse:
    395       case IrOpcode::kReturn:
    396       case IrOpcode::kMerge:
    397       case IrOpcode::kThrow:
    398         return VisitInputs(node);  // default visit for all node inputs.
    399 
    400       case IrOpcode::kBranch:
    401         ProcessInput(node, 0, kRepBit);
    402         Enqueue(NodeProperties::GetControlInput(node, 0));
    403         break;
    404       case IrOpcode::kPhi:
    405         return VisitPhi(node, use, lowering);
    406 
    407 //------------------------------------------------------------------
    408 // JavaScript operators.
    409 //------------------------------------------------------------------
    410 // For now, we assume that all JS operators were too complex to lower
    411 // to Simplified and that they will always require tagged value inputs
    412 // and produce tagged value outputs.
    413 // TODO(turbofan): it might be possible to lower some JSOperators here,
    414 // but that responsibility really lies in the typed lowering phase.
    415 #define DEFINE_JS_CASE(x) case IrOpcode::k##x:
    416         JS_OP_LIST(DEFINE_JS_CASE)
    417 #undef DEFINE_JS_CASE
    418         contains_js_nodes_ = true;
    419         VisitInputs(node);
    420         return SetOutput(node, kRepTagged);
    421 
    422       //------------------------------------------------------------------
    423       // Simplified operators.
    424       //------------------------------------------------------------------
    425       case IrOpcode::kBooleanNot: {
    426         if (lower()) {
    427           MachineTypeUnion input = GetInfo(node->InputAt(0))->output;
    428           if (input & kRepBit) {
    429             // BooleanNot(x: kRepBit) => WordEqual(x, #0)
    430             node->set_op(lowering->machine()->WordEqual());
    431             node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0));
    432           } else {
    433             // BooleanNot(x: kRepTagged) => WordEqual(x, #false)
    434             node->set_op(lowering->machine()->WordEqual());
    435             node->AppendInput(jsgraph_->zone(), jsgraph_->FalseConstant());
    436           }
    437         } else {
    438           // No input representation requirement; adapt during lowering.
    439           ProcessInput(node, 0, kTypeBool);
    440           SetOutput(node, kRepBit);
    441         }
    442         break;
    443       }
    444       case IrOpcode::kBooleanToNumber: {
    445         if (lower()) {
    446           MachineTypeUnion input = GetInfo(node->InputAt(0))->output;
    447           if (input & kRepBit) {
    448             // BooleanToNumber(x: kRepBit) => x
    449             DeferReplacement(node, node->InputAt(0));
    450           } else {
    451             // BooleanToNumber(x: kRepTagged) => WordEqual(x, #true)
    452             node->set_op(lowering->machine()->WordEqual());
    453             node->AppendInput(jsgraph_->zone(), jsgraph_->TrueConstant());
    454           }
    455         } else {
    456           // No input representation requirement; adapt during lowering.
    457           ProcessInput(node, 0, kTypeBool);
    458           SetOutput(node, kMachInt32);
    459         }
    460         break;
    461       }
    462       case IrOpcode::kNumberEqual:
    463       case IrOpcode::kNumberLessThan:
    464       case IrOpcode::kNumberLessThanOrEqual: {
    465         // Number comparisons reduce to integer comparisons for integer inputs.
    466         if (BothInputsAre(node, Type::Signed32())) {
    467           // => signed Int32Cmp
    468           VisitInt32Cmp(node);
    469           if (lower()) node->set_op(Int32Op(node));
    470         } else if (BothInputsAre(node, Type::Unsigned32())) {
    471           // => unsigned Int32Cmp
    472           VisitUint32Cmp(node);
    473           if (lower()) node->set_op(Uint32Op(node));
    474         } else {
    475           // => Float64Cmp
    476           VisitFloat64Cmp(node);
    477           if (lower()) node->set_op(Float64Op(node));
    478         }
    479         break;
    480       }
    481       case IrOpcode::kNumberAdd:
    482       case IrOpcode::kNumberSubtract: {
    483         // Add and subtract reduce to Int32Add/Sub if the inputs
    484         // are already integers and all uses are truncating.
    485         if (BothInputsAre(node, Type::Signed32()) &&
    486             (use & (kTypeUint32 | kTypeNumber | kTypeAny)) == 0) {
    487           // => signed Int32Add/Sub
    488           VisitInt32Binop(node);
    489           if (lower()) node->set_op(Int32Op(node));
    490         } else if (BothInputsAre(node, Type::Unsigned32()) &&
    491                    (use & (kTypeInt32 | kTypeNumber | kTypeAny)) == 0) {
    492           // => unsigned Int32Add/Sub
    493           VisitUint32Binop(node);
    494           if (lower()) node->set_op(Uint32Op(node));
    495         } else {
    496           // => Float64Add/Sub
    497           VisitFloat64Binop(node);
    498           if (lower()) node->set_op(Float64Op(node));
    499         }
    500         break;
    501       }
    502       case IrOpcode::kNumberMultiply:
    503       case IrOpcode::kNumberDivide:
    504       case IrOpcode::kNumberModulus: {
    505         // Float64Mul/Div/Mod
    506         VisitFloat64Binop(node);
    507         if (lower()) node->set_op(Float64Op(node));
    508         break;
    509       }
    510       case IrOpcode::kNumberToInt32: {
    511         MachineTypeUnion use_rep = use & kRepMask;
    512         if (lower()) {
    513           MachineTypeUnion in = GetInfo(node->InputAt(0))->output;
    514           if ((in & kTypeMask) == kTypeInt32 || (in & kRepMask) == kRepWord32) {
    515             // If the input has type int32, or is already a word32, just change
    516             // representation if necessary.
    517             VisitUnop(node, kTypeInt32 | use_rep, kTypeInt32 | use_rep);
    518             DeferReplacement(node, node->InputAt(0));
    519           } else {
    520             // Require the input in float64 format and perform truncation.
    521             // TODO(turbofan): avoid a truncation with a smi check.
    522             VisitUnop(node, kTypeInt32 | kRepFloat64, kTypeInt32 | kRepWord32);
    523             node->set_op(lowering->machine()->TruncateFloat64ToInt32());
    524           }
    525         } else {
    526           // Propagate a type to the input, but pass through representation.
    527           VisitUnop(node, kTypeInt32, kTypeInt32 | use_rep);
    528         }
    529         break;
    530       }
    531       case IrOpcode::kNumberToUint32: {
    532         MachineTypeUnion use_rep = use & kRepMask;
    533         if (lower()) {
    534           MachineTypeUnion in = GetInfo(node->InputAt(0))->output;
    535           if ((in & kTypeMask) == kTypeUint32 ||
    536               (in & kRepMask) == kRepWord32) {
    537             // The input has type int32, just change representation.
    538             VisitUnop(node, kTypeUint32 | use_rep, kTypeUint32 | use_rep);
    539             DeferReplacement(node, node->InputAt(0));
    540           } else {
    541             // Require the input in float64 format to perform truncation.
    542             // TODO(turbofan): avoid the truncation with a smi check.
    543             VisitUnop(node, kTypeUint32 | kRepFloat64,
    544                       kTypeUint32 | kRepWord32);
    545             node->set_op(lowering->machine()->TruncateFloat64ToInt32());
    546           }
    547         } else {
    548           // Propagate a type to the input, but pass through representation.
    549           VisitUnop(node, kTypeUint32, kTypeUint32 | use_rep);
    550         }
    551         break;
    552       }
    553       case IrOpcode::kReferenceEqual: {
    554         VisitBinop(node, kMachAnyTagged, kRepBit);
    555         if (lower()) node->set_op(lowering->machine()->WordEqual());
    556         break;
    557       }
    558       case IrOpcode::kStringEqual: {
    559         VisitBinop(node, kMachAnyTagged, kRepBit);
    560         if (lower()) lowering->DoStringEqual(node);
    561         break;
    562       }
    563       case IrOpcode::kStringLessThan: {
    564         VisitBinop(node, kMachAnyTagged, kRepBit);
    565         if (lower()) lowering->DoStringLessThan(node);
    566         break;
    567       }
    568       case IrOpcode::kStringLessThanOrEqual: {
    569         VisitBinop(node, kMachAnyTagged, kRepBit);
    570         if (lower()) lowering->DoStringLessThanOrEqual(node);
    571         break;
    572       }
    573       case IrOpcode::kStringAdd: {
    574         VisitBinop(node, kMachAnyTagged, kMachAnyTagged);
    575         if (lower()) lowering->DoStringAdd(node);
    576         break;
    577       }
    578       case IrOpcode::kLoadField: {
    579         FieldAccess access = FieldAccessOf(node->op());
    580         ProcessInput(node, 0, changer_->TypeForBasePointer(access));
    581         ProcessRemainingInputs(node, 1);
    582         SetOutput(node, AssumeImplicitFloat32Change(access.machine_type));
    583         if (lower()) lowering->DoLoadField(node);
    584         break;
    585       }
    586       case IrOpcode::kStoreField: {
    587         FieldAccess access = FieldAccessOf(node->op());
    588         ProcessInput(node, 0, changer_->TypeForBasePointer(access));
    589         ProcessInput(node, 1, AssumeImplicitFloat32Change(access.machine_type));
    590         ProcessRemainingInputs(node, 2);
    591         SetOutput(node, 0);
    592         if (lower()) lowering->DoStoreField(node);
    593         break;
    594       }
    595       case IrOpcode::kLoadElement: {
    596         ElementAccess access = ElementAccessOf(node->op());
    597         ProcessInput(node, 0, changer_->TypeForBasePointer(access));
    598         ProcessInput(node, 1, kMachInt32);  // element index
    599         ProcessInput(node, 2, kMachInt32);  // length
    600         ProcessRemainingInputs(node, 3);
    601         SetOutput(node, AssumeImplicitFloat32Change(access.machine_type));
    602         if (lower()) lowering->DoLoadElement(node);
    603         break;
    604       }
    605       case IrOpcode::kStoreElement: {
    606         ElementAccess access = ElementAccessOf(node->op());
    607         ProcessInput(node, 0, changer_->TypeForBasePointer(access));
    608         ProcessInput(node, 1, kMachInt32);  // element index
    609         ProcessInput(node, 2, kMachInt32);  // length
    610         ProcessInput(node, 3, AssumeImplicitFloat32Change(access.machine_type));
    611         ProcessRemainingInputs(node, 4);
    612         SetOutput(node, 0);
    613         if (lower()) lowering->DoStoreElement(node);
    614         break;
    615       }
    616 
    617       //------------------------------------------------------------------
    618       // Machine-level operators.
    619       //------------------------------------------------------------------
    620       case IrOpcode::kLoad: {
    621         // TODO(titzer): machine loads/stores need to know BaseTaggedness!?
    622         MachineType tBase = kRepTagged;
    623         LoadRepresentation rep = OpParameter<LoadRepresentation>(node);
    624         ProcessInput(node, 0, tBase);   // pointer or object
    625         ProcessInput(node, 1, kMachInt32);  // index
    626         ProcessRemainingInputs(node, 2);
    627         SetOutput(node, rep);
    628         break;
    629       }
    630       case IrOpcode::kStore: {
    631         // TODO(titzer): machine loads/stores need to know BaseTaggedness!?
    632         MachineType tBase = kRepTagged;
    633         StoreRepresentation rep = OpParameter<StoreRepresentation>(node);
    634         ProcessInput(node, 0, tBase);   // pointer or object
    635         ProcessInput(node, 1, kMachInt32);  // index
    636         ProcessInput(node, 2, rep.machine_type());
    637         ProcessRemainingInputs(node, 3);
    638         SetOutput(node, 0);
    639         break;
    640       }
    641       case IrOpcode::kWord32Shr:
    642         // We output unsigned int32 for shift right because JavaScript.
    643         return VisitBinop(node, kRepWord32, kRepWord32 | kTypeUint32);
    644       case IrOpcode::kWord32And:
    645       case IrOpcode::kWord32Or:
    646       case IrOpcode::kWord32Xor:
    647       case IrOpcode::kWord32Shl:
    648       case IrOpcode::kWord32Sar:
    649         // We use signed int32 as the output type for these word32 operations,
    650         // though the machine bits are the same for either signed or unsigned,
    651         // because JavaScript considers the result from these operations signed.
    652         return VisitBinop(node, kRepWord32, kRepWord32 | kTypeInt32);
    653       case IrOpcode::kWord32Equal:
    654         return VisitBinop(node, kRepWord32, kRepBit);
    655 
    656       case IrOpcode::kInt32Add:
    657       case IrOpcode::kInt32Sub:
    658       case IrOpcode::kInt32Mul:
    659       case IrOpcode::kInt32Div:
    660       case IrOpcode::kInt32Mod:
    661         return VisitInt32Binop(node);
    662       case IrOpcode::kInt32UDiv:
    663       case IrOpcode::kInt32UMod:
    664         return VisitUint32Binop(node);
    665       case IrOpcode::kInt32LessThan:
    666       case IrOpcode::kInt32LessThanOrEqual:
    667         return VisitInt32Cmp(node);
    668 
    669       case IrOpcode::kUint32LessThan:
    670       case IrOpcode::kUint32LessThanOrEqual:
    671         return VisitUint32Cmp(node);
    672 
    673       case IrOpcode::kInt64Add:
    674       case IrOpcode::kInt64Sub:
    675       case IrOpcode::kInt64Mul:
    676       case IrOpcode::kInt64Div:
    677       case IrOpcode::kInt64Mod:
    678         return VisitInt64Binop(node);
    679       case IrOpcode::kInt64LessThan:
    680       case IrOpcode::kInt64LessThanOrEqual:
    681         return VisitInt64Cmp(node);
    682 
    683       case IrOpcode::kInt64UDiv:
    684       case IrOpcode::kInt64UMod:
    685         return VisitUint64Binop(node);
    686 
    687       case IrOpcode::kWord64And:
    688       case IrOpcode::kWord64Or:
    689       case IrOpcode::kWord64Xor:
    690       case IrOpcode::kWord64Shl:
    691       case IrOpcode::kWord64Shr:
    692       case IrOpcode::kWord64Sar:
    693         return VisitBinop(node, kRepWord64, kRepWord64);
    694       case IrOpcode::kWord64Equal:
    695         return VisitBinop(node, kRepWord64, kRepBit);
    696 
    697       case IrOpcode::kChangeInt32ToInt64:
    698         return VisitUnop(node, kTypeInt32 | kRepWord32,
    699                          kTypeInt32 | kRepWord64);
    700       case IrOpcode::kChangeUint32ToUint64:
    701         return VisitUnop(node, kTypeUint32 | kRepWord32,
    702                          kTypeUint32 | kRepWord64);
    703       case IrOpcode::kTruncateInt64ToInt32:
    704         // TODO(titzer): Is kTypeInt32 correct here?
    705         return VisitUnop(node, kTypeInt32 | kRepWord64,
    706                          kTypeInt32 | kRepWord32);
    707 
    708       case IrOpcode::kChangeInt32ToFloat64:
    709         return VisitUnop(node, kTypeInt32 | kRepWord32,
    710                          kTypeInt32 | kRepFloat64);
    711       case IrOpcode::kChangeUint32ToFloat64:
    712         return VisitUnop(node, kTypeUint32 | kRepWord32,
    713                          kTypeUint32 | kRepFloat64);
    714       case IrOpcode::kChangeFloat64ToInt32:
    715         return VisitUnop(node, kTypeInt32 | kRepFloat64,
    716                          kTypeInt32 | kRepWord32);
    717       case IrOpcode::kChangeFloat64ToUint32:
    718         return VisitUnop(node, kTypeUint32 | kRepFloat64,
    719                          kTypeUint32 | kRepWord32);
    720 
    721       case IrOpcode::kFloat64Add:
    722       case IrOpcode::kFloat64Sub:
    723       case IrOpcode::kFloat64Mul:
    724       case IrOpcode::kFloat64Div:
    725       case IrOpcode::kFloat64Mod:
    726         return VisitFloat64Binop(node);
    727       case IrOpcode::kFloat64Sqrt:
    728         return VisitUnop(node, kMachFloat64, kMachFloat64);
    729       case IrOpcode::kFloat64Equal:
    730       case IrOpcode::kFloat64LessThan:
    731       case IrOpcode::kFloat64LessThanOrEqual:
    732         return VisitFloat64Cmp(node);
    733       default:
    734         VisitInputs(node);
    735         break;
    736     }
    737   }
    738 
    739   void DeferReplacement(Node* node, Node* replacement) {
    740     if (replacement->id() < count_) {
    741       // Replace with a previously existing node eagerly.
    742       node->ReplaceUses(replacement);
    743     } else {
    744       // Otherwise, we are replacing a node with a representation change.
    745       // Such a substitution must be done after all lowering is done, because
    746       // new nodes do not have {NodeInfo} entries, and that would confuse
    747       // the representation change insertion for uses of it.
    748       replacements_.push_back(node);
    749       replacements_.push_back(replacement);
    750     }
    751     // TODO(titzer) node->RemoveAllInputs();  // Node is now dead.
    752   }
    753 
    754   void PrintUseInfo(Node* node) {
    755     TRACE(("#%d:%-20s ", node->id(), node->op()->mnemonic()));
    756     PrintInfo(GetUseInfo(node));
    757     TRACE(("\n"));
    758   }
    759 
    760   void PrintInfo(MachineTypeUnion info) {
    761     if (FLAG_trace_representation) {
    762       OFStream os(stdout);
    763       os << static_cast<MachineType>(info);
    764     }
    765   }
    766 
    767  private:
    768   JSGraph* jsgraph_;
    769   int count_;                       // number of nodes in the graph
    770   NodeInfo* info_;                  // node id -> usage information
    771   NodeVector nodes_;                // collected nodes
    772   NodeVector replacements_;         // replacements to be done after lowering
    773   bool contains_js_nodes_;          // {true} if a JS operator was seen
    774   Phase phase_;                     // current phase of algorithm
    775   RepresentationChanger* changer_;  // for inserting representation changes
    776   ZoneQueue<Node*> queue_;          // queue for traversing the graph
    777 
    778   NodeInfo* GetInfo(Node* node) {
    779     DCHECK(node->id() >= 0);
    780     DCHECK(node->id() < count_);
    781     return &info_[node->id()];
    782   }
    783 
    784   MachineTypeUnion GetUseInfo(Node* node) { return GetInfo(node)->use; }
    785 };
    786 
    787 
    788 Node* SimplifiedLowering::IsTagged(Node* node) {
    789   // TODO(titzer): factor this out to a TaggingScheme abstraction.
    790   STATIC_ASSERT(kSmiTagMask == 1);  // Only works if tag is the low bit.
    791   return graph()->NewNode(machine()->WordAnd(), node,
    792                           jsgraph()->Int32Constant(kSmiTagMask));
    793 }
    794 
    795 
    796 void SimplifiedLowering::LowerAllNodes() {
    797   SimplifiedOperatorBuilder simplified(graph()->zone());
    798   RepresentationChanger changer(jsgraph(), &simplified,
    799                                 graph()->zone()->isolate());
    800   RepresentationSelector selector(jsgraph(), zone(), &changer);
    801   selector.Run(this);
    802 }
    803 
    804 
    805 Node* SimplifiedLowering::Untag(Node* node) {
    806   // TODO(titzer): factor this out to a TaggingScheme abstraction.
    807   Node* shift_amount = jsgraph()->Int32Constant(kSmiTagSize + kSmiShiftSize);
    808   return graph()->NewNode(machine()->WordSar(), node, shift_amount);
    809 }
    810 
    811 
    812 Node* SimplifiedLowering::SmiTag(Node* node) {
    813   // TODO(titzer): factor this out to a TaggingScheme abstraction.
    814   Node* shift_amount = jsgraph()->Int32Constant(kSmiTagSize + kSmiShiftSize);
    815   return graph()->NewNode(machine()->WordShl(), node, shift_amount);
    816 }
    817 
    818 
    819 Node* SimplifiedLowering::OffsetMinusTagConstant(int32_t offset) {
    820   return jsgraph()->Int32Constant(offset - kHeapObjectTag);
    821 }
    822 
    823 
    824 static WriteBarrierKind ComputeWriteBarrierKind(BaseTaggedness base_is_tagged,
    825                                                 MachineType representation,
    826                                                 Type* type) {
    827   // TODO(turbofan): skip write barriers for Smis, etc.
    828   if (base_is_tagged == kTaggedBase &&
    829       RepresentationOf(representation) == kRepTagged) {
    830     // Write barriers are only for writes into heap objects (i.e. tagged base).
    831     return kFullWriteBarrier;
    832   }
    833   return kNoWriteBarrier;
    834 }
    835 
    836 
    837 void SimplifiedLowering::DoLoadField(Node* node) {
    838   const FieldAccess& access = FieldAccessOf(node->op());
    839   node->set_op(machine()->Load(access.machine_type));
    840   Node* offset = jsgraph()->Int32Constant(access.offset - access.tag());
    841   node->InsertInput(zone(), 1, offset);
    842 }
    843 
    844 
    845 void SimplifiedLowering::DoStoreField(Node* node) {
    846   const FieldAccess& access = FieldAccessOf(node->op());
    847   WriteBarrierKind kind = ComputeWriteBarrierKind(
    848       access.base_is_tagged, access.machine_type, access.type);
    849   node->set_op(
    850       machine()->Store(StoreRepresentation(access.machine_type, kind)));
    851   Node* offset = jsgraph()->Int32Constant(access.offset - access.tag());
    852   node->InsertInput(zone(), 1, offset);
    853 }
    854 
    855 
    856 Node* SimplifiedLowering::ComputeIndex(const ElementAccess& access,
    857                                        Node* index) {
    858   int element_size = ElementSizeOf(access.machine_type);
    859   if (element_size != 1) {
    860     index = graph()->NewNode(machine()->Int32Mul(),
    861                              jsgraph()->Int32Constant(element_size), index);
    862   }
    863   int fixed_offset = access.header_size - access.tag();
    864   if (fixed_offset == 0) return index;
    865   return graph()->NewNode(machine()->Int32Add(), index,
    866                           jsgraph()->Int32Constant(fixed_offset));
    867 }
    868 
    869 
    870 void SimplifiedLowering::DoLoadElement(Node* node) {
    871   const ElementAccess& access = ElementAccessOf(node->op());
    872   node->set_op(machine()->Load(access.machine_type));
    873   node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
    874   node->RemoveInput(2);
    875 }
    876 
    877 
    878 void SimplifiedLowering::DoStoreElement(Node* node) {
    879   const ElementAccess& access = ElementAccessOf(node->op());
    880   WriteBarrierKind kind = ComputeWriteBarrierKind(
    881       access.base_is_tagged, access.machine_type, access.type);
    882   node->set_op(
    883       machine()->Store(StoreRepresentation(access.machine_type, kind)));
    884   node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
    885   node->RemoveInput(2);
    886 }
    887 
    888 
    889 void SimplifiedLowering::DoStringAdd(Node* node) {
    890   Callable callable = CodeFactory::StringAdd(
    891       zone()->isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED);
    892   CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
    893   CallDescriptor* desc =
    894       Linkage::GetStubCallDescriptor(callable.descriptor(), 0, flags, zone());
    895   node->set_op(common()->Call(desc));
    896   node->InsertInput(zone(), 0, jsgraph()->HeapConstant(callable.code()));
    897   node->AppendInput(zone(), jsgraph()->UndefinedConstant());
    898   node->AppendInput(zone(), graph()->start());
    899   node->AppendInput(zone(), graph()->start());
    900 }
    901 
    902 
    903 Node* SimplifiedLowering::StringComparison(Node* node, bool requires_ordering) {
    904   CEntryStub stub(zone()->isolate(), 1);
    905   Runtime::FunctionId f =
    906       requires_ordering ? Runtime::kStringCompare : Runtime::kStringEquals;
    907   ExternalReference ref(f, zone()->isolate());
    908   Operator::Properties props = node->op()->properties();
    909   // TODO(mstarzinger): We should call StringCompareStub here instead, once an
    910   // interface descriptor is available for it.
    911   CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(f, 2, props, zone());
    912   return graph()->NewNode(common()->Call(desc),
    913                           jsgraph()->HeapConstant(stub.GetCode()),
    914                           NodeProperties::GetValueInput(node, 0),
    915                           NodeProperties::GetValueInput(node, 1),
    916                           jsgraph()->ExternalConstant(ref),
    917                           jsgraph()->Int32Constant(2),
    918                           jsgraph()->UndefinedConstant());
    919 }
    920 
    921 
    922 void SimplifiedLowering::DoStringEqual(Node* node) {
    923   node->set_op(machine()->WordEqual());
    924   node->ReplaceInput(0, StringComparison(node, false));
    925   node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL));
    926 }
    927 
    928 
    929 void SimplifiedLowering::DoStringLessThan(Node* node) {
    930   node->set_op(machine()->IntLessThan());
    931   node->ReplaceInput(0, StringComparison(node, true));
    932   node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL));
    933 }
    934 
    935 
    936 void SimplifiedLowering::DoStringLessThanOrEqual(Node* node) {
    937   node->set_op(machine()->IntLessThanOrEqual());
    938   node->ReplaceInput(0, StringComparison(node, true));
    939   node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL));
    940 }
    941 
    942 
    943 }  // namespace compiler
    944 }  // namespace internal
    945 }  // namespace v8
    946