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(BigIntMapConstant) \
96 : V(BooleanMapConstant) \
97 : V(HeapNumberMapConstant) \
98 : V(NoContextConstant) \
99 : V(EmptyStringConstant) \
100 : V(UndefinedConstant) \
101 : V(TheHoleConstant) \
102 : V(FixedArrayMapConstant) \
103 : V(FixedDoubleArrayMapConstant) \
104 : V(ToNumberBuiltinConstant) \
105 : V(AllocateInYoungGenerationStubConstant) \
106 : V(AllocateInOldGenerationStubConstant)
107 :
108 : class GraphAssembler;
109 :
110 : enum class GraphAssemblerLabelType { kDeferred, kNonDeferred, kLoop };
111 :
112 : // Label with statically known count of incoming branches and phis.
113 : template <size_t VarCount>
114 : class GraphAssemblerLabel {
115 : public:
116 : Node* PhiAt(size_t index);
117 :
118 : template <typename... Reps>
119 : explicit GraphAssemblerLabel(GraphAssemblerLabelType type, Reps... reps)
120 : : type_(type) {
121 : STATIC_ASSERT(VarCount == sizeof...(reps));
122 : MachineRepresentation reps_array[] = {MachineRepresentation::kNone,
123 536162 : reps...};
124 1076923 : for (size_t i = 0; i < VarCount; i++) {
125 540761 : representations_[i] = reps_array[i + 1];
126 : }
127 : }
128 :
129 1280986 : ~GraphAssemblerLabel() { DCHECK(IsBound() || merged_count_ == 0); }
130 :
131 : private:
132 : friend class GraphAssembler;
133 :
134 : void SetBound() {
135 : DCHECK(!IsBound());
136 1371475 : is_bound_ = true;
137 : }
138 : bool IsBound() const { return is_bound_; }
139 : bool IsDeferred() const {
140 25224 : return type_ == GraphAssemblerLabelType::kDeferred;
141 : }
142 : bool IsLoop() const { return type_ == GraphAssemblerLabelType::kLoop; }
143 :
144 : bool is_bound_ = false;
145 : GraphAssemblerLabelType const type_;
146 : size_t merged_count_ = 0;
147 : Node* effect_;
148 : Node* control_;
149 : Node* bindings_[VarCount + 1];
150 : MachineRepresentation representations_[VarCount + 1];
151 : };
152 :
153 : class GraphAssembler {
154 : public:
155 : GraphAssembler(JSGraph* jsgraph, Node* effect, Node* control, Zone* zone);
156 :
157 : void Reset(Node* effect, Node* control);
158 :
159 : // Create label.
160 : template <typename... Reps>
161 : static GraphAssemblerLabel<sizeof...(Reps)> MakeLabelFor(
162 : GraphAssemblerLabelType type, Reps... reps) {
163 : return GraphAssemblerLabel<sizeof...(Reps)>(type, reps...);
164 : }
165 :
166 : // Convenience wrapper for creating non-deferred labels.
167 : template <typename... Reps>
168 : static GraphAssemblerLabel<sizeof...(Reps)> MakeLabel(Reps... reps) {
169 : return MakeLabelFor(GraphAssemblerLabelType::kNonDeferred, reps...);
170 : }
171 :
172 : // Convenience wrapper for creating loop labels.
173 : template <typename... Reps>
174 : static GraphAssemblerLabel<sizeof...(Reps)> MakeLoopLabel(Reps... reps) {
175 : return MakeLabelFor(GraphAssemblerLabelType::kLoop, reps...);
176 : }
177 :
178 : // Convenience wrapper for creating deferred labels.
179 : template <typename... Reps>
180 : static GraphAssemblerLabel<sizeof...(Reps)> MakeDeferredLabel(Reps... reps) {
181 : return MakeLabelFor(GraphAssemblerLabelType::kDeferred, reps...);
182 : }
183 :
184 : // Value creation.
185 : Node* IntPtrConstant(intptr_t value);
186 : Node* Uint32Constant(int32_t value);
187 : Node* Int32Constant(int32_t value);
188 : Node* Int64Constant(int64_t value);
189 : Node* UniqueIntPtrConstant(intptr_t value);
190 : Node* SmiConstant(int32_t value);
191 : Node* Float64Constant(double value);
192 : Node* Projection(int index, Node* value);
193 : Node* HeapConstant(Handle<HeapObject> object);
194 : Node* CEntryStubConstant(int result_size);
195 : Node* ExternalConstant(ExternalReference ref);
196 :
197 : Node* LoadFramePointer();
198 :
199 : #define SINGLETON_CONST_DECL(Name) Node* Name();
200 : JSGRAPH_SINGLETON_CONSTANT_LIST(SINGLETON_CONST_DECL)
201 : #undef SINGLETON_CONST_DECL
202 :
203 : #define PURE_UNOP_DECL(Name) Node* Name(Node* input);
204 : PURE_ASSEMBLER_MACH_UNOP_LIST(PURE_UNOP_DECL)
205 : #undef PURE_UNOP_DECL
206 :
207 : #define BINOP_DECL(Name) Node* Name(Node* left, Node* right);
208 : PURE_ASSEMBLER_MACH_BINOP_LIST(BINOP_DECL)
209 : CHECKED_ASSEMBLER_MACH_BINOP_LIST(BINOP_DECL)
210 : #undef BINOP_DECL
211 :
212 : // Debugging
213 : Node* DebugBreak();
214 :
215 : Node* Unreachable();
216 :
217 : Node* Float64RoundDown(Node* value);
218 : Node* Float64RoundTruncate(Node* value);
219 :
220 : Node* ToNumber(Node* value);
221 : Node* BitcastWordToTagged(Node* value);
222 : Node* BitcastTaggedToWord(Node* value);
223 : Node* Allocate(AllocationType allocation, Node* size);
224 : Node* LoadField(FieldAccess const&, Node* object);
225 : Node* LoadElement(ElementAccess const&, Node* object, Node* index);
226 : Node* StoreField(FieldAccess const&, Node* object, Node* value);
227 : Node* StoreElement(ElementAccess const&, Node* object, Node* index,
228 : Node* value);
229 :
230 : Node* Store(StoreRepresentation rep, Node* object, Node* offset, Node* value);
231 : Node* Load(MachineType rep, Node* object, Node* offset);
232 :
233 : Node* StoreUnaligned(MachineRepresentation rep, Node* object, Node* offset,
234 : Node* value);
235 : Node* LoadUnaligned(MachineType rep, Node* object, Node* offset);
236 :
237 : Node* Retain(Node* buffer);
238 : Node* UnsafePointerAdd(Node* base, Node* external);
239 :
240 : Node* Word32PoisonOnSpeculation(Node* value);
241 :
242 : Node* DeoptimizeIf(
243 : DeoptimizeReason reason, VectorSlotPair const& feedback, Node* condition,
244 : Node* frame_state,
245 : IsSafetyCheck is_safety_check = IsSafetyCheck::kSafetyCheck);
246 : Node* DeoptimizeIfNot(
247 : DeoptimizeReason reason, VectorSlotPair const& feedback, Node* condition,
248 : Node* frame_state,
249 : IsSafetyCheck is_safety_check = IsSafetyCheck::kSafetyCheck);
250 : template <typename... Args>
251 : Node* Call(const CallDescriptor* call_descriptor, Args... args);
252 : template <typename... Args>
253 : Node* Call(const Operator* op, Args... args);
254 :
255 : // Basic control operations.
256 : template <size_t VarCount>
257 : void Bind(GraphAssemblerLabel<VarCount>* label);
258 :
259 : template <typename... Vars>
260 : void Goto(GraphAssemblerLabel<sizeof...(Vars)>* label, Vars...);
261 :
262 : void Branch(Node* condition, GraphAssemblerLabel<0u>* if_true,
263 : GraphAssemblerLabel<0u>* if_false,
264 : IsSafetyCheck is_safety_check = IsSafetyCheck::kNoSafetyCheck);
265 :
266 : // Control helpers.
267 : // {GotoIf(c, l)} is equivalent to {Branch(c, l, templ);Bind(templ)}.
268 : template <typename... Vars>
269 : void GotoIf(Node* condition, GraphAssemblerLabel<sizeof...(Vars)>* label,
270 : Vars...);
271 :
272 : // {GotoIfNot(c, l)} is equivalent to {Branch(c, templ, l);Bind(templ)}.
273 : template <typename... Vars>
274 : void GotoIfNot(Node* condition, GraphAssemblerLabel<sizeof...(Vars)>* label,
275 : Vars...);
276 :
277 : // Extractors (should be only used when destructing/resetting the assembler).
278 : Node* ExtractCurrentControl();
279 : Node* ExtractCurrentEffect();
280 :
281 : private:
282 : template <typename... Vars>
283 : void MergeState(GraphAssemblerLabel<sizeof...(Vars)>* label, Vars... vars);
284 :
285 : Operator const* ToNumberOperator();
286 :
287 : JSGraph* jsgraph() const { return jsgraph_; }
288 : Isolate* isolate() const { return jsgraph_->isolate(); }
289 : Graph* graph() const { return jsgraph_->graph(); }
290 : Zone* temp_zone() const { return temp_zone_; }
291 : CommonOperatorBuilder* common() const { return jsgraph()->common(); }
292 : MachineOperatorBuilder* machine() const { return jsgraph()->machine(); }
293 : SimplifiedOperatorBuilder* simplified() const {
294 : return jsgraph()->simplified();
295 : }
296 :
297 : SetOncePointer<Operator const> to_number_operator_;
298 : Zone* temp_zone_;
299 : JSGraph* jsgraph_;
300 : Node* current_effect_;
301 : Node* current_control_;
302 : };
303 :
304 : template <size_t VarCount>
305 : Node* GraphAssemblerLabel<VarCount>::PhiAt(size_t index) {
306 : DCHECK(IsBound());
307 : DCHECK_LT(index, VarCount);
308 739400 : return bindings_[index];
309 : }
310 :
311 : template <typename... Vars>
312 2429672 : void GraphAssembler::MergeState(GraphAssemblerLabel<sizeof...(Vars)>* label,
313 : Vars... vars) {
314 2429672 : int merged_count = static_cast<int>(label->merged_count_);
315 1319351 : Node* var_array[] = {nullptr, vars...};
316 2429672 : if (label->IsLoop()) {
317 5604 : if (merged_count == 0) {
318 : DCHECK(!label->IsBound());
319 5604 : label->control_ = graph()->NewNode(common()->Loop(2), current_control_,
320 : current_control_);
321 5604 : label->effect_ = graph()->NewNode(common()->EffectPhi(2), current_effect_,
322 : current_effect_, label->control_);
323 : Node* terminate = graph()->NewNode(common()->Terminate(), label->effect_,
324 2802 : label->control_);
325 2802 : NodeProperties::MergeControlToEnd(graph(), common(), terminate);
326 13006 : for (size_t i = 0; i < sizeof...(vars); i++) {
327 10204 : label->bindings_[i] = graph()->NewNode(
328 : common()->Phi(label->representations_[i], 2), var_array[i + 1],
329 : var_array[i + 1], label->control_);
330 : }
331 : } else {
332 : DCHECK(label->IsBound());
333 : DCHECK_EQ(1, merged_count);
334 2802 : label->control_->ReplaceInput(1, current_control_);
335 2802 : label->effect_->ReplaceInput(1, current_effect_);
336 13006 : for (size_t i = 0; i < sizeof...(vars); i++) {
337 5102 : label->bindings_[i]->ReplaceInput(1, var_array[i + 1]);
338 : }
339 : }
340 : } else {
341 : DCHECK(!label->IsBound());
342 2424068 : if (merged_count == 0) {
343 : // Just set the control, effect and variables directly.
344 : DCHECK(!label->IsBound());
345 1431301 : label->control_ = current_control_;
346 1431301 : label->effect_ = current_effect_;
347 1604674 : for (size_t i = 0; i < sizeof...(vars); i++) {
348 535658 : label->bindings_[i] = var_array[i + 1];
349 : }
350 992767 : } else if (merged_count == 1) {
351 : // Create merge, effect phi and a phi for each variable.
352 1400468 : label->control_ = graph()->NewNode(common()->Merge(2), label->control_,
353 : current_control_);
354 1400469 : label->effect_ = graph()->NewNode(common()->EffectPhi(2), label->effect_,
355 : current_effect_, label->control_);
356 1604682 : for (size_t i = 0; i < sizeof...(vars); i++) {
357 1071321 : label->bindings_[i] = graph()->NewNode(
358 : common()->Phi(label->representations_[i], 2), label->bindings_[i],
359 : var_array[i + 1], label->control_);
360 : }
361 : } else {
362 : // Append to the merge, effect phi and phis.
363 : DCHECK_EQ(IrOpcode::kMerge, label->control_->opcode());
364 292534 : label->control_->AppendInput(graph()->zone(), current_control_);
365 292534 : NodeProperties::ChangeOp(label->control_,
366 : common()->Merge(merged_count + 1));
367 :
368 : DCHECK_EQ(IrOpcode::kEffectPhi, label->effect_->opcode());
369 292534 : label->effect_->ReplaceInput(merged_count, current_effect_);
370 292534 : label->effect_->AppendInput(graph()->zone(), label->control_);
371 292534 : NodeProperties::ChangeOp(label->effect_,
372 : common()->EffectPhi(merged_count + 1));
373 :
374 745687 : for (size_t i = 0; i < sizeof...(vars); i++) {
375 : DCHECK_EQ(IrOpcode::kPhi, label->bindings_[i]->opcode());
376 249329 : label->bindings_[i]->ReplaceInput(merged_count, var_array[i + 1]);
377 249329 : label->bindings_[i]->AppendInput(graph()->zone(), label->control_);
378 249329 : NodeProperties::ChangeOp(
379 : label->bindings_[i],
380 : common()->Phi(label->representations_[i], merged_count + 1));
381 : }
382 : }
383 : }
384 2429674 : label->merged_count_++;
385 2429674 : }
386 :
387 : template <size_t VarCount>
388 : void GraphAssembler::Bind(GraphAssemblerLabel<VarCount>* label) {
389 : DCHECK_NULL(current_control_);
390 : DCHECK_NULL(current_effect_);
391 : DCHECK_LT(0, label->merged_count_);
392 :
393 1434106 : current_control_ = label->control_;
394 1434106 : current_effect_ = label->effect_;
395 :
396 : label->SetBound();
397 : }
398 :
399 : template <typename... Vars>
400 : void GraphAssembler::Goto(GraphAssemblerLabel<sizeof...(Vars)>* label,
401 : Vars... vars) {
402 : DCHECK_NOT_NULL(current_control_);
403 : DCHECK_NOT_NULL(current_effect_);
404 1408886 : MergeState(label, vars...);
405 1408882 : current_control_ = nullptr;
406 1408882 : current_effect_ = nullptr;
407 : }
408 :
409 : template <typename... Vars>
410 668004 : void GraphAssembler::GotoIf(Node* condition,
411 : GraphAssemblerLabel<sizeof...(Vars)>* label,
412 : Vars... vars) {
413 : BranchHint hint =
414 668004 : label->IsDeferred() ? BranchHint::kFalse : BranchHint::kNone;
415 : Node* branch =
416 668004 : graph()->NewNode(common()->Branch(hint), condition, current_control_);
417 :
418 1336010 : current_control_ = graph()->NewNode(common()->IfTrue(), branch);
419 668005 : MergeState(label, vars...);
420 :
421 1336008 : current_control_ = graph()->NewNode(common()->IfFalse(), branch);
422 668005 : }
423 :
424 : template <typename... Vars>
425 302339 : void GraphAssembler::GotoIfNot(Node* condition,
426 : GraphAssemblerLabel<sizeof...(Vars)>* label,
427 : Vars... vars) {
428 302339 : BranchHint hint = label->IsDeferred() ? BranchHint::kTrue : BranchHint::kNone;
429 : Node* branch =
430 302339 : graph()->NewNode(common()->Branch(hint), condition, current_control_);
431 :
432 604681 : current_control_ = graph()->NewNode(common()->IfFalse(), branch);
433 302340 : MergeState(label, vars...);
434 :
435 604682 : current_control_ = graph()->NewNode(common()->IfTrue(), branch);
436 302341 : }
437 :
438 : template <typename... Args>
439 85432 : Node* GraphAssembler::Call(const CallDescriptor* call_descriptor,
440 : Args... args) {
441 85432 : const Operator* op = common()->Call(call_descriptor);
442 85432 : return Call(op, args...);
443 : }
444 :
445 : template <typename... Args>
446 302809 : Node* GraphAssembler::Call(const Operator* op, Args... args) {
447 : DCHECK_EQ(IrOpcode::kCall, op->opcode());
448 302809 : Node* args_array[] = {args..., current_effect_, current_control_};
449 : int size = static_cast<int>(sizeof...(args)) + op->EffectInputCount() +
450 605618 : op->ControlInputCount();
451 302809 : Node* call = graph()->NewNode(op, size, args_array);
452 : DCHECK_EQ(0, op->ControlOutputCount());
453 302809 : current_effect_ = call;
454 302809 : return call;
455 : }
456 :
457 : } // namespace compiler
458 : } // namespace internal
459 : } // namespace v8
460 :
461 : #endif // V8_COMPILER_GRAPH_ASSEMBLER_H_
|