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