Skip to content

Commit 932be31

Browse files
pratikasharigcbot
authored andcommitted
Restrict augmentation live-intervals to "home" function only
Consider following program: main: a = call foo = a b = call foo = b foo: c = 1 return a, b are both live in foo due to IPA. Howver, their liveness is temporally disjoint so they shouldn't be marked as interfering. However, a and c as well as b and c must be marked as interfering. As per logic prior to this PR, 2 sub-intervals will be created for a (b). First live-interval extends from definition of a (b) to use and second on exists from start to end of foo() given that a (b) is live-in/live-out of foo(). This PR introduces concept of "home" function. Each G4_Declare has a "home" function that's either nullptr or pointer to an actual FuncInfo* instance. When a G4_Declare is defined or used in a single function, its "home" function is set to that function's FuncInfo instance. Whereas when a G4_Declare is referenced in multiple functions (eg, kernel and sub), its "home" function is not unique and is set to nullptr. In augmentation, live-interval construction for a variable depends on its "home" function. If "home" function is set to nullptr (ie, args, retval) then live-intervals are constructed across functions. This means one sub-interval may be in one function and another sub-interval may be in another function. Whereas when "home" location contains a non-nullptr value, we restrict live-intervals to only be contained in "home" function. It means that in above example, variables a and b have their home location set to kernel and a single non-overlapping live-interval is created for each. Since no live-interval is created for these in function foo(), they don't overlap and therefore there's no interference between them.
1 parent 53e28e8 commit 932be31

File tree

5 files changed

+210
-16
lines changed

5 files changed

+210
-16
lines changed

visa/GraphColor.cpp

Lines changed: 119 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2770,6 +2770,56 @@ void GlobalRA::getBankAlignment(LiveRange *lr, BankAlign &align) {
27702770
}
27712771
}
27722772

2773+
// Compute homeFunc for dcl. Following rules are used:
2774+
// 1. A variable that's defined or used in a single function has
2775+
// that function as its home function.
2776+
// 2. A variable that's defined or used across functions (eg,
2777+
// args, retval) have their home function set to nullptr.
2778+
// 3. homeFunc is set only on root G4_Declare.
2779+
FuncInfo *Augmentation::computeHomeFunc(G4_Declare *dcl) {
2780+
vISA_ASSERT(!dcl->getAliasDeclare(), "root dcl expected");
2781+
// If there are no subroutines then all dcls have kernel as home function
2782+
if (!hasSubroutines)
2783+
return kernel.fg.kernelInfo;
2784+
2785+
if (hasUniqueFuncHome(dcl))
2786+
return getUniqueFuncHome(dcl);
2787+
2788+
FuncInfo *homeFunction = nullptr;
2789+
// Live-ins to kernel are modeled as being implicitly defined in kernel.
2790+
if (dcl->isInput())
2791+
homeFunction = kernel.fg.kernelInfo;
2792+
auto *defs = refs.getDefs(dcl);
2793+
if (defs) {
2794+
for (auto &def : *defs) {
2795+
auto *bb = std::get<1>(def);
2796+
auto *curDefFunc = bbToFunc.at(bb);
2797+
if (!homeFunction) {
2798+
homeFunction = curDefFunc;
2799+
continue;
2800+
} else if (homeFunction != curDefFunc) {
2801+
return nullptr;
2802+
}
2803+
}
2804+
}
2805+
2806+
auto *uses = refs.getUses(dcl);
2807+
if (uses) {
2808+
for (auto &use : *uses) {
2809+
auto *bb = std::get<1>(use);
2810+
auto *curUseFunc = bbToFunc.at(bb);
2811+
if (!homeFunction) {
2812+
homeFunction = curUseFunc;
2813+
continue;
2814+
} else if (homeFunction != curUseFunc) {
2815+
return nullptr;
2816+
}
2817+
}
2818+
}
2819+
2820+
return homeFunction;
2821+
}
2822+
27732823
void Augmentation::populateFuncMaps() {
27742824
vISA_ASSERT(kernel.fg.getBBList().back()->size() > 0, "last BB empty");
27752825
instToFunc.resize(kernel.fg.getBBList().back()->back()->getLexicalId() + 1);
@@ -2783,10 +2833,24 @@ void Augmentation::populateFuncMaps() {
27832833
}
27842834
}
27852835

