Skip to content
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

JIT: Port loop cloning to the new loop representation #95326

Merged
merged 14 commits into from
Dec 5, 2023
Merged
106 changes: 83 additions & 23 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -1996,6 +1996,42 @@ class FlowGraphDfsTree
bool IsAncestor(BasicBlock* ancestor, BasicBlock* descendant) const;
};

struct NaturalLoopIterInfo
{
unsigned IterVar = BAD_VAR_NUM;
int ConstInitValue = 0;
BasicBlock* InitBlock = nullptr;
GenTree* TestTree = nullptr;
GenTree* IterTree = nullptr;
bool HasConstInit : 1;
bool HasConstLimit : 1;
bool HasSimdLimit : 1;
bool HasInvariantLocalLimit : 1;
bool HasArrayLengthLimit : 1;

NaturalLoopIterInfo()
: HasConstInit(false)
, HasConstLimit(false)
, HasSimdLimit(false)
, HasInvariantLocalLimit(false)
, HasArrayLengthLimit(false)
{
}

int IterConst();
genTreeOps IterOper();
var_types IterOperType();
bool IsReversed();
genTreeOps TestOper();
bool IsIncreasingLoop();
bool IsDecreasingLoop();
GenTree* Iterator();
GenTree* Limit();
int ConstLimit();
unsigned VarLimit();
bool ArrLenLimit(Compiler* comp, ArrIndex* index);
};

class FlowGraphNaturalLoop
{
friend class FlowGraphNaturalLoops;
Expand All @@ -2018,6 +2054,14 @@ class FlowGraphNaturalLoop
bool TryGetLoopBlockBitVecIndex(BasicBlock* block, unsigned* pIndex);

BitVecTraits LoopBlockTraits();

template<typename TFunc>
bool VisitDefs(TFunc func);

GenTreeLclVarCommon* FindDef(unsigned lclNum);

void MatchInit(NaturalLoopIterInfo* info, BasicBlock* initBlock, GenTree* init);
bool MatchLimit(NaturalLoopIterInfo* info, GenTree* test);
public:
BasicBlock* GetHeader() const
{
Expand Down Expand Up @@ -2056,6 +2100,8 @@ class FlowGraphNaturalLoop

bool ContainsBlock(BasicBlock* block);

unsigned NumLoopBlocks();

template<typename TFunc>
BasicBlockVisit VisitLoopBlocksReversePostOrder(TFunc func);

Expand All @@ -2064,6 +2110,16 @@ class FlowGraphNaturalLoop

template<typename TFunc>
BasicBlockVisit VisitLoopBlocks(TFunc func);

template<typename TFunc>
BasicBlockVisit VisitLoopBlocksLexical(TFunc func);

BasicBlock* GetLexicallyTopMostBlock();
BasicBlock* GetLexicallyBottomMostBlock();

bool AnalyzeIteration(NaturalLoopIterInfo* info);

bool HasDef(unsigned lclNum);
};

class FlowGraphNaturalLoops
Expand Down Expand Up @@ -4713,6 +4769,10 @@ class Compiler
unsigned fgDomBBcount; // # of BBs for which we have dominator and reachability information
BasicBlock** fgBBReversePostorder; // Blocks in reverse postorder
FlowGraphDfsTree* m_dfs;
FlowGraphNaturalLoops* m_loops;
struct LoopDsc;
LoopDsc** m_newToOldLoop;
FlowGraphNaturalLoop** m_oldToNewLoop;

// After the dominance tree is computed, we cache a DFS preorder number and DFS postorder number to compute
// dominance queries in O(1). fgDomTreePreOrder and fgDomTreePostOrder are arrays giving the block's preorder and
Expand Down Expand Up @@ -6558,7 +6618,7 @@ class Compiler
void optFindLoops();

PhaseStatus optCloneLoops();
void optCloneLoop(unsigned loopInd, LoopCloneContext* context);
void optCloneLoop(FlowGraphNaturalLoop* loop, LoopCloneContext* context);
PhaseStatus optUnrollLoops(); // Unrolls loops (needs to have cost info)
void optRemoveRedundantZeroInits();
PhaseStatus optIfConversion(); // If conversion
Expand Down Expand Up @@ -6870,7 +6930,7 @@ class Compiler
bool optComputeIterInfo(GenTree* incr, BasicBlock* from, BasicBlock* to, unsigned* pIterVar);
bool optPopulateInitInfo(unsigned loopInd, BasicBlock* initBlock, GenTree* init, unsigned iterVar);
bool optExtractInitTestIncr(
BasicBlock** pInitBlock, BasicBlock* bottom, BasicBlock* exit, GenTree** ppInit, GenTree** ppTest, GenTree** ppIncr);
BasicBlock** pInitBlock, BasicBlock* bottom, BasicBlock* top, GenTree** ppInit, GenTree** ppTest, GenTree** ppIncr);

void optFindNaturalLoops();

