Skip to content

JIT: Avoid unnecessary write backs during physical promotion #112949

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
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/coreclr/jit/bitsetasshortlong.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class BitSetOps</*BitSetType*/ BitSetShortLongRep,
static bool TryAddElemDLong(Env env, BitSetShortLongRep& bs, unsigned i);
static void RemoveElemDLong(Env env, BitSetShortLongRep& bs, unsigned i);
static void ClearDLong(Env env, BitSetShortLongRep& bs);
static void FillDLong(Env env, BitSetShortLongRep& bs);
static BitSetShortLongRep MakeUninitArrayBits(Env env);
static BitSetShortLongRep MakeEmptyArrayBits(Env env);
static BitSetShortLongRep MakeFullArrayBits(Env env);
Expand Down Expand Up @@ -136,6 +137,19 @@ class BitSetOps</*BitSetType*/ BitSetShortLongRep,
}
}

static void FillD(Env env, BitSetShortLongRep& bs)
{
if (IsShort(env))
{
bs = (BitSetShortLongRep)size_t(-1);
}
else
{
assert(bs != UninitVal());
FillDLong(env, bs);
}
}

static BitSetShortLongRep MakeSingleton(Env env, unsigned bitNum)
{
assert(bitNum < BitSetTraits::GetSize(env));
Expand Down Expand Up @@ -865,6 +879,20 @@ void BitSetOps</*BitSetType*/ BitSetShortLongRep,
}
}

template <typename Env, typename BitSetTraits>
void BitSetOps</*BitSetType*/ BitSetShortLongRep,
/*Brand*/ BSShortLong,
/*Env*/ Env,
/*BitSetTraits*/ BitSetTraits>::FillDLong(Env env, BitSetShortLongRep& bs)
{
assert(!IsShort(env));
unsigned len = BitSetTraits::GetArrSize(env);
for (unsigned i = 0; i < len; i++)
{
bs[i] = size_t(-1);
}
}

template <typename Env, typename BitSetTraits>
BitSetShortLongRep BitSetOps</*BitSetType*/ BitSetShortLongRep,
/*Brand*/ BSShortLong,
Expand Down
23 changes: 23 additions & 0 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -2514,6 +2514,29 @@ struct LoopSideEffects
void AddModifiedElemType(Compiler* comp, CORINFO_CLASS_HANDLE structHnd);
};

// Data structure that keeps track of local definitions inside loops.
class LoopDefinitions
{
typedef JitHashTable<unsigned, JitSmallPrimitiveKeyFuncs<unsigned>, bool> LocalDefinitionsMap;

FlowGraphNaturalLoops* m_loops;
// For every loop, we track all definitions exclusive to that loop.
// Definitions in descendant loops are not kept in their ancestor's maps.
LocalDefinitionsMap** m_maps;
// Blocks whose IR we have visited to find local definitions in.
BitVec m_visitedBlocks;

LocalDefinitionsMap* GetOrCreateMap(FlowGraphNaturalLoop* loop);

template <typename TFunc>
bool VisitLoopNestMaps(FlowGraphNaturalLoop* loop, TFunc& func);
public:
LoopDefinitions(FlowGraphNaturalLoops* loops);

template <typename TFunc>
void VisitDefinedLocalNums(FlowGraphNaturalLoop* loop, TFunc func);
};

// The following holds information about instr offsets in terms of generated code.

enum class IPmappingDscKind
Expand Down
52 changes: 52 additions & 0 deletions src/coreclr/jit/compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5205,6 +5205,58 @@ BasicBlockVisit FlowGraphNaturalLoop::VisitRegularExitBlocks(TFunc func)
return BasicBlockVisit::Continue;
}

//------------------------------------------------------------------------------
// LoopDefinitions:VisitLoopNestMaps:
// Visit all occurrence maps of the specified loop nest.
//
// Type parameters:
// TFunc - bool(LocalToOccurrenceMap*) functor that returns true to continue
// the visit and false to abort.
//
// Parameters:
// loop - Root loop of the nest.
// func - Functor instance
//
// Returns:
// True if the visit completed; false if "func" returned false for any map.
//
template <typename TFunc>
bool LoopDefinitions::VisitLoopNestMaps(FlowGraphNaturalLoop* loop, TFunc& func)
{
for (FlowGraphNaturalLoop* child = loop->GetChild(); child != nullptr; child = child->GetSibling())
{
if (!VisitLoopNestMaps(child, func))
{
return false;
}
}

return func(GetOrCreateMap(loop));
}