2836+
void Augmentation::populateHomeFunc() {
2837+
// Assume last G4_Declare has max declId
2838+
homeFunc.resize(kernel.Declares.back()->getDeclId() + 1);
2839+
for (auto dcl : kernel.Declares) {
2840+
if (dcl->getAliasDeclare())
2841+
dcl = dcl->getRootDeclare();
2842+
auto *func = computeHomeFunc(dcl);
2843+
vISA_ASSERT(!hasUniqueFuncHome(dcl) || getUniqueFuncHome(dcl) == func,
2844+
"different home func set");
2845+
homeFunc[dcl->getDeclId()] = func;
2846+
}
2847+
}
2848+
27862849
Augmentation::Augmentation(Interference &i, const LivenessAnalysis &l,
27872850
GlobalRA &g)
27882851
: kernel(g.kernel), intf(i), gra(g), liveAnalysis(l), lrs(g.incRA.getLRs()),
2789-
fcallRetMap(g.fcallRetMap), refs(g.kernel, false, false, true),
2852+
fcallRetMap(g.fcallRetMap),
2853+
refs(g.kernel, false, false, true, &g.pointsToAnalysis),
27902854
hasSubroutines(kernel.fg.sortedFuncTable.size() > 0 &&
27912855
g.kernel.getOption(vISA_NewAugmentation)) {
27922856
useGenericAugAlign =
@@ -3813,6 +3877,16 @@ void Augmentation::buildUnknownArgRetval() {
38133877
}
38143878
}
38153879

