| Index: src/compiler/simplified-lowering.cc
 | 
| diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc
 | 
| index 5033c1919ec073acc57dda0b34a8c8b6f52169f4..3402607790e52ac593f8ca71f996fa13bd4681ff 100644
 | 
| --- a/src/compiler/simplified-lowering.cc
 | 
| +++ b/src/compiler/simplified-lowering.cc
 | 
| @@ -56,6 +56,120 @@ enum Phase {
 | 
|  };
 | 
|  
 | 
|  
 | 
| +namespace {
 | 
| +
 | 
| +// The {UseInfo} class is used to describe a use of an input of a node.
 | 
| +//
 | 
| +// This information is used in two different ways, based on the phase:
 | 
| +//
 | 
| +// 1. During propagation, the use info is used to inform the input node
 | 
| +//    about what part of the input is used (we call this truncation) and what
 | 
| +//    is the preferred representation.
 | 
| +//
 | 
| +// 2. During lowering, the use info is used to properly convert the input
 | 
| +//    to the preferred representation. The preferred representation might be
 | 
| +//    insufficient to do the conversion (e.g. word32->float64 conv), so we also
 | 
| +//    need the signedness information to produce the correct value.
 | 
| +class UseInfo {
 | 
| + public:
 | 
| +  // Constructors
 | 
| +  // ================================================================
 | 
| +
 | 
| +  // Uses truncating to the preferred representation.
 | 
| +  static UseInfo TruncatingWord32() {
 | 
| +    return UseInfo(kTypeInt32 | kTypeUint32 | kRepWord32);
 | 
| +  }
 | 
| +  static UseInfo TruncatingWord64() {
 | 
| +    return UseInfo(kTypeInt64 | kTypeUint64 | kRepWord64);
 | 
| +  }
 | 
| +  static UseInfo Bool() { return UseInfo(kMachBool); }
 | 
| +  static UseInfo Float32() { return UseInfo(kMachFloat32); }
 | 
| +  static UseInfo Float64() { return UseInfo(kMachFloat64); }
 | 
| +  static UseInfo PointerInt() {
 | 
| +    return kPointerSize == 4 ? TruncatingWord32() : TruncatingWord64();
 | 
| +  }
 | 
| +
 | 
| +  // Non-truncating uses.
 | 
| +  static UseInfo AnyTagged() { return UseInfo(kMachAnyTagged); }
 | 
| +  static UseInfo Any() { return UseInfo(kTypeAny); }
 | 
| +
 | 
| +  // Ignored-value 'use'.
 | 
| +  static UseInfo None() { return UseInfo(kMachNone); }
 | 
| +
 | 
| +  // Truncating to a representation that is smaller than the preferred
 | 
| +  // one.
 | 
| +  static UseInfo Float64TruncatingToWord32() {
 | 
| +    return UseInfo(kRepFloat64 | kTypeInt32 | kTypeUint32);
 | 
| +  }
 | 
| +  static UseInfo Word64TruncatingToWord32() {
 | 
| +    return UseInfo(kRepWord64 | kTypeInt32 | kTypeUint32);
 | 
| +  }
 | 
| +  static UseInfo AnyTruncatingToBool() { return UseInfo(kTypeBool); }
 | 
| +
 | 
| +  UseInfo(MachineTypeUnion representation, MachineTypeUnion truncation)
 | 
| +      : type_(representation | truncation) {
 | 
| +    DCHECK(base::bits::CountPopulation32(representation & kRepMask) == 1);
 | 
| +    DCHECK((representation & kTypeMask) == 0);
 | 
| +    DCHECK((truncation & kRepMask) == 0);
 | 
| +    // TODO(jarin) Check/normalize truncation?
 | 
| +  }
 | 
| +
 | 
| +  // Queries
 | 
| +  // ================================================================
 | 
| +  MachineType GetRepresentation() const {
 | 
| +    return static_cast<MachineType>(type_ & kRepMask);
 | 
| +  }
 | 
| +
 | 
| +  // This should only be used by the Enqueue method.
 | 
| +  MachineTypeUnion machine_type() const { return type_; }
 | 
| +
 | 
| + private:
 | 
| +  explicit UseInfo(MachineTypeUnion type) : type_(type) {}
 | 
| +
 | 
| +  MachineTypeUnion type_;
 | 
| +};
 | 
| +
 | 
| +
 | 
| +UseInfo UseInfoFromRepresentation(MachineTypeUnion rep) {
 | 
| +  DCHECK((rep & kTypeMask) == 0);
 | 
| +  if (rep & kRepTagged) return UseInfo::AnyTagged();
 | 
| +  if (rep & kRepFloat64) {
 | 
| +    DCHECK((rep & kRepWord64) == 0);
 | 
| +    return UseInfo::Float64();
 | 
| +  }
 | 
| +  if (rep & kRepFloat32) {
 | 
| +    if (rep == kRepFloat32) return UseInfo::Float32();
 | 
| +    return UseInfo::AnyTagged();
 | 
| +  }
 | 
| +  if (rep & kRepWord64) {
 | 
| +    return UseInfo::TruncatingWord64();
 | 
| +  }
 | 
| +  if (rep & (kRepWord32 | kRepWord16 | kRepWord8)) {
 | 
| +    CHECK(!(rep & kRepBit));
 | 
| +    return UseInfo::TruncatingWord32();
 | 
| +  }
 | 
| +  DCHECK(rep & kRepBit);
 | 
| +  return UseInfo::Bool();
 | 
| +}
 | 
| +
 | 
| +
 | 
| +UseInfo UseInfoFromMachineType(MachineType type) {
 | 
| +  return UseInfoFromRepresentation(RepresentationOf(type));
 | 
| +}
 | 
| +
 | 
| +
 | 
| +UseInfo UseInfoForBasePointer(const FieldAccess& access) {
 | 
| +  return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::PointerInt();
 | 
| +}
 | 
| +
 | 
| +
 | 
| +UseInfo UseInfoForBasePointer(const ElementAccess& access) {
 | 
| +  return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::PointerInt();
 | 
| +}
 | 
| +
 | 
| +}  // namespace
 | 
| +
 | 
| +
 | 
