-
Notifications
You must be signed in to change notification settings - Fork 5.2k
JIT: make global morph its own phase, morph blocks in RPO #86822
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13372,13 +13372,12 @@ void Compiler::fgMorphStmtBlockOps(BasicBlock* block, Statement* stmt) | |
| } | ||
| } | ||
|
|
||
| /***************************************************************************** | ||
| * | ||
| * Morph the statements of the given block. | ||
| * This function should be called just once for a block. Use fgMorphBlockStmt() | ||
| * for reentrant calls. | ||
| */ | ||
|
|
||
| //------------------------------------------------------------------------ | ||
| // fgMorphStmts: Morph all statements in a block | ||
| // | ||
| // Arguments: | ||
| // block - block in question | ||
| // | ||
| void Compiler::fgMorphStmts(BasicBlock* block) | ||
| { | ||
| fgRemoveRestOfBlock = false; | ||
|
|
@@ -13569,36 +13568,65 @@ void Compiler::fgMorphStmts(BasicBlock* block) | |
| fgRemoveRestOfBlock = false; | ||
| } | ||
|
|
||
| /***************************************************************************** | ||
| * | ||
| * Morph the blocks of the method. | ||
| * Returns true if the basic block list is modified. | ||
| * This function should be called just once. | ||
| */ | ||
|
|
||
| void Compiler::fgMorphBlocks() | ||
| //------------------------------------------------------------------------ | ||
| // fgMorphBlock: Morph a basic block | ||
| // | ||
| // Arguments: | ||
| // block - block in question | ||
| // | ||
| void Compiler::fgMorphBlock(BasicBlock* block) | ||
| { | ||
| #ifdef DEBUG | ||
| if (verbose) | ||
| JITDUMP("\nMorphing " FMT_BB "\n", block->bbNum); | ||
|
|
||
| if (optLocalAssertionProp) | ||
| { | ||
| printf("\n*************** In fgMorphBlocks()\n"); | ||
| // Clear out any currently recorded assertion candidates | ||
| // before processing each basic block, | ||
| // also we must handle QMARK-COLON specially | ||
| // | ||
| optAssertionReset(0); | ||
| } | ||
| #endif | ||
|
|
||
| /* Since fgMorphTree can be called after various optimizations to re-arrange | ||
| * the nodes we need a global flag to signal if we are during the one-pass | ||
| * global morphing */ | ||
| // Make the current basic block address available globally. | ||
| compCurBB = block; | ||
|
|
||
| fgGlobalMorph = true; | ||
| // Process all statement trees in the basic block. | ||
| fgMorphStmts(block); | ||
|
|
||
| // Do we need to merge the result of this block into a single return block? | ||
| if ((block->bbJumpKind == BBJ_RETURN) && ((block->bbFlags & BBF_HAS_JMP) == 0)) | ||
| { | ||
| if ((genReturnBB != nullptr) && (genReturnBB != block)) | ||
| { | ||
| fgMergeBlockReturn(block); | ||
| } | ||
| } | ||
|
|
||
| compCurBB = nullptr; | ||
| } | ||
|
|
||
| //------------------------------------------------------------------------ | ||
| // fgMorphBlocks: Morph all blocks in the method | ||
| // | ||
| // Returns: | ||
| // Suitable phase status. | ||
| // | ||
| // Note: | ||
| // Morph almost always changes IR, so we don't actually bother to | ||
| // track if it made any changees. | ||
| // | ||
| PhaseStatus Compiler::fgMorphBlocks() | ||
| { | ||
| // This is the one and only global morph phase | ||
| // | ||
| fgGlobalMorph = true; | ||
|
|
||
| // Local assertion prop is enabled if we are optimized | ||
| // | ||
| optLocalAssertionProp = opts.OptimizationEnabled(); | ||
|
|
||
| if (optLocalAssertionProp) | ||
| { | ||
| // | ||
| // Initialize for local assertion prop | ||
| // | ||
| optAssertionInit(true); | ||
|
|
@@ -13614,53 +13642,57 @@ void Compiler::fgMorphBlocks() | |
| lvSetMinOptsDoNotEnreg(); | ||
| } | ||
|
|
||
| /*------------------------------------------------------------------------- | ||
| * Process all basic blocks in the function | ||
| */ | ||
|
|
||
| BasicBlock* block = fgFirstBB; | ||
| noway_assert(block); | ||
|
|
||
| do | ||
| // Morph all blocks. If we aren't then we just morph in normal bbNext order. | ||
| // | ||
| if (!optLocalAssertionProp) | ||
| { | ||
| #ifdef DEBUG | ||
| if (verbose) | ||
| // Note morph can add blocks downstream from the current block, | ||
| // and alter (but not null out) the current block's bbNext; | ||
| // this iterator ensures they all get visited. | ||
| // | ||
| for (BasicBlock* block : Blocks()) | ||
| { | ||
| printf("\nMorphing " FMT_BB " of '%s'\n", block->bbNum, info.compFullName); | ||
| fgMorphBlock(block); | ||
| } | ||
| #endif | ||
| } | ||
| else | ||
| { | ||
| // We are optimizing. Process in RPO. | ||
| // | ||
| fgRenumberBlocks(); | ||
| EnsureBasicBlockEpoch(); | ||
| fgComputeEnterBlocksSet(); | ||
| fgDfsReversePostorder(); | ||
|
|
||
| if (optLocalAssertionProp) | ||
| // Morph can introduce new blocks, so enable tracking block creation | ||
| // | ||
| unsigned const bbNumMax = fgBBNumMax; | ||
| fgEnableNewBlockTracking(); | ||
| for (unsigned i = 1; i <= bbNumMax; i++) | ||
| { | ||
| // | ||
| // Clear out any currently recorded assertion candidates | ||
| // before processing each basic block, | ||
| // also we must handle QMARK-COLON specially | ||
| // | ||
| optAssertionReset(0); | ||
| BasicBlock* const block = fgBBReversePostorder[i]; | ||
| fgMorphBlock(block); | ||
| } | ||
| fgDisableNewBlockTracking(); | ||
|
|
||
| // Make the current basic block address available globally. | ||
| compCurBB = block; | ||
|
|
||
| // Process all statement trees in the basic block. | ||
| fgMorphStmts(block); | ||
|
|
||
| // Do we need to merge the result of this block into a single return block? | ||
| if ((block->bbJumpKind == BBJ_RETURN) && ((block->bbFlags & BBF_HAS_JMP) == 0)) | ||
| // If morph created new blocks, then morph them as well. | ||
| // Temporarily forbid creating even more new blocks so | ||
| // we don't have to iterate until closure. | ||
| // | ||
| // (TODO: verify that this potential out of order processing does not cause issues) | ||
| // | ||
| if (fgNewBBs->size() > 0) | ||
| { | ||
| if ((genReturnBB != nullptr) && (genReturnBB != block)) | ||
| JITDUMP("Morph created %u new blocks, processing them out of RPO\n", fgNewBBs->size()); | ||
|
|
||
| INDEBUG(fgSafeBasicBlockCreation = false); | ||
| for (BasicBlock* const block : *fgNewBBs) | ||
| { | ||
| fgMergeBlockReturn(block); | ||
| fgMorphBlock(block); | ||
| } | ||
|
Comment on lines
+13689
to
13692
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this a significant chunk of throughput cost? What is the improvement of this tracking mechanism alone? |
||
| INDEBUG(fgSafeBasicBlockCreation = true); | ||
| } | ||
|
|
||
| block = block->bbNext; | ||
| } while (block != nullptr); | ||
|
|
||
| // We are done with the global morphing phase | ||
| fgGlobalMorph = false; | ||
| compCurBB = nullptr; | ||
| } | ||
|
|
||
| // Under OSR, we no longer need to specially protect the original method entry | ||
| // | ||
|
|
@@ -13676,12 +13708,11 @@ void Compiler::fgMorphBlocks() | |
| fgEntryBB = nullptr; | ||
| } | ||
|
|
||
| #ifdef DEBUG | ||
| if (verboseTrees) | ||
| { | ||
| fgDispBasicBlocks(true); | ||
| } | ||
| #endif | ||
| // We are done with the global morphing phase | ||
| // | ||
| fgGlobalMorph = false; | ||
|
|
||
| return PhaseStatus::MODIFIED_EVERYTHING; | ||
| } | ||
|
|
||
| //------------------------------------------------------------------------ | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious why we need to do so much work to set up for the RPO traversal. SSA's
TopologicalSortdoes not do any of this work; it simply starts atfgFirstBB(well, the BB root, but then the originalfgFirstBBvery soon after that). Would it be incorrect to do the same here?Another idea: can we avoid the two step iteration process, and instead have a version of
fgDfsReversePostorderthat just invokes a callback instead of recording the order into ambient state? Would it make any difference? I'm not totally sure where the throughput cost comes from in this change.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can try and do all this on the fly, that's more or less what I was suggesting above:
I don't understand it either, seems like this latest version should (aside from building the RPO) be fairly efficient. Will have to take a look.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect this is tricky for phases like morph that also can alter the flow graph.