Expand Down Expand Up @@ -7989,34 +8049,34 @@ class Compiler
public:
struct LoopCloneVisitorInfo
{
LoopCloneContext* context;
Statement* stmt;
const unsigned loopNum;
const bool cloneForArrayBounds;
const bool cloneForGDVTests;
LoopCloneVisitorInfo(LoopCloneContext* context,
unsigned loopNum,
Statement* stmt,
bool cloneForArrayBounds,
bool cloneForGDVTests)
LoopCloneContext* context;
Statement* stmt;
FlowGraphNaturalLoop* loop;
const bool cloneForArrayBounds;
const bool cloneForGDVTests;
LoopCloneVisitorInfo(LoopCloneContext* context,
FlowGraphNaturalLoop* loop,
Statement* stmt,
bool cloneForArrayBounds,
bool cloneForGDVTests)
: context(context)
, stmt(nullptr)
, loopNum(loopNum)
, loop(loop)
, cloneForArrayBounds(cloneForArrayBounds)
, cloneForGDVTests(cloneForGDVTests)
{
}
};

bool optIsStackLocalInvariant(unsigned loopNum, unsigned lclNum);
bool optIsStackLocalInvariant(FlowGraphNaturalLoop* loop, unsigned lclNum);
bool optExtractArrIndex(GenTree* tree, ArrIndex* result, unsigned lhsNum, bool* topLevelIsFinal);
bool optReconstructArrIndexHelp(GenTree* tree, ArrIndex* result, unsigned lhsNum, bool* topLevelIsFinal);
bool optReconstructArrIndex(GenTree* tree, ArrIndex* result);
bool optIdentifyLoopOptInfo(unsigned loopNum, LoopCloneContext* context);
bool optIdentifyLoopOptInfo(FlowGraphNaturalLoop* loop, LoopCloneContext* context);
static fgWalkPreFn optCanOptimizeByLoopCloningVisitor;
fgWalkResult optCanOptimizeByLoopCloning(GenTree* tree, LoopCloneVisitorInfo* info);
bool optObtainLoopCloningOpts(LoopCloneContext* context);
bool optIsLoopClonable(unsigned loopInd);
bool optIsLoopClonable(FlowGraphNaturalLoop* loop, LoopCloneContext* context);
bool optCheckLoopCloningGDVTestProfitable(GenTreeOp* guard, LoopCloneVisitorInfo* info);
bool optIsHandleOrIndirOfHandle(GenTree* tree, GenTreeFlags handleType);

Expand All @@ -8025,13 +8085,13 @@ class Compiler
#ifdef DEBUG
void optDebugLogLoopCloning(BasicBlock* block, Statement* insertBefore);
#endif
void optPerformStaticOptimizations(unsigned loopNum, LoopCloneContext* context DEBUGARG(bool fastPath));
bool optComputeDerefConditions(unsigned loopNum, LoopCloneContext* context);
bool optDeriveLoopCloningConditions(unsigned loopNum, LoopCloneContext* context);
BasicBlock* optInsertLoopChoiceConditions(LoopCloneContext* context,
unsigned loopNum,
BasicBlock* slowHead,
BasicBlock* insertAfter);
void optPerformStaticOptimizations(FlowGraphNaturalLoop* loop, LoopCloneContext* context DEBUGARG(bool fastPath));
bool optComputeDerefConditions(FlowGraphNaturalLoop* loop, LoopCloneContext* context);
bool optDeriveLoopCloningConditions(FlowGraphNaturalLoop* loop, LoopCloneContext* context);
BasicBlock* optInsertLoopChoiceConditions(LoopCloneContext* context,
FlowGraphNaturalLoop* loop,
BasicBlock* slowHead,
BasicBlock* insertAfter);

protected:
ssize_t optGetArrayRefScaleAndIndex(GenTree* mul, GenTree** pIndex DEBUGARG(bool bRngChk));
Expand Down
41 changes: 41 additions & 0 deletions src/coreclr/jit/compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5015,6 +5015,47 @@ BasicBlockVisit FlowGraphNaturalLoop::VisitLoopBlocks(TFunc func)
return VisitLoopBlocksReversePostOrder(func);
}

//------------------------------------------------------------------------------
// FlowGraphNaturalLoop::VisitLoopBlocksLexical: Visit the loop's blocks in
// lexical order.
//
// Type parameters:
// TFunc - Callback functor type
//
// Arguments:
// func - Callback functor that takes a BasicBlock* and returns a
// BasicBlockVisit.
//
// Returns:
// BasicBlockVisit that indicated whether the visit was aborted by the
// callback or whether all blocks were visited.
//
template <typename TFunc>
BasicBlockVisit FlowGraphNaturalLoop::VisitLoopBlocksLexical(TFunc func)
{
BasicBlock* top = m_header;
BasicBlock* bottom = m_header;
VisitLoopBlocks([&](BasicBlock* block) {
if (block->bbNum < top->bbNum)
top = block;
if (block->bbNum > bottom->bbNum)
bottom = block;
return BasicBlockVisit::Continue;
});

BasicBlock* block = top;
while (true)
{
if (ContainsBlock(block) && (func(block) == BasicBlockVisit::Abort))
return BasicBlockVisit::Abort;

if (block == bottom)
return BasicBlockVisit::Continue;

block = block->Next();
}
}

/*****************************************************************************/
#endif //_COMPILER_HPP_
/*****************************************************************************/
3 changes: 2 additions & 1 deletion src/coreclr/jit/fgbasic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ void Compiler::fgInit()
fgBBVarSetsInited = false;
fgReturnCount = 0;

m_dfs = nullptr;
m_dfs = nullptr;
m_loops = nullptr;

// Initialize BlockSet data.
fgCurBBEpoch = 0;
Expand Down
Loading
Loading