|  class RepresentationSelector {
 | 
|   public:
 | 
|    // Information for each node tracked during the fixpoint.
 | 
| @@ -131,7 +245,9 @@ class RepresentationSelector {
 | 
|  
 | 
|    // Enqueue {node} if the {use} contains new information for that node.
 | 
|    // Add {node} to {nodes_} if this is the first time it's been visited.
 | 
| -  void Enqueue(Node* node, MachineTypeUnion use = 0) {
 | 
| +  void Enqueue(Node* node, UseInfo use_info = UseInfo::None()) {
 | 
| +    MachineTypeUnion use = use_info.machine_type();
 | 
| +
 | 
|      if (phase_ != PROPAGATE) return;
 | 
|      NodeInfo* info = GetInfo(node);
 | 
|      if (!info->visited) {
 | 
| @@ -163,10 +279,6 @@ class RepresentationSelector {
 | 
|  
 | 
|    bool lower() { return phase_ == LOWER; }
 | 
|  
 | 
| -  void Enqueue(Node* node, MachineType use) {
 | 
| -    Enqueue(node, static_cast<MachineTypeUnion>(use));
 | 
| -  }
 | 
| -
 | 
|    void SetOutput(Node* node, MachineTypeUnion output) {
 | 
|      // Every node should have at most one output representation. Note that
 | 
|      // phis can have 0, if they have not been used in a representation-inducing
 | 
| @@ -182,11 +294,11 @@ class RepresentationSelector {
 | 
|             NodeProperties::GetType(node->InputAt(1))->Is(type);
 | 
|    }
 | 
|  
 | 
| -  void ProcessTruncateWord32Input(Node* node, int index, MachineTypeUnion use) {
 | 
| +  void ProcessTruncateWord32Input(Node* node, int index) {
 | 
|      Node* input = node->InputAt(index);
 | 
|      if (phase_ == PROPAGATE) {
 | 
|        // In the propagate phase, propagate the usage information backward.
 | 
| -      Enqueue(input, use);
 | 
| +      Enqueue(input, UseInfo::TruncatingWord32());
 | 
|      } else {
 | 
|        // In the change phase, insert a change before the use if necessary.
 | 
|        MachineTypeUnion output = GetInfo(input)->output;
 | 
| @@ -197,8 +309,6 @@ class RepresentationSelector {
 | 
|                input->op()->mnemonic());
 | 
|          TRACE(" from ");
 | 
|          PrintInfo(output);
 | 
| -        TRACE(" to ");
 | 
| -        PrintInfo(use);
 | 
|          TRACE("\n");
 | 
|          Node* n = changer_->GetTruncatedWord32For(input, output);
 | 
|          node->ReplaceInput(index, n);
 | 
| @@ -206,28 +316,36 @@ class RepresentationSelector {
 | 
|      }
 | 
|    }
 | 
|  
 | 
| -  void ProcessInput(Node* node, int index, MachineTypeUnion use) {
 | 
| +  void EnqueueInputUse(Node* node, int index, UseInfo use) {
 | 
| +    Enqueue(node->InputAt(index), use);
 | 
| +  }
 | 
| +
 | 
| +  void ConvertInput(Node* node, int index, UseInfo use) {
 | 
|      Node* input = node->InputAt(index);
 | 
| +    // In the change phase, insert a change before the use if necessary.
 | 
| +    if (use.GetRepresentation() == kMachNone)
 | 
| +      return;  // No input requirement on the use.
 | 
| +    MachineTypeUnion output = GetInfo(input)->output;
 | 
| +    if ((output & kRepMask) != use.GetRepresentation()) {
 | 
| +      // Output representation doesn't match usage.
 | 
| +      TRACE("  change: #%d:%s(@%d #%d:%s) ", node->id(), node->op()->mnemonic(),
 | 
| +            index, input->id(), input->op()->mnemonic());
 | 
| +      TRACE(" from ");
 | 
| +      PrintInfo(output);
 | 
| +      TRACE(" to ");
 | 
| +      PrintUseInfo(use);
 | 
| +      TRACE("\n");
 | 
| +      Node* n =
 | 
| +          changer_->GetRepresentationFor(input, output, use.machine_type());
 | 
| +      node->ReplaceInput(index, n);
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  void ProcessInput(Node* node, int index, UseInfo use) {
 | 
|      if (phase_ == PROPAGATE) {
 | 
| -      // In the propagate phase, propagate the usage information backward.
 | 
| -      Enqueue(input, use);
 | 
| +      EnqueueInputUse(node, index, use);
 | 
|      } else {
 | 
| -      // In the change phase, insert a change before the use if necessary.
 | 
| -      if ((use & kRepMask) == 0) return;  // No input requirement on the use.
 | 
| -      MachineTypeUnion output = GetInfo(input)->output;
 | 
| -      if ((output & kRepMask & use) == 0) {
 | 
| -        // Output representation doesn't match usage.
 | 
| -        TRACE("  change: #%d:%s(@%d #%d:%s) ", node->id(),
 | 
| -              node->op()->mnemonic(), index, input->id(),
 | 
| -              input->op()->mnemonic());
 | 
| -        TRACE(" from ");
 | 
| -        PrintInfo(output);
 | 
| -        TRACE(" to ");
 | 
| -        PrintInfo(use);
 | 
| -        TRACE("\n");
 | 
| -        Node* n = changer_->GetRepresentationFor(input, output, use);
 | 
| -        node->ReplaceInput(index, n);
 | 
| -      }
 | 
| +      ConvertInput(node, index, use);
 | 
|      }
 | 
|    }
 | 
|  
 | 
| @@ -253,7 +371,7 @@ class RepresentationSelector {
 | 
|                         OperatorProperties::GetContextInputCount(node->op());
 | 
|      // Visit value and context inputs as tagged.
 | 
|      for (int i = 0; i < tagged_count; i++) {
 | 
| -      ProcessInput(node, i, kMachAnyTagged);
 | 
| +      ProcessInput(node, i, UseInfo::AnyTagged());
 | 
|      }
 | 
|      // Only enqueue other inputs (framestates, effects, control).
 | 
|      for (int i = tagged_count; i < node->InputCount(); i++) {
 | 
| @@ -264,8 +382,8 @@ class RepresentationSelector {
 | 
|    }
 | 
|  
 | 
|    // Helper for binops of the R x L -> O variety.
 | 
| -  void VisitBinop(Node* node, MachineTypeUnion left_use,
 | 
| -                  MachineTypeUnion right_use, MachineTypeUnion output) {
 | 
| +  void VisitBinop(Node* node, UseInfo left_use, UseInfo right_use,
 | 
| +                  MachineTypeUnion output) {
 | 
|      DCHECK_EQ(2, node->op()->ValueInputCount());
 | 
|      ProcessInput(node, 0, left_use);
 | 
|      ProcessInput(node, 1, right_use);
 | 
| @@ -276,14 +394,12 @@ class RepresentationSelector {
 | 
|    }
 | 
|  
 | 
|    // Helper for binops of the I x I -> O variety.
 | 
| -  void VisitBinop(Node* node, MachineTypeUnion input_use,
 | 
| -                  MachineTypeUnion output) {
 | 
| +  void VisitBinop(Node* node, UseInfo input_use, MachineTypeUnion output) {
 | 
|      VisitBinop(node, input_use, input_use, output);
 | 
|    }
 | 
|  
 | 
|    // Helper for unops of the I -> O variety.
 | 
| -  void VisitUnop(Node* node, MachineTypeUnion input_use,
 | 
| -                 MachineTypeUnion output) {
 | 
| +  void VisitUnop(Node* node, UseInfo input_use, MachineTypeUnion output) {
 | 
|      DCHECK_EQ(1, node->InputCount());
 | 
|      ProcessInput(node, 0, input_use);
 | 
|      SetOutput(node, output);
 | 
| @@ -297,24 +413,38 @@ class RepresentationSelector {
 | 
|  
 | 
|    // Helpers for specific types of binops.
 | 
|    void VisitFloat64Binop(Node* node) {
 | 
| -    VisitBinop(node, kMachFloat64, kMachFloat64);
 | 
| +    VisitBinop(node, UseInfo::Float64(), kMachFloat64);
 | 
| +  }
 | 
| +  void VisitInt32Binop(Node* node) {
 | 
| +    VisitBinop(node, UseInfo::TruncatingWord32(), kMachInt32);
 | 
|    }
 | 
| -  void VisitInt32Binop(Node* node) { VisitBinop(node, kMachInt32, kMachInt32); }
 | 
|    void VisitUint32Binop(Node* node) {
 | 
| -    VisitBinop(node, kMachUint32, kMachUint32);
 | 
| +    VisitBinop(node, UseInfo::TruncatingWord32(), kMachUint32);
 | 
| +  }
 | 
| +  void VisitInt64Binop(Node* node) {
 | 
| +    VisitBinop(node, UseInfo::TruncatingWord64(), kMachInt64);
 | 
|    }
 | 
| -  void VisitInt64Binop(Node* node) { VisitBinop(node, kMachInt64, kMachInt64); }
 | 
|    void VisitUint64Binop(Node* node) {
 | 
| -    VisitBinop(node, kMachUint64, kMachUint64);
 | 
| +    VisitBinop(node, UseInfo::TruncatingWord64(), kMachUint64);
 | 
| +  }
 | 
| +  void VisitFloat64Cmp(Node* node) {
 | 
| +    VisitBinop(node, UseInfo::Float64(), kMachBool);
 | 
| +  }
 | 
| +  void VisitInt32Cmp(Node* node) {
 | 
| +    VisitBinop(node, UseInfo::TruncatingWord32(), kMachBool);
 | 
| +  }
 | 
| +  void VisitUint32Cmp(Node* node) {
 | 
| +    VisitBinop(node, UseInfo::TruncatingWord32(), kMachBool);
 | 
| +  }
 | 
| +  void VisitInt64Cmp(Node* node) {
 | 
| +    VisitBinop(node, UseInfo::TruncatingWord64(), kMachBool);
 | 
| +  }
 | 
| +  void VisitUint64Cmp(Node* node) {
 | 
| +    VisitBinop(node, UseInfo::TruncatingWord64(), kMachBool);
 | 
|    }
 | 
| -  void VisitFloat64Cmp(Node* node) { VisitBinop(node, kMachFloat64, kRepBit); }
 | 
| -  void VisitInt32Cmp(Node* node) { VisitBinop(node, kMachInt32, kRepBit); }
 | 
| -  void VisitUint32Cmp(Node* node) { VisitBinop(node, kMachUint32, kRepBit); }
 | 
| -  void VisitInt64Cmp(Node* node) { VisitBinop(node, kMachInt64, kRepBit); }
 | 
| -  void VisitUint64Cmp(Node* node) { VisitBinop(node, kMachUint64, kRepBit); }
 | 
|  
 | 
|    // Infer representation for phi-like nodes.
 | 
| -  MachineType GetRepresentationForPhi(Node* node, MachineTypeUnion use) {
 | 
| +  static MachineType GetRepresentationForPhi(Node* node, MachineTypeUnion use) {
 | 
|      // Phis adapt to the output representation their uses demand.
 | 
|      Type* upper = NodeProperties::GetType(node);
 | 
|      if ((use & kRepMask) == kRepFloat32) {
 | 
| @@ -331,9 +461,8 @@ class RepresentationSelector {
 | 
|        if (upper->Is(Type::Signed32()) || upper->Is(Type::Unsigned32())) {
 | 
|          // multiple uses, but we are within 32 bits range => pick kRepWord32.
 | 
|          return kRepWord32;
 | 
| -      } else if ((use & kTypeMask) == kTypeInt32 ||
 | 
| -                 (use & kTypeMask) == kTypeUint32) {
 | 
| -        // We only use 32 bits or we use the result consistently.
 | 
| +      } else if (!CanObserveNonWord32(use)) {
 | 
| +        // We only use 32 bits.
 | 
|          return kRepWord32;
 | 
|        } else {
 | 
|          return kRepFloat64;
 | 
| @@ -353,7 +482,7 @@ class RepresentationSelector {
 | 
|    // Helper for handling selects.
 | 
|    void VisitSelect(Node* node, MachineTypeUnion use,
 | 
|                     SimplifiedLowering* lowering) {
 | 
| -    ProcessInput(node, 0, kRepBit);
 | 
| +    ProcessInput(node, 0, UseInfo::Bool());
 | 
|      MachineType output = GetRepresentationForPhi(node, use);
 | 
|  
 | 
|      Type* upper = NodeProperties::GetType(node);
 | 
| @@ -369,17 +498,12 @@ class RepresentationSelector {
 | 
|          NodeProperties::ChangeOp(node,
 | 
|                                   lowering->common()->Select(type, p.hint()));
 | 
|        }
 | 
| -
 | 
| -      // Convert inputs to the output representation of this select.
 | 
| -      ProcessInput(node, 1, output_type);
 | 
| -      ProcessInput(node, 2, output_type);
 | 
| -    } else {
 | 
| -      // Propagate {use} of the select to value inputs.
 | 
| -      MachineType use_type =
 | 
| -          static_cast<MachineType>((use & kTypeMask) | output);
 | 
| -      ProcessInput(node, 1, use_type);
 | 
| -      ProcessInput(node, 2, use_type);
 | 
|      }
 | 
| +    // Convert inputs to the output representation of this phi, pass the
 | 
| +    // use truncation along.
 | 
| +    UseInfo input_use(output, use & kTypeMask);
 | 
| +    ProcessInput(node, 1, input_use);
 | 
| +    ProcessInput(node, 2, input_use);
 | 
|    }
 | 
|  
 | 
|    // Helper for handling phis.
 | 
| @@ -404,9 +528,9 @@ class RepresentationSelector {
 | 
|  
 | 
|      // Convert inputs to the output representation of this phi, pass the
 | 
|      // use truncation along.
 | 
| -    MachineType use_type = static_cast<MachineType>((use & kTypeMask) | output);
 | 
| +    UseInfo input_use(output, use & kTypeMask);
 | 
|      for (int i = 0; i < node->InputCount(); i++) {
 | 
| -      ProcessInput(node, i, i < values ? use_type : 0);
 | 
| +      ProcessInput(node, i, i < values ? input_use : UseInfo::None());
 | 
|      }
 | 
|    }
 | 
|  
 | 
| @@ -418,11 +542,11 @@ class RepresentationSelector {
 | 
|      for (int i = 0; i < node->InputCount(); i++) {
 | 
|        if (i == 0) {
 | 
|          // The target of the call.
 | 
| -        ProcessInput(node, i, 0);
 | 
| +        ProcessInput(node, i, UseInfo::None());
 | 
|        } else if ((i - 1) < params) {
 | 
| -        ProcessInput(node, i, sig->GetParam(i - 1));
 | 
| +        ProcessInput(node, i, UseInfoFromMachineType(sig->GetParam(i - 1)));
 | 
|        } else {
 | 
| -        ProcessInput(node, i, 0);
 | 
| +        ProcessInput(node, i, UseInfo::None());
 | 
|        }
 | 
|      }
 | 
|  
 | 
| @@ -436,7 +560,7 @@ class RepresentationSelector {
 | 
|    void VisitStateValues(Node* node) {
 | 
|      if (phase_ == PROPAGATE) {
 | 
|        for (int i = 0; i < node->InputCount(); i++) {
 | 
| -        Enqueue(node->InputAt(i), kTypeAny);
 | 
| +        Enqueue(node->InputAt(i), UseInfo::Any());
 | 
|        }
 | 
|      } else {
 | 
|        Zone* zone = jsgraph_->zone();
 | 
| @@ -482,11 +606,11 @@ class RepresentationSelector {
 | 
|              NodeProperties::GetType(node)->Is(Type::Unsigned32()));
 | 
|    }
 | 
|  
 | 
| -  bool CanObserveNonWord32(MachineTypeUnion use) {
 | 
| +  static bool CanObserveNonWord32(MachineTypeUnion use) {
 | 
|      return (use & kTypeMask & ~(kTypeInt32 | kTypeUint32)) != 0;
 | 
|    }
 | 
|  
 | 
| -  bool CanObserveNaN(MachineTypeUnion use) {
 | 
| +  static bool CanObserveNaN(MachineTypeUnion use) {
 | 
|      return (use & (kTypeNumber | kTypeAny)) != 0;
 | 
|    }
 | 
|  
 | 
| @@ -504,7 +628,7 @@ class RepresentationSelector {
 | 
|        case IrOpcode::kParameter: {
 | 
|          // TODO(titzer): use representation from linkage.
 | 
|          Type* upper = NodeProperties::GetType(node);
 | 
| -        ProcessInput(node, 0, 0);
 | 
| +        ProcessInput(node, 0, UseInfo::None());
 | 
|          SetOutput(node, kRepTagged | changer_->TypeFromUpperBound(upper));
 | 
|          return;
 | 
|        }
 | 
| @@ -524,11 +648,11 @@ class RepresentationSelector {
 | 
|          return VisitLeaf(node, kRepTagged);
 | 
|  
 | 
|        case IrOpcode::kBranch:
 | 
| -        ProcessInput(node, 0, kRepBit);
 | 
| +        ProcessInput(node, 0, UseInfo::Bool());
 | 
|          Enqueue(NodeProperties::GetControlInput(node, 0));
 | 
|          break;
 | 
|        case IrOpcode::kSwitch:
 | 
| -        ProcessInput(node, 0, kRepWord32);
 | 
| +        ProcessInput(node, 0, UseInfo::TruncatingWord32());
 | 
|          Enqueue(NodeProperties::GetControlInput(node, 0));
 | 
|          break;
 | 
|        case IrOpcode::kSelect:
 | 
| @@ -569,7 +693,7 @@ class RepresentationSelector {
 | 
|            }
 | 
|          } else {
 | 
|            // No input representation requirement; adapt during lowering.
 | 
| -          ProcessInput(node, 0, kTypeBool);
 | 
| +          ProcessInput(node, 0, UseInfo::AnyTruncatingToBool());
 | 
|            SetOutput(node, kRepBit);
 | 
|          }
 | 
|          break;
 | 
| @@ -587,7 +711,7 @@ class RepresentationSelector {
 | 
|            }
 | 
|          } else {
 | 
|            // No input representation requirement; adapt during lowering.
 | 
| -          ProcessInput(node, 0, kTypeBool);
 | 
| +          ProcessInput(node, 0, UseInfo::AnyTruncatingToBool());
 | 
|            SetOutput(node, kMachInt32);
 | 
|          }
 | 
|          break;
 | 
| @@ -625,8 +749,8 @@ class RepresentationSelector {
 | 
|            if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
 | 
|          } else if (CanLowerToWord32AdditiveBinop(node, use)) {
 | 
|            // => signed Int32Add/Sub, truncating inputs
 | 
| -          ProcessTruncateWord32Input(node, 0, kTypeInt32);
 | 
| -          ProcessTruncateWord32Input(node, 1, kTypeInt32);
 | 
| +          ProcessTruncateWord32Input(node, 0);
 | 
| +          ProcessTruncateWord32Input(node, 1);
 | 
|            SetOutput(node, kMachInt32);
 | 
|            if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
 | 
|          } else {
 | 
| @@ -695,17 +819,20 @@ class RepresentationSelector {
 | 
|          break;
 | 
|        }
 | 
|        case IrOpcode::kNumberShiftLeft: {
 | 
| -        VisitBinop(node, kMachInt32, kMachUint32, kMachInt32);
 | 
| +        VisitBinop(node, UseInfo::TruncatingWord32(),
 | 
| +                   UseInfo::TruncatingWord32(), kMachInt32);
 | 
|          if (lower()) lowering->DoShift(node, lowering->machine()->Word32Shl());
 | 
|          break;
 | 
|        }
 | 
|        case IrOpcode::kNumberShiftRight: {
 | 
| -        VisitBinop(node, kMachInt32, kMachUint32, kMachInt32);
 | 
| +        VisitBinop(node, UseInfo::TruncatingWord32(),
 | 
| +                   UseInfo::TruncatingWord32(), kMachInt32);
 | 
|          if (lower()) lowering->DoShift(node, lowering->machine()->Word32Sar());
 | 
|          break;
 | 
|        }
 | 
|        case IrOpcode::kNumberShiftRightLogical: {
 | 
| -        VisitBinop(node, kMachUint32, kMachUint32, kMachUint32);
 | 
| +        VisitBinop(node, UseInfo::TruncatingWord32(),
 | 
| +                   UseInfo::TruncatingWord32(), kMachUint32);
 | 
|          if (lower()) lowering->DoShift(node, lowering->machine()->Word32Shr());
 | 
|          break;
 | 
|        }
 | 
| @@ -716,22 +843,24 @@ class RepresentationSelector {
 | 
|          MachineTypeUnion in = GetInfo(input)->output;
 | 
|          if (in_upper->Is(Type::Signed32())) {
 | 
|            // If the input has type int32, pass through representation.
 | 
| -          VisitUnop(node, kTypeInt32 | use_rep, kTypeInt32 | use_rep);
 | 
| +          VisitUnop(node, UseInfoFromRepresentation(use_rep),
 | 
| +                    kTypeInt32 | use_rep);
 | 
|            if (lower()) DeferReplacement(node, node->InputAt(0));
 | 
|          } else if ((in & kTypeMask) == kTypeUint32 ||
 | 
|                     in_upper->Is(Type::Unsigned32())) {
 | 
|            // Just change representation if necessary.
 | 
| -          VisitUnop(node, kTypeUint32 | kRepWord32, kTypeInt32 | kRepWord32);
 | 
| +          VisitUnop(node, UseInfo::TruncatingWord32(), kTypeInt32 | kRepWord32);
 | 
|            if (lower()) DeferReplacement(node, node->InputAt(0));
 | 
|          } else if ((in & kTypeMask) == kTypeInt32 ||
 | 
|                     (in & kRepMask) == kRepWord32) {
 | 
|            // Just change representation if necessary.
 | 
| -          VisitUnop(node, kTypeInt32 | kRepWord32, kTypeInt32 | kRepWord32);
 | 
| +          VisitUnop(node, UseInfo::TruncatingWord32(), kTypeInt32 | kRepWord32);
 | 
|            if (lower()) DeferReplacement(node, node->InputAt(0));
 | 
|          } else {
 | 
|            // Require the input in float64 format and perform truncation.
 | 
|            // TODO(turbofan): avoid a truncation with a smi check.
 | 
| -          VisitUnop(node, kTypeInt32 | kRepFloat64, kTypeInt32 | kRepWord32);
 | 
| +          VisitUnop(node, UseInfo::Float64TruncatingToWord32(),
 | 
| +                    kTypeInt32 | kRepWord32);
 | 
|            if (lower()) {
 | 
|              NodeProperties::ChangeOp(
 | 
|                  node, lowering->machine()->TruncateFloat64ToInt32(
 | 
| @@ -747,22 +876,26 @@ class RepresentationSelector {
 | 
|          MachineTypeUnion in = GetInfo(input)->output;
 | 
|          if (in_upper->Is(Type::Unsigned32())) {
 | 
|            // If the input has type uint32, pass through representation.
 | 
| -          VisitUnop(node, kTypeUint32 | use_rep, kTypeUint32 | use_rep);
 | 
| +          VisitUnop(node, UseInfoFromRepresentation(use_rep),
 | 
| +                    kTypeUint32 | use_rep);
 | 
|            if (lower()) DeferReplacement(node, node->InputAt(0));
 | 
|          } else if ((in & kTypeMask) == kTypeInt32 ||
 | 
|                     in_upper->Is(Type::Signed32())) {
 | 
|            // Just change representation if necessary.
 | 
| -          VisitUnop(node, kTypeInt32 | kRepWord32, kTypeUint32 | kRepWord32);
 | 
| +          VisitUnop(node, UseInfo::TruncatingWord32(),
 | 
| +                    kTypeUint32 | kRepWord32);
 | 
|            if (lower()) DeferReplacement(node, node->InputAt(0));
 | 
|          } else if ((in & kTypeMask) == kTypeUint32 ||
 | 
|                     (in & kRepMask) == kRepWord32) {
 | 
|            // Just change representation if necessary.
 | 
| -          VisitUnop(node, kTypeUint32 | kRepWord32, kTypeUint32 | kRepWord32);
 | 
| +          VisitUnop(node, UseInfo::TruncatingWord32(),
 | 
| +                    kTypeUint32 | kRepWord32);
 | 
|            if (lower()) DeferReplacement(node, node->InputAt(0));
 | 
|          } else {
 | 
|            // Require the input in float64 format and perform truncation.
 | 
|            // TODO(turbofan): avoid a truncation with a smi check.
 | 
| -          VisitUnop(node, kTypeUint32 | kRepFloat64, kTypeUint32 | kRepWord32);
 | 
| +          VisitUnop(node, UseInfo::Float64TruncatingToWord32(),
 | 
| +                    kTypeUint32 | kRepWord32);
 | 
|            if (lower()) {
 | 
|              NodeProperties::ChangeOp(
 | 
|                  node, lowering->machine()->TruncateFloat64ToInt32(
 | 
| @@ -772,7 +905,7 @@ class RepresentationSelector {
 | 
|          break;
 | 
|        }
 | 
|        case IrOpcode::kNumberIsHoleNaN: {
 | 
| -        VisitUnop(node, kMachFloat64, kMachBool);
 | 
| +        VisitUnop(node, UseInfo::Float64(), kMachBool);
 | 
|          if (lower()) {
 | 
|            // NumberIsHoleNaN(x) => Word32Equal(Float64ExtractLowWord32(x),
 | 
|            //                                   #HoleNaNLower32)
 | 
| @@ -787,7 +920,7 @@ class RepresentationSelector {
 | 
|          break;
 | 
|        }
 | 
|        case IrOpcode::kPlainPrimitiveToNumber: {
 | 
| -        VisitUnop(node, kMachAnyTagged, kTypeNumber | kRepTagged);
 | 
| +        VisitUnop(node, UseInfo::AnyTagged(), kTypeNumber | kRepTagged);
 | 
|          if (lower()) {
 | 
|            // PlainPrimitiveToNumber(x) => Call(ToNumberStub, x, no-context)
 | 
|            Operator::Properties properties = node->op()->properties();
 | 
| @@ -804,53 +937,53 @@ class RepresentationSelector {
 | 
|          break;
 | 
|        }
 | 
|        case IrOpcode::kReferenceEqual: {
 | 
| -        VisitBinop(node, kMachAnyTagged, kRepBit);
 | 
| +        VisitBinop(node, UseInfo::AnyTagged(), kMachBool);
 | 
|          if (lower()) {
 | 
|            NodeProperties::ChangeOp(node, lowering->machine()->WordEqual());
 | 
|          }
 | 
|          break;
 | 
|        }
 | 
|        case IrOpcode::kStringEqual: {
 | 
| -        VisitBinop(node, kMachAnyTagged, kRepBit);
 | 
| +        VisitBinop(node, UseInfo::AnyTagged(), kMachBool);
 | 
|          if (lower()) lowering->DoStringEqual(node);
 | 
|          break;
 | 
|        }
 | 
|        case IrOpcode::kStringLessThan: {
 | 
| -        VisitBinop(node, kMachAnyTagged, kRepBit);
 | 
| +        VisitBinop(node, UseInfo::AnyTagged(), kMachBool);
 | 
|          if (lower()) lowering->DoStringLessThan(node);
 | 
|          break;
 | 
|        }
 | 
|        case IrOpcode::kStringLessThanOrEqual: {
 | 
| -        VisitBinop(node, kMachAnyTagged, kRepBit);
 | 
| +        VisitBinop(node, UseInfo::AnyTagged(), kMachBool);
 | 
|          if (lower()) lowering->DoStringLessThanOrEqual(node);
 | 
|          break;
 | 
|        }
 | 
|        case IrOpcode::kAllocate: {
 | 
| -        ProcessInput(node, 0, kMachAnyTagged);
 | 
| +        ProcessInput(node, 0, UseInfo::AnyTagged());
 | 
|          ProcessRemainingInputs(node, 1);
 | 
|          SetOutput(node, kMachAnyTagged);
 | 
|          break;
 | 
|        }
 | 
|        case IrOpcode::kLoadField: {
 | 
|          FieldAccess access = FieldAccessOf(node->op());
 | 
| -        ProcessInput(node, 0, changer_->TypeForBasePointer(access));
 | 
| +        ProcessInput(node, 0, UseInfoForBasePointer(access));
 | 
|          ProcessRemainingInputs(node, 1);
 | 
|          SetOutput(node, access.machine_type);
 | 
|          break;
 | 
|        }
 | 
|        case IrOpcode::kStoreField: {
 | 
|          FieldAccess access = FieldAccessOf(node->op());
 | 
| -        ProcessInput(node, 0, changer_->TypeForBasePointer(access));
 | 
| -        ProcessInput(node, 1, access.machine_type);
 | 
| +        ProcessInput(node, 0, UseInfoForBasePointer(access));
 | 
| +        ProcessInput(node, 1, UseInfoFromMachineType(access.machine_type));
 | 
|          ProcessRemainingInputs(node, 2);
 | 
|          SetOutput(node, 0);
 | 
|          break;
 | 
|        }
 | 
|        case IrOpcode::kLoadBuffer: {
 | 
|          BufferAccess access = BufferAccessOf(node->op());
 | 
| -        ProcessInput(node, 0, kMachPtr);    // buffer
 | 
| -        ProcessInput(node, 1, kMachInt32);  // offset
 | 
| -        ProcessInput(node, 2, kMachInt32);  // length
 | 
| +        ProcessInput(node, 0, UseInfo::PointerInt());        // buffer
 | 
| +        ProcessInput(node, 1, UseInfo::TruncatingWord32());  // offset
 | 
| +        ProcessInput(node, 2, UseInfo::TruncatingWord32());  // length
 | 
|          ProcessRemainingInputs(node, 3);
 | 
|          // Tagged overrides everything if we have to do a typed array bounds
 | 
|          // check, because we may need to return undefined then.
 | 
| @@ -874,10 +1007,11 @@ class RepresentationSelector {
 | 
|        }
 | 
|        case IrOpcode::kStoreBuffer: {
 | 
|          BufferAccess access = BufferAccessOf(node->op());
 | 
| -        ProcessInput(node, 0, kMachPtr);               // buffer
 | 
| -        ProcessInput(node, 1, kMachInt32);             // offset
 | 
| -        ProcessInput(node, 2, kMachInt32);             // length
 | 
| -        ProcessInput(node, 3, access.machine_type());  // value
 | 
| +        ProcessInput(node, 0, UseInfo::PointerInt());        // buffer
 | 
| +        ProcessInput(node, 1, UseInfo::TruncatingWord32());  // offset
 | 
| +        ProcessInput(node, 2, UseInfo::TruncatingWord32());  // length
 | 
| +        ProcessInput(node, 3,
 | 
| +                     UseInfoFromMachineType(access.machine_type()));  // value
 | 
|          ProcessRemainingInputs(node, 4);
 | 
|          SetOutput(node, 0);
 | 
|          if (lower()) lowering->DoStoreBuffer(node);
 | 
| @@ -885,30 +1019,31 @@ class RepresentationSelector {
 | 
|        }
 | 
|        case IrOpcode::kLoadElement: {
 | 
|          ElementAccess access = ElementAccessOf(node->op());
 | 
| -        ProcessInput(node, 0, changer_->TypeForBasePointer(access));  // base
 | 
| -        ProcessInput(node, 1, kMachInt32);                            // index
 | 
| +        ProcessInput(node, 0, UseInfoForBasePointer(access));  // base
 | 
| +        ProcessInput(node, 1, UseInfo::TruncatingWord32());    // index
 | 
|          ProcessRemainingInputs(node, 2);
 | 
|          SetOutput(node, access.machine_type);
 | 
|          break;
 | 
|        }
 | 
|        case IrOpcode::kStoreElement: {
 | 
|          ElementAccess access = ElementAccessOf(node->op());
 | 
| -        ProcessInput(node, 0, changer_->TypeForBasePointer(access));  // base
 | 
| -        ProcessInput(node, 1, kMachInt32);                            // index
 | 
| -        ProcessInput(node, 2, access.machine_type);                   // value
 | 
| +        ProcessInput(node, 0, UseInfoForBasePointer(access));  // base
 | 
| +        ProcessInput(node, 1, UseInfo::TruncatingWord32());    // index
 | 
| +        ProcessInput(node, 2,
 | 
| +                     UseInfoFromMachineType(access.machine_type));  // value
 | 
|          ProcessRemainingInputs(node, 3);
 | 
|          SetOutput(node, 0);
 | 
|          break;
 | 
|        }
 | 
|        case IrOpcode::kObjectIsNumber: {
 | 
| -        ProcessInput(node, 0, kMachAnyTagged);
 | 
| -        SetOutput(node, kRepBit | kTypeBool);
 | 
| +        ProcessInput(node, 0, UseInfo::AnyTagged());
 | 
| +        SetOutput(node, kMachBool);
 | 
|          if (lower()) lowering->DoObjectIsNumber(node);
 | 
|          break;
 | 
|        }
 | 
|        case IrOpcode::kObjectIsSmi: {
 | 
| -        ProcessInput(node, 0, kMachAnyTagged);
 | 
| -        SetOutput(node, kRepBit | kTypeBool);
 | 
| +        ProcessInput(node, 0, UseInfo::AnyTagged());
 | 
| +        SetOutput(node, kMachBool);
 | 
|          if (lower()) lowering->DoObjectIsSmi(node);
 | 
|          break;
 | 
|        }
 | 
| @@ -917,29 +1052,29 @@ class RepresentationSelector {
 | 
|        // Machine-level operators.
 | 
|        //------------------------------------------------------------------
 | 
|        case IrOpcode::kLoad: {
 | 
| -        // TODO(titzer): machine loads/stores need to know BaseTaggedness!?
 | 
| -        MachineTypeUnion tBase = kRepTagged | kMachPtr;
 | 
| +        // TODO(jarin) Eventually, we should get rid of all machine stores
 | 
| +        // from the high-level phases, then this becomes UNREACHABLE.
 | 
|          LoadRepresentation rep = OpParameter<LoadRepresentation>(node);
 | 
| -        ProcessInput(node, 0, tBase);   // pointer or object
 | 
| -        ProcessInput(node, 1, kMachIntPtr);  // index
 | 
| +        ProcessInput(node, 0, UseInfo::AnyTagged());   // tagged pointer
 | 
| +        ProcessInput(node, 1, UseInfo::PointerInt());  // index
 | 
|          ProcessRemainingInputs(node, 2);
 | 
|          SetOutput(node, rep);
 | 
|          break;
 | 
|        }
 | 
|        case IrOpcode::kStore: {
 | 
| -        // TODO(titzer): machine loads/stores need to know BaseTaggedness!?
 | 
| -        MachineTypeUnion tBase = kRepTagged | kMachPtr;
 | 
| +        // TODO(jarin) Eventually, we should get rid of all machine stores
 | 
| +        // from the high-level phases, then this becomes UNREACHABLE.
 | 
|          StoreRepresentation rep = OpParameter<StoreRepresentation>(node);
 | 
| -        ProcessInput(node, 0, tBase);   // pointer or object
 | 
| -        ProcessInput(node, 1, kMachIntPtr);  // index
 | 
| -        ProcessInput(node, 2, rep.machine_type());
 | 
| +        ProcessInput(node, 0, UseInfo::AnyTagged());   // tagged pointer
 | 
| +        ProcessInput(node, 1, UseInfo::PointerInt());  // index
 | 
| +        ProcessInput(node, 2, UseInfoFromMachineType(rep.machine_type()));
 | 
|          ProcessRemainingInputs(node, 3);
 | 
|          SetOutput(node, 0);
 | 
|          break;
 | 
|        }
 | 
|        case IrOpcode::kWord32Shr:
 | 
|          // We output unsigned int32 for shift right because JavaScript.
 | 
| -        return VisitBinop(node, kMachUint32, kMachUint32);
 | 
| +        return VisitBinop(node, UseInfo::TruncatingWord32(), kMachUint32);
 | 
|        case IrOpcode::kWord32And:
 | 
|        case IrOpcode::kWord32Or:
 | 
|        case IrOpcode::kWord32Xor:
 | 
| @@ -948,12 +1083,13 @@ class RepresentationSelector {
 | 
|          // We use signed int32 as the output type for these word32 operations,
 | 
|          // though the machine bits are the same for either signed or unsigned,
 | 
|          // because JavaScript considers the result from these operations signed.
 | 
| -        return VisitBinop(node, kRepWord32, kRepWord32 | kTypeInt32);
 | 
| +        return VisitBinop(node, UseInfo::TruncatingWord32(),
 | 
| +                          kRepWord32 | kTypeInt32);
 | 
|        case IrOpcode::kWord32Equal:
 | 
| -        return VisitBinop(node, kRepWord32, kRepBit);
 | 
| +        return VisitBinop(node, UseInfo::TruncatingWord32(), kMachBool);
 | 
|  
 | 
|        case IrOpcode::kWord32Clz:
 | 
| -        return VisitUnop(node, kMachUint32, kMachUint32);
 | 
| +        return VisitUnop(node, UseInfo::TruncatingWord32(), kMachUint32);
 | 
|  
 | 
|        case IrOpcode::kInt32Add:
 | 
|        case IrOpcode::kInt32Sub:
 | 
| @@ -997,41 +1133,38 @@ class RepresentationSelector {
 | 
|        case IrOpcode::kWord64Shl:
 | 
|        case IrOpcode::kWord64Shr:
 | 
|        case IrOpcode::kWord64Sar:
 | 
| -        return VisitBinop(node, kRepWord64, kRepWord64);
 | 
| +        return VisitBinop(node, UseInfo::TruncatingWord64(), kRepWord64);
 | 
|        case IrOpcode::kWord64Equal:
 | 
| -        return VisitBinop(node, kRepWord64, kRepBit);
 | 
| +        return VisitBinop(node, UseInfo::TruncatingWord64(), kMachBool);
 | 
|  
 | 
|        case IrOpcode::kChangeInt32ToInt64:
 | 
| -        return VisitUnop(node, kTypeInt32 | kRepWord32,
 | 
| +        return VisitUnop(node, UseInfo::TruncatingWord32(),
 | 
|                           kTypeInt32 | kRepWord64);
 | 
|        case IrOpcode::kChangeUint32ToUint64:
 | 
| -        return VisitUnop(node, kTypeUint32 | kRepWord32,
 | 
| +        return VisitUnop(node, UseInfo::TruncatingWord32(),
 | 
|                           kTypeUint32 | kRepWord64);
 | 
|        case IrOpcode::kTruncateFloat64ToFloat32:
 | 
| -        return VisitUnop(node, kTypeNumber | kRepFloat64,
 | 
| -                         kTypeNumber | kRepFloat32);
 | 
| +        return VisitUnop(node, UseInfo::Float64(), kTypeNumber | kRepFloat32);
 | 
|        case IrOpcode::kTruncateFloat64ToInt32:
 | 
| -        return VisitUnop(node, kTypeNumber | kRepFloat64,
 | 
| -                         kTypeInt32 | kRepWord32);
 | 
| +        return VisitUnop(node, UseInfo::Float64(), kTypeInt32 | kRepWord32);
 | 
|        case IrOpcode::kTruncateInt64ToInt32:
 | 
|          // TODO(titzer): Is kTypeInt32 correct here?
 | 
| -        return VisitUnop(node, kTypeInt32 | kRepWord64,
 | 
| +        return VisitUnop(node, UseInfo::Word64TruncatingToWord32(),
 | 
|                           kTypeInt32 | kRepWord32);
 | 
|  
 | 
|        case IrOpcode::kChangeFloat32ToFloat64:
 | 
| -        return VisitUnop(node, kTypeNumber | kRepFloat32,
 | 
| -                         kTypeNumber | kRepFloat64);
 | 
| +        return VisitUnop(node, UseInfo::Float32(), kTypeNumber | kRepFloat64);
 | 
|        case IrOpcode::kChangeInt32ToFloat64:
 | 
| -        return VisitUnop(node, kTypeInt32 | kRepWord32,
 | 
| +        return VisitUnop(node, UseInfo::TruncatingWord32(),
 | 
|                           kTypeInt32 | kRepFloat64);
 | 
|        case IrOpcode::kChangeUint32ToFloat64:
 | 
| -        return VisitUnop(node, kTypeUint32 | kRepWord32,
 | 
| +        return VisitUnop(node, UseInfo::TruncatingWord32(),
 | 
|                           kTypeUint32 | kRepFloat64);
 | 
|        case IrOpcode::kChangeFloat64ToInt32:
 | 
| -        return VisitUnop(node, kTypeInt32 | kRepFloat64,
 | 
| +        return VisitUnop(node, UseInfo::Float64TruncatingToWord32(),
 | 
|                           kTypeInt32 | kRepWord32);
 | 
|        case IrOpcode::kChangeFloat64ToUint32:
 | 
| -        return VisitUnop(node, kTypeUint32 | kRepFloat64,
 | 
| +        return VisitUnop(node, UseInfo::Float64TruncatingToWord32(),
 | 
|                           kTypeUint32 | kRepWord32);
 | 
|  
 | 
|        case IrOpcode::kFloat64Add:
 | 
| @@ -1046,17 +1179,18 @@ class RepresentationSelector {
 | 
|        case IrOpcode::kFloat64RoundDown:
 | 
|        case IrOpcode::kFloat64RoundTruncate:
 | 
|        case IrOpcode::kFloat64RoundTiesAway:
 | 
| -        return VisitUnop(node, kMachFloat64, kMachFloat64);
 | 
| +        return VisitUnop(node, UseInfo::Float64(), kMachFloat64);
 | 
|        case IrOpcode::kFloat64Equal:
 | 
|        case IrOpcode::kFloat64LessThan:
 | 
|        case IrOpcode::kFloat64LessThanOrEqual:
 | 
|          return VisitFloat64Cmp(node);
 | 
|        case IrOpcode::kFloat64ExtractLowWord32:
 | 
|        case IrOpcode::kFloat64ExtractHighWord32:
 | 
| -        return VisitUnop(node, kMachFloat64, kMachInt32);
 | 
| +        return VisitUnop(node, UseInfo::Float64(), kMachInt32);
 | 
|        case IrOpcode::kFloat64InsertLowWord32:
 | 
|        case IrOpcode::kFloat64InsertHighWord32:
 | 
| -        return VisitBinop(node, kMachFloat64, kMachInt32, kMachFloat64);
 | 
| +        return VisitBinop(node, UseInfo::Float64(), UseInfo::TruncatingWord32(),
 | 
| +                          kMachFloat64);
 | 
|        case IrOpcode::kLoadStackPointer:
 | 
|        case IrOpcode::kLoadFramePointer:
 | 
|          return VisitLeaf(node, kMachPtr);
 | 
| @@ -1103,6 +1237,13 @@ class RepresentationSelector {
 | 
|      }
 | 
|    }
 | 
|  
 | 
| +  void PrintUseInfo(UseInfo info) {
 | 
| +    if (FLAG_trace_representation) {
 | 
| +      OFStream os(stdout);
 | 
| +      os << static_cast<MachineType>(info.machine_type());
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
|   private:
 | 
|    JSGraph* jsgraph_;
 | 
|    size_t const count_;              // number of nodes in the graph
 | 
| 
 |