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 #ifndef V8_COMPILER_REPRESENTATION_CHANGE_H_
      6 #define V8_COMPILER_REPRESENTATION_CHANGE_H_
      7 
      8 #include "src/compiler/js-graph.h"
      9 #include "src/compiler/simplified-operator.h"
     10 
     11 namespace v8 {
     12 namespace internal {
     13 namespace compiler {
     14 
     15 enum IdentifyZeros { kIdentifyZeros, kDistinguishZeros };
     16 
     17 class Truncation final {
     18  public:
     19   // Constructors.
     20   static Truncation None() {
     21     return Truncation(TruncationKind::kNone, kIdentifyZeros);
     22   }
     23   static Truncation Bool() {
     24     return Truncation(TruncationKind::kBool, kIdentifyZeros);
     25   }
     26   static Truncation Word32() {
     27     return Truncation(TruncationKind::kWord32, kIdentifyZeros);
     28   }
     29   static Truncation Word64() {
     30     return Truncation(TruncationKind::kWord64, kIdentifyZeros);
     31   }
     32   static Truncation Float64(IdentifyZeros identify_zeros = kDistinguishZeros) {
     33     return Truncation(TruncationKind::kFloat64, identify_zeros);
     34   }
     35   static Truncation Any(IdentifyZeros identify_zeros = kDistinguishZeros) {
     36     return Truncation(TruncationKind::kAny, identify_zeros);
     37   }
     38 
     39   static Truncation Generalize(Truncation t1, Truncation t2) {
     40     return Truncation(
     41         Generalize(t1.kind(), t2.kind()),
     42         GeneralizeIdentifyZeros(t1.identify_zeros(), t2.identify_zeros()));
     43   }
     44 
     45   // Queries.
     46   bool IsUnused() const { return kind_ == TruncationKind::kNone; }
     47   bool IsUsedAsBool() const {
     48     return LessGeneral(kind_, TruncationKind::kBool);
     49   }
     50   bool IsUsedAsWord32() const {
     51     return LessGeneral(kind_, TruncationKind::kWord32);
     52   }
     53   bool IsUsedAsFloat64() const {
     54     return LessGeneral(kind_, TruncationKind::kFloat64);
     55   }
     56   bool IdentifiesUndefinedAndZero() {
     57     return LessGeneral(kind_, TruncationKind::kWord32) ||
     58            LessGeneral(kind_, TruncationKind::kBool);
     59   }
     60   bool IdentifiesUndefinedAndNaN() {
     61     return LessGeneral(kind_, TruncationKind::kFloat64) ||
     62            LessGeneral(kind_, TruncationKind::kWord64);
     63   }
     64   bool IdentifiesZeroAndMinusZero() const {
     65     return identify_zeros() == kIdentifyZeros;
     66   }
     67 
     68   // Operators.
     69   bool operator==(Truncation other) const {
     70     return kind() == other.kind() && identify_zeros() == other.identify_zeros();
     71   }
     72   bool operator!=(Truncation other) const { return !(*this == other); }
     73 
     74   // Debug utilities.
     75   const char* description() const;
     76   bool IsLessGeneralThan(Truncation other) {
     77     return LessGeneral(kind(), other.kind()) &&
     78            LessGeneralIdentifyZeros(identify_zeros(), other.identify_zeros());
     79   }
     80 
     81   IdentifyZeros identify_zeros() const { return identify_zeros_; }
     82 
     83  private:
     84   enum class TruncationKind : uint8_t {
     85     kNone,
     86     kBool,
     87     kWord32,
     88     kWord64,
     89     kFloat64,
     90     kAny
     91   };
     92 
     93   explicit Truncation(TruncationKind kind, IdentifyZeros identify_zeros)
     94       : kind_(kind), identify_zeros_(identify_zeros) {
     95     DCHECK(kind == TruncationKind::kAny || kind == TruncationKind::kFloat64 ||
     96            identify_zeros == kIdentifyZeros);
     97   }
     98   TruncationKind kind() const { return kind_; }
     99 
    100   TruncationKind kind_;
    101   IdentifyZeros identify_zeros_;
    102 
    103   static TruncationKind Generalize(TruncationKind rep1, TruncationKind rep2);
    104   static IdentifyZeros GeneralizeIdentifyZeros(IdentifyZeros i1,
    105                                                IdentifyZeros i2);
    106   static bool LessGeneral(TruncationKind rep1, TruncationKind rep2);
    107   static bool LessGeneralIdentifyZeros(IdentifyZeros u1, IdentifyZeros u2);
    108 };
    109 
    110 enum class TypeCheckKind : uint8_t {
    111   kNone,
    112   kSignedSmall,
    113   kSigned32,
    114   kNumber,
    115   kNumberOrOddball,
    116   kHeapObject
    117 };
    118 
    119 inline std::ostream& operator<<(std::ostream& os, TypeCheckKind type_check) {
    120   switch (type_check) {
    121     case TypeCheckKind::kNone:
    122       return os << "None";
    123     case TypeCheckKind::kSignedSmall:
    124       return os << "SignedSmall";
    125     case TypeCheckKind::kSigned32:
    126       return os << "Signed32";
    127     case TypeCheckKind::kNumber:
    128       return os << "Number";
    129     case TypeCheckKind::kNumberOrOddball:
    130       return os << "NumberOrOddball";
    131     case TypeCheckKind::kHeapObject:
    132       return os << "HeapObject";
    133   }
    134   UNREACHABLE();
    135 }
    136 
    137 // The {UseInfo} class is used to describe a use of an input of a node.
    138 //
    139 // This information is used in two different ways, based on the phase:
    140 //
    141 // 1. During propagation, the use info is used to inform the input node
    142 //    about what part of the input is used (we call this truncation) and what
    143 //    is the preferred representation. For conversions that will require
    144 //    checks, we also keep track of whether a minus zero check is needed.
    145 //
    146 // 2. During lowering, the use info is used to properly convert the input
    147 //    to the preferred representation. The preferred representation might be
    148 //    insufficient to do the conversion (e.g. word32->float64 conv), so we also
    149 //    need the signedness information to produce the correct value.
    150 //    Additionally, use info may contain {CheckParameters} which contains
    151 //    information for the deoptimizer such as a CallIC on which speculation
    152 //    should be disallowed if the check fails.
    153 class UseInfo {
    154  public:
    155   UseInfo(MachineRepresentation representation, Truncation truncation,
    156           TypeCheckKind type_check = TypeCheckKind::kNone,
    157           const VectorSlotPair& feedback = VectorSlotPair())
    158       : representation_(representation),
    159         truncation_(truncation),
    160         type_check_(type_check),
    161         feedback_(feedback) {}
    162   static UseInfo TruncatingWord32() {
    163     return UseInfo(MachineRepresentation::kWord32, Truncation::Word32());
    164   }
    165   static UseInfo TruncatingWord64() {
    166     return UseInfo(MachineRepresentation::kWord64, Truncation::Word64());
    167   }
    168   static UseInfo Bool() {
    169     return UseInfo(MachineRepresentation::kBit, Truncation::Bool());
    170   }
    171   static UseInfo Float32() {
    172     return UseInfo(MachineRepresentation::kFloat32, Truncation::Any());
    173   }
    174   static UseInfo TruncatingFloat64() {
    175     return UseInfo(MachineRepresentation::kFloat64, Truncation::Float64());
    176   }
    177   static UseInfo PointerInt() {
    178     return kPointerSize == 4 ? TruncatingWord32() : TruncatingWord64();
    179   }
    180   static UseInfo AnyTagged() {
    181     return UseInfo(MachineRepresentation::kTagged, Truncation::Any());
    182   }
    183   static UseInfo TaggedSigned() {
    184     return UseInfo(MachineRepresentation::kTaggedSigned, Truncation::Any());
    185   }
    186   static UseInfo TaggedPointer() {
    187     return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any());
    188   }
    189 
    190   // Possibly deoptimizing conversions.
    191   static UseInfo CheckedHeapObjectAsTaggedPointer() {
    192     return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any(),
    193                    TypeCheckKind::kHeapObject);
    194   }
    195   static UseInfo CheckedSignedSmallAsTaggedSigned(
    196       const VectorSlotPair& feedback) {
    197     return UseInfo(MachineRepresentation::kTaggedSigned, Truncation::Any(),
    198                    TypeCheckKind::kSignedSmall, feedback);
    199   }
    200   static UseInfo CheckedSignedSmallAsWord32(IdentifyZeros identify_zeros,
    201                                             const VectorSlotPair& feedback) {
    202     return UseInfo(MachineRepresentation::kWord32,
    203                    Truncation::Any(identify_zeros), TypeCheckKind::kSignedSmall,
    204                    feedback);
    205   }
    206   static UseInfo CheckedSigned32AsWord32(IdentifyZeros identify_zeros,
    207                                          const VectorSlotPair& feedback) {
    208     return UseInfo(MachineRepresentation::kWord32,
    209                    Truncation::Any(identify_zeros), TypeCheckKind::kSigned32,
    210                    feedback);
    211   }
    212   static UseInfo CheckedNumberAsFloat64(const VectorSlotPair& feedback) {
    213     return UseInfo(MachineRepresentation::kFloat64, Truncation::Any(),
    214                    TypeCheckKind::kNumber, feedback);
    215   }
    216   static UseInfo CheckedNumberAsWord32(const VectorSlotPair& feedback) {
    217     return UseInfo(MachineRepresentation::kWord32, Truncation::Word32(),
    218                    TypeCheckKind::kNumber, feedback);
    219   }
    220   static UseInfo CheckedNumberOrOddballAsFloat64(
    221       const VectorSlotPair& feedback) {
    222     return UseInfo(MachineRepresentation::kFloat64, Truncation::Any(),
    223                    TypeCheckKind::kNumberOrOddball, feedback);
    224   }
    225   static UseInfo CheckedNumberOrOddballAsWord32(
    226       const VectorSlotPair& feedback) {
    227     return UseInfo(MachineRepresentation::kWord32, Truncation::Word32(),
    228                    TypeCheckKind::kNumberOrOddball, feedback);
    229   }
    230 
    231   // Undetermined representation.
    232   static UseInfo Any() {
    233     return UseInfo(MachineRepresentation::kNone, Truncation::Any());
    234   }
    235   static UseInfo AnyTruncatingToBool() {
    236     return UseInfo(MachineRepresentation::kNone, Truncation::Bool());
    237   }
    238 
    239   // Value not used.
    240   static UseInfo None() {
    241     return UseInfo(MachineRepresentation::kNone, Truncation::None());
    242   }
    243 
    244   MachineRepresentation representation() const { return representation_; }
    245   Truncation truncation() const { return truncation_; }
    246   TypeCheckKind type_check() const { return type_check_; }
    247   CheckForMinusZeroMode minus_zero_check() const {
    248     return truncation().IdentifiesZeroAndMinusZero()
    249                ? CheckForMinusZeroMode::kDontCheckForMinusZero
    250                : CheckForMinusZeroMode::kCheckForMinusZero;
    251   }
    252   const VectorSlotPair& feedback() const { return feedback_; }
    253 
    254  private:
    255   MachineRepresentation representation_;
    256   Truncation truncation_;
    257   TypeCheckKind type_check_;
    258   VectorSlotPair feedback_;
    259 };
    260 
    261 // Contains logic related to changing the representation of values for constants
    262 // and other nodes, as well as lowering Simplified->Machine operators.
    263 // Eagerly folds any representation changes for constants.
    264 class RepresentationChanger final {
    265  public:
    266   RepresentationChanger(JSGraph* jsgraph, Isolate* isolate)
    267       : jsgraph_(jsgraph),
    268         isolate_(isolate),
    269         testing_type_errors_(false),
    270         type_error_(false) {}
    271 
    272   // Changes representation from {output_type} to {use_rep}. The {truncation}
    273   // parameter is only used for sanity checking - if the changer cannot figure
    274   // out signedness for the word32->float64 conversion, then we check that the
    275   // uses truncate to word32 (so they do not care about signedness).
    276   Node* GetRepresentationFor(Node* node, MachineRepresentation output_rep,
    277                              Type output_type, Node* use_node,
    278                              UseInfo use_info);
    279   const Operator* Int32OperatorFor(IrOpcode::Value opcode);
    280   const Operator* Int32OverflowOperatorFor(IrOpcode::Value opcode);
    281   const Operator* TaggedSignedOperatorFor(IrOpcode::Value opcode);
    282   const Operator* Uint32OperatorFor(IrOpcode::Value opcode);
    283   const Operator* Uint32OverflowOperatorFor(IrOpcode::Value opcode);
    284   const Operator* Float64OperatorFor(IrOpcode::Value opcode);
    285 
    286   MachineType TypeForBasePointer(const FieldAccess& access) {
    287     return access.tag() != 0 ? MachineType::AnyTagged()
    288                              : MachineType::Pointer();
    289   }
    290 
    291   MachineType TypeForBasePointer(const ElementAccess& access) {
    292     return access.tag() != 0 ? MachineType::AnyTagged()
    293                              : MachineType::Pointer();
    294   }
    295 
    296  private:
    297   JSGraph* jsgraph_;
    298   Isolate* isolate_;
    299 
    300   friend class RepresentationChangerTester;  // accesses the below fields.
    301 
    302   bool testing_type_errors_;  // If {true}, don't abort on a type error.
    303   bool type_error_;           // Set when a type error is detected.
    304 
    305   Node* GetTaggedSignedRepresentationFor(Node* node,
    306                                          MachineRepresentation output_rep,
    307                                          Type output_type, Node* use_node,
    308                                          UseInfo use_info);
    309   Node* GetTaggedPointerRepresentationFor(Node* node,
    310                                           MachineRepresentation output_rep,
    311                                           Type output_type, Node* use_node,
    312                                           UseInfo use_info);
    313   Node* GetTaggedRepresentationFor(Node* node, MachineRepresentation output_rep,
    314                                    Type output_type, Truncation truncation);
    315   Node* GetFloat32RepresentationFor(Node* node,
    316                                     MachineRepresentation output_rep,
    317                                     Type output_type, Truncation truncation);
    318   Node* GetFloat64RepresentationFor(Node* node,
    319                                     MachineRepresentation output_rep,
    320                                     Type output_type, Node* use_node,
    321                                     UseInfo use_info);
    322   Node* GetWord32RepresentationFor(Node* node, MachineRepresentation output_rep,
    323                                    Type output_type, Node* use_node,
    324                                    UseInfo use_info);
    325   Node* GetBitRepresentationFor(Node* node, MachineRepresentation output_rep,
    326                                 Type output_type);
    327   Node* GetWord64RepresentationFor(Node* node, MachineRepresentation output_rep,
    328                                    Type output_type);
    329   Node* TypeError(Node* node, MachineRepresentation output_rep,
    330                   Type output_type, MachineRepresentation use);
    331   Node* MakeTruncatedInt32Constant(double value);
    332   Node* InsertChangeBitToTagged(Node* node);
    333   Node* InsertChangeFloat32ToFloat64(Node* node);
    334   Node* InsertChangeFloat64ToInt32(Node* node);
    335   Node* InsertChangeFloat64ToUint32(Node* node);
    336   Node* InsertChangeInt32ToFloat64(Node* node);
    337   Node* InsertChangeTaggedSignedToInt32(Node* node);
    338   Node* InsertChangeTaggedToFloat64(Node* node);
    339   Node* InsertChangeUint32ToFloat64(Node* node);
    340   Node* InsertConversion(Node* node, const Operator* op, Node* use_node);
    341   void InsertUnconditionalDeopt(Node* node, DeoptimizeReason reason);
    342 
    343   JSGraph* jsgraph() const { return jsgraph_; }
    344   Isolate* isolate() const { return isolate_; }
    345   Factory* factory() const { return isolate()->factory(); }
    346   SimplifiedOperatorBuilder* simplified() { return jsgraph()->simplified(); }
    347   MachineOperatorBuilder* machine() { return jsgraph()->machine(); }
    348 };
    349 
    350 }  // namespace compiler
    351 }  // namespace internal
    352 }  // namespace v8
    353 
    354 #endif  // V8_COMPILER_REPRESENTATION_CHANGE_H_
    355