From a7b024958ed7fa2d3ce5a005cfb9390b153853a0 Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Tue, 31 Oct 2023 10:39:38 -0700 Subject: [PATCH] JIT: make global morph its own phase (#94185) Contributes to #93246. --- src/coreclr/jit/compiler.cpp | 22 +++--- src/coreclr/jit/compiler.h | 3 +- src/coreclr/jit/compphases.h | 1 + src/coreclr/jit/morph.cpp | 143 ++++++++++++++++------------------- 4 files changed, 82 insertions(+), 87 deletions(-) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index fb6abb6364889..435f9d5e1cafc 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -4747,9 +4747,10 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl // Morph the trees in all the blocks of the method // - auto morphGlobalPhase = [this]() { - unsigned prevBBCount = fgBBcount; - fgMorphBlocks(); + unsigned const preMorphBBCount = fgBBcount; + DoPhase(this, PHASE_MORPH_GLOBAL, &Compiler::fgMorphBlocks); + + auto postMorphPhase = [this]() { // Fix any LclVar annotations on discarded struct promotion temps for implicit by-ref args fgMarkDemotedImplicitByRefArgs(); @@ -4765,16 +4766,17 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl compCurBB = nullptr; #endif // DEBUG - // If we needed to create any new BasicBlocks then renumber the blocks - if (fgBBcount > prevBBCount) - { - fgRenumberBlocks(); - } - // Enable IR checks activePhaseChecks |= PhaseChecks::CHECK_IR; }; - DoPhase(this, PHASE_MORPH_GLOBAL, morphGlobalPhase); + DoPhase(this, PHASE_POST_MORPH, postMorphPhase); + + // If we needed to create any new BasicBlocks then renumber the blocks + // + if (fgBBcount > preMorphBBCount) + { + fgRenumberBlocks(); + } // GS security checks for unsafe buffers // diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 65e1474b26ab2..dfafe03461d34 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -4797,8 +4797,9 @@ class Compiler FoldResult fgFoldConditional(BasicBlock* block); + PhaseStatus fgMorphBlocks(); + void fgMorphBlock(BasicBlock* block); void fgMorphStmts(BasicBlock* block); - void fgMorphBlocks(); void fgMergeBlockReturn(BasicBlock* block); diff --git a/src/coreclr/jit/compphases.h b/src/coreclr/jit/compphases.h index 12cc374546e43..486a6de7ce5f8 100644 --- a/src/coreclr/jit/compphases.h +++ b/src/coreclr/jit/compphases.h @@ -49,6 +49,7 @@ CompPhaseNameMacro(PHASE_IMPBYREF_COPY_OMISSION, "Identify candidates for im CompPhaseNameMacro(PHASE_MORPH_IMPBYREF, "Morph - ByRefs", false, -1, false) CompPhaseNameMacro(PHASE_PROMOTE_STRUCTS, "Morph - Promote Structs", false, -1, false) CompPhaseNameMacro(PHASE_MORPH_GLOBAL, "Morph - Global", false, -1, false) +CompPhaseNameMacro(PHASE_POST_MORPH, "Post-Morph", false, -1, false) CompPhaseNameMacro(PHASE_MORPH_END, "Morph - Finish", false, -1, true) CompPhaseNameMacro(PHASE_GS_COOKIE, "GS Cookie", false, -1, false) CompPhaseNameMacro(PHASE_COMPUTE_EDGE_WEIGHTS, "Compute edge weights (1, false)",false, -1, false) diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index f257cf44cd8ed..e7b54cf37a826 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -13619,13 +13619,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; @@ -13809,36 +13808,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->KindIs(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); @@ -13862,53 +13890,16 @@ void Compiler::fgMorphBlocks() fgEnsureFirstBBisScratch(); } - /*------------------------------------------------------------------------- - * Process all basic blocks in the function - */ - - BasicBlock* block = fgFirstBB; - noway_assert(block); - - do + // Morph all blocks. + // + // 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()) { -#ifdef DEBUG - if (verbose) - { - printf("\nMorphing " FMT_BB " of '%s'\n", block->bbNum, info.compFullName); - } -#endif - - if (optLocalAssertionProp) - { - // - // Clear out any currently recorded assertion candidates - // before processing each basic block, - // also we must handle QMARK-COLON specially - // - optAssertionReset(0); - } - - // 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->KindIs(BBJ_RETURN) && ((block->bbFlags & BBF_HAS_JMP) == 0)) - { - if ((genReturnBB != nullptr) && (genReturnBB != block)) - { - fgMergeBlockReturn(block); - } - } - - block = block->Next(); - } while (block != nullptr); - - // We are done with the global morphing phase - fgGlobalMorph = false; - compCurBB = nullptr; + fgMorphBlock(block); + } // Under OSR, we no longer need to specially protect the original method entry // @@ -13924,12 +13915,12 @@ void Compiler::fgMorphBlocks() fgEntryBB = nullptr; } -#ifdef DEBUG - if (verboseTrees) - { - fgDispBasicBlocks(true); - } -#endif + // We are done with the global morphing phase + // + fgGlobalMorph = false; + compCurBB = nullptr; + + return PhaseStatus::MODIFIED_EVERYTHING; } //------------------------------------------------------------------------