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(Word32Xor) \
41 : V(Word32Shr) \
42 : V(Word32Shl) \
43 : V(IntAdd) \
44 : V(IntSub) \
45 : V(IntMul) \
46 : V(IntLessThan) \
47 : V(UintLessThan) \
48 : V(Int32Add) \
49 : V(Int32Sub) \
50 : V(Int32Mul) \
51 : V(Int32LessThanOrEqual) \
52 : V(Uint32LessThanOrEqual) \
53 : V(Uint32LessThan) \
54 : V(Int32LessThan) \
55 : V(Float64Add) \
56 : V(Float64Sub) \
57 : V(Float64Div) \
58 : V(Float64Mod) \
59 : V(Float64Equal) \
60 : V(Float64LessThan) \
61 : V(Float64LessThanOrEqual) \
62 : V(Word32Equal) \
63 : V(WordEqual)
64 :
65 : #define CHECKED_ASSEMBLER_MACH_BINOP_LIST(V) \
66 : V(Int32AddWithOverflow) \
67 : V(Int32SubWithOverflow) \
68 : V(Int32MulWithOverflow) \
69 : V(Int32Mod) \
70 : V(Int32Div) \
71 : V(Uint32Mod) \
72 : V(Uint32Div)
73 :
74 : #define JSGRAPH_SINGLETON_CONSTANT_LIST(V) \
75 : V(TrueConstant) \
76 : V(FalseConstant) \
77 : V(HeapNumberMapConstant) \
78 : V(NoContextConstant) \
79 : V(EmptyStringConstant) \
80 : V(UndefinedConstant) \
81 : V(TheHoleConstant) \
82 : V(FixedArrayMapConstant) \
83 : V(FixedDoubleArrayMapConstant) \
84 : V(ToNumberBuiltinConstant) \
85 : V(AllocateInNewSpaceStubConstant) \
86 : V(AllocateInOldSpaceStubConstant)
87 :
88 : class GraphAssembler;
89 :
90 : enum class GraphAssemblerLabelType { kDeferred, kNonDeferred, kLoop };
91 :
92 : // Label with statically known count of incoming branches and phis.
93 : template <size_t VarCount>
94 : class GraphAssemblerLabel {
95 : public:
96 : Node* PhiAt(size_t index);
97 :
98 : template <typename... Reps>
99 : explicit GraphAssemblerLabel(GraphAssemblerLabelType type, Reps... reps)
100 : : type_(type) {
101 : STATIC_ASSERT(VarCount == sizeof...(reps));
102 : MachineRepresentation reps_array[] = {MachineRepresentation::kNone,
103 391467 : reps...};
104 782934 : for (size_t i = 0; i < VarCount; i++) {
105 391467 : representations_[i] = reps_array[i + 1];
106 : }
107 : }
108 :
109 : ~GraphAssemblerLabel() { DCHECK(IsBound() || merged_count_ == 0); }
110 :
111 : private:
112 : friend class GraphAssembler;
113 :
114 : void SetBound() {
115 : DCHECK(!IsBound());
116 930304 : is_bound_ = true;
117 : }
118 : bool IsBound() const { return is_bound_; }
119 : bool IsDeferred() const {
120 408 : return type_ == GraphAssemblerLabelType::kDeferred;
121 : }
122 : bool IsLoop() const { return type_ == GraphAssemblerLabelType::kLoop; }
123 :
124 : bool is_bound_ = false;
125 : GraphAssemblerLabelType const type_;
126 : size_t merged_count_ = 0;
127 : Node* effect_;
128 : Node* control_;
129 : Node* bindings_[VarCount + 1];
130 : MachineRepresentation representations_[VarCount + 1];
131 : };
132 :
133 : class GraphAssembler {
134 : public:
135 : GraphAssembler(JSGraph* jsgraph, Node* effect, Node* control, Zone* zone);
136 :
137 : void Reset(Node* effect, Node* control);
138 :
139 : // Create label.
140 : template <typename... Reps>
141 : static GraphAssemblerLabel<sizeof...(Reps)> MakeLabelFor(
142 : GraphAssemblerLabelType type, Reps... reps) {
143 : return GraphAssemblerLabel<sizeof...(Reps)>(type, reps...);
144 : }
145 :
146 : // Convenience wrapper for creating non-deferred labels.
147 : template <typename... Reps>
148 : static GraphAssemblerLabel<sizeof...(Reps)> MakeLabel(Reps... reps) {
149 : return MakeLabelFor(GraphAssemblerLabelType::kNonDeferred, reps...);
150 : }
151 :
152 : // Convenience wrapper for creating loop labels.
153 : template <typename... Reps>
154 : static GraphAssemblerLabel<sizeof...(Reps)> MakeLoopLabel(Reps... reps) {
155 : return MakeLabelFor(GraphAssemblerLabelType::kLoop, reps...);
156 : }
157 :
158 : // Convenience wrapper for creating deferred labels.
159 : template <typename... Reps>
160 : static GraphAssemblerLabel<sizeof...(Reps)> MakeDeferredLabel(Reps... reps) {
161 : return MakeLabelFor(GraphAssemblerLabelType::kDeferred, reps...);
162 : }
163 :
164 : // Value creation.
165 : Node* IntPtrConstant(intptr_t value);
166 : Node* Uint32Constant(int32_t value);
167 : Node* Int32Constant(int32_t value);
168 : Node* UniqueInt32Constant(int32_t value);
169 : Node* SmiConstant(int32_t value);
170 : Node* Float64Constant(double value);
171 : Node* Projection(int index, Node* value);
172 : Node* HeapConstant(Handle<HeapObject> object);
173 : Node* CEntryStubConstant(int result_size);
174 : Node* ExternalConstant(ExternalReference ref);
175 :
176 : Node* LoadFramePointer();
177 :
178 : #define SINGLETON_CONST_DECL(Name) Node* Name();
179 : JSGRAPH_SINGLETON_CONSTANT_LIST(SINGLETON_CONST_DECL)
180 : #undef SINGLETON_CONST_DECL
181 :
182 : #define PURE_UNOP_DECL(Name) Node* Name(Node* input);
183 : PURE_ASSEMBLER_MACH_UNOP_LIST(PURE_UNOP_DECL)
184 : #undef PURE_UNOP_DECL
185 :
186 : #define BINOP_DECL(Name) Node* Name(Node* left, Node* right);
187 : PURE_ASSEMBLER_MACH_BINOP_LIST(BINOP_DECL)
188 : CHECKED_ASSEMBLER_MACH_BINOP_LIST(BINOP_DECL)
189 : #undef BINOP_DECL
190 :
191 : // Debugging
192 : Node* DebugBreak();
193 :
194 : Node* Float64RoundDown(Node* value);
195 :
196 : Node* ToNumber(Node* value);
197 : Node* Allocate(PretenureFlag pretenure, Node* size);
198 : Node* LoadField(FieldAccess const&, Node* object);
199 : Node* LoadElement(ElementAccess const&, Node* object, Node* index);
200 : Node* StoreField(FieldAccess const&, Node* object, Node* value);
201 : Node* StoreElement(ElementAccess const&, Node* object, Node* index,
202 : Node* value);
203 :
204 : Node* Store(StoreRepresentation rep, Node* object, Node* offset, Node* value);
205 : Node* Load(MachineType rep, Node* object, Node* offset);
206 :
207 : Node* Retain(Node* buffer);
208 : Node* UnsafePointerAdd(Node* base, Node* external);
209 :
210 : Node* DeoptimizeIf(DeoptimizeReason reason, Node* condition,
211 : Node* frame_state);
212 : Node* DeoptimizeIfNot(DeoptimizeKind kind, DeoptimizeReason reason,
213 : Node* condition, Node* frame_state);
214 : Node* DeoptimizeIfNot(DeoptimizeReason reason, Node* condition,
215 : Node* frame_state);
216 : template <typename... Args>
217 : Node* Call(const CallDescriptor* desc, Args... args);
218 : template <typename... Args>
219 : Node* Call(const Operator* op, Args... args);
220 :
221 : // Basic control operations.
222 : template <size_t VarCount>
223 : void Bind(GraphAssemblerLabel<VarCount>* label);
224 :
225 : template <typename... Vars>
226 : void Goto(GraphAssemblerLabel<sizeof...(Vars)>* label, Vars...);
227 :
228 : void Branch(Node* condition, GraphAssemblerLabel<0u>* if_true,
229 : GraphAssemblerLabel<0u>* if_false);
230 :
231 : // Control helpers.
232 : // {GotoIf(c, l)} is equivalent to {Branch(c, l, templ);Bind(templ)}.
233 : template <typename... Vars>
234 : void GotoIf(Node* condition, GraphAssemblerLabel<sizeof...(Vars)>* label,
235 : Vars...);
236 :
237 : // {GotoIfNot(c, l)} is equivalent to {Branch(c, templ, l);Bind(templ)}.
238 : template <typename... Vars>
239 : void GotoIfNot(Node* condition, GraphAssemblerLabel<sizeof...(Vars)>* label,
240 : Vars...);
241 :
242 : // Extractors (should be only used when destructing/resetting the assembler).
243 : Node* ExtractCurrentControl();
244 : Node* ExtractCurrentEffect();
245 :
246 : private:
247 : template <typename... Vars>
248 : void MergeState(GraphAssemblerLabel<sizeof...(Vars)>* label, Vars... vars);
249 :
250 : Operator const* ToNumberOperator();
251 :
252 : JSGraph* jsgraph() const { return jsgraph_; }
253 9294740 : Graph* graph() const { return jsgraph_->graph(); }
254 : Zone* temp_zone() const { return temp_zone_; }
255 4807301 : CommonOperatorBuilder* common() const { return jsgraph()->common(); }
256 3764700 : MachineOperatorBuilder* machine() const { return jsgraph()->machine(); }
257 595231 : SimplifiedOperatorBuilder* simplified() const {
258 595231 : return jsgraph()->simplified();
259 : }
260 :
261 : SetOncePointer<Operator const> to_number_operator_;
262 : Zone* temp_zone_;
263 : JSGraph* jsgraph_;
264 : Node* current_effect_;
265 : Node* current_control_;
266 : };
267 :
268 : template <size_t VarCount>
269 : Node* GraphAssemblerLabel<VarCount>::PhiAt(size_t index) {
270 : DCHECK(IsBound());
271 : DCHECK_LT(index, VarCount);
272 509187 : return bindings_[index];
273 : }
274 :
275 : template <typename... Vars>
276 3383042 : void GraphAssembler::MergeState(GraphAssemblerLabel<sizeof...(Vars)>* label,
277 2028855 : Vars... vars) {
278 1691521 : int merged_count = static_cast<int>(label->merged_count_);
279 1017035 : Node* var_array[] = {nullptr, vars...};
280 1691521 : if (label->IsLoop()) {
281 708 : if (merged_count == 0) {
282 : DCHECK(!label->IsBound());
283 354 : label->control_ = graph()->NewNode(common()->Loop(2), current_control_,
284 708 : current_control_);
285 1062 : label->effect_ = graph()->NewNode(common()->EffectPhi(2), current_effect_,
286 : current_effect_, label->control_);
287 1062 : for (size_t i = 0; i < sizeof...(vars); i++) {
288 1062 : label->bindings_[i] = graph()->NewNode(
289 : common()->Phi(label->representations_[i], 2), var_array[i + 1],
290 : var_array[i + 1], label->control_);
291 : }
292 : } else {
293 : DCHECK(label->IsBound());
294 : DCHECK_EQ(1, merged_count);
295 354 : label->control_->ReplaceInput(1, current_control_);
296 354 : label->effect_->ReplaceInput(1, current_effect_);
297 1062 : for (size_t i = 0; i < sizeof...(vars); i++) {
298 354 : label->bindings_[i]->ReplaceInput(1, var_array[i + 1]);
299 : }
300 : }
301 : } else {
302 : DCHECK(!label->IsBound());
303 1690813 : if (merged_count == 0) {
304 : // Just set the control, effect and variables directly.
305 : DCHECK(!label->IsBound());
306 989526 : label->control_ = current_control_;
307 989526 : label->effect_ = current_effect_;
308 1173342 : for (size_t i = 0; i < sizeof...(vars); i++) {
309 391114 : label->bindings_[i] = var_array[i + 1];
310 : }
311 701287 : } else if (merged_count == 1) {
312 : // Create merge, effect phi and a phi for each variable.
313 1398006 : label->control_ = graph()->NewNode(common()->Merge(2), label->control_,
314 : current_control_);
315 1398013 : label->effect_ = graph()->NewNode(common()->EffectPhi(2), label->effect_,
316 : current_effect_, label->control_);
317 1173352 : for (size_t i = 0; i < sizeof...(vars); i++) {
318 1173354 : label->bindings_[i] = graph()->NewNode(
319 : common()->Phi(label->representations_[i], 2), label->bindings_[i],
320 : var_array[i + 1], label->control_);
321 : }
322 : } else {
323 : // Append to the merge, effect phi and phis.
324 : DCHECK_EQ(IrOpcode::kMerge, label->control_->opcode());
325 470572 : label->control_->AppendInput(graph()->zone(), current_control_);
326 235286 : NodeProperties::ChangeOp(label->control_,
327 470572 : common()->Merge(merged_count + 1));
328 :
329 : DCHECK_EQ(IrOpcode::kEffectPhi, label->effect_->opcode());
330 235286 : label->effect_->ReplaceInput(merged_count, current_effect_);
331 470572 : label->effect_->AppendInput(graph()->zone(), label->control_);
332 235286 : NodeProperties::ChangeOp(label->effect_,
333 235286 : common()->EffectPhi(merged_count + 1));
334 :
335 703484 : for (size_t i = 0; i < sizeof...(vars); i++) {
336 : DCHECK_EQ(IrOpcode::kPhi, label->bindings_[i]->opcode());
337 234099 : label->bindings_[i]->ReplaceInput(merged_count, var_array[i + 1]);
338 468198 : label->bindings_[i]->AppendInput(graph()->zone(), label->control_);
339 234099 : NodeProperties::ChangeOp(
340 : label->bindings_[i],
341 468198 : common()->Phi(label->representations_[i], merged_count + 1));
342 : }
343 : }
344 : }
345 1691525 : label->merged_count_++;
346 1691525 : }
347 :
348 : template <size_t VarCount>
349 : void GraphAssembler::Bind(GraphAssemblerLabel<VarCount>* label) {
350 : DCHECK_NULL(current_control_);
351 : DCHECK_NULL(current_effect_);
352 : DCHECK_LT(0, label->merged_count_);
353 :
354 989883 : current_control_ = label->control_;
355 989883 : current_effect_ = label->effect_;
356 :
357 : label->SetBound();
358 : }
359 :
360 : template <typename... Vars>
361 : void GraphAssembler::Goto(GraphAssemblerLabel<sizeof...(Vars)>* label,
362 : Vars... vars) {
363 : DCHECK_NOT_NULL(current_control_);
364 : DCHECK_NOT_NULL(current_effect_);
365 989683 : MergeState(label, vars...);
366 989679 : current_control_ = nullptr;
367 989679 : current_effect_ = nullptr;
368 : }
369 :
370 : template <typename... Vars>
371 470840 : void GraphAssembler::GotoIf(Node* condition,
372 470840 : GraphAssemblerLabel<sizeof...(Vars)>* label,
373 1412521 : Vars... vars) {
374 : BranchHint hint =
375 470840 : label->IsDeferred() ? BranchHint::kFalse : BranchHint::kNone;
376 : Node* branch =
377 941680 : graph()->NewNode(common()->Branch(hint), condition, current_control_);
378 :
379 941682 : current_control_ = graph()->NewNode(common()->IfTrue(), branch);
380 470841 : MergeState(label, vars...);
381 :
382 941681 : current_control_ = graph()->NewNode(common()->IfFalse(), branch);
383 470841 : }
384 :
385 : template <typename... Vars>
386 230597 : void GraphAssembler::GotoIfNot(Node* condition,
387 230597 : GraphAssemblerLabel<sizeof...(Vars)>* label,
388 691798 : Vars... vars) {
389 230597 : BranchHint hint = label->IsDeferred() ? BranchHint::kTrue : BranchHint::kNone;
390 : Node* branch =
391 461194 : graph()->NewNode(common()->Branch(hint), condition, current_control_);
392 :
393 461202 : current_control_ = graph()->NewNode(common()->IfFalse(), branch);
394 230601 : MergeState(label, vars...);
395 :
396 461198 : current_control_ = graph()->NewNode(common()->IfTrue(), branch);
397 230601 : }
398 :
399 : template <typename... Args>
400 50743 : Node* GraphAssembler::Call(const CallDescriptor* desc, Args... args) {
401 50743 : const Operator* op = common()->Call(desc);
402 50743 : return Call(op, args...);
403 : }
404 :
405 : template <typename... Args>
406 675660 : Node* GraphAssembler::Call(const Operator* op, Args... args) {
407 : DCHECK_EQ(IrOpcode::kCall, op->opcode());
408 168915 : Node* args_array[] = {args..., current_effect_, current_control_};
409 : int size = static_cast<int>(sizeof...(args)) + op->EffectInputCount() +
410 337830 : op->ControlInputCount();
411 168915 : Node* call = graph()->NewNode(op, size, args_array);
412 : DCHECK_EQ(0, op->ControlOutputCount());
413 168915 : current_effect_ = call;
414 168915 : return call;
415 : }
416 :
417 : } // namespace compiler
418 : } // namespace internal
419 : } // namespace v8
420 :
421 : #endif // V8_COMPILER_GRAPH_ASSEMBLER_H_
|