3880+
bool Augmentation::hasUniqueFuncHome(G4_Declare *dcl) const {
3881+
auto *homeFunction = homeFunc[dcl->getDeclId()];
3882+
return homeFunction != nullptr;
3883+
}
3884+
3885+
FuncInfo* Augmentation::getUniqueFuncHome(G4_Declare* dcl) const {
3886+
vISA_ASSERT(hasUniqueFuncHome(dcl), "expecting unique home func");
3887+
return homeFunc[dcl->getDeclId()];
3888+
}
3889+
38163890
void Augmentation::startIntervalForLiveIn(FuncInfo *funcInfo, G4_BB *bb) {
38173891
// Start live-in intervals
38183892
auto liveInBB = liveAnalysis.getLiveAtEntry(bb) & liveAnalysis.globalVars;
@@ -3821,6 +3895,9 @@ void Augmentation::startIntervalForLiveIn(FuncInfo *funcInfo, G4_BB *bb) {
38213895
if (isUnknownArgOrRetval(dcl))
38223896
continue;
38233897

3898+
if (hasUniqueFuncHome(dcl) && getUniqueFuncHome(dcl) != funcInfo)
3899+
continue;
3900+
38243901
vISA_ASSERT(bb->size() > 0, "empty instlist");
38253902
vISA_ASSERT(funcInfo == kernel.fg.kernelInfo ||
38263903
argsPerSub.count(funcInfo) > 0 ||
@@ -4022,7 +4099,7 @@ void Augmentation::handlePred(FuncInfo* funcInfo, G4_INST *inst) {
40224099
}
40234100
}
40244101

4025-
void Augmentation::endIntervalForLiveOut(G4_BB *bb) {
4102+
void Augmentation::endIntervalForLiveOut(FuncInfo* funcInfo, G4_BB *bb) {
40264103
auto liveOutBB = liveAnalysis.getLiveAtExit(bb) & liveAnalysis.globalVars;
40274104
if (bb->isEndWithCall() && liveAnalysis.livenessClass(G4_GRF)) {
40284105
// reset bit for RET__loc as we handle it specially later to
@@ -4050,6 +4127,10 @@ void Augmentation::endIntervalForLiveOut(G4_BB *bb) {
40504127
G4_Declare *dcl = lrs[i]->getDcl()->getRootDeclare();
40514128
if (isUnknownArgOrRetval(dcl))
40524129
continue;
4130+
4131+
if (hasUniqueFuncHome(dcl) && getUniqueFuncHome(dcl) != funcInfo)
4132+
continue;
4133+
40534134
vISA_ASSERT(bb->size() > 0, "empty instlist");
40544135
updateEndInterval(dcl, bb->back());
40554136
}
@@ -4079,7 +4160,7 @@ void Augmentation::handleNonReducibleExtension(FuncInfo *funcInfo) {
40794160
}
40804161
}
40814162
for (auto exitBB : SCCSucc) {
4082-
extendVarLiveness(exitBB, headBB->front());
4163+
extendVarLiveness(funcInfo, exitBB, headBB->front());
40834164
}
40844165
}
40854166
}
@@ -4118,7 +4199,7 @@ void Augmentation::handleLoopExtension(FuncInfo *funcInfo) {
41184199
std::cout << "==> Extend live-in for BB" << exitBB->getId() << "\n";
41194200
exitBB->emit(std::cout);
41204201
});
4121-
extendVarLiveness(exitBB, startInst);
4202+
extendVarLiveness(funcInfo, exitBB, startInst);
41224203
}
41234204
}
41244205
}
@@ -4133,6 +4214,10 @@ void Augmentation::handleLoopExtension(FuncInfo *funcInfo) {
41334214

41344215
for (auto i : globalsLiveInAndLiveOut) {
41354216
auto *dcl = lrs[i]->getDcl()->getRootDeclare();
4217+
// If dcl has non-nullptr home function then extend liveness only
4218+
// in same function.
4219+
if (hasUniqueFuncHome(dcl) && getUniqueFuncHome(dcl) != funcInfo)
4220+
continue;
41364221

41374222
updateEndInterval(dcl, endBB->back());
41384223
VISA_DEBUG_VERBOSE({
@@ -4150,11 +4235,16 @@ void Augmentation::handleLoopExtension(FuncInfo *funcInfo) {
41504235
}
41514236

41524237
// Extend all variables that are live at bb entry to the given inst
4153-
void Augmentation::extendVarLiveness(G4_BB *bb, G4_INST *inst) {
4238+
void Augmentation::extendVarLiveness(FuncInfo *funcInfo, G4_BB *bb,
4239+
G4_INST *inst) {
41544240
auto liveAtEntryBB =
41554241
liveAnalysis.getLiveAtEntry(bb) & liveAnalysis.globalVars;
41564242
for (auto i : liveAtEntryBB) {
41574243
G4_Declare *dcl = lrs[i]->getDcl()->getRootDeclare();
4244+
// If dcl has non-nullptr home function then extend liveness only
4245+
// in same function.
4246+
if (hasUniqueFuncHome(dcl) && getUniqueFuncHome(dcl) != funcInfo)
4247+
continue;
41584248

41594249
if (!kernel.fg.isPseudoDcl(dcl)) {
41604250
// Extend ith live-interval
@@ -4181,7 +4271,7 @@ void Augmentation::buildLiveIntervals(FuncInfo* funcInfo) {
41814271
for (G4_BB *curBB : funcInfo->getBBList()) {
41824272
if (!curBB->empty()) {
41834273
startIntervalForLiveIn(funcInfo, curBB);
4184-
endIntervalForLiveOut(curBB);
4274+
endIntervalForLiveOut(funcInfo, curBB);
41854275
}
41864276

41874277
for (G4_INST *inst : *curBB) {
@@ -5041,6 +5131,8 @@ void Augmentation::discoverRetVal(FuncInfo *func) {
50415131
retValPerSub[func].insert(dcl);
50425132
if (retValInfo.subroutines.size() > 1)
50435133
retValInfo.retValType = RetValType::Unknown;
5134+
vISA_ASSERT(!hasUniqueFuncHome(dcl),
5135+
"retval cannot have non-nullptr home function");
50445136
}
50455137

50465138
if (kernel.getOption(vISA_VerifyAugmentation)) {
@@ -5057,7 +5149,8 @@ void Augmentation::discoverArgs(FuncInfo *func) {
50575149

50585150
SparseBitVector subArgs;
50595151
if (func == kernel.fg.kernelInfo)
5060-
subArgs = liveAnalysis.use_in[kernel.fg.getEntryBB()->getId()];
5152+
subArgs = liveAnalysis.use_in[kernel.fg.getEntryBB()->getId()] &
5153+
liveAnalysis.def_in[kernel.fg.getEntryBB()->getId()];
50615154
else
50625155
subArgs = liveAnalysis.args.at(func);
50635156

@@ -5074,6 +5167,10 @@ void Augmentation::discoverArgs(FuncInfo *func) {
50745167
if (argInfo.subroutines.size() > 1 &&
50755168
argInfo.argType == ArgType::DefBeforeEachCall)
50765169
argInfo.argType = ArgType::Unknown;
5170+
vISA_ASSERT(
5171+
argInfo.argType != ArgType::DefBeforeEachCall ||
5172+
!hasUniqueFuncHome(dcl),
5173+
"def before each call arg cannot have non-nullptr home function");
50775174
}
50785175

50795176

@@ -5113,6 +5210,16 @@ void Augmentation::dumpSortedIntervals() {
51135210
std::cout << " (LiveThroughArg)";
51145211
else if (isRegularRetVal(dcl))
51155212
std::cout << " (RegularRetVal)";
5213+
if (dcl->getDeclId() >= homeFunc.size()) {
5214+
std::cout << " @ (new var)";
5215+
}
5216+
else {
5217+
auto *homeFunction = homeFunc[dcl->getDeclId()];
5218+
if (!homeFunction)
5219+
std::cout << " @ (global)";
5220+
else
5221+
std::cout << " @ (func " << (int)homeFunction->getId() << ")";
5222+
}
51165223
std::cout << " - (" << gra.getIntervalStart(interval)->getLexicalId()
51175224
<< ", " << gra.getIntervalEnd(interval)->getLexicalId() << "]";
51185225
if (intervalsPerVar[dcl].size() > 1) {
@@ -5572,16 +5679,17 @@ void Augmentation::augmentIntfGraph() {
55725679
bool nonDefaultMaskDef = markNonDefaultMaskDef();
55735680

55745681
if (nonDefaultMaskDef == true) {
5575-
if (augWithHoles && kernel.fg.getNumFuncs() > 0)
5576-
populateFuncMaps();
5577-
55785682
if (augWithHoles) {
5683+
if (kernel.fg.getNumFuncs() > 0)
5684+
populateFuncMaps();
5685+
5686+
populateHomeFunc();
5687+
55795688
// Atleast one definition with non-default mask was found so
55805689
// perform steps to augment intf graph with such defs
55815690

55825691
// Discover and store subroutine arguments
55835692
if (hasSubroutines) {
5584-
55855693
for (auto &subroutine : kernel.fg.sortedFuncTable) {
55865694
discoverArgs(subroutine);
55875695
discoverRetVal(subroutine);

visa/GraphColor.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,17 @@ class Augmentation {
429429
std::unordered_map<G4_Declare *, std::unordered_set<FuncInfo *>> unknownArgRetvalRefs;
430430
std::unordered_map<G4_Declare *, std::unordered_set<FuncInfo *>> nonGRFRefs;
431431
std::unordered_map<G4_BB *, FuncInfo *> bbToFunc;
432+
// Store home function for given variable. Home function is defined as
433+
// function that contains explicit def or use of the variable. Each regular
434+
// variable has a unique home function. Arg/retval don't have a unique home
435+
// function as they're usually defined in caller and used in callee, ie
436+
// they're referenced in different functions.
437+
//
438+
// This vector is indexed by G4_Declare's dclId.
439+
//
440+
// It's assumed that augmentation doesn't require resizing this vector
441+
// despite inserting new SCALL dcls as they're all function local.
442+
std::vector<FuncInfo *> homeFunc;
432443
// Sadly, we don't have a way to map G4_INST to containing G4_BB.
433444
// So we create it in Augmentation using below vector. To get
434445
// FuncInfo* for a G4_INST, we dereference instToFunc using
@@ -439,6 +450,7 @@ class Augmentation {
439450
const bool hasSubroutines = false;
440451

441452
void populateFuncMaps();
453+
void populateHomeFunc();
442454
bool isSubroutineArg(G4_Declare *dcl) const {
443455
auto it = argsRetVal.find(dcl);
444456
if (it == argsRetVal.end())
@@ -484,6 +496,11 @@ class Augmentation {
484496
bool isUnknownRetVal(G4_Declare *dcl) const;
485497
bool isRegularRetVal(G4_Declare *dcl) const;
486498
bool isUnknownArgOrRetval(G4_Declare *dcl) const;
499+
FuncInfo *computeHomeFunc(G4_Declare *dcl);
500+
bool hasUniqueFuncHome(G4_Declare *dcl) const;
501+
FuncInfo *getUniqueFuncHome(G4_Declare *dcl) const;
502+
503+
void verifyHomeLocation();
487504

488505
bool updateDstMaskForGather(G4_INST *inst, std::vector<unsigned char> &mask);
489506
bool updateDstMaskForGatherRaw(G4_INST *inst,
@@ -522,12 +539,12 @@ class Augmentation {
522539
void handleCallSite(G4_BB *curBB, unsigned int &funcCnt);
523540
void handleDstOpnd(FuncInfo *funcInfo, G4_BB *curBB, G4_INST *inst);
524541
void handleCondMod(FuncInfo* funcInfo, G4_INST *inst);
525-
void endIntervalForLiveOut(G4_BB *bb);
542+
void endIntervalForLiveOut(FuncInfo *funcInfo, G4_BB *bb);
526543
void handleSrcOpnd(FuncInfo *funcInfo, G4_BB *curBB, G4_Operand *src);
527544
void handlePred(FuncInfo* funcInfo, G4_INST *inst);
528545
void handleNonReducibleExtension(FuncInfo *funcInfo);
529546
void handleLoopExtension(FuncInfo *funcInfo);
530-
void extendVarLiveness(G4_BB *bb, G4_INST *inst);
547+
void extendVarLiveness(FuncInfo *funcInfo, G4_BB *bb, G4_INST *inst);
531548
unsigned getEnd(const G4_Declare *dcl) const;
532549
bool isNoMask(const G4_Declare *dcl, unsigned size) const;
533550
bool isConsecutiveBits(const G4_Declare *dcl, unsigned size) const;

visa/LoopAnalysis.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ SPDX-License-Identifier: MIT
1111
#include "BitSet.h"
1212
#include "G4_BB.hpp"
1313
#include "G4_Kernel.hpp"
14+
#include "PointsToAnalysis.h"
1415

1516
using namespace vISA;
1617

@@ -1032,6 +1033,17 @@ void VarReferences::run() {
10321033
auto &Defs = VarRefs[topdcl].first;
10331034
Defs.push_back(std::make_tuple(inst, bb, lb, rb));
10341035
}
1036+
1037+
if (p2a && dst->isIndirect()) {
1038+
auto *pointees = p2a->getAllInPointsTo(topdcl->getRegVar());
1039+
vISA_ASSERT(pointees, "expecting valid pointee list");
1040+
for (const auto& pointee : *pointees) {
1041+
auto &Defs = VarRefs[pointee.var->getDeclare()->getRootDeclare()].first;
1042+
// lb, rb are both unknown for indirects
1043+
Defs.push_back(
1044+
std::make_tuple(inst, bb, UnknownBound, UnknownBound));
1045+
}
1046+
}
10351047
}
10361048

10371049
if (!onlyGRF) {
@@ -1057,6 +1069,16 @@ void VarReferences::run() {
10571069
auto &Uses = VarRefs[topdcl].second;
10581070
Uses.push_back(std::make_tuple(inst, bb));
10591071
}
1072+
1073+
if (p2a && src->isIndirect()) {
1074+
auto *pointees = p2a->getAllInPointsTo(topdcl->getRegVar());
1075+
vISA_ASSERT(pointees, "expecting valid pointee list");
1076+
for (const auto &pointee : *pointees) {
1077+
auto &Uses =
1078+
VarRefs[pointee.var->getDeclare()->getRootDeclare()].second;
1079+
Uses.push_back(std::make_tuple(inst, bb));
1080+
}
1081+
}
10601082
}
10611083
}
10621084

visa/LoopAnalysis.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ SPDX-License-Identifier: MIT
1616
namespace vISA {
1717
class G4_BB;
1818
class FlowGraph;
19+
class PointsToAnalysis;
1920

2021
// Top level Analysis class that each analysis needs to inherit.
2122
// Each inherited class needs to implement their own reset() and
@@ -91,19 +92,24 @@ class PostDom : public Analysis {
9192
};
9293

9394
// Computes and stores direct references of variables.
94-
// Indirects references are not computed here.
95+
// Indirects references are computed only if PointsToAnalysis instance
96+
// is valid.
9597
class VarReferences : public Analysis {
9698
public:
9799
VarReferences(G4_Kernel &k, bool GRF = false, bool bounds = true,
98-
bool pseudoKills = false)
100+
bool pseudoKills = false, PointsToAnalysis* p = nullptr)
99101
: kernel(k), onlyGRF(GRF), needBounds(bounds),
100-
reportPseudoKill(pseudoKills) {}
102+
reportPseudoKill(pseudoKills), p2a(p) {}
101103

102104
// Defs -> vector[tuple<inst, bb, lb, rb>]
103105
// Uses -> vector[tuple<inst, bb>]
106+
// TODO: Store G4_DstRegRegion instead of G4_INST* in Defs,
107+
// G4_SrcRegResion instead of G4_INST* in Uses
104108
using Defs =
105109
std::vector<std::tuple<G4_INST *, G4_BB *, unsigned int, unsigned int>>;
106110
using Uses = std::vector<std::tuple<G4_INST *, G4_BB *>>;
111+
// Set to large enough number so its never a valid bound
112+
const unsigned int UnknownBound = 0xffff;
107113

108114
bool isUniqueDef(G4_Operand *dst);
109115
unsigned int getDefCount(G4_Declare *dcl);
@@ -120,6 +126,7 @@ class VarReferences : public Analysis {
120126
bool onlyGRF = false;
121127
bool needBounds = true;
122128
bool reportPseudoKill = false;
129+
PointsToAnalysis *p2a = nullptr;
123130

124131
void reset() override;
125132
void run() override;

0 commit comments

Comments
 (0)