Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 12 namespace v8 { | |
| 13 namespace internal { | |
| 14 | |
| 15 class JSGraph; | |
| 16 class Graph; | |
| 17 | |
| 18 namespace compiler { | |
| 19 | |
| 20 #define PURE_ASSEMBLER_MACH_UNOP_LIST(V) \ | |
| 21 V(ChangeInt32ToInt64) \ | |
| 22 V(ChangeInt32ToFloat64) \ | |
| 23 V(ChangeUint32ToFloat64) \ | |
| 24 V(ChangeUint32ToUint64) \ | |
| 25 V(ChangeFloat64ToInt32) \ | |
| 26 V(ChangeFloat64ToUint32) \ | |
| 27 V(TruncateInt64ToInt32) \ | |
| 28 V(RoundFloat64ToInt32) \ | |
| 29 V(TruncateFloat64ToWord32) \ | |
| 30 V(Float64ExtractHighWord32) \ | |
| 31 V(Float64Abs) | |
| 32 | |
| 33 #define PURE_ASSEMBLER_MACH_BINOP_LIST(V) \ | |
| 34 V(WordShl) \ | |
| 35 V(WordSar) \ | |
| 36 V(WordAnd) \ | |
| 37 V(Word32Or) \ | |
| 38 V(Word32And) \ | |
| 39 V(Word32Shr) \ | |
| 40 V(Word32Shl) \ | |
| 41 V(Int32Add) \ | |
| 42 V(Int32Sub) \ | |
| 43 V(Int32Mul) \ | |
| 44 V(Int32LessThanOrEqual) \ | |
| 45 V(Uint32LessThanOrEqual) \ | |
| 46 V(Uint32LessThan) \ | |
| 47 V(Int32LessThan) \ | |
| 48 V(Float64Add) \ | |
| 49 V(Float64Sub) \ | |
| 50 V(Float64Mod) \ | |
| 51 V(Float64Equal) \ | |
| 52 V(Float64LessThan) \ | |
| 53 V(Float64LessThanOrEqual) \ | |
| 54 V(Word32Equal) \ | |
| 55 V(WordEqual) | |
| 56 | |
| 57 #define CHECKED_ASSEMBLER_MACH_BINOP_LIST(V) \ | |
| 58 V(Int32AddWithOverflow) \ | |
| 59 V(Int32SubWithOverflow) \ | |
| 60 V(Int32MulWithOverflow) \ | |
| 61 V(Int32Mod) \ | |
| 62 V(Int32Div) \ | |
| 63 V(Uint32Mod) \ | |
| 64 V(Uint32Div) | |
| 65 | |
| 66 class GraphAssembler; | |
| 67 | |
| 68 enum class GraphAssemblerLabelType { kDeferred, kNonDeferred }; | |
| 69 | |
| 70 // Label with statically known count of incoming branches and phis. | |
| 71 template <size_t MergeCount, size_t VarCount = 0u> | |
| 72 class GraphAssemblerStaticLabel { | |
| 73 public: | |
| 74 Node* PhiAt(size_t index); | |
| 75 | |
| 76 template <typename... Reps> | |
| 77 explicit GraphAssemblerStaticLabel(GraphAssemblerLabelType is_deferred, | |
| 78 Reps... reps) | |
| 79 : is_deferred_(is_deferred == GraphAssemblerLabelType::kDeferred) { | |
| 80 STATIC_ASSERT(VarCount == sizeof...(reps)); | |
| 81 MachineRepresentation reps_array[] = {MachineRepresentation::kNone, | |
| 82 reps...}; | |
| 83 for (size_t i = 0; i < VarCount; i++) { | |
| 84 representations_[i] = reps_array[i + 1]; | |
| 85 } | |
| 86 } | |
| 87 | |
| 88 ~GraphAssemblerStaticLabel() { DCHECK(IsBound() || MergedCount() == 0); } | |
| 89 | |
| 90 private: | |
| 91 friend class GraphAssembler; | |
| 92 | |
| 93 void SetBound() { | |
| 94 DCHECK(!IsBound()); | |
| 95 DCHECK_EQ(merged_count_, MergeCount); | |
| 96 is_bound_ = true; | |
| 97 } | |
| 98 bool IsBound() { return is_bound_; } | |
|
Igor Sheludko
2017/01/02 13:23:27
Please make all getters const.
Jarin
2017/01/03 09:27:55
Done.
| |
| 99 | |
| 100 size_t PhiCount() { return VarCount; } | |
| 101 size_t MaxMergeCount() { return MergeCount; } | |
| 102 size_t MergedCount() { return merged_count_; } | |
| 103 bool IsDeferred() { return is_deferred_; } | |
| 104 | |
| 105 // For each phi, the buffer must have at least MaxMergeCount() + 1 | |
| 106 // node entries. | |
| 107 Node** GetBindingsPtrFor(size_t phi_index) { | |
|
Igor Sheludko
2017/01/02 13:23:27
Please add bounds checks here and in other getters
Jarin
2017/01/03 09:27:55
Done.
| |
| 108 return &bindings_[phi_index * (MergeCount + 1)]; | |
| 109 } | |
| 110 MachineRepresentation GetRepresentationFor(size_t phi_index) { | |
| 111 return representations_[phi_index]; | |
| 112 } | |
| 113 // The controls buffer must have at least MaxMergeCount() entries. | |
| 114 Node** GetControlsPtr() { return controls_; } | |
| 115 // The effects buffer must have at least MaxMergeCount() + 1 entries. | |
| 116 Node** GetEffectsPtr() { return effects_; } | |
| 117 void IncrementMergedCount() { merged_count_++; } | |
| 118 | |
| 119 bool is_bound_ = false; | |
| 120 bool is_deferred_; | |
| 121 size_t merged_count_ = 0; | |
| 122 Node* effects_[MergeCount + 1]; // Extra element for control edge, | |
| 123 // so that we can use the array to | |
| 124 // construct EffectPhi. | |
| 125 Node* controls_[MergeCount]; | |
| 126 Node* bindings_[(MergeCount + 1) * VarCount + 1]; | |
| 127 MachineRepresentation representations_[VarCount + 1]; | |
| 128 }; | |
| 129 | |
| 130 // General label (with zone allocated buffers for incoming branches and phi | |
| 131 // inputs). | |
| 132 class GraphAssemblerLabel { | |
| 133 public: | |
| 134 Node* PhiAt(size_t index); | |
| 135 | |
| 136 GraphAssemblerLabel(GraphAssemblerLabelType is_deferred, size_t merge_count, | |
| 137 size_t var_count, MachineRepresentation* representations, | |
| 138 Zone* zone); | |
| 139 | |
| 140 ~GraphAssemblerLabel(); | |
| 141 | |
| 142 private: | |
| 143 friend class GraphAssembler; | |
| 144 | |
| 145 void SetBound() { | |
| 146 DCHECK(!is_bound_); | |
| 147 is_bound_ = true; | |
| 148 } | |
| 149 bool IsBound() { return is_bound_; } | |
|
Igor Sheludko
2017/01/02 13:23:27
Same here.
Jarin
2017/01/03 09:27:55
Done.
| |
| 150 size_t PhiCount() { return var_count_; } | |
| 151 size_t MaxMergeCount() { return max_merge_count_; } | |
| 152 size_t MergedCount() { return merged_count_; } | |
| 153 bool IsDeferred() { return is_deferred_; } | |
| 154 | |
| 155 // For each phi, the buffer must have at least MaxMergeCount() + 1 | |
| 156 // node entries. | |
| 157 Node** GetBindingsPtrFor(size_t phi_index); | |
| 158 MachineRepresentation GetRepresentationFor(size_t phi_index); | |
| 159 // The controls buffer must have at least MaxMergeCount() entries. | |
| 160 Node** GetControlsPtr(); | |
| 161 // The effects buffer must have at least MaxMergeCount() + 1 entries. | |
| 162 Node** GetEffectsPtr(); | |
| 163 void IncrementMergedCount() { merged_count_++; } | |
| 164 | |
| 165 bool is_bound_ = false; | |
| 166 bool is_deferred_; | |
| 167 size_t merged_count_ = 0; | |
| 168 size_t max_merge_count_; | |
| 169 size_t var_count_; | |
| 170 Node** effects_ = nullptr; | |
| 171 Node** controls_ = nullptr; | |
| 172 Node** bindings_ = nullptr; | |
| 173 MachineRepresentation* representations_ = nullptr; | |
| 174 }; | |
| 175 | |
| 176 class GraphAssembler { | |
| 177 public: | |
| 178 GraphAssembler(JSGraph* jsgraph, Node* effect, Node* control, Zone* zone); | |
| 179 | |
| 180 void Reset(Node* effect, Node* control); | |
| 181 | |
| 182 // Create non-deferred label with statically known number of incoming | |
| 183 // gotos/branches. | |
| 184 template <size_t MergeCount, typename... Reps> | |
| 185 static GraphAssemblerStaticLabel<MergeCount, sizeof...(Reps)> MakeLabel( | |
|
Jarin
2016/12/27 13:51:06
There is one thing I do not like about this: the M
Igor Sheludko
2017/01/02 13:23:27
I think it's fine for labels to support move seman
| |
| 186 Reps... reps) { | |
| 187 return GraphAssemblerStaticLabel<MergeCount, sizeof...(Reps)>( | |
| 188 GraphAssemblerLabelType::kNonDeferred, reps...); | |
| 189 } | |
| 190 | |
| 191 // Create deferred label with statically known number of incoming | |
| 192 // gotos/branches. | |
| 193 template <size_t MergeCount, typename... Reps> | |
| 194 static GraphAssemblerStaticLabel<MergeCount, sizeof...(Reps)> | |
| 195 MakeDeferredLabel(Reps... reps) { | |
| 196 return GraphAssemblerStaticLabel<MergeCount, sizeof...(Reps)>( | |
| 197 GraphAssemblerLabelType::kDeferred, reps...); | |
| 198 } | |
| 199 | |
| 200 // Create label with number of incoming branches supplied at runtime. | |
| 201 template <typename... Reps> | |
| 202 GraphAssemblerLabel MakeLabelFor(GraphAssemblerLabelType is_deferred, | |
| 203 size_t merge_count, Reps... reps) { | |
| 204 MachineRepresentation reps_array[] = {MachineRepresentation::kNone, | |
| 205 reps...}; | |
| 206 return GraphAssemblerLabel(is_deferred, merge_count, sizeof...(reps), | |
| 207 &(reps_array[1]), temp_zone()); | |
| 208 } | |
| 209 | |
| 210 // Value creation. | |
| 211 Node* TrueConstant(); | |
| 212 Node* FalseConstant(); | |
| 213 Node* HeapNumberMapConstant(); | |
| 214 Node* IntPtrConstant(intptr_t value); | |
| 215 Node* Uint32Constant(int32_t value); | |
| 216 Node* Int32Constant(int32_t value); | |
| 217 Node* SmiConstant(int32_t value); | |
| 218 Node* Float64Constant(double value); | |
| 219 Node* Projection(int index, Node* value); | |
| 220 Node* HeapConstant(Handle<HeapObject> object); | |
| 221 Node* NoContextConstant(); | |
| 222 Node* CEntryStubConstant(int result_size); | |
| 223 Node* ExternalConstant(ExternalReference ref); | |
| 224 Node* EmptyStringConstant(); | |
| 225 Node* UndefinedConstant(); | |
| 226 Node* TheHoleConstant(); | |
| 227 Node* FixedArrayMapConstant(); | |
| 228 | |
| 229 #define PURE_UNOP_DECL(Name) Node* Name(Node* input); | |
| 230 PURE_ASSEMBLER_MACH_UNOP_LIST(PURE_UNOP_DECL) | |
| 231 #undef PURE_UNOP_DECL | |
| 232 | |
| 233 #define BINOP_DECL(Name) Node* Name(Node* left, Node* right); | |
| 234 PURE_ASSEMBLER_MACH_BINOP_LIST(BINOP_DECL) | |
| 235 CHECKED_ASSEMBLER_MACH_BINOP_LIST(BINOP_DECL) | |
| 236 #undef BINOP_DECL | |
| 237 | |
| 238 Node* Float64RoundDown(Node* value); | |
| 239 | |
| 240 Node* ToNumber(Node* value); | |
| 241 Node* Allocate(PretenureFlag pretenure, Node* size); | |
| 242 Node* LoadField(FieldAccess const&, Node* object); | |
| 243 Node* LoadElement(ElementAccess const&, Node* object, Node* index); | |
| 244 Node* StoreField(FieldAccess const&, Node* object, Node* value); | |
| 245 Node* StoreElement(ElementAccess const&, Node* object, Node* index, | |
| 246 Node* value); | |
| 247 | |
| 248 Node* Store(StoreRepresentation rep, Node* object, Node* offset, Node* value); | |
| 249 | |
| 250 Node* Retain(Node* buffer); | |
| 251 Node* UnsafePointerAdd(Node* base, Node* external); | |
| 252 | |
| 253 Node* DeoptimizeIf(DeoptimizeReason reason, Node* condition, | |
| 254 Node* frame_state); | |
| 255 Node* DeoptimizeUnless(DeoptimizeReason reason, Node* condition, | |
| 256 Node* frame_state); | |
| 257 template <typename... Args> | |
| 258 Node* Call(const CallDescriptor* desc, Args... args); | |
| 259 | |
| 260 // Basic control operations. | |
| 261 template <class LabelType> | |
| 262 void Bind(LabelType* label); | |
| 263 | |
| 264 template <class LabelType, typename... vars> | |
| 265 void Goto(LabelType* label, vars...); | |
| 266 | |
| 267 void Branch(Node* condition, GraphAssemblerStaticLabel<1>* if_true, | |
| 268 GraphAssemblerStaticLabel<1>* if_false); | |
| 269 | |
| 270 // Control helpers. | |
| 271 // {GotoIf(c, l)} is equivalent to {Branch(c, l, templ);Bind(templ)}. | |
| 272 template <class LabelType, typename... vars> | |
| 273 void GotoIf(Node* condition, LabelType* label, vars...); | |
| 274 | |
| 275 // {GotoUnless(c, l)} is equivalent to {Branch(c, templ, l);Bind(templ)}. | |
| 276 template <class LabelType, typename... vars> | |
| 277 void GotoUnless(Node* condition, LabelType* label, vars...); | |
| 278 | |
| 279 // Extractors (should be only used when destructing/resetting the assembler). | |
| 280 Node* ExtractCurrentControl(); | |
| 281 Node* ExtractCurrentEffect(); | |
| 282 | |
| 283 private: | |
| 284 template <class LabelType, typename... Vars> | |
| 285 void MergeState(LabelType label, Vars... vars); | |
| 286 | |
| 287 Operator const* ToNumberOperator(); | |
| 288 | |
| 289 JSGraph* jsgraph() const { return jsgraph_; } | |
| 290 Graph* graph() const { return jsgraph_->graph(); } | |
| 291 Zone* temp_zone() const { return temp_zone_; } | |
| 292 CommonOperatorBuilder* common() const { return jsgraph()->common(); } | |
| 293 MachineOperatorBuilder* machine() const { return jsgraph()->machine(); } | |
| 294 SimplifiedOperatorBuilder* simplified() const { | |
| 295 return jsgraph()->simplified(); | |
| 296 } | |
| 297 | |
| 298 SetOncePointer<Operator const> to_number_operator_; | |
| 299 Zone* temp_zone_; | |
| 300 JSGraph* jsgraph_; | |
| 301 Node* current_effect_; | |
| 302 Node* current_control_; | |
| 303 }; | |
| 304 | |
| 305 template <size_t MergeCount, size_t VarCount> | |
| 306 Node* GraphAssemblerStaticLabel<MergeCount, VarCount>::PhiAt(size_t index) { | |
| 307 DCHECK(IsBound()); | |
| 308 return GetBindingsPtrFor(index)[0]; | |
| 309 } | |
| 310 | |
| 311 template <class LabelType, typename... Vars> | |
| 312 void GraphAssembler::MergeState(LabelType label, Vars... vars) { | |
| 313 DCHECK(!label->IsBound()); | |
| 314 size_t merged_count = label->MergedCount(); | |
| 315 DCHECK_LT(merged_count, label->MaxMergeCount()); | |
| 316 DCHECK_EQ(label->PhiCount(), sizeof...(vars)); | |
| 317 label->GetEffectsPtr()[merged_count] = current_effect_; | |
| 318 label->GetControlsPtr()[merged_count] = current_control_; | |
| 319 // We need to start with nullptr to avoid 0-length arrays. | |
| 320 Node* var_array[] = {nullptr, vars...}; | |
| 321 for (size_t i = 0; i < sizeof...(vars); i++) { | |
| 322 label->GetBindingsPtrFor(i)[merged_count] = var_array[i + 1]; | |
|
Igor Sheludko
2017/01/02 13:23:27
I think it would be better to call here a setter t
Jarin
2017/01/03 09:27:55
Done.
| |
| 323 } | |
| 324 label->IncrementMergedCount(); | |
| 325 } | |
| 326 | |
| 327 template <class LabelType> | |
| 328 void GraphAssembler::Bind(LabelType* label) { | |
| 329 DCHECK(current_control_ == nullptr); | |
| 330 DCHECK(current_effect_ == nullptr); | |
| 331 DCHECK(label->MaxMergeCount() > 0); | |
| 332 DCHECK_EQ(label->MaxMergeCount(), label->MergedCount()); | |
| 333 | |
| 334 int merge_count = static_cast<int>(label->MaxMergeCount()); | |
| 335 if (merge_count == 1) { | |
| 336 current_control_ = label->GetControlsPtr()[0]; | |
| 337 current_effect_ = label->GetEffectsPtr()[0]; | |
| 338 label->SetBound(); | |
| 339 return; | |
| 340 } | |
| 341 | |
| 342 current_control_ = graph()->NewNode(common()->Merge(merge_count), merge_count, | |
| 343 label->GetControlsPtr()); | |
| 344 | |
| 345 Node** effects = label->GetEffectsPtr(); | |
| 346 current_effect_ = effects[0]; | |
| 347 for (size_t i = 1; i < label->MaxMergeCount(); i++) { | |
| 348 if (current_effect_ != effects[i]) { | |
| 349 effects[label->MaxMergeCount()] = current_control_; | |
| 350 current_effect_ = graph()->NewNode(common()->EffectPhi(merge_count), | |
| 351 merge_count + 1, effects); | |
| 352 break; | |
| 353 } | |
| 354 } | |
| 355 | |
| 356 for (size_t var = 0; var < label->PhiCount(); var++) { | |
| 357 Node** bindings = label->GetBindingsPtrFor(var); | |
| 358 bindings[label->MaxMergeCount()] = current_control_; | |
| 359 bindings[0] = graph()->NewNode( | |
| 360 common()->Phi(label->GetRepresentationFor(var), merge_count), | |
| 361 merge_count + 1, bindings); | |
| 362 } | |
| 363 | |
| 364 label->SetBound(); | |
| 365 } | |
| 366 | |
| 367 template <class LabelType, typename... Vars> | |
| 368 void GraphAssembler::Goto(LabelType* label, Vars... vars) { | |
| 369 DCHECK_NOT_NULL(current_control_); | |
| 370 DCHECK_NOT_NULL(current_effect_); | |
| 371 MergeState(label, vars...); | |
| 372 current_control_ = nullptr; | |
| 373 current_effect_ = nullptr; | |
| 374 } | |
| 375 | |
| 376 template <class LabelType, typename... Vars> | |
| 377 void GraphAssembler::GotoIf(Node* condition, LabelType* label, Vars... vars) { | |
| 378 BranchHint hint = | |
| 379 label->IsDeferred() ? BranchHint::kFalse : BranchHint::kNone; | |
| 380 Node* branch = | |
| 381 graph()->NewNode(common()->Branch(hint), condition, current_control_); | |
| 382 | |
| 383 current_control_ = graph()->NewNode(common()->IfTrue(), branch); | |
| 384 MergeState(label, vars...); | |
| 385 | |
| 386 current_control_ = graph()->NewNode(common()->IfFalse(), branch); | |
| 387 } | |
| 388 | |
| 389 template <class LabelType, typename... Vars> | |
| 390 void GraphAssembler::GotoUnless(Node* condition, LabelType* label, | |
| 391 Vars... vars) { | |
| 392 BranchHint hint = label->IsDeferred() ? BranchHint::kTrue : BranchHint::kNone; | |
| 393 Node* branch = | |
| 394 graph()->NewNode(common()->Branch(hint), condition, current_control_); | |
| 395 | |
| 396 current_control_ = graph()->NewNode(common()->IfFalse(), branch); | |
| 397 MergeState(label, vars...); | |
| 398 | |
| 399 current_control_ = graph()->NewNode(common()->IfTrue(), branch); | |
| 400 } | |
| 401 | |
| 402 template <typename... Args> | |
| 403 Node* GraphAssembler::Call(const CallDescriptor* desc, Args... args) { | |
| 404 const Operator* op = common()->Call(desc); | |
| 405 Node* args_array[] = {args..., current_effect_, current_control_}; | |
| 406 int size = static_cast<int>(sizeof...(args)) + op->EffectInputCount() + | |
| 407 op->ControlInputCount(); | |
| 408 Node* call = graph()->NewNode(op, size, args_array); | |
| 409 DCHECK_EQ(0, op->ControlOutputCount()); | |
| 410 current_effect_ = call; | |
| 411 return call; | |
| 412 } | |
| 413 | |
| 414 } // namespace compiler | |
| 415 } // namespace internal | |
| 416 } // namespace v8 | |
| 417 | |
| 418 #endif // V8_COMPILER_GRAPH_ASSEMBLER_H_ | |
| OLD | NEW |