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