1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
|
/*========================== begin_copyright_notice ============================
Copyright (C) 2019-2021 Intel Corporation
SPDX-License-Identifier: MIT
============================= end_copyright_notice ===========================*/
#ifndef _VARSPLIT_H_
#define _VARSPLIT_H_
#include "BuildIR.h"
#include "FlowGraph.h"
#include "RPE.h"
namespace vISA {
class LiveRange;
class GraphColor;
class RPE;
class GlobalRA;
// store mapping of a split variable to original variable. if any split
// variable is spilled, we can reuse spill location of original variable.
// also store all instructions emitted in preheader, loop exit for each
// split variable. this helps eliminate those instruction in case the
// split variable itself spills.
class SplitResults {
public:
G4_Declare *origDcl = nullptr;
std::unordered_map<G4_BB *, std::unordered_set<G4_INST *>> insts;
};
class CComparator {
public:
bool operator()(const G4_Declare *first, const G4_Declare *second) const {
return first->getDeclId() < second->getDeclId();
}
};
class LoopVarSplit {
public:
LoopVarSplit(G4_Kernel &k, GraphColor *c,
const LivenessAnalysis *liveAnalysis);
~LoopVarSplit() { delete rpe; }
LoopVarSplit(const LoopVarSplit&) = delete;
LoopVarSplit& operator=(const LoopVarSplit&) = delete;
void run();
std::vector<G4_SrcRegRegion *> getReads(G4_Declare *dcl, Loop &loop);
std::vector<G4_DstRegRegion *> getWrites(G4_Declare *dcl, Loop &loop);
unsigned int getMaxRegPressureInLoop(Loop &loop);
void dump(std::ostream &of = std::cerr);
static void removeAllSplitInsts(GlobalRA *gra, G4_Declare *dcl);
static void removeSplitInsts(GlobalRA *gra, G4_Declare *spillDcl, G4_BB *bb);
static bool removeFromPreheader(GlobalRA *gra, G4_Declare *spillDcl,
G4_BB *bb, INST_LIST_ITER filledInstIter);
static bool removeFromLoopExit(GlobalRA *gra, G4_Declare *spillDcl, G4_BB *bb,
INST_LIST_ITER filledInstIter);
static const std::unordered_set<G4_INST *> getSplitInsts(GlobalRA *gra,
G4_BB *bb);
private:
const unsigned int cLargeLoop = 500;
bool split(G4_Declare *dcl, Loop &loop);
void copy(G4_BB *bb, G4_Declare *dst, G4_Declare *src,
SplitResults *splitData, bool isDefault32bMask,
bool isDefault64bMask, bool pushBack = true);
void replaceSrc(G4_SrcRegRegion *src, G4_Declare *dcl, const Loop &loop);
void replaceDst(G4_DstRegRegion *dst, G4_Declare *dcl, const Loop &loop);
G4_Declare *getNewDcl(G4_Declare *dcl1, G4_Declare *dcl2, const Loop &loop);
std::vector<Loop *> getLoopsToSplitAround(G4_Declare *dcl);
void adjustLoopMaxPressure(Loop &loop, unsigned int numRows);
G4_Kernel &kernel;
GraphColor *coloring = nullptr;
RPE *rpe = nullptr;
VarReferences references;
const LivenessAnalysis *liveness;
// store set of dcls marked as spill in current RA iteration
std::unordered_set<G4_Declare *> spilledDclSet;
// store spill cost for each dcl
std::map<G4_Declare *, float, CComparator> dclSpillCost;
std::unordered_map<const Loop *,
std::unordered_map<G4_Declare *, G4_Declare *>>
oldNewDclPerLoop;
std::unordered_map<Loop *, std::unordered_set<G4_Declare *>> splitsPerLoop;
std::unordered_map<Loop *, unsigned int> maxRegPressureCache;
std::unordered_map<Loop *, unsigned int> scalarBytesSplit;
// a spilled dcl may be split multiple times, once per loop
// store this information to uplevel to GlobalRA class so
// anytime we spill a split variable, we reuse spill location.
// Orig dcl, vector<Tmp Dcl, Loop>
std::unordered_map<G4_Declare *, std::vector<std::pair<G4_Declare *, Loop *>>>
splitResults;
class Size {
public:
enum class State {
Undef = 0,
Small = 1,
Large = 2,
};
State state = State::Undef;
};
std::unordered_map<Loop *, Size> loopSizeCache;
bool isLargeLoop(Loop &loop) {
auto &size = loopSizeCache[&loop];
if (size.state != Size::State::Undef)
return size.state == Size::State::Large;
unsigned int instCount = 0;
std::for_each(loop.getBBs().begin(), loop.getBBs().end(),
[&instCount](G4_BB *bb) { instCount += bb->size(); });
if (instCount > cLargeLoop)
size.state = Size::State::Large;
return size.state == Size::State::Large;
}
};
class VarProperties {
public:
enum class AccessGranularity { OneGrf = 1, TwoGrf = 2, Unknown = 3 };
AccessGranularity ag = AccessGranularity::Unknown;
unsigned int numDefs = 0;
std::pair<G4_DstRegRegion *, G4_BB *> def;
std::vector<std::pair<G4_SrcRegRegion *, G4_BB *>> srcs;
bool candidateDef = false;
bool legitCandidate = true;
// API to check whether variable is local or global
bool isDefUsesInSameBB() {
auto defBB = def.second;
for (auto src : srcs) {
if (src.second != defBB)
return false;
}
return true;
}
bool isPartDclUsed(unsigned int lb, unsigned int rb) {
// Return true if lb/rb is part of any src regions
for (auto &src : srcs) {
if (src.first->getLeftBound() >= lb && src.first->getRightBound() <= rb)
return true;
}
return false;
}
};
}; // namespace vISA
#endif
|