From e5df81039fb1c01088e872475894daed9c4a01fc Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Wed, 10 Sep 2025 17:16:49 +0200 Subject: [PATCH 1/3] JIT: Generalize pattern-based IV analysis - Follow unique preds when locating the init statement for the iterator variable - Generalize zero-trip detection by similarly following unique preds --- src/coreclr/jit/compiler.h | 14 ++- src/coreclr/jit/flowgraph.cpp | 220 +++++++++++++++++----------------- src/coreclr/jit/gentree.cpp | 70 +++++++++++ src/coreclr/jit/optimizer.cpp | 67 +---------- 4 files changed, 194 insertions(+), 177 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 90a74bd016dbe2..1c90416bf84c53 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -1996,11 +1996,12 @@ class FlowGraphNaturalLoop GenTreeLclVarCommon* FindDef(unsigned lclNum); - void MatchInit(NaturalLoopIterInfo* info, BasicBlock* initBlock, GenTree* init); bool MatchLimit(unsigned iterVar, GenTree* test, NaturalLoopIterInfo* info); + bool FindConstInit(BasicBlock* preheader, NaturalLoopIterInfo* info); bool CheckLoopConditionBaseCase(BasicBlock* initBlock, NaturalLoopIterInfo* info); - bool IsZeroTripTest(BasicBlock* initBlock, NaturalLoopIterInfo* info); - bool InitBlockEntersLoopOnTrue(BasicBlock* initBlock); + bool HasZeroTripTest(BasicBlock* preheader, NaturalLoopIterInfo* info); + bool IsZeroTripTest(BasicBlock* guardBlock, bool entersOnTrue, NaturalLoopIterInfo* info); + template static bool EvaluateRelop(T op1, T op2, genTreeOps oper); public: @@ -3645,6 +3646,7 @@ class Compiler unsigned gtSetEvalOrderMinOpts(GenTree* tree); bool gtMayHaveStoreInterference(GenTree* treeWithStores, GenTree* tree); bool gtTreeHasLocalRead(GenTree* tree, unsigned lclNum); + bool gtTreeHasLocalStore(GenTree* tree, unsigned lclNum); void gtSetStmtInfo(Statement* stmt); @@ -7063,8 +7065,8 @@ class Compiler bool optIsLoopTestEvalIntoTemp(Statement* testStmt, Statement** newTestStmt); unsigned optIsLoopIncrTree(GenTree* incr); - bool optExtractInitTestIncr( - BasicBlock** pInitBlock, BasicBlock* bottom, BasicBlock* top, GenTree** ppInit, GenTree** ppTest, GenTree** ppIncr); + bool optExtractTestIncr( + BasicBlock* bottom, BasicBlock* top, GenTree** ppTest, GenTree** ppIncr); void optSetMappedBlockTargets(BasicBlock* blk, BasicBlock* newBlk, @@ -7667,7 +7669,7 @@ class Compiler bool optJumpThreadCheck(BasicBlock* const block, BasicBlock* const domBlock); bool optJumpThreadCore(JumpThreadInfo& jti); bool optReachable(BasicBlock* const fromBlock, BasicBlock* const toBlock, BasicBlock* const excludedBlock); - BitVecTraits* optReachableBitVecTraits; + BitVecTraits* optReachableBitVecTraits = nullptr; BitVec optReachableBitVec; void optRelopImpliesRelop(RelopImplicationInfo* rii); bool optRelopTryInferWithOneEqualOperand(const VNFuncApp& domApp, diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 1bff7f951db56e..eeee96575ccfa0 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -5504,9 +5504,7 @@ bool FlowGraphNaturalLoop::AnalyzeIteration(NaturalLoopIterInfo* info) JITDUMP(" Preheader = " FMT_BB "\n", preheader->bbNum); - BasicBlock* initBlock = nullptr; - GenTree* init = nullptr; - GenTree* test = nullptr; + GenTree* test = nullptr; info->IterVar = BAD_VAR_NUM; @@ -5521,8 +5519,7 @@ bool FlowGraphNaturalLoop::AnalyzeIteration(NaturalLoopIterInfo* info) } GenTree* iterTree = nullptr; - initBlock = preheader; - if (!comp->optExtractInitTestIncr(&initBlock, cond, m_header, &init, &test, &iterTree)) + if (!comp->optExtractTestIncr(cond, m_header, &test, &iterTree)) { JITDUMP(" Could not extract an IV\n"); continue; @@ -5580,19 +5577,17 @@ bool FlowGraphNaturalLoop::AnalyzeIteration(NaturalLoopIterInfo* info) return false; } - if (init == nullptr) + if (FindConstInit(preheader, info)) { - JITDUMP(" Init = , test = [%06u], incr = [%06u]\n", Compiler::dspTreeID(test), - Compiler::dspTreeID(info->IterTree)); + JITDUMP(" Init = [%06u], test = [%06u], incr = [%06u]\n", Compiler::dspTreeID(info->InitTree), + Compiler::dspTreeID(test), Compiler::dspTreeID(info->IterTree)); } else { - JITDUMP(" Init = [%06u], test = [%06u], incr = [%06u]\n", Compiler::dspTreeID(init), Compiler::dspTreeID(test), + JITDUMP(" Init = , test = [%06u], incr = [%06u]\n", Compiler::dspTreeID(test), Compiler::dspTreeID(info->IterTree)); } - MatchInit(info, initBlock, init); - bool result = VisitDefs([=](GenTreeLclVarCommon* def) { if ((def->GetLclNum() != info->IterVar) || (def == info->IterTree)) return true; @@ -5606,7 +5601,7 @@ bool FlowGraphNaturalLoop::AnalyzeIteration(NaturalLoopIterInfo* info) return false; } - if (!CheckLoopConditionBaseCase(initBlock, info)) + if (!CheckLoopConditionBaseCase(preheader, info)) { JITDUMP(" Loop condition may not be true on the first iteration\n"); return false; @@ -5637,33 +5632,6 @@ bool FlowGraphNaturalLoop::AnalyzeIteration(NaturalLoopIterInfo* info) return true; } -//------------------------------------------------------------------------ -// FlowGraphNaturalLoop::MatchInit: Try to pattern match the initialization of -// an induction variable. -// -// Parameters: -// info - [in, out] Info structure to query and fill out -// initBlock - Block containing the initialization tree -// init - Initialization tree -// -// Remarks: -// We do not necessarily guarantee or require to be able to find any -// initialization. -// -void FlowGraphNaturalLoop::MatchInit(NaturalLoopIterInfo* info, BasicBlock* initBlock, GenTree* init) -{ - if ((init == nullptr) || !init->OperIs(GT_STORE_LCL_VAR) || (init->AsLclVarCommon()->GetLclNum() != info->IterVar)) - return; - - GenTree* initValue = init->AsLclVar()->Data(); - if (!initValue->IsCnsIntOrI() || !initValue->TypeIs(TYP_INT)) - return; - - info->HasConstInit = true; - info->ConstInitValue = (int)initValue->AsIntCon()->IconValue(); - INDEBUG(info->InitTree = init); -} - //------------------------------------------------------------------------ // FlowGraphNaturalLoop::MatchLimit: Try to pattern match the loop test of an // induction variable. @@ -5801,6 +5769,62 @@ bool FlowGraphNaturalLoop::MatchLimit(unsigned iterVar, GenTree* test, NaturalLo return true; } +//------------------------------------------------------------------------ +// FlowGraphNaturalLoop::FindConstInit: +// Find an unconditional constant initialization of the iteration variable, +// recording and returning its information. +// +// Parameters: +// preheader - Preheader of the loop, to start the search from +// info - [in, out] Loop information +// +// Returns: +// True if a constant init of the iteration variable was found; otherwise false. +// +bool FlowGraphNaturalLoop::FindConstInit(BasicBlock* preheader, NaturalLoopIterInfo* info) +{ + BasicBlock* curBlock = preheader; + do + { + Statement* stmt = curBlock->lastStmt(); + if (stmt != nullptr) + { + while (true) + { + GenTree* tree = stmt->GetRootNode(); + if (tree->OperIs(GT_STORE_LCL_VAR)) + { + GenTreeLclVarCommon* store = tree->AsLclVarCommon(); + GenTree* data = store->Data(); + if ((store->GetLclNum() == info->IterVar) && data->IsCnsIntOrI() && data->TypeIs(TYP_INT)) + { + info->HasConstInit = true; + info->ConstInitValue = (int)data->AsIntCon()->IconValue(); + INDEBUG(info->InitTree = tree); + return true; + } + } + + if (GetDfsTree()->GetCompiler()->gtTreeHasLocalStore(tree, info->IterVar)) + { + return false; + } + + if (stmt == curBlock->firstStmt()) + { + break; + } + + stmt = stmt->GetPrevStmt(); + } + } + + curBlock = curBlock->GetUniquePred(GetDfsTree()->GetCompiler()); + } while (curBlock != nullptr); + + return false; +} + //------------------------------------------------------------------------ // EvaluateRelop: Evaluate a relational operator with constant arguments. // @@ -5852,7 +5876,7 @@ bool FlowGraphNaturalLoop::EvaluateRelop(T op1, T op2, genTreeOps oper) // * The condition being trivially true in the first iteration (e.g. for (int i = 0; i < 3; i++)) // * The condition is checked before entry (often due to loop inversion) // -bool FlowGraphNaturalLoop::CheckLoopConditionBaseCase(BasicBlock* initBlock, NaturalLoopIterInfo* info) +bool FlowGraphNaturalLoop::CheckLoopConditionBaseCase(BasicBlock* preheader, NaturalLoopIterInfo* info) { // TODO: A common loop idiom is to enter the loop at the test, with the // unique in-loop predecessor of the header block being the increment. We @@ -5883,8 +5907,7 @@ bool FlowGraphNaturalLoop::CheckLoopConditionBaseCase(BasicBlock* initBlock, Nat } } - // Do we have a zero-trip test? - if (initBlock->KindIs(BBJ_COND) && IsZeroTripTest(initBlock, info)) + if (HasZeroTripTest(preheader, info)) { return true; } @@ -5893,18 +5916,55 @@ bool FlowGraphNaturalLoop::CheckLoopConditionBaseCase(BasicBlock* initBlock, Nat } //------------------------------------------------------------------------ -// IsZeroTripTest: Check whether `initBlock`, a BBJ_COND block that enters the -// loop in one case and not in the other, implies that the loop invariant is -// true on entry. +// HasZeroTripTest: Check whether the loop has a zero trip test guarding it +// from being entered. +// +// Parameters: +// preheader - The preheader block +// info - Iteration information +// +// Returns: +// True if we could prove that the loop invariant is true on entry. +// +bool FlowGraphNaturalLoop::HasZeroTripTest(BasicBlock* preheader, NaturalLoopIterInfo* info) +{ + assert(!preheader->KindIs(BBJ_COND)); + BasicBlock* curBlock = preheader; + while (true) + { + BasicBlock* prevBlock = curBlock; + curBlock = curBlock->GetUniquePred(GetDfsTree()->GetCompiler()); + + if (curBlock == nullptr) + { + return false; + } + + if (curBlock->KindIs(BBJ_COND) && (curBlock->GetFalseTarget() != curBlock->GetTrueTarget()) && + IsZeroTripTest(curBlock, curBlock->TrueTargetIs(prevBlock), info)) + { + return true; + } + } +} + +//------------------------------------------------------------------------ +// IsZeroTripTest: Check whether the loop has a zero trip test guarding it +// from being entered. +// +// Parameters: +// guardBlock - The preheader block +// entersWhenTrue - Whether the loop is entered on true or false of the guard block. +// info - Iteration information // // Returns: // True if we could prove that the loop invariant is true on entry through -// "initBlock". +// "guardBlock". // -bool FlowGraphNaturalLoop::IsZeroTripTest(BasicBlock* initBlock, NaturalLoopIterInfo* info) +bool FlowGraphNaturalLoop::IsZeroTripTest(BasicBlock* guardBlock, bool entersWhenTrue, NaturalLoopIterInfo* info) { - assert(initBlock->KindIs(BBJ_COND)); - GenTree* enteringJTrue = initBlock->lastStmt()->GetRootNode(); + assert(guardBlock->KindIs(BBJ_COND)); + GenTree* enteringJTrue = guardBlock->lastStmt()->GetRootNode(); assert(enteringJTrue->OperIs(GT_JTRUE)); GenTree* relop = enteringJTrue->gtGetOp1(); if (!relop->OperIsCmpCompare()) @@ -5912,14 +5972,8 @@ bool FlowGraphNaturalLoop::IsZeroTripTest(BasicBlock* initBlock, NaturalLoopIter return false; } - // Technically optExtractInitTestIncr only handles the "false" - // entry case, and preheader creation should ensure that that's the - // only time we'll see a BBJ_COND init block. However, it does not - // hurt to let this logic be correct by construction. - bool enterOnTrue = InitBlockEntersLoopOnTrue(initBlock); - - JITDUMP(" Init block " FMT_BB " enters the loop when condition [%06u] evaluates to %s\n", initBlock->bbNum, - Compiler::dspTreeID(relop), enterOnTrue ? "true" : "false"); + JITDUMP(" Guard block " FMT_BB " enters the loop when condition [%06u] evaluates to %s\n", guardBlock->bbNum, + Compiler::dspTreeID(relop), entersWhenTrue ? "true" : "false"); GenTree* limitCandidate; genTreeOps oper; @@ -5943,7 +5997,7 @@ bool FlowGraphNaturalLoop::IsZeroTripTest(BasicBlock* initBlock, NaturalLoopIter return false; } - if (!enterOnTrue) + if (!entersWhenTrue) { oper = GenTree::ReverseRelop(oper); } @@ -5968,56 +6022,6 @@ bool FlowGraphNaturalLoop::IsZeroTripTest(BasicBlock* initBlock, NaturalLoopIter return true; } -//------------------------------------------------------------------------ -// InitBlockEntersLoopOnTrue: Determine whether a BBJ_COND init block enters the -// loop in the false or true case. -// -// Parameters: -// initBlock - A BBJ_COND block that is assumed to dominate the loop, and -// only enter the loop in one of the two cases. -// -// Returns: -// True if the loop is entered if the condition evaluates to true; otherwise false. -// -// Remarks: -// Handles only limited cases (optExtractInitTestIncr ensures that we see -// only limited cases). -// -bool FlowGraphNaturalLoop::InitBlockEntersLoopOnTrue(BasicBlock* initBlock) -{ - assert(initBlock->KindIs(BBJ_COND)); - - if (initBlock->FalseTargetIs(GetHeader())) - { - return false; - } - - if (initBlock->TrueTargetIs(GetHeader())) - { - return true; - } - - // `optExtractInitTestIncr` may look at preds of preds to find an init - // block, so try a little bit harder. Today this always happens since we - // always have preheaders created in the places we call - // FlowGraphNaturalLoop::AnalyzeIteration. - for (FlowEdge* enterEdge : EntryEdges()) - { - BasicBlock* entering = enterEdge->getSourceBlock(); - if (initBlock->FalseTargetIs(entering)) - { - return false; - } - if (initBlock->TrueTargetIs(entering)) - { - return true; - } - } - - assert(!"Could not find init block enter side"); - return false; -} - //------------------------------------------------------------------------ // GetLexicallyTopMostBlock: Get the lexically top-most block contained within // the loop. diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 10bde780a8534f..9fea3352a55776 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -6496,6 +6496,76 @@ bool Compiler::gtTreeHasLocalRead(GenTree* tree, unsigned lclNum) return visitor.WalkTree(&tree, nullptr) == WALK_ABORT; } +//------------------------------------------------------------------------ +// gtTreeHasLocalStore: Check if a tree has a store that affects the specified local, +// taking promotion into account. +// +// Parameters: +// tree - The tree to check. +// lclNum - The local to look for. +// +// Returns: +// True if there is any GT_STORE_LCL_VAR or GT_STORE_LCL_FLD that affects "lclNum". +// +bool Compiler::gtTreeHasLocalStore(GenTree* tree, unsigned lclNum) +{ + class Visitor final : public GenTreeVisitor + { + public: + enum + { + DoPreOrder = true, + DoLclVarsOnly = true, + }; + + unsigned m_lclNum; + LclVarDsc* m_lclDsc; + + Visitor(Compiler* compiler, unsigned lclNum) + : GenTreeVisitor(compiler) + , m_lclNum(lclNum) + { + m_lclDsc = compiler->lvaGetDesc(lclNum); + assert(!m_lclDsc->IsAddressExposed()); + } + + Compiler::fgWalkResult PreOrderVisit(GenTree** use, GenTree* user) + { + GenTree* node = *use; + if ((node->gtFlags & GTF_ASG) == 0) + { + return WALK_SKIP_SUBTREES; + } + + if (node->OperIsLocalStore()) + { + if (node->AsLclVarCommon()->GetLclNum() == m_lclNum) + { + return WALK_ABORT; + } + + if (m_lclDsc->lvIsStructField && (node->AsLclVarCommon()->GetLclNum() == m_lclDsc->lvParentLcl)) + { + // Store to parent local also affects the field + return WALK_ABORT; + } + + if (m_lclDsc->lvPromoted && (node->AsLclVarCommon()->GetLclNum() >= m_lclDsc->lvFieldLclStart) && + (node->AsLclVarCommon()->GetLclNum() < m_lclDsc->lvFieldLclStart + m_lclDsc->lvFieldCnt)) + { + // Store to field also affects the parent + return WALK_ABORT; + } + } + + return WALK_CONTINUE; + } + }; + + Visitor visitor(this, lclNum); + return visitor.WalkTree(&tree, nullptr) == WALK_ABORT; +} + #ifdef DEBUG bool GenTree::OperSupportsReverseOpEvalOrder(Compiler* comp) const { diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index 383a1b425c2b37..508735fa272228 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -331,23 +331,18 @@ bool Compiler::optIsLoopTestEvalIntoTemp(Statement* testStmt, Statement** newTes } //---------------------------------------------------------------------------------- -// optExtractInitTestIncr: -// Extract the "init", "test" and "incr" nodes of the loop. +// optExtractTestIncr: +// Extract the "test" and "incr" nodes of the loop. // // Arguments: -// pInitBlock - [IN/OUT] *pInitBlock is the loop head block on entry, and is set to the initBlock on exit, -// if `**ppInit` is non-null. // cond - A BBJ_COND block that exits the loop // header - Loop header block -// ppInit - [out] The init stmt of the loop if found. // ppTest - [out] The test stmt of the loop if found. // ppIncr - [out] The incr stmt of the loop if found. // // Return Value: -// The results are put in "ppInit", "ppTest" and "ppIncr" if the method +// The results are put in "ppTest" and "ppIncr" if the method // returns true. Returns false if the information can't be extracted. -// Extracting the `init` is optional; if one is not found, *ppInit is set -// to nullptr. Return value will never be false if `init` is not found. // // Operation: // Check if the "test" stmt is last stmt in an exiting BBJ_COND block of the loop. Try to find the "incr" stmt. @@ -357,11 +352,8 @@ bool Compiler::optIsLoopTestEvalIntoTemp(Statement* testStmt, Statement** newTes // This method just retrieves what it thinks is the "test" node, // the callers are expected to verify that "iterVar" is used in the test. // -bool Compiler::optExtractInitTestIncr( - BasicBlock** pInitBlock, BasicBlock* cond, BasicBlock* header, GenTree** ppInit, GenTree** ppTest, GenTree** ppIncr) +bool Compiler::optExtractTestIncr(BasicBlock* cond, BasicBlock* header, GenTree** ppTest, GenTree** ppIncr) { - assert(pInitBlock != nullptr); - assert(ppInit != nullptr); assert(ppTest != nullptr); assert(ppIncr != nullptr); @@ -396,57 +388,6 @@ bool Compiler::optExtractInitTestIncr( assert(testStmt != incrStmt); - // Find the last statement in the loop pre-header which we expect to be the initialization of - // the loop iterator. - BasicBlock* initBlock = *pInitBlock; - Statement* phdrStmt = initBlock->firstStmt(); - if (phdrStmt == nullptr) - { - // When we build the loops, we canonicalize by introducing loop pre-headers for all loops. - // If we are rebuilding the loops, we would already have the pre-header block introduced - // the first time, which might be empty if no hoisting has yet occurred. In this case, look a - // little harder for the possible loop initialization statement. - if (initBlock->KindIs(BBJ_ALWAYS) && initBlock->TargetIs(header)) - { - BasicBlock* uniquePred = initBlock->GetUniquePred(this); - if (uniquePred != nullptr) - { - initBlock = uniquePred; - phdrStmt = initBlock->firstStmt(); - } - } - } - - if (phdrStmt != nullptr) - { - Statement* initStmt = phdrStmt->GetPrevStmt(); - noway_assert(initStmt != nullptr && (initStmt->GetNextStmt() == nullptr)); - - // If it is a duplicated loop condition, skip it. - if (initStmt->GetRootNode()->OperIs(GT_JTRUE)) - { - bool doGetPrev = true; - if (opts.optRepeat) - { - // Previous optimization passes may have inserted compiler-generated - // statements other than duplicated loop conditions. - doGetPrev = (initStmt->GetPrevStmt() != nullptr); - } - if (doGetPrev) - { - initStmt = initStmt->GetPrevStmt(); - } - noway_assert(initStmt != nullptr); - } - - *ppInit = initStmt->GetRootNode(); - *pInitBlock = initBlock; - } - else - { - *ppInit = nullptr; - } - *ppTest = testStmt->GetRootNode(); *ppIncr = incrStmt->GetRootNode(); From c951c2473f8285605615a0f6e3f3bfa44a8cd190 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Wed, 10 Sep 2025 17:52:30 +0200 Subject: [PATCH 2/3] JIT: Avoid inverting already-inverted loops that are IV tested Graph-based loop inversion works by inverting the loop such that we do not jump into the loop to immediately test a condition. However, we are not detecting the case where the loop is already inverted because its latch is an exit that tests a different condition. If the loop has multiple exits that means we may end up creating a suboptimal latch condition. Detect this case based on the pattern-based IV analysis that we already have. --- src/coreclr/jit/optimizer.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index f3bafc6dcfcc63..9e2255b068405c 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -1839,6 +1839,18 @@ bool Compiler::optTryInvertWhileLoop(FlowGraphNaturalLoop* loop) return false; } + // There may be multiple exits, and one of the other exits may also be a + // latch. That latch could be preferable to leave (for example because it + // is an IV test). + NaturalLoopIterInfo iterInfo; + if (loop->AnalyzeIteration(&iterInfo) && + (iterInfo.TestBlock->TrueTargetIs(loop->GetHeader()) != iterInfo.TestBlock->FalseTargetIs(loop->GetHeader()))) + { + // Test block is both a latch and exit, so the loop is already inverted in a preferable way. + JITDUMP("No loop-inversion for " FMT_LP " since it is already inverted (with an IV test)\n", loop->GetIndex()); + return false; + } + JITDUMP("Condition in block " FMT_BB " of loop " FMT_LP " is a candidate for duplication to invert the loop\n", condBlock->bbNum, loop->GetIndex()); From 8b4954cf4c1096c89541fb6515254c32b4dd5bb9 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Fri, 12 Sep 2025 11:39:55 +0200 Subject: [PATCH 3/3] Clean up --- src/coreclr/jit/compiler.h | 3 +-- src/coreclr/jit/flowgraph.cpp | 2 +- src/coreclr/jit/optimizer.cpp | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 125005128dccaf..a79d82d01f1145 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -7065,8 +7065,7 @@ class Compiler bool optIsLoopTestEvalIntoTemp(Statement* testStmt, Statement** newTestStmt); unsigned optIsLoopIncrTree(GenTree* incr); - bool optExtractTestIncr( - BasicBlock* bottom, BasicBlock* top, GenTree** ppTest, GenTree** ppIncr); + bool optExtractTestIncr(BasicBlock* cond, GenTree** ppTest, GenTree** ppIncr); void optSetMappedBlockTargets(BasicBlock* blk, BasicBlock* newBlk, diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index eeee96575ccfa0..dc7e334b309b0f 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -5519,7 +5519,7 @@ bool FlowGraphNaturalLoop::AnalyzeIteration(NaturalLoopIterInfo* info) } GenTree* iterTree = nullptr; - if (!comp->optExtractTestIncr(cond, m_header, &test, &iterTree)) + if (!comp->optExtractTestIncr(cond, &test, &iterTree)) { JITDUMP(" Could not extract an IV\n"); continue; diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index 9e2255b068405c..d538ca44b2413d 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -336,7 +336,6 @@ bool Compiler::optIsLoopTestEvalIntoTemp(Statement* testStmt, Statement** newTes // // Arguments: // cond - A BBJ_COND block that exits the loop -// header - Loop header block // ppTest - [out] The test stmt of the loop if found. // ppIncr - [out] The incr stmt of the loop if found. // @@ -352,7 +351,7 @@ bool Compiler::optIsLoopTestEvalIntoTemp(Statement* testStmt, Statement** newTes // This method just retrieves what it thinks is the "test" node, // the callers are expected to verify that "iterVar" is used in the test. // -bool Compiler::optExtractTestIncr(BasicBlock* cond, BasicBlock* header, GenTree** ppTest, GenTree** ppIncr) +bool Compiler::optExtractTestIncr(BasicBlock* cond, GenTree** ppTest, GenTree** ppIncr) { assert(ppTest != nullptr); assert(ppIncr != nullptr);