//------------------------------------------------------------------------------
// LoopDefinitions:VisitDefinedLocalNums:
// Call a callback for all locals that are defined in the specified loop.
//
// Parameters:
// loop - The loop
// func - The callback
//
template <typename TFunc>
void LoopDefinitions::VisitDefinedLocalNums(FlowGraphNaturalLoop* loop, TFunc func)
{
auto visit = [=, &func](LocalDefinitionsMap* map) {
for (unsigned lclNum : LocalDefinitionsMap::KeyIteration(map))
{
func(lclNum);
}

return true;
};

VisitLoopNestMaps(loop, visit);
}

/*****************************************************************************/
#endif //_COMPILER_HPP_
/*****************************************************************************/
77 changes: 1 addition & 76 deletions src/coreclr/jit/lclmorph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,29 +175,6 @@ void Compiler::fgSequenceLocals(Statement* stmt)
seq.Sequence(stmt);
}

// Data structure that keeps track of local definitions inside loops.
class LoopDefinitions
{
typedef JitHashTable<unsigned, JitSmallPrimitiveKeyFuncs<unsigned>, bool> LocalDefinitionsMap;

FlowGraphNaturalLoops* m_loops;
// For every loop, we track all definitions exclusive to that loop.
// Definitions in descendant loops are not kept in their ancestor's maps.
LocalDefinitionsMap** m_maps;
// Blocks whose IR we have visited to find local definitions in.
BitVec m_visitedBlocks;

LocalDefinitionsMap* GetOrCreateMap(FlowGraphNaturalLoop* loop);

template <typename TFunc>
bool VisitLoopNestMaps(FlowGraphNaturalLoop* loop, TFunc& func);
public:
LoopDefinitions(FlowGraphNaturalLoops* loops);

template <typename TFunc>
void VisitDefinedLocalNums(FlowGraphNaturalLoop* loop, TFunc func);
};

LoopDefinitions::LoopDefinitions(FlowGraphNaturalLoops* loops)
: m_loops(loops)
{
Expand Down Expand Up @@ -263,7 +240,7 @@ LoopDefinitions::LocalDefinitionsMap* LoopDefinitions::GetOrCreateMap(FlowGraphN
fgWalkResult PreOrderVisit(GenTree** use, GenTree* user)
{
GenTreeLclVarCommon* lcl = (*use)->AsLclVarCommon();
if (!lcl->OperIsLocalStore())
if (!lcl->OperIsLocalStore() && !lcl->OperIs(GT_LCL_ADDR))
{
return Compiler::WALK_CONTINUE;
}
Expand Down Expand Up @@ -320,58 +297,6 @@ LoopDefinitions::LocalDefinitionsMap* LoopDefinitions::GetOrCreateMap(FlowGraphN
return map;
}

//------------------------------------------------------------------------------
// LoopDefinitions:VisitLoopNestMaps:
// Visit all occurrence maps of the specified loop nest.
//
// Type parameters:
// TFunc - bool(LocalToOccurrenceMap*) functor that returns true to continue
// the visit and false to abort.
//
// Parameters:
// loop - Root loop of the nest.
// func - Functor instance
//
// Returns:
// True if the visit completed; false if "func" returned false for any map.
//
template <typename TFunc>
bool LoopDefinitions::VisitLoopNestMaps(FlowGraphNaturalLoop* loop, TFunc& func)
{
for (FlowGraphNaturalLoop* child = loop->GetChild(); child != nullptr; child = child->GetSibling())
{
if (!VisitLoopNestMaps(child, func))
{
return false;
}
}

return func(GetOrCreateMap(loop));
}

//------------------------------------------------------------------------------
// LoopDefinitions:VisitDefinedLocalNums:
// Call a callback for all locals that are defined in the specified loop.
//
// Parameters:
// loop - The loop
// func - The callback
//
template <typename TFunc>
void LoopDefinitions::VisitDefinedLocalNums(FlowGraphNaturalLoop* loop, TFunc func)
{
auto visit = [=, &func](LocalDefinitionsMap* map) {
for (unsigned lclNum : LocalDefinitionsMap::KeyIteration(map))
{
func(lclNum);
}

return true;
};

VisitLoopNestMaps(loop, visit);
}

struct LocalEqualsLocalAddrAssertion
{
// Local num on the LHS
Expand Down
Loading
Loading