1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
10 // This file declares the data structures used to build a control-flow graph
13 #include "jit/CompileInfo.h"
14 #include "jit/FixedList.h"
15 #include "jit/InlineScriptTree.h"
16 #include "jit/JitAllocPolicy.h"
26 class MDefinitionIterator
;
28 using MInstructionIterator
= InlineListIterator
<MInstruction
>;
29 using MInstructionReverseIterator
= InlineListReverseIterator
<MInstruction
>;
30 using MPhiIterator
= InlineListIterator
<MPhi
>;
33 typedef InlineForwardListIterator
<MResumePoint
> MResumePointIterator
;
38 class MBasicBlock
: public TempObject
, public InlineListNode
<MBasicBlock
> {
51 MBasicBlock(MIRGraph
& graph
, const CompileInfo
& info
, BytecodeSite
* site
,
53 [[nodiscard
]] bool init();
54 void copySlots(MBasicBlock
* from
);
55 [[nodiscard
]] bool inherit(TempAllocator
& alloc
, size_t stackDepth
,
56 MBasicBlock
* maybePred
, uint32_t popped
);
58 // This block cannot be reached by any means.
59 bool unreachable_
= false;
61 // This block will unconditionally bail out.
62 bool alwaysBails_
= false;
64 // Will be used for branch hinting in wasm.
65 wasm::BranchHint branchHint_
= wasm::BranchHint::Invalid
;
67 // Pushes a copy of a local variable or argument.
68 void pushVariable(uint32_t slot
) { push(slots_
[slot
]); }
70 // Sets a variable slot to the top of the stack, correctly creating copies
72 void setVariable(uint32_t slot
) {
73 MOZ_ASSERT(stackPosition_
> info_
.firstStackSlot());
74 setSlot(slot
, slots_
[stackPosition_
- 1]);
80 // Assert that the instruction is unused.
81 RefType_AssertNoUses
= 1 << 0,
83 // Discard the operands of the resume point / instructions if the
84 // following flag are given too.
85 RefType_DiscardOperands
= 1 << 1,
86 RefType_DiscardResumePoint
= 1 << 2,
87 RefType_DiscardInstruction
= 1 << 3,
89 // Discard operands of the instruction and its resume point.
90 RefType_DefaultNoAssert
= RefType_DiscardOperands
|
91 RefType_DiscardResumePoint
|
92 RefType_DiscardInstruction
,
94 // Discard everything and assert that the instruction is not used.
95 RefType_Default
= RefType_AssertNoUses
| RefType_DefaultNoAssert
,
97 // Discard resume point operands only, without discarding the operands
98 // of the current instruction. Asserts that the instruction is unused.
99 RefType_IgnoreOperands
= RefType_AssertNoUses
| RefType_DiscardOperands
|
100 RefType_DiscardResumePoint
103 void discardResumePoint(MResumePoint
* rp
,
104 ReferencesType refType
= RefType_Default
);
105 void removeResumePoint(MResumePoint
* rp
);
107 // Remove all references to an instruction such that it can be removed from
108 // the list of instruction, without keeping any dangling pointer to it. This
109 // includes the operands of the instruction, and the resume point if
111 void prepareForDiscard(MInstruction
* ins
,
112 ReferencesType refType
= RefType_Default
);
115 ///////////////////////////////////////////////////////
116 ////////// BEGIN GRAPH BUILDING INSTRUCTIONS //////////
117 ///////////////////////////////////////////////////////
119 // Creates a new basic block for a MIR generator. If |pred| is not nullptr,
120 // its slots and stack depth are initialized from |pred|.
121 static MBasicBlock
* New(MIRGraph
& graph
, size_t stackDepth
,
122 const CompileInfo
& info
, MBasicBlock
* maybePred
,
123 BytecodeSite
* site
, Kind kind
);
124 static MBasicBlock
* New(MIRGraph
& graph
, const CompileInfo
& info
,
125 MBasicBlock
* pred
, Kind kind
);
126 static MBasicBlock
* NewPopN(MIRGraph
& graph
, const CompileInfo
& info
,
127 MBasicBlock
* pred
, BytecodeSite
* site
, Kind kind
,
129 static MBasicBlock
* NewPendingLoopHeader(MIRGraph
& graph
,
130 const CompileInfo
& info
,
133 static MBasicBlock
* NewSplitEdge(MIRGraph
& graph
, MBasicBlock
* pred
,
134 size_t predEdgeIdx
, MBasicBlock
* succ
);
135 static MBasicBlock
* NewFakeLoopPredecessor(MIRGraph
& graph
,
136 MBasicBlock
* header
);
138 // Create a new basic block for internal control flow not present in the
140 static MBasicBlock
* NewInternal(MIRGraph
& graph
, MBasicBlock
* orig
,
141 MResumePoint
* activeResumePoint
);
143 bool dominates(const MBasicBlock
* other
) const {
144 return other
->domIndex() - domIndex() < numDominated();
147 void setId(uint32_t id
) { id_
= id
; }
149 // Mark this block (and only this block) as unreachable.
150 void setUnreachable() {
151 MOZ_ASSERT(!unreachable_
);
152 setUnreachableUnchecked();
154 void setUnreachableUnchecked() { unreachable_
= true; }
155 bool unreachable() const { return unreachable_
; }
157 void setAlwaysBails() { alwaysBails_
= true; }
158 bool alwaysBails() const { return alwaysBails_
; }
160 // Move the definition to the top of the stack.
161 void pick(int32_t depth
);
163 // Move the top of the stack definition under the depth-th stack value.
164 void unpick(int32_t depth
);
166 // Exchange 2 stack slots at the defined depth
167 void swapAt(int32_t depth
);
169 // Note: most of the methods below are hot. Do not un-inline them without
170 // measuring the impact.
172 // Gets the instruction associated with various slot types.
173 MDefinition
* peek(int32_t depth
) {
174 MOZ_ASSERT(depth
< 0);
175 MOZ_ASSERT(stackPosition_
+ depth
>= info_
.firstStackSlot());
176 return peekUnchecked(depth
);
179 MDefinition
* peekUnchecked(int32_t depth
) {
180 MOZ_ASSERT(depth
< 0);
181 return getSlot(stackPosition_
+ depth
);
184 MDefinition
* environmentChain();
185 MDefinition
* argumentsObject();
187 // Increase the number of slots available
188 [[nodiscard
]] bool increaseSlots(size_t num
);
189 [[nodiscard
]] bool ensureHasSlots(size_t num
);
191 // Initializes a slot value; must not be called for normal stack
192 // operations, as it will not create new SSA names for copies.
193 void initSlot(uint32_t slot
, MDefinition
* ins
) {
195 if (entryResumePoint()) {
196 entryResumePoint()->initOperand(slot
, ins
);
200 // Sets the instruction associated with various slot types. The
201 // instruction must lie at the top of the stack.
202 void setLocal(uint32_t local
) { setVariable(info_
.localSlot(local
)); }
203 void setArg(uint32_t arg
) { setVariable(info_
.argSlot(arg
)); }
204 void setSlot(uint32_t slot
, MDefinition
* ins
) { slots_
[slot
] = ins
; }
206 // Tracks an instruction as being pushed onto the operand stack.
207 void push(MDefinition
* ins
) {
208 MOZ_ASSERT(stackPosition_
< nslots());
209 slots_
[stackPosition_
++] = ins
;
211 void pushArg(uint32_t arg
) { pushVariable(info_
.argSlot(arg
)); }
212 void pushArgUnchecked(uint32_t arg
) {
213 pushVariable(info_
.argSlotUnchecked(arg
));
215 void pushLocal(uint32_t local
) { pushVariable(info_
.localSlot(local
)); }
216 void pushSlot(uint32_t slot
) { pushVariable(slot
); }
217 void setEnvironmentChain(MDefinition
* ins
);
218 void setArgumentsObject(MDefinition
* ins
);
220 // Returns the top of the stack, then decrements the virtual stack pointer.
222 MOZ_ASSERT(stackPosition_
> info_
.firstStackSlot());
223 return slots_
[--stackPosition_
];
225 void popn(uint32_t n
) {
226 MOZ_ASSERT(stackPosition_
- n
>= info_
.firstStackSlot());
227 MOZ_ASSERT(stackPosition_
>= stackPosition_
- n
);
231 // Adds an instruction to this block's instruction list.
232 inline void add(MInstruction
* ins
);
234 // Marks the last instruction of the block; no further instructions
236 void end(MControlInstruction
* ins
) {
237 MOZ_ASSERT(!hasLastIns()); // Existing control instructions should be
243 // Adds a phi instruction, but does not set successorWithPhis.
244 void addPhi(MPhi
* phi
);
246 // Adds a resume point to this block.
247 void addResumePoint(MResumePoint
* resume
) {
249 resumePoints_
.pushFront(resume
);
253 // Discard pre-allocated resume point.
254 void discardPreAllocatedResumePoint(MResumePoint
* resume
) {
255 MOZ_ASSERT(!resume
->instruction());
256 discardResumePoint(resume
);
259 // Adds a predecessor. Every predecessor must have the same exit stack
260 // depth as the entry state to this block. Adding a predecessor
261 // automatically creates phi nodes and rewrites uses as needed.
262 [[nodiscard
]] bool addPredecessor(TempAllocator
& alloc
, MBasicBlock
* pred
);
263 [[nodiscard
]] bool addPredecessorPopN(TempAllocator
& alloc
, MBasicBlock
* pred
,
266 // Add a predecessor which won't introduce any new phis to this block.
267 // This may be called after the contents of this block have been built.
268 [[nodiscard
]] bool addPredecessorSameInputsAs(MBasicBlock
* pred
,
269 MBasicBlock
* existingPred
);
271 // Stranger utilities used for inlining.
272 [[nodiscard
]] bool addPredecessorWithoutPhis(MBasicBlock
* pred
);
273 void inheritSlots(MBasicBlock
* parent
);
274 [[nodiscard
]] bool initEntrySlots(TempAllocator
& alloc
);
276 // Replaces an edge for a given block with a new block. This is
277 // used for critical edge splitting.
279 // Note: If successorWithPhis is set, you must not be replacing it.
280 void replacePredecessor(MBasicBlock
* old
, MBasicBlock
* split
);
281 void replaceSuccessor(size_t pos
, MBasicBlock
* split
);
283 // Removes `pred` from the predecessor list. If this block defines phis,
284 // removes the entry for `pred` and updates the indices of later entries.
285 // This may introduce redundant phis if the new block has fewer
286 // than two predecessors.
287 void removePredecessor(MBasicBlock
* pred
);
289 // A version of removePredecessor which expects that phi operands to
290 // |pred| have already been removed.
291 void removePredecessorWithoutPhiOperands(MBasicBlock
* pred
, size_t predIndex
);
293 // Resets all the dominator info so that it can be recomputed.
294 void clearDominatorInfo();
296 // Sets a back edge. This places phi nodes and rewrites instructions within
297 // the current loop as necessary.
298 [[nodiscard
]] bool setBackedge(MBasicBlock
* block
);
299 [[nodiscard
]] bool setBackedgeWasm(MBasicBlock
* block
, size_t paramCount
);
301 // Resets a LOOP_HEADER block to a NORMAL block. This is needed when
302 // optimizations remove the backedge.
303 void clearLoopHeader();
305 // Sets a block to a LOOP_HEADER block, with newBackedge as its backedge.
306 // This is needed when optimizations remove the normal entry to a loop
307 // with multiple entries.
308 void setLoopHeader(MBasicBlock
* newBackedge
);
310 // Propagates backedge slots into phis operands of the loop header.
311 [[nodiscard
]] bool inheritPhisFromBackedge(MBasicBlock
* backedge
);
313 void insertBefore(MInstruction
* at
, MInstruction
* ins
);
314 void insertAfter(MInstruction
* at
, MInstruction
* ins
);
316 void insertAtEnd(MInstruction
* ins
);
318 // Move an instruction. Movement may cross block boundaries.
319 void moveBefore(MInstruction
* at
, MInstruction
* ins
);
321 enum IgnoreTop
{ IgnoreNone
= 0, IgnoreRecover
= 1 << 0 };
323 // Locate the top of the |block|, where it is safe to insert a new
325 MInstruction
* safeInsertTop(MDefinition
* ins
= nullptr,
326 IgnoreTop ignore
= IgnoreNone
);
328 // Removes an instruction with the intention to discard it.
329 void discard(MInstruction
* ins
);
330 void discardLastIns();
331 void discardAllInstructions();
332 void discardAllInstructionsStartingAt(MInstructionIterator iter
);
333 void discardAllPhis();
334 void discardAllResumePoints(bool discardEntry
= true);
337 // Splits this block in two at a given instruction, inserting a new control
338 // flow diamond with |ins| in the slow path, |fastpath| in the other, and
339 // |condition| determining which path to take.
340 bool wrapInstructionInFastpath(MInstruction
* ins
, MInstruction
* fastpath
,
341 MInstruction
* condition
);
343 void moveOuterResumePointTo(MBasicBlock
* dest
);
345 // Move an instruction from this block to a block that has not yet been
347 void moveToNewBlock(MInstruction
* ins
, MBasicBlock
* dst
);
349 // Same as |void discard(MInstruction* ins)| but assuming that
350 // all operands are already discarded.
351 void discardIgnoreOperands(MInstruction
* ins
);
353 // Discards a phi instruction and updates predecessor successorWithPhis.
354 void discardPhi(MPhi
* phi
);
356 // Some instruction which are guarding against some MIRType value, or
357 // against a type expectation should be considered as removing a potenatial
358 // branch where the guard does not hold. We need to register such
359 // instructions in order to do destructive optimizations correctly, such as
361 void flagOperandsOfPrunedBranches(MInstruction
* ins
);
363 // Mark this block as having been removed from the graph.
365 MOZ_ASSERT(kind_
!= DEAD
);
369 ///////////////////////////////////////////////////////
370 /////////// END GRAPH BUILDING INSTRUCTIONS ///////////
371 ///////////////////////////////////////////////////////
373 MIRGraph
& graph() { return graph_
; }
374 const CompileInfo
& info() const { return info_
; }
375 jsbytecode
* pc() const { return trackedSite_
->pc(); }
376 jsbytecode
* entryPC() const { return entryResumePoint()->pc(); }
377 uint32_t nslots() const { return slots_
.length(); }
378 uint32_t id() const { return id_
; }
379 uint32_t numPredecessors() const { return predecessors_
.length(); }
381 bool branchHintingUnlikely() const {
382 return branchHint_
== wasm::BranchHint::Unlikely
;
384 bool branchHintingLikely() const {
385 return branchHint_
== wasm::BranchHint::Likely
;
388 void setBranchHinting(wasm::BranchHint value
) { branchHint_
= value
; }
390 uint32_t domIndex() const {
391 MOZ_ASSERT(!isDead());
394 void setDomIndex(uint32_t d
) { domIndex_
= d
; }
396 MBasicBlock
* getPredecessor(uint32_t i
) const { return predecessors_
[i
]; }
397 size_t indexForPredecessor(MBasicBlock
* block
) const {
398 // This should only be called before critical edge splitting.
399 MOZ_ASSERT(!block
->successorWithPhis());
401 for (size_t i
= 0; i
< predecessors_
.length(); i
++) {
402 if (predecessors_
[i
] == block
) {
408 bool hasAnyIns() const { return !instructions_
.empty(); }
409 bool hasLastIns() const {
410 return hasAnyIns() && instructions_
.rbegin()->isControlInstruction();
412 MControlInstruction
* lastIns() const {
413 MOZ_ASSERT(hasLastIns());
414 return instructions_
.rbegin()->toControlInstruction();
416 // Find or allocate an optimized out constant.
417 MConstant
* optimizedOutConstant(TempAllocator
& alloc
);
418 MPhiIterator
phisBegin() const { return phis_
.begin(); }
419 MPhiIterator
phisBegin(MPhi
* at
) const { return phis_
.begin(at
); }
420 MPhiIterator
phisEnd() const { return phis_
.end(); }
421 bool phisEmpty() const { return phis_
.empty(); }
423 MResumePointIterator
resumePointsBegin() const {
424 return resumePoints_
.begin();
426 MResumePointIterator
resumePointsEnd() const { return resumePoints_
.end(); }
427 bool resumePointsEmpty() const { return resumePoints_
.empty(); }
429 MInstructionIterator
begin() { return instructions_
.begin(); }
430 MInstructionIterator
begin(MInstruction
* at
) {
431 MOZ_ASSERT(at
->block() == this);
432 return instructions_
.begin(at
);
434 MInstructionIterator
end() { return instructions_
.end(); }
435 MInstructionReverseIterator
rbegin() { return instructions_
.rbegin(); }
436 MInstructionReverseIterator
rbegin(MInstruction
* at
) {
437 MOZ_ASSERT(at
->block() == this);
438 return instructions_
.rbegin(at
);
440 MInstructionReverseIterator
rend() { return instructions_
.rend(); }
442 bool isLoopHeader() const { return kind_
== LOOP_HEADER
; }
443 bool isPendingLoopHeader() const { return kind_
== PENDING_LOOP_HEADER
; }
445 bool hasUniqueBackedge() const {
446 MOZ_ASSERT(isLoopHeader());
447 MOZ_ASSERT(numPredecessors() >= 1);
448 if (numPredecessors() == 1 || numPredecessors() == 2) {
451 if (numPredecessors() == 3) {
452 // fixup block added by NewFakeLoopPredecessor
453 return getPredecessor(1)->numPredecessors() == 0;
457 MBasicBlock
* backedge() const {
458 MOZ_ASSERT(hasUniqueBackedge());
459 return getPredecessor(numPredecessors() - 1);
461 MBasicBlock
* loopHeaderOfBackedge() const {
462 MOZ_ASSERT(isLoopBackedge());
463 return getSuccessor(numSuccessors() - 1);
465 MBasicBlock
* loopPredecessor() const {
466 MOZ_ASSERT(isLoopHeader());
467 return getPredecessor(0);
469 bool isLoopBackedge() const {
470 if (!numSuccessors()) {
473 MBasicBlock
* lastSuccessor
= getSuccessor(numSuccessors() - 1);
474 return lastSuccessor
->isLoopHeader() &&
475 lastSuccessor
->hasUniqueBackedge() &&
476 lastSuccessor
->backedge() == this;
478 bool isSplitEdge() const { return kind_
== SPLIT_EDGE
; }
479 bool isDead() const { return kind_
== DEAD
; }
480 bool isFakeLoopPred() const { return kind_
== FAKE_LOOP_PRED
; }
482 uint32_t stackDepth() const { return stackPosition_
; }
483 bool isMarked() const { return mark_
; }
485 MOZ_ASSERT(!mark_
, "Marking already-marked block");
488 void markUnchecked() { mark_
= true; }
490 MOZ_ASSERT(mark_
, "Unarking unmarked block");
493 void unmarkUnchecked() { mark_
= false; }
495 MBasicBlock
* immediateDominator() const { return immediateDominator_
; }
497 void setImmediateDominator(MBasicBlock
* dom
) { immediateDominator_
= dom
; }
499 MTest
* immediateDominatorBranch(BranchDirection
* pdirection
);
501 size_t numImmediatelyDominatedBlocks() const {
502 return immediatelyDominated_
.length();
505 MBasicBlock
* getImmediatelyDominatedBlock(size_t i
) const {
506 return immediatelyDominated_
[i
];
509 MBasicBlock
** immediatelyDominatedBlocksBegin() {
510 return immediatelyDominated_
.begin();
513 MBasicBlock
** immediatelyDominatedBlocksEnd() {
514 return immediatelyDominated_
.end();
517 // Return the number of blocks dominated by this block. All blocks
518 // dominate at least themselves, so this will always be non-zero.
519 size_t numDominated() const {
520 MOZ_ASSERT(numDominated_
!= 0);
521 return numDominated_
;
524 void addNumDominated(size_t n
) { numDominated_
+= n
; }
526 // Add |child| to this block's immediately-dominated set.
527 bool addImmediatelyDominatedBlock(MBasicBlock
* child
);
529 // Remove |child| from this block's immediately-dominated set.
530 void removeImmediatelyDominatedBlock(MBasicBlock
* child
);
532 // This function retrieves the internal instruction associated with a
533 // slot, and should not be used for normal stack operations. It is an
534 // internal helper that is also used to enhance spew.
535 MDefinition
* getSlot(uint32_t index
) {
536 MOZ_ASSERT(index
< stackPosition_
);
537 return slots_
[index
];
540 MResumePoint
* entryResumePoint() const { return entryResumePoint_
; }
541 void setEntryResumePoint(MResumePoint
* rp
) { entryResumePoint_
= rp
; }
542 void clearEntryResumePoint() {
543 discardResumePoint(entryResumePoint_
);
544 entryResumePoint_
= nullptr;
546 MResumePoint
* outerResumePoint() const { return outerResumePoint_
; }
547 void setOuterResumePoint(MResumePoint
* outer
) {
548 MOZ_ASSERT(!outerResumePoint_
);
549 outerResumePoint_
= outer
;
551 void clearOuterResumePoint() {
552 discardResumePoint(outerResumePoint_
);
553 outerResumePoint_
= nullptr;
555 MResumePoint
* callerResumePoint() const { return callerResumePoint_
; }
556 void setCallerResumePoint(MResumePoint
* caller
) {
557 callerResumePoint_
= caller
;
560 LBlock
* lir() const { return lir_
; }
561 void assignLir(LBlock
* lir
) {
566 MBasicBlock
* successorWithPhis() const { return successorWithPhis_
; }
567 uint32_t positionInPhiSuccessor() const {
568 MOZ_ASSERT(successorWithPhis());
569 return positionInPhiSuccessor_
;
571 void setSuccessorWithPhis(MBasicBlock
* successor
, uint32_t id
) {
572 successorWithPhis_
= successor
;
573 positionInPhiSuccessor_
= id
;
575 void clearSuccessorWithPhis() { successorWithPhis_
= nullptr; }
576 size_t numSuccessors() const {
577 MOZ_ASSERT(lastIns());
578 return lastIns()->numSuccessors();
580 MBasicBlock
* getSuccessor(size_t index
) const {
581 MOZ_ASSERT(lastIns());
582 return lastIns()->getSuccessor(index
);
584 MBasicBlock
* getSingleSuccessor() const {
585 MOZ_ASSERT(numSuccessors() == 1);
586 return getSuccessor(0);
588 size_t getSuccessorIndex(MBasicBlock
*) const;
589 size_t getPredecessorIndex(MBasicBlock
*) const;
591 void setLoopDepth(uint32_t loopDepth
) { loopDepth_
= loopDepth
; }
592 uint32_t loopDepth() const { return loopDepth_
; }
594 void dumpStack(GenericPrinter
& out
);
597 void dump(GenericPrinter
& out
);
600 void updateTrackedSite(BytecodeSite
* site
) {
601 MOZ_ASSERT(site
->tree() == trackedSite_
->tree());
604 BytecodeSite
* trackedSite() const { return trackedSite_
; }
605 InlineScriptTree
* trackedTree() const { return trackedSite_
->tree(); }
607 // Find the previous resume point that would be used if this instruction
609 MResumePoint
* activeResumePoint(MInstruction
* ins
);
613 const CompileInfo
& info_
; // Each block originates from a particular script.
614 InlineList
<MInstruction
> instructions_
;
615 Vector
<MBasicBlock
*, 1, JitAllocPolicy
> predecessors_
;
616 InlineList
<MPhi
> phis_
;
617 FixedList
<MDefinition
*> slots_
;
618 uint32_t stackPosition_
;
620 uint32_t domIndex_
; // Index in the dominator tree.
621 uint32_t numDominated_
;
624 // Copy of a dominator block's outerResumePoint_ which holds the state of
625 // caller frame at the time of the call. If not null, this implies that this
626 // basic block corresponds to an inlined script.
627 MResumePoint
* callerResumePoint_
;
629 // Resume point holding baseline-like frame for the PC corresponding to the
630 // entry of this basic block.
631 MResumePoint
* entryResumePoint_
;
633 // Resume point holding baseline-like frame for the PC corresponding to the
634 // beginning of the call-site which is being inlined after this block.
635 MResumePoint
* outerResumePoint_
;
638 // Unordered list used to verify that all the resume points which are
639 // registered are correctly removed when a basic block is removed.
640 InlineForwardList
<MResumePoint
> resumePoints_
;
643 MBasicBlock
* successorWithPhis_
;
644 uint32_t positionInPhiSuccessor_
;
648 // Utility mark for traversal algorithms.
651 Vector
<MBasicBlock
*, 1, JitAllocPolicy
> immediatelyDominated_
;
652 MBasicBlock
* immediateDominator_
;
654 // Track bailouts by storing the current pc in MIR instruction added at
655 // this cycle. This is also used for tracking calls and optimizations when
657 BytecodeSite
* trackedSite_
;
660 using MBasicBlockIterator
= InlineListIterator
<MBasicBlock
>;
661 using ReversePostorderIterator
= InlineListIterator
<MBasicBlock
>;
662 using PostorderIterator
= InlineListReverseIterator
<MBasicBlock
>;
664 typedef Vector
<MBasicBlock
*, 1, JitAllocPolicy
> MIRGraphReturns
;
667 InlineList
<MBasicBlock
> blocks_
;
668 TempAllocator
* alloc_
;
669 MIRGraphReturns
* returnAccumulator_
;
670 uint32_t blockIdGen_
;
672 MBasicBlock
* osrBlock_
;
677 InlineList
<MPhi
> phiFreeList_
;
678 size_t phiFreeListLength_
;
681 explicit MIRGraph(TempAllocator
* alloc
)
683 returnAccumulator_(nullptr),
689 phiFreeListLength_(0) {}
691 TempAllocator
& alloc() const { return *alloc_
; }
693 void addBlock(MBasicBlock
* block
);
694 void insertBlockAfter(MBasicBlock
* at
, MBasicBlock
* block
);
695 void insertBlockBefore(MBasicBlock
* at
, MBasicBlock
* block
);
699 void setReturnAccumulator(MIRGraphReturns
* accum
) {
700 returnAccumulator_
= accum
;
702 MIRGraphReturns
* returnAccumulator() const { return returnAccumulator_
; }
704 [[nodiscard
]] bool addReturn(MBasicBlock
* returnBlock
) {
705 if (!returnAccumulator_
) {
709 return returnAccumulator_
->append(returnBlock
);
712 MBasicBlock
* entryBlock() { return *blocks_
.begin(); }
713 MBasicBlockIterator
begin() { return blocks_
.begin(); }
714 MBasicBlockIterator
begin(MBasicBlock
* at
) { return blocks_
.begin(at
); }
715 MBasicBlockIterator
end() { return blocks_
.end(); }
716 PostorderIterator
poBegin() { return blocks_
.rbegin(); }
717 PostorderIterator
poBegin(MBasicBlock
* at
) { return blocks_
.rbegin(at
); }
718 PostorderIterator
poEnd() { return blocks_
.rend(); }
719 ReversePostorderIterator
rpoBegin() { return blocks_
.begin(); }
720 ReversePostorderIterator
rpoBegin(MBasicBlock
* at
) {
721 return blocks_
.begin(at
);
723 ReversePostorderIterator
rpoEnd() { return blocks_
.end(); }
724 void removeBlock(MBasicBlock
* block
);
725 void moveBlockToEnd(MBasicBlock
* block
) {
726 blocks_
.remove(block
);
727 MOZ_ASSERT_IF(!blocks_
.empty(), block
->id());
728 blocks_
.pushBack(block
);
730 void moveBlockBefore(MBasicBlock
* at
, MBasicBlock
* block
) {
731 MOZ_ASSERT(block
->id());
732 blocks_
.remove(block
);
733 blocks_
.insertBefore(at
, block
);
735 void moveBlockAfter(MBasicBlock
* at
, MBasicBlock
* block
) {
736 MOZ_ASSERT(block
->id());
737 blocks_
.remove(block
);
738 blocks_
.insertAfter(at
, block
);
740 size_t numBlocks() const { return numBlocks_
; }
741 uint32_t numBlockIds() const { return blockIdGen_
; }
742 void allocDefinitionId(MDefinition
* ins
) { ins
->setId(idGen_
++); }
743 uint32_t getNumInstructionIds() { return idGen_
; }
744 MResumePoint
* entryResumePoint() { return entryBlock()->entryResumePoint(); }
746 void setOsrBlock(MBasicBlock
* osrBlock
) {
747 MOZ_ASSERT(!osrBlock_
);
748 osrBlock_
= osrBlock
;
750 MBasicBlock
* osrBlock() const { return osrBlock_
; }
752 MBasicBlock
* osrPreHeaderBlock() const {
753 return osrBlock() ? osrBlock()->getSingleSuccessor() : nullptr;
756 bool hasTryBlock() const { return hasTryBlock_
; }
757 void setHasTryBlock() { hasTryBlock_
= true; }
759 void dump(GenericPrinter
& out
);
762 void addPhiToFreeList(MPhi
* phi
) {
763 phiFreeList_
.pushBack(phi
);
764 phiFreeListLength_
++;
766 size_t phiFreeListLength() const { return phiFreeListLength_
; }
767 MPhi
* takePhiFromFreeList() {
768 MOZ_ASSERT(phiFreeListLength_
> 0);
769 phiFreeListLength_
--;
770 return phiFreeList_
.popBack();
773 void removeFakeLoopPredecessors();
776 // Dominators can't be built after we remove fake loop predecessors.
778 bool canBuildDominators_
= true;
781 bool canBuildDominators() const { return canBuildDominators_
; }
785 class MDefinitionIterator
{
786 friend class MBasicBlock
;
787 friend class MNodeIterator
;
791 MPhiIterator phiIter_
;
792 MInstructionIterator iter_
;
794 bool atPhi() const { return phiIter_
!= block_
->phisEnd(); }
796 MDefinition
* getIns() {
803 bool more() const { return atPhi() || (*iter_
) != block_
->lastIns(); }
806 explicit MDefinitionIterator(MBasicBlock
* block
)
807 : block_(block
), phiIter_(block
->phisBegin()), iter_(block
->begin()) {}
809 MDefinitionIterator
operator++() {
819 MDefinitionIterator
operator++(int) {
820 MDefinitionIterator
old(*this);
825 explicit operator bool() const { return more(); }
827 MDefinition
* operator*() { return getIns(); }
829 MDefinition
* operator->() { return getIns(); }
832 // Iterates on all resume points, phis, and instructions of a MBasicBlock.
833 // Resume points are visited as long as they have not been discarded.
834 class MNodeIterator
{
836 // If this is non-null, the resume point that we will visit next (unless
837 // it has been discarded). Initialized to the entry resume point.
838 // Otherwise, resume point of the most recently visited instruction.
839 MResumePoint
* resumePoint_
;
841 mozilla::DebugOnly
<MInstruction
*> lastInstruction_
= nullptr;
843 // Definition iterator which is one step ahead when visiting resume points.
844 // This is in order to avoid incrementing the iterator while it is settled
845 // on a discarded instruction.
846 MDefinitionIterator defIter_
;
848 MBasicBlock
* block() const { return defIter_
.block_
; }
850 bool atResumePoint() const {
851 MOZ_ASSERT_IF(lastInstruction_
&& !lastInstruction_
->isDiscarded(),
852 lastInstruction_
->resumePoint() == resumePoint_
);
853 return resumePoint_
&& !resumePoint_
->isDiscarded();
857 if (atResumePoint()) {
864 if (!atResumePoint()) {
865 if (defIter_
->isInstruction()) {
866 resumePoint_
= defIter_
->toInstruction()->resumePoint();
867 lastInstruction_
= defIter_
->toInstruction();
871 resumePoint_
= nullptr;
872 lastInstruction_
= nullptr;
876 bool more() const { return defIter_
|| atResumePoint(); }
879 explicit MNodeIterator(MBasicBlock
* block
)
880 : resumePoint_(block
->entryResumePoint()), defIter_(block
) {
881 MOZ_ASSERT(bool(block
->entryResumePoint()) == atResumePoint());
884 MNodeIterator
operator++(int) {
885 MNodeIterator
old(*this);
892 explicit operator bool() const { return more(); }
894 MNode
* operator*() { return getNode(); }
896 MNode
* operator->() { return getNode(); }
899 void MBasicBlock::add(MInstruction
* ins
) {
900 MOZ_ASSERT(!hasLastIns());
901 ins
->setInstructionBlock(this, trackedSite_
);
902 graph().allocDefinitionId(ins
);
903 instructions_
.pushBack(ins
);
909 #endif /* jit_MIRGraph_h */