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/base/bits.h"
      9 #include "src/compiler/js-graph.h"
     10 #include "src/compiler/machine-operator.h"
     11 #include "src/compiler/node-properties-inl.h"
     12 #include "src/compiler/simplified-operator.h"
     13 
     14 namespace v8 {
     15 namespace internal {
     16 namespace compiler {
     17 
     18 // Contains logic related to changing the representation of values for constants
     19 // and other nodes, as well as lowering Simplified->Machine operators.
     20 // Eagerly folds any representation changes for constants.
     21 class RepresentationChanger {
     22  public:
     23   RepresentationChanger(JSGraph* jsgraph, SimplifiedOperatorBuilder* simplified,
     24                         Isolate* isolate)
     25       : jsgraph_(jsgraph),
     26         simplified_(simplified),
     27         isolate_(isolate),
     28         testing_type_errors_(false),
     29         type_error_(false) {}
     30 
     31   // TODO(titzer): should Word64 also be implicitly convertable to others?
     32   static const MachineTypeUnion rWord =
     33       kRepBit | kRepWord8 | kRepWord16 | kRepWord32;
     34 
     35   Node* GetRepresentationFor(Node* node, MachineTypeUnion output_type,
     36                              MachineTypeUnion use_type) {
     37     if (!base::bits::IsPowerOfTwo32(output_type & kRepMask)) {
     38       // There should be only one output representation.
     39       return TypeError(node, output_type, use_type);
     40     }
     41     if ((use_type & kRepMask) == (output_type & kRepMask)) {
     42       // Representations are the same. That's a no-op.
     43       return node;
     44     }
     45     if ((use_type & rWord) && (output_type & rWord)) {
     46       // Both are words less than or equal to 32-bits.
     47       // Since loads of integers from memory implicitly sign or zero extend the
     48       // value to the full machine word size and stores implicitly truncate,
     49       // no representation change is necessary.
     50       return node;
     51     }
     52     if (use_type & kRepTagged) {
     53       return GetTaggedRepresentationFor(node, output_type);
     54     } else if (use_type & kRepFloat64) {
     55       return GetFloat64RepresentationFor(node, output_type);
     56     } else if (use_type & kRepFloat32) {
     57       return TypeError(node, output_type, use_type);  // TODO(titzer): handle
     58     } else if (use_type & kRepBit) {
     59       return GetBitRepresentationFor(node, output_type);
     60     } else if (use_type & rWord) {
     61       return GetWord32RepresentationFor(node, output_type,
     62                                         use_type & kTypeUint32);
     63     } else if (use_type & kRepWord64) {
     64       return GetWord64RepresentationFor(node, output_type);
     65     } else {
     66       return node;
     67     }
     68   }
     69 
     70   Node* GetTaggedRepresentationFor(Node* node, MachineTypeUnion output_type) {
     71     // Eagerly fold representation changes for constants.
     72     switch (node->opcode()) {
     73       case IrOpcode::kNumberConstant:
     74       case IrOpcode::kHeapConstant:
     75         return node;  // No change necessary.
     76       case IrOpcode::kInt32Constant:
     77         if (output_type & kTypeUint32) {
     78           uint32_t value = OpParameter<uint32_t>(node);
     79           return jsgraph()->Constant(static_cast<double>(value));
     80         } else if (output_type & kTypeInt32) {
     81           int32_t value = OpParameter<int32_t>(node);
     82           return jsgraph()->Constant(value);
     83         } else if (output_type & kRepBit) {
     84           return OpParameter<int32_t>(node) == 0 ? jsgraph()->FalseConstant()
     85                                                  : jsgraph()->TrueConstant();
     86         } else {
     87           return TypeError(node, output_type, kRepTagged);
     88         }
     89       case IrOpcode::kFloat64Constant:
     90         return jsgraph()->Constant(OpParameter<double>(node));
     91       default:
     92         break;
     93     }
     94     // Select the correct X -> Tagged operator.
     95     const Operator* op;
     96     if (output_type & kRepBit) {
     97       op = simplified()->ChangeBitToBool();
     98     } else if (output_type & rWord) {
     99       if (output_type & kTypeUint32) {
    100         op = simplified()->ChangeUint32ToTagged();
    101       } else if (output_type & kTypeInt32) {
    102         op = simplified()->ChangeInt32ToTagged();
    103       } else {
    104         return TypeError(node, output_type, kRepTagged);
    105       }
    106     } else if (output_type & kRepFloat64) {
    107       op = simplified()->ChangeFloat64ToTagged();
    108     } else {
    109       return TypeError(node, output_type, kRepTagged);
    110     }
    111     return jsgraph()->graph()->NewNode(op, node);
    112   }
    113 
    114   Node* GetFloat64RepresentationFor(Node* node, MachineTypeUnion output_type) {
    115     // Eagerly fold representation changes for constants.
    116     switch (node->opcode()) {
    117       case IrOpcode::kNumberConstant:
    118         return jsgraph()->Float64Constant(OpParameter<double>(node));
    119       case IrOpcode::kInt32Constant:
    120         if (output_type & kTypeUint32) {
    121           uint32_t value = OpParameter<uint32_t>(node);
    122           return jsgraph()->Float64Constant(static_cast<double>(value));
    123         } else {
    124           int32_t value = OpParameter<int32_t>(node);
    125           return jsgraph()->Float64Constant(value);
    126         }
    127       case IrOpcode::kFloat64Constant:
    128         return node;  // No change necessary.
    129       default:
    130         break;
    131     }
    132     // Select the correct X -> Float64 operator.
    133     const Operator* op;
    134     if (output_type & kRepBit) {
    135       return TypeError(node, output_type, kRepFloat64);
    136     } else if (output_type & rWord) {
    137       if (output_type & kTypeUint32) {
    138         op = machine()->ChangeUint32ToFloat64();
    139       } else {
    140         op = machine()->ChangeInt32ToFloat64();
    141       }
    142     } else if (output_type & kRepTagged) {
    143       op = simplified()->ChangeTaggedToFloat64();
    144     } else {
    145       return TypeError(node, output_type, kRepFloat64);
    146     }
    147     return jsgraph()->graph()->NewNode(op, node);
    148   }
    149 
    150   Node* GetWord32RepresentationFor(Node* node, MachineTypeUnion output_type,
    151                                    bool use_unsigned) {
    152     // Eagerly fold representation changes for constants.
    153     switch (node->opcode()) {
    154       case IrOpcode::kInt32Constant:
    155         return node;  // No change necessary.
    156       case IrOpcode::kNumberConstant:
    157       case IrOpcode::kFloat64Constant: {
    158         double value = OpParameter<double>(node);
    159         if (value < 0) {
    160           DCHECK(IsInt32Double(value));
    161           int32_t iv = static_cast<int32_t>(value);
    162           return jsgraph()->Int32Constant(iv);
    163         } else {
    164           DCHECK(IsUint32Double(value));
    165           int32_t iv = static_cast<int32_t>(static_cast<uint32_t>(value));
    166           return jsgraph()->Int32Constant(iv);
    167         }
    168       }
    169       default:
    170         break;
    171     }
    172     // Select the correct X -> Word32 operator.
    173     const Operator* op = NULL;
    174     if (output_type & kRepFloat64) {
    175       if (output_type & kTypeUint32 || use_unsigned) {
    176         op = machine()->ChangeFloat64ToUint32();
    177       } else {
    178         op = machine()->ChangeFloat64ToInt32();
    179       }
    180     } else if (output_type & kRepTagged) {
    181       if (output_type & kTypeUint32 || use_unsigned) {
    182         op = simplified()->ChangeTaggedToUint32();
    183       } else {
    184         op = simplified()->ChangeTaggedToInt32();
    185       }
    186     } else {
    187       return TypeError(node, output_type, kRepWord32);
    188     }
    189     return jsgraph()->graph()->NewNode(op, node);
    190   }
    191 
    192   Node* GetBitRepresentationFor(Node* node, MachineTypeUnion output_type) {
    193     // Eagerly fold representation changes for constants.
    194     switch (node->opcode()) {
    195       case IrOpcode::kInt32Constant: {
    196         int32_t value = OpParameter<int32_t>(node);
    197         if (value == 0 || value == 1) return node;
    198         return jsgraph()->OneConstant();  // value != 0
    199       }
    200       case IrOpcode::kHeapConstant: {
    201         Handle<Object> handle = OpParameter<Unique<Object> >(node).handle();
    202         DCHECK(*handle == isolate()->heap()->true_value() ||
    203                *handle == isolate()->heap()->false_value());
    204         return jsgraph()->Int32Constant(
    205             *handle == isolate()->heap()->true_value() ? 1 : 0);
    206       }
    207       default:
    208         break;
    209     }
    210     // Select the correct X -> Bit operator.
    211     const Operator* op;
    212     if (output_type & rWord) {
    213       return node;  // No change necessary.
    214     } else if (output_type & kRepWord64) {
    215       return node;  // TODO(titzer): No change necessary, on 64-bit.
    216     } else if (output_type & kRepTagged) {
    217       op = simplified()->ChangeBoolToBit();
    218     } else {
    219       return TypeError(node, output_type, kRepBit);
    220     }
    221     return jsgraph()->graph()->NewNode(op, node);
    222   }
    223 
    224   Node* GetWord64RepresentationFor(Node* node, MachineTypeUnion output_type) {
    225     if (output_type & kRepBit) {
    226       return node;  // Sloppy comparison -> word64
    227     }
    228     // Can't really convert Word64 to anything else. Purported to be internal.
    229     return TypeError(node, output_type, kRepWord64);
    230   }
    231 
    232   const Operator* Int32OperatorFor(IrOpcode::Value opcode) {
    233     switch (opcode) {
    234       case IrOpcode::kNumberAdd:
    235         return machine()->Int32Add();
    236       case IrOpcode::kNumberSubtract:
    237         return machine()->Int32Sub();
    238       case IrOpcode::kNumberMultiply:
    239         return machine()->Int32Mul();
    240       case IrOpcode::kNumberDivide:
    241         return machine()->Int32Div();
    242       case IrOpcode::kNumberModulus:
    243         return machine()->Int32Mod();
    244       case IrOpcode::kNumberEqual:
    245         return machine()->Word32Equal();
    246       case IrOpcode::kNumberLessThan:
    247         return machine()->Int32LessThan();
    248       case IrOpcode::kNumberLessThanOrEqual:
    249         return machine()->Int32LessThanOrEqual();
    250       default:
    251         UNREACHABLE();
    252         return NULL;
    253     }
    254   }
    255 
    256   const Operator* Uint32OperatorFor(IrOpcode::Value opcode) {
    257     switch (opcode) {
    258       case IrOpcode::kNumberAdd:
    259         return machine()->Int32Add();
    260       case IrOpcode::kNumberSubtract:
    261         return machine()->Int32Sub();
    262       case IrOpcode::kNumberMultiply:
    263         return machine()->Int32Mul();
    264       case IrOpcode::kNumberDivide:
    265         return machine()->Int32UDiv();
    266       case IrOpcode::kNumberModulus:
    267         return machine()->Int32UMod();
    268       case IrOpcode::kNumberEqual:
    269         return machine()->Word32Equal();
    270       case IrOpcode::kNumberLessThan:
    271         return machine()->Uint32LessThan();
    272       case IrOpcode::kNumberLessThanOrEqual:
    273         return machine()->Uint32LessThanOrEqual();
    274       default:
    275         UNREACHABLE();
    276         return NULL;
    277     }
    278   }
    279 
    280   const Operator* Float64OperatorFor(IrOpcode::Value opcode) {
    281     switch (opcode) {
    282       case IrOpcode::kNumberAdd:
    283         return machine()->Float64Add();
    284       case IrOpcode::kNumberSubtract:
    285         return machine()->Float64Sub();
    286       case IrOpcode::kNumberMultiply:
    287         return machine()->Float64Mul();
    288       case IrOpcode::kNumberDivide:
    289         return machine()->Float64Div();
    290       case IrOpcode::kNumberModulus:
    291         return machine()->Float64Mod();
    292       case IrOpcode::kNumberEqual:
    293         return machine()->Float64Equal();
    294       case IrOpcode::kNumberLessThan:
    295         return machine()->Float64LessThan();
    296       case IrOpcode::kNumberLessThanOrEqual:
    297         return machine()->Float64LessThanOrEqual();
    298       default:
    299         UNREACHABLE();
    300         return NULL;
    301     }
    302   }
    303 
    304   MachineType TypeForBasePointer(const FieldAccess& access) {
    305     return access.tag() != 0 ? kMachAnyTagged : kMachPtr;
    306   }
    307 
    308   MachineType TypeForBasePointer(const ElementAccess& access) {
    309     return access.tag() != 0 ? kMachAnyTagged : kMachPtr;
    310   }
    311 
    312   MachineType TypeFromUpperBound(Type* type) {
    313     if (type->Is(Type::None()))
    314       return kTypeAny;  // TODO(titzer): should be an error
    315     if (type->Is(Type::Signed32())) return kTypeInt32;
    316     if (type->Is(Type::Unsigned32())) return kTypeUint32;
    317     if (type->Is(Type::Number())) return kTypeNumber;
    318     if (type->Is(Type::Boolean())) return kTypeBool;
    319     return kTypeAny;
    320   }
    321 
    322  private:
    323   JSGraph* jsgraph_;
    324   SimplifiedOperatorBuilder* simplified_;
    325   Isolate* isolate_;
    326 
    327   friend class RepresentationChangerTester;  // accesses the below fields.
    328 
    329   bool testing_type_errors_;  // If {true}, don't abort on a type error.
    330   bool type_error_;           // Set when a type error is detected.
    331 
    332   Node* TypeError(Node* node, MachineTypeUnion output_type,
    333                   MachineTypeUnion use) {
    334     type_error_ = true;
    335     if (!testing_type_errors_) {
    336       OStringStream out_str;
    337       out_str << static_cast<MachineType>(output_type);
    338 
    339       OStringStream use_str;
    340       use_str << static_cast<MachineType>(use);
    341 
    342       V8_Fatal(__FILE__, __LINE__,
    343                "RepresentationChangerError: node #%d:%s of "
    344                "%s cannot be changed to %s",
    345                node->id(), node->op()->mnemonic(), out_str.c_str(),
    346                use_str.c_str());
    347     }
    348     return node;
    349   }
    350 
    351   JSGraph* jsgraph() { return jsgraph_; }
    352   Isolate* isolate() { return isolate_; }
    353   SimplifiedOperatorBuilder* simplified() { return simplified_; }
    354   MachineOperatorBuilder* machine() { return jsgraph()->machine(); }
    355 };
    356 }
    357 }
    358 }  // namespace v8::internal::compiler
    359 
    360 #endif  // V8_COMPILER_REPRESENTATION_CHANGE_H_
    361