Line data Source code
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 : V(BitcastWordToTagged)
33 :
34 : #define PURE_ASSEMBLER_MACH_BINOP_LIST(V) \
35 : V(WordShl) \
36 : V(WordSar) \
37 : V(WordAnd) \
38 : V(Word32Or) \
39 : V(Word32And) \
40 : V(Word32Shr) \
41 : V(Word32Shl) \
42 : V(IntAdd) \
43 : V(IntSub) \
44 : V(IntLessThan) \
45 : V(UintLessThan) \
46 : V(Int32Add) \
47 : V(Int32Sub) \
48 : V(Int32Mul) \
49 : V(Int32LessThanOrEqual) \
50 : V(Uint32LessThanOrEqual) \
51 : V(Uint32LessThan) \
52 : V(Int32LessThan) \
53 : V(Float64Add) \
54 : V(Float64Sub) \
55 : V(Float64Mod) \
56 : V(Float64Equal) \
57 : V(Float64LessThan) \
58 : V(Float64LessThanOrEqual) \
59 : V(Word32Equal) \
60 : V(WordEqual)
61 :
62 : #define CHECKED_ASSEMBLER_MACH_BINOP_LIST(V) \
63 : V(Int32AddWithOverflow) \
64 : V(Int32SubWithOverflow) \
65 : V(Int32MulWithOverflow) \
66 : V(Int32Mod) \
67 : V(Int32Div) \
68 : V(Uint32Mod) \
69 : V(Uint32Div)
70 :
71 : #define JSGRAPH_SINGLETON_CONSTANT_LIST(V) \
72 : V(TrueConstant) \
73 : V(FalseConstant) \
74 : V(HeapNumberMapConstant) \
75 : V(NoContextConstant) \
76 : V(EmptyStringConstant) \
77 : V(UndefinedConstant) \
78 : V(TheHoleConstant) \
79 : V(FixedArrayMapConstant) \
80 : V(ToNumberBuiltinConstant) \
81 : V(AllocateInNewSpaceStubConstant) \
82 : V(AllocateInOldSpaceStubConstant)
83 :
84 : class GraphAssembler;
85 :
86 : enum class GraphAssemblerLabelType { kDeferred, kNonDeferred };
87 :
88 : // Label with statically known count of incoming branches and phis.
89 : template <size_t MergeCount, size_t VarCount = 0u>
90 : class GraphAssemblerStaticLabel {
91 : public:
92 : Node* PhiAt(size_t index);
93 :
94 : template <typename... Reps>
95 : explicit GraphAssemblerStaticLabel(GraphAssemblerLabelType is_deferred,
96 : Reps... reps)
97 : : is_deferred_(is_deferred == GraphAssemblerLabelType::kDeferred) {
98 : STATIC_ASSERT(VarCount == sizeof...(reps));
99 : MachineRepresentation reps_array[] = {MachineRepresentation::kNone,
100 423670 : reps...};
101 847340 : for (size_t i = 0; i < VarCount; i++) {
102 423670 : representations_[i] = reps_array[i + 1];
103 : }
104 : }
105 :
106 : ~GraphAssemblerStaticLabel() { DCHECK(IsBound() || MergedCount() == 0); }
107 :
108 : private:
109 : friend class GraphAssembler;
110 :
111 : void SetBound() {
112 : DCHECK(!IsBound());
113 : DCHECK_EQ(merged_count_, MergeCount);
114 1018400 : is_bound_ = true;
115 : }
116 : bool IsBound() const { return is_bound_; }
117 :
118 : size_t PhiCount() const { return VarCount; }
119 : size_t MaxMergeCount() const { return MergeCount; }
120 : size_t MergedCount() const { return merged_count_; }
121 : bool IsDeferred() const { return is_deferred_; }
122 :
123 : // For each phi, the buffer must have at least MaxMergeCount() + 1
124 : // node entries.
125 : Node** GetBindingsPtrFor(size_t phi_index) {
126 : DCHECK_LT(phi_index, PhiCount());
127 423670 : return &bindings_[phi_index * (MergeCount + 1)];
128 : }
129 : void SetBinding(size_t phi_index, size_t merge_index, Node* binding) {
130 : DCHECK_LT(phi_index, PhiCount());
131 : DCHECK_LT(merge_index, MergeCount);
132 1177172 : bindings_[phi_index * (MergeCount + 1) + merge_index] = binding;
133 : }
134 : MachineRepresentation GetRepresentationFor(size_t phi_index) {
135 : DCHECK_LT(phi_index, PhiCount());
136 423670 : return representations_[phi_index];
137 : }
138 : // The controls buffer must have at least MaxMergeCount() entries.
139 : Node** GetControlsPtr() { return controls_; }
140 : // The effects buffer must have at least MaxMergeCount() + 1 entries.
141 : Node** GetEffectsPtr() { return effects_; }
142 1835919 : void IncrementMergedCount() { merged_count_++; }
143 :
144 : bool is_bound_ = false;
145 : bool is_deferred_;
146 : size_t merged_count_ = 0;
147 : Node* effects_[MergeCount + 1]; // Extra element for control edge,
148 : // so that we can use the array to
149 : // construct EffectPhi.
150 : Node* controls_[MergeCount];
151 : Node* bindings_[(MergeCount + 1) * VarCount + 1];
152 : MachineRepresentation representations_[VarCount + 1];
153 : };
154 :
155 : // General label (with zone allocated buffers for incoming branches and phi
156 : // inputs).
157 : class GraphAssemblerLabel {
158 : public:
159 : Node* PhiAt(size_t index);
160 :
161 : GraphAssemblerLabel(GraphAssemblerLabelType is_deferred, size_t merge_count,
162 : size_t var_count, MachineRepresentation* representations,
163 : Zone* zone);
164 :
165 : ~GraphAssemblerLabel();
166 :
167 : private:
168 : friend class GraphAssembler;
169 :
170 : void SetBound() {
171 : DCHECK(!is_bound_);
172 93866 : is_bound_ = true;
173 : }
174 : bool IsBound() const { return is_bound_; }
175 : size_t PhiCount() const { return var_count_; }
176 : size_t MaxMergeCount() const { return max_merge_count_; }
177 : size_t MergedCount() const { return merged_count_; }
178 : bool IsDeferred() const { return is_deferred_; }
179 :
180 : // For each phi, the buffer must have at least MaxMergeCount() + 1
181 : // node entries.
182 : Node** GetBindingsPtrFor(size_t phi_index);
183 : void SetBinding(size_t phi_index, size_t merge_index, Node* binding);
184 : MachineRepresentation GetRepresentationFor(size_t phi_index);
185 : // The controls buffer must have at least MaxMergeCount() entries.
186 : Node** GetControlsPtr();
187 : // The effects buffer must have at least MaxMergeCount() + 1 entries.
188 : Node** GetEffectsPtr();
189 123208 : void IncrementMergedCount() { merged_count_++; }
190 :
191 : bool is_bound_ = false;
192 : bool is_deferred_;
193 : size_t merged_count_ = 0;
194 : size_t max_merge_count_;
195 : size_t var_count_;
196 : Node** effects_ = nullptr;
197 : Node** controls_ = nullptr;
198 : Node** bindings_ = nullptr;
199 : MachineRepresentation* representations_ = nullptr;
200 : };
201 :
202 : class GraphAssembler {
203 : public:
204 : GraphAssembler(JSGraph* jsgraph, Node* effect, Node* control, Zone* zone);
205 :
206 : void Reset(Node* effect, Node* control);
207 :
208 : // Create non-deferred label with statically known number of incoming
209 : // gotos/branches.
210 : template <size_t MergeCount, typename... Reps>
211 : static GraphAssemblerStaticLabel<MergeCount, sizeof...(Reps)> MakeLabel(
212 : Reps... reps) {
213 : return GraphAssemblerStaticLabel<MergeCount, sizeof...(Reps)>(
214 : GraphAssemblerLabelType::kNonDeferred, reps...);
215 : }
216 :
217 : // Create deferred label with statically known number of incoming
218 : // gotos/branches.
219 : template <size_t MergeCount, typename... Reps>
220 : static GraphAssemblerStaticLabel<MergeCount, sizeof...(Reps)>
221 : MakeDeferredLabel(Reps... reps) {
222 : return GraphAssemblerStaticLabel<MergeCount, sizeof...(Reps)>(
223 : GraphAssemblerLabelType::kDeferred, reps...);
224 : }
225 :
226 : // Create label with number of incoming branches supplied at runtime.
227 : template <typename... Reps>
228 : GraphAssemblerLabel MakeLabelFor(GraphAssemblerLabelType is_deferred,
229 93867 : size_t merge_count, Reps... reps) {
230 : MachineRepresentation reps_array[] = {MachineRepresentation::kNone,
231 93867 : reps...};
232 : return GraphAssemblerLabel(is_deferred, merge_count, sizeof...(reps),
233 93867 : &(reps_array[1]), temp_zone());
234 : }
235 :
236 : // Value creation.
237 : Node* IntPtrConstant(intptr_t value);
238 : Node* Uint32Constant(int32_t value);
239 : Node* Int32Constant(int32_t value);
240 : Node* UniqueInt32Constant(int32_t value);
241 : Node* SmiConstant(int32_t value);
242 : Node* Float64Constant(double value);
243 : Node* Projection(int index, Node* value);
244 : Node* HeapConstant(Handle<HeapObject> object);
245 : Node* CEntryStubConstant(int result_size);
246 : Node* ExternalConstant(ExternalReference ref);
247 :
248 : Node* LoadFramePointer();
249 :
250 : #define SINGLETON_CONST_DECL(Name) Node* Name();
251 : JSGRAPH_SINGLETON_CONSTANT_LIST(SINGLETON_CONST_DECL)
252 : #undef SINGLETON_CONST_DECL
253 :
254 : #define PURE_UNOP_DECL(Name) Node* Name(Node* input);
255 : PURE_ASSEMBLER_MACH_UNOP_LIST(PURE_UNOP_DECL)
256 : #undef PURE_UNOP_DECL
257 :
258 : #define BINOP_DECL(Name) Node* Name(Node* left, Node* right);
259 : PURE_ASSEMBLER_MACH_BINOP_LIST(BINOP_DECL)
260 : CHECKED_ASSEMBLER_MACH_BINOP_LIST(BINOP_DECL)
261 : #undef BINOP_DECL
262 :
263 : Node* Float64RoundDown(Node* value);
264 :
265 : Node* ToNumber(Node* value);
266 : Node* Allocate(PretenureFlag pretenure, Node* size);
267 : Node* LoadField(FieldAccess const&, Node* object);
268 : Node* LoadElement(ElementAccess const&, Node* object, Node* index);
269 : Node* StoreField(FieldAccess const&, Node* object, Node* value);
270 : Node* StoreElement(ElementAccess const&, Node* object, Node* index,
271 : Node* value);
272 :
273 : Node* Store(StoreRepresentation rep, Node* object, Node* offset, Node* value);
274 : Node* Load(MachineType rep, Node* object, Node* offset);
275 :
276 : Node* Retain(Node* buffer);
277 : Node* UnsafePointerAdd(Node* base, Node* external);
278 :
279 : Node* DeoptimizeIf(DeoptimizeReason reason, Node* condition,
280 : Node* frame_state);
281 : Node* DeoptimizeUnless(DeoptimizeKind kind, DeoptimizeReason reason,
282 : Node* condition, Node* frame_state);
283 : Node* DeoptimizeUnless(DeoptimizeReason reason, Node* condition,
284 : Node* frame_state);
285 : template <typename... Args>
286 : Node* Call(const CallDescriptor* desc, Args... args);
287 : template <typename... Args>
288 : Node* Call(const Operator* op, Args... args);
289 :
290 : // Basic control operations.
291 : template <class LabelType>
292 : void Bind(LabelType* label);
293 :
294 : template <class LabelType, typename... vars>
295 : void Goto(LabelType* label, vars...);
296 :
297 : void Branch(Node* condition, GraphAssemblerStaticLabel<1>* if_true,
298 : GraphAssemblerStaticLabel<1>* if_false);
299 :
300 : // Control helpers.
301 : // {GotoIf(c, l)} is equivalent to {Branch(c, l, templ);Bind(templ)}.
302 : template <class LabelType, typename... vars>
303 : void GotoIf(Node* condition, LabelType* label, vars...);
304 :
305 : // {GotoUnless(c, l)} is equivalent to {Branch(c, templ, l);Bind(templ)}.
306 : template <class LabelType, typename... vars>
307 : void GotoUnless(Node* condition, LabelType* label, vars...);
308 :
309 : // Extractors (should be only used when destructing/resetting the assembler).
310 : Node* ExtractCurrentControl();
311 : Node* ExtractCurrentEffect();
312 :
313 : private:
314 : template <class LabelType, typename... Vars>
315 : void MergeState(LabelType label, Vars... vars);
316 :
317 : Operator const* ToNumberOperator();
318 :
319 : JSGraph* jsgraph() const { return jsgraph_; }
320 9371085 : Graph* graph() const { return jsgraph_->graph(); }
321 : Zone* temp_zone() const { return temp_zone_; }
322 4486990 : CommonOperatorBuilder* common() const { return jsgraph()->common(); }
323 4044584 : MachineOperatorBuilder* machine() const { return jsgraph()->machine(); }
324 716711 : SimplifiedOperatorBuilder* simplified() const {
325 716711 : return jsgraph()->simplified();
326 : }
327 :
328 : SetOncePointer<Operator const> to_number_operator_;
329 : Zone* temp_zone_;
330 : JSGraph* jsgraph_;
331 : Node* current_effect_;
332 : Node* current_control_;
333 : };
334 :
335 : template <size_t MergeCount, size_t VarCount>
336 : Node* GraphAssemblerStaticLabel<MergeCount, VarCount>::PhiAt(size_t index) {
337 : DCHECK(IsBound());
338 538181 : return GetBindingsPtrFor(index)[0];
339 : }
340 :
341 : template <class LabelType, typename... Vars>
342 1955128 : void GraphAssembler::MergeState(LabelType label, Vars... vars) {
343 : DCHECK(!label->IsBound());
344 : size_t merged_count = label->MergedCount();
345 : DCHECK_LT(merged_count, label->MaxMergeCount());
346 : DCHECK_EQ(label->PhiCount(), sizeof...(vars));
347 1959126 : label->GetEffectsPtr()[merged_count] = current_effect_;
348 1959126 : label->GetControlsPtr()[merged_count] = current_control_;
349 : // We need to start with nullptr to avoid 0-length arrays.
350 1177173 : Node* var_array[] = {nullptr, vars...};
351 3531518 : for (size_t i = 0; i < sizeof...(vars); i++) {
352 1177172 : label->SetBinding(i, merged_count, var_array[i + 1]);
353 : }
354 : label->IncrementMergedCount();
355 1300381 : }
356 :
357 : template <class LabelType>
358 2046843 : void GraphAssembler::Bind(LabelType* label) {
359 : DCHECK(current_control_ == nullptr);
360 : DCHECK(current_effect_ == nullptr);
361 : DCHECK(label->MaxMergeCount() > 0);
362 : DCHECK_EQ(label->MaxMergeCount(), label->MergedCount());
363 :
364 93867 : int merge_count = static_cast<int>(label->MaxMergeCount());
365 93867 : if (merge_count == 1) {
366 595877 : current_control_ = label->GetControlsPtr()[0];
367 595877 : current_effect_ = label->GetEffectsPtr()[0];
368 : label->SetBound();
369 581549 : return;
370 : }
371 :
372 1549168 : current_control_ = graph()->NewNode(common()->Merge(merge_count), merge_count,
373 : label->GetControlsPtr());
374 :
375 516391 : Node** effects = label->GetEffectsPtr();
376 516390 : current_effect_ = effects[0];
377 727662 : for (size_t i = 1; i < label->MaxMergeCount(); i++) {
378 597199 : if (current_effect_ != effects[i]) {
379 441229 : effects[label->MaxMergeCount()] = current_control_;
380 441229 : current_effect_ = graph()->NewNode(common()->EffectPhi(merge_count),
381 885095 : merge_count + 1, effects);
382 441229 : break;
383 : }
384 : }
385 :
386 452375 : for (size_t var = 0; var < label->PhiCount(); var++) {
387 423670 : Node** bindings = label->GetBindingsPtrFor(var);
388 423670 : bindings[label->MaxMergeCount()] = current_control_;
389 847338 : bindings[0] = graph()->NewNode(
390 : common()->Phi(label->GetRepresentationFor(var), merge_count),
391 : merge_count + 1, bindings);
392 : }
393 :
394 : label->SetBound();
395 : }
396 :
397 : template <class LabelType, typename... Vars>
398 : void GraphAssembler::Goto(LabelType* label, Vars... vars) {
399 : DCHECK_NOT_NULL(current_control_);
400 : DCHECK_NOT_NULL(current_effect_);
401 1019493 : MergeState(label, vars...);
402 1112268 : current_control_ = nullptr;
403 1112268 : current_effect_ = nullptr;
404 : }
405 :
406 : template <class LabelType, typename... Vars>
407 2330945 : void GraphAssembler::GotoIf(Node* condition, LabelType* label, Vars... vars) {
408 : BranchHint hint =
409 582736 : label->IsDeferred() ? BranchHint::kFalse : BranchHint::kNone;
410 : Node* branch =
411 1165472 : graph()->NewNode(common()->Branch(hint), condition, current_control_);
412 :
413 1165475 : current_control_ = graph()->NewNode(common()->IfTrue(), branch);
414 198648 : MergeState(label, vars...);
415 :
416 1165474 : current_control_ = graph()->NewNode(common()->IfFalse(), branch);
417 582737 : }
418 :
419 : template <class LabelType, typename... Vars>
420 264120 : void GraphAssembler::GotoUnless(Node* condition, LabelType* label,
421 792366 : Vars... vars) {
422 264120 : BranchHint hint = label->IsDeferred() ? BranchHint::kTrue : BranchHint::kNone;
423 : Node* branch =
424 528240 : graph()->NewNode(common()->Branch(hint), condition, current_control_);
425 :
426 528246 : current_control_ = graph()->NewNode(common()->IfFalse(), branch);
427 82240 : MergeState(label, vars...);
428 :
429 528246 : current_control_ = graph()->NewNode(common()->IfTrue(), branch);
430 264123 : }
431 :
432 : template <typename... Args>
433 11265 : Node* GraphAssembler::Call(const CallDescriptor* desc, Args... args) {
434 11265 : const Operator* op = common()->Call(desc);
435 11265 : return Call(op, args...);
436 : }
437 :
438 : template <typename... Args>
439 503104 : Node* GraphAssembler::Call(const Operator* op, Args... args) {
440 : DCHECK_EQ(IrOpcode::kCall, op->opcode());
441 125776 : Node* args_array[] = {args..., current_effect_, current_control_};
442 : int size = static_cast<int>(sizeof...(args)) + op->EffectInputCount() +
443 251552 : op->ControlInputCount();
444 125776 : Node* call = graph()->NewNode(op, size, args_array);
445 : DCHECK_EQ(0, op->ControlOutputCount());
446 125777 : current_effect_ = call;
447 125777 : return call;
448 : }
449 :
450 : } // namespace compiler
451 : } // namespace internal
452 : } // namespace v8
453 :
454 : #endif // V8_COMPILER_GRAPH_ASSEMBLER_H_
|