Home | History | Annotate | Download | only in compiler
      1 // Copyright 2016 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_GRAPH_ASSEMBLER_H_
      6 #define V8_COMPILER_GRAPH_ASSEMBLER_H_
      7 
      8 #include "src/compiler/js-graph.h"
      9 #include "src/compiler/node.h"
     10 #include "src/compiler/simplified-operator.h"
     11 #include "src/vector-slot-pair.h"
     12 
     13 namespace v8 {
     14 namespace internal {
     15 
     16 class JSGraph;
     17 class Graph;
     18 
     19 namespace compiler {
     20 
     21 #define PURE_ASSEMBLER_MACH_UNOP_LIST(V) \
     22   V(ChangeInt32ToInt64)                  \
     23   V(ChangeInt32ToFloat64)                \
     24   V(ChangeUint32ToFloat64)               \
     25   V(ChangeUint32ToUint64)                \
     26   V(ChangeFloat64ToInt32)                \
     27   V(ChangeFloat64ToUint32)               \
     28   V(TruncateInt64ToInt32)                \
     29   V(RoundFloat64ToInt32)                 \
     30   V(TruncateFloat64ToWord32)             \
     31   V(Float64ExtractLowWord32)             \
     32   V(Float64ExtractHighWord32)            \
     33   V(BitcastInt32ToFloat32)               \
     34   V(BitcastInt64ToFloat64)               \
     35   V(BitcastFloat32ToInt32)               \
     36   V(BitcastFloat64ToInt64)               \
     37   V(Float64Abs)                          \
     38   V(Word32ReverseBytes)                  \
     39   V(Word64ReverseBytes)
     40 
     41 #define PURE_ASSEMBLER_MACH_BINOP_LIST(V) \
     42   V(WordShl)                              \
     43   V(WordSar)                              \
     44   V(WordAnd)                              \
     45   V(Word32Or)                             \
     46   V(Word32And)                            \
     47   V(Word32Xor)                            \
     48   V(Word32Shr)                            \
     49   V(Word32Shl)                            \
     50   V(Word32Sar)                            \
     51   V(IntAdd)                               \
     52   V(IntSub)                               \
     53   V(IntMul)                               \
     54   V(IntLessThan)                          \
     55   V(UintLessThan)                         \
     56   V(Int32Add)                             \
     57   V(Int32Sub)                             \
     58   V(Int32Mul)                             \
     59   V(Int32LessThanOrEqual)                 \
     60   V(Uint32LessThanOrEqual)                \
     61   V(Uint32LessThan)                       \
     62   V(Int32LessThan)                        \
     63   V(Float64Add)                           \
     64   V(Float64Sub)                           \
     65   V(Float64Div)                           \
     66   V(Float64Mod)                           \
     67   V(Float64Equal)                         \
     68   V(Float64LessThan)                      \
     69   V(Float64LessThanOrEqual)               \
     70   V(Float64InsertLowWord32)               \
     71   V(Float64InsertHighWord32)              \
     72   V(Word32Equal)                          \
     73   V(WordEqual)
     74 
     75 #define CHECKED_ASSEMBLER_MACH_BINOP_LIST(V) \
     76   V(Int32AddWithOverflow)                    \
     77   V(Int32SubWithOverflow)                    \
     78   V(Int32MulWithOverflow)                    \
     79   V(Int32Mod)                                \
     80   V(Int32Div)                                \
     81   V(Uint32Mod)                               \
     82   V(Uint32Div)
     83 
     84 #define JSGRAPH_SINGLETON_CONSTANT_LIST(V) \
     85   V(TrueConstant)                          \
     86   V(FalseConstant)                         \
     87   V(NullConstant)                          \
     88   V(HeapNumberMapConstant)                 \
     89   V(NoContextConstant)                     \
     90   V(EmptyStringConstant)                   \
     91   V(UndefinedConstant)                     \
     92   V(TheHoleConstant)                       \
     93   V(FixedArrayMapConstant)                 \
     94   V(FixedDoubleArrayMapConstant)           \
     95   V(ToNumberBuiltinConstant)               \
     96   V(AllocateInNewSpaceStubConstant)        \
     97   V(AllocateInOldSpaceStubConstant)
     98 
     99 class GraphAssembler;
    100 
    101 enum class GraphAssemblerLabelType { kDeferred, kNonDeferred, kLoop };
    102 
    103 // Label with statically known count of incoming branches and phis.
    104 template <size_t VarCount>
    105 class GraphAssemblerLabel {
    106  public:
    107   Node* PhiAt(size_t index);
    108 
    109   template <typename... Reps>
    110   explicit GraphAssemblerLabel(GraphAssemblerLabelType type, Reps... reps)
    111       : type_(type) {
    112     STATIC_ASSERT(VarCount == sizeof...(reps));
    113     MachineRepresentation reps_array[] = {MachineRepresentation::kNone,
    114                                           reps...};
    115     for (size_t i = 0; i < VarCount; i++) {
    116       representations_[i] = reps_array[i + 1];
    117     }
    118   }
    119 
    120   ~GraphAssemblerLabel() { DCHECK(IsBound() || merged_count_ == 0); }
    121 
    122  private:
    123   friend class GraphAssembler;
    124 
    125   void SetBound() {
    126     DCHECK(!IsBound());
    127     is_bound_ = true;
    128   }
    129   bool IsBound() const { return is_bound_; }
    130   bool IsDeferred() const {
    131     return type_ == GraphAssemblerLabelType::kDeferred;
    132   }
    133   bool IsLoop() const { return type_ == GraphAssemblerLabelType::kLoop; }
    134 
    135   bool is_bound_ = false;
    136   GraphAssemblerLabelType const type_;
    137   size_t merged_count_ = 0;
    138   Node* effect_;
    139   Node* control_;
    140   Node* bindings_[VarCount + 1];
    141   MachineRepresentation representations_[VarCount + 1];
    142 };
    143 
    144 class GraphAssembler {
    145  public:
    146   GraphAssembler(JSGraph* jsgraph, Node* effect, Node* control, Zone* zone);
    147 
    148   void Reset(Node* effect, Node* control);
    149 
    150   // Create label.
    151   template <typename... Reps>
    152   static GraphAssemblerLabel<sizeof...(Reps)> MakeLabelFor(
    153       GraphAssemblerLabelType type, Reps... reps) {
    154     return GraphAssemblerLabel<sizeof...(Reps)>(type, reps...);
    155   }
    156 
    157   // Convenience wrapper for creating non-deferred labels.
    158   template <typename... Reps>
    159   static GraphAssemblerLabel<sizeof...(Reps)> MakeLabel(Reps... reps) {
    160     return MakeLabelFor(GraphAssemblerLabelType::kNonDeferred, reps...);
    161   }
    162 
    163   // Convenience wrapper for creating loop labels.
    164   template <typename... Reps>
    165   static GraphAssemblerLabel<sizeof...(Reps)> MakeLoopLabel(Reps... reps) {
    166     return MakeLabelFor(GraphAssemblerLabelType::kLoop, reps...);
    167   }
    168 
    169   // Convenience wrapper for creating deferred labels.
    170   template <typename... Reps>
    171   static GraphAssemblerLabel<sizeof...(Reps)> MakeDeferredLabel(Reps... reps) {
    172     return MakeLabelFor(GraphAssemblerLabelType::kDeferred, reps...);
    173   }
    174 
    175   // Value creation.
    176   Node* IntPtrConstant(intptr_t value);
    177   Node* Uint32Constant(int32_t value);
    178   Node* Int32Constant(int32_t value);
    179   Node* UniqueInt32Constant(int32_t value);
    180   Node* SmiConstant(int32_t value);
    181   Node* Float64Constant(double value);
    182   Node* Projection(int index, Node* value);
    183   Node* HeapConstant(Handle<HeapObject> object);
    184   Node* CEntryStubConstant(int result_size);
    185   Node* ExternalConstant(ExternalReference ref);
    186 
    187   Node* LoadFramePointer();
    188 
    189 #define SINGLETON_CONST_DECL(Name) Node* Name();
    190   JSGRAPH_SINGLETON_CONSTANT_LIST(SINGLETON_CONST_DECL)
    191 #undef SINGLETON_CONST_DECL
    192 
    193 #define PURE_UNOP_DECL(Name) Node* Name(Node* input);
    194   PURE_ASSEMBLER_MACH_UNOP_LIST(PURE_UNOP_DECL)
    195 #undef PURE_UNOP_DECL
    196 
    197 #define BINOP_DECL(Name) Node* Name(Node* left, Node* right);
    198   PURE_ASSEMBLER_MACH_BINOP_LIST(BINOP_DECL)
    199   CHECKED_ASSEMBLER_MACH_BINOP_LIST(BINOP_DECL)
    200 #undef BINOP_DECL
    201 
    202   // Debugging
    203   Node* DebugBreak();
    204 
    205   Node* Unreachable();
    206 
    207   Node* Float64RoundDown(Node* value);
    208   Node* Float64RoundTruncate(Node* value);
    209 
    210   Node* ToNumber(Node* value);
    211   Node* BitcastWordToTagged(Node* value);
    212   Node* Allocate(PretenureFlag pretenure, Node* size);
    213   Node* LoadField(FieldAccess const&, Node* object);
    214   Node* LoadElement(ElementAccess const&, Node* object, Node* index);
    215   Node* StoreField(FieldAccess const&, Node* object, Node* value);
    216   Node* StoreElement(ElementAccess const&, Node* object, Node* index,
    217                      Node* value);
    218 
    219   Node* Store(StoreRepresentation rep, Node* object, Node* offset, Node* value);
    220   Node* Load(MachineType rep, Node* object, Node* offset);
    221 
    222   Node* StoreUnaligned(MachineRepresentation rep, Node* object, Node* offset,
    223                        Node* value);
    224   Node* LoadUnaligned(MachineType rep, Node* object, Node* offset);
    225 
    226   Node* Retain(Node* buffer);
    227   Node* UnsafePointerAdd(Node* base, Node* external);
    228 
    229   Node* Word32PoisonOnSpeculation(Node* value);
    230 
    231   Node* DeoptimizeIf(DeoptimizeReason reason, VectorSlotPair const& feedback,
    232                      Node* condition, Node* frame_state);
    233   Node* DeoptimizeIfNot(
    234       DeoptimizeReason reason, VectorSlotPair const& feedback, Node* condition,
    235       Node* frame_state,
    236       IsSafetyCheck is_safety_check = IsSafetyCheck::kSafetyCheck);
    237   template <typename... Args>
    238   Node* Call(const CallDescriptor* call_descriptor, Args... args);
    239   template <typename... Args>
    240   Node* Call(const Operator* op, Args... args);
    241 
    242   // Basic control operations.
    243   template <size_t VarCount>
    244   void Bind(GraphAssemblerLabel<VarCount>* label);
    245 
    246   template <typename... Vars>
    247   void Goto(GraphAssemblerLabel<sizeof...(Vars)>* label, Vars...);
    248 
    249   void Branch(Node* condition, GraphAssemblerLabel<0u>* if_true,
    250               GraphAssemblerLabel<0u>* if_false);
    251 
    252   // Control helpers.
    253   // {GotoIf(c, l)} is equivalent to {Branch(c, l, templ);Bind(templ)}.
    254   template <typename... Vars>
    255   void GotoIf(Node* condition, GraphAssemblerLabel<sizeof...(Vars)>* label,
    256               Vars...);
    257 
    258   // {GotoIfNot(c, l)} is equivalent to {Branch(c, templ, l);Bind(templ)}.
    259   template <typename... Vars>
    260   void GotoIfNot(Node* condition, GraphAssemblerLabel<sizeof...(Vars)>* label,
    261                  Vars...);
    262 
    263   // Extractors (should be only used when destructing/resetting the assembler).
    264   Node* ExtractCurrentControl();
    265   Node* ExtractCurrentEffect();
    266 
    267  private:
    268   template <typename... Vars>
    269   void MergeState(GraphAssemblerLabel<sizeof...(Vars)>* label, Vars... vars);
    270 
    271   Operator const* ToNumberOperator();
    272 
    273   JSGraph* jsgraph() const { return jsgraph_; }
    274   Isolate* isolate() const { return jsgraph_->isolate(); }
    275   Graph* graph() const { return jsgraph_->graph(); }
    276   Zone* temp_zone() const { return temp_zone_; }
    277   CommonOperatorBuilder* common() const { return jsgraph()->common(); }
    278   MachineOperatorBuilder* machine() const { return jsgraph()->machine(); }
    279   SimplifiedOperatorBuilder* simplified() const {
    280     return jsgraph()->simplified();
    281   }
    282 
    283   SetOncePointer<Operator const> to_number_operator_;
    284   Zone* temp_zone_;
    285   JSGraph* jsgraph_;
    286   Node* current_effect_;
    287   Node* current_control_;
    288 };
    289 
    290 template <size_t VarCount>
    291 Node* GraphAssemblerLabel<VarCount>::PhiAt(size_t index) {
    292   DCHECK(IsBound());
    293   DCHECK_LT(index, VarCount);
    294   return bindings_[index];
    295 }
    296 
    297 template <typename... Vars>
    298 void GraphAssembler::MergeState(GraphAssemblerLabel<sizeof...(Vars)>* label,
    299                                 Vars... vars) {
    300   int merged_count = static_cast<int>(label->merged_count_);
    301   Node* var_array[] = {nullptr, vars...};
    302   if (label->IsLoop()) {
    303     if (merged_count == 0) {
    304       DCHECK(!label->IsBound());
    305       label->control_ = graph()->NewNode(common()->Loop(2), current_control_,
    306                                          current_control_);
    307       label->effect_ = graph()->NewNode(common()->EffectPhi(2), current_effect_,
    308                                         current_effect_, label->control_);
    309       Node* terminate = graph()->NewNode(common()->Terminate(), label->effect_,
    310                                          label->control_);
    311       NodeProperties::MergeControlToEnd(graph(), common(), terminate);
    312       for (size_t i = 0; i < sizeof...(vars); i++) {
    313         label->bindings_[i] = graph()->NewNode(
    314             common()->Phi(label->representations_[i], 2), var_array[i + 1],
    315             var_array[i + 1], label->control_);
    316       }
    317     } else {
    318       DCHECK(label->IsBound());
    319       DCHECK_EQ(1, merged_count);
    320       label->control_->ReplaceInput(1, current_control_);
    321       label->effect_->ReplaceInput(1, current_effect_);
    322       for (size_t i = 0; i < sizeof...(vars); i++) {
    323         label->bindings_[i]->ReplaceInput(1, var_array[i + 1]);
    324       }
    325     }
    326   } else {
    327     DCHECK(!label->IsBound());
    328     if (merged_count == 0) {
    329       // Just set the control, effect and variables directly.
    330       DCHECK(!label->IsBound());
    331       label->control_ = current_control_;
    332       label->effect_ = current_effect_;
    333       for (size_t i = 0; i < sizeof...(vars); i++) {
    334         label->bindings_[i] = var_array[i + 1];
    335       }
    336     } else if (merged_count == 1) {
    337       // Create merge, effect phi and a phi for each variable.
    338       label->control_ = graph()->NewNode(common()->Merge(2), label->control_,
    339                                          current_control_);
    340       label->effect_ = graph()->NewNode(common()->EffectPhi(2), label->effect_,
    341                                         current_effect_, label->control_);
    342       for (size_t i = 0; i < sizeof...(vars); i++) {
    343         label->bindings_[i] = graph()->NewNode(
    344             common()->Phi(label->representations_[i], 2), label->bindings_[i],
    345             var_array[i + 1], label->control_);
    346       }
    347     } else {
    348       // Append to the merge, effect phi and phis.
    349       DCHECK_EQ(IrOpcode::kMerge, label->control_->opcode());
    350       label->control_->AppendInput(graph()->zone(), current_control_);
    351       NodeProperties::ChangeOp(label->control_,
    352                                common()->Merge(merged_count + 1));
    353 
    354       DCHECK_EQ(IrOpcode::kEffectPhi, label->effect_->opcode());
    355       label->effect_->ReplaceInput(merged_count, current_effect_);
    356       label->effect_->AppendInput(graph()->zone(), label->control_);
    357       NodeProperties::ChangeOp(label->effect_,
    358                                common()->EffectPhi(merged_count + 1));
    359 
    360       for (size_t i = 0; i < sizeof...(vars); i++) {
    361         DCHECK_EQ(IrOpcode::kPhi, label->bindings_[i]->opcode());
    362         label->bindings_[i]->ReplaceInput(merged_count, var_array[i + 1]);
    363         label->bindings_[i]->AppendInput(graph()->zone(), label->control_);
    364         NodeProperties::ChangeOp(
    365             label->bindings_[i],
    366             common()->Phi(label->representations_[i], merged_count + 1));
    367       }
    368     }
    369   }
    370   label->merged_count_++;
    371 }
    372 
    373 template <size_t VarCount>
    374 void GraphAssembler::Bind(GraphAssemblerLabel<VarCount>* label) {
    375   DCHECK_NULL(current_control_);
    376   DCHECK_NULL(current_effect_);
    377   DCHECK_LT(0, label->merged_count_);
    378 
    379   current_control_ = label->control_;
    380   current_effect_ = label->effect_;
    381 
    382   label->SetBound();
    383 }
    384 
    385 template <typename... Vars>
    386 void GraphAssembler::Goto(GraphAssemblerLabel<sizeof...(Vars)>* label,
    387                           Vars... vars) {
    388   DCHECK_NOT_NULL(current_control_);
    389   DCHECK_NOT_NULL(current_effect_);
    390   MergeState(label, vars...);
    391   current_control_ = nullptr;
    392   current_effect_ = nullptr;
    393 }
    394 
    395 template <typename... Vars>
    396 void GraphAssembler::GotoIf(Node* condition,
    397                             GraphAssemblerLabel<sizeof...(Vars)>* label,
    398                             Vars... vars) {
    399   BranchHint hint =
    400       label->IsDeferred() ? BranchHint::kFalse : BranchHint::kNone;
    401   Node* branch =
    402       graph()->NewNode(common()->Branch(hint), condition, current_control_);
    403 
    404   current_control_ = graph()->NewNode(common()->IfTrue(), branch);
    405   MergeState(label, vars...);
    406 
    407   current_control_ = graph()->NewNode(common()->IfFalse(), branch);
    408 }
    409 
    410 template <typename... Vars>
    411 void GraphAssembler::GotoIfNot(Node* condition,
    412                                GraphAssemblerLabel<sizeof...(Vars)>* label,
    413                                Vars... vars) {
    414   BranchHint hint = label->IsDeferred() ? BranchHint::kTrue : BranchHint::kNone;
    415   Node* branch =
    416       graph()->NewNode(common()->Branch(hint), condition, current_control_);
    417 
    418   current_control_ = graph()->NewNode(common()->IfFalse(), branch);
    419   MergeState(label, vars...);
    420 
    421   current_control_ = graph()->NewNode(common()->IfTrue(), branch);
    422 }
    423 
    424 template <typename... Args>
    425 Node* GraphAssembler::Call(const CallDescriptor* call_descriptor,
    426                            Args... args) {
    427   const Operator* op = common()->Call(call_descriptor);
    428   return Call(op, args...);
    429 }
    430 
    431 template <typename... Args>
    432 Node* GraphAssembler::Call(const Operator* op, Args... args) {
    433   DCHECK_EQ(IrOpcode::kCall, op->opcode());
    434   Node* args_array[] = {args..., current_effect_, current_control_};
    435   int size = static_cast<int>(sizeof...(args)) + op->EffectInputCount() +
    436              op->ControlInputCount();
    437   Node* call = graph()->NewNode(op, size, args_array);
    438   DCHECK_EQ(0, op->ControlOutputCount());
    439   current_effect_ = call;
    440   return call;
    441 }
    442 
    443 }  // namespace compiler
    444 }  // namespace internal
    445 }  // namespace v8
    446 
    447 #endif  // V8_COMPILER_GRAPH_ASSEMBLER_H_
    448