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 |