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