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