mirror of
https://github.com/intel/intel-graphics-compiler.git
synced 2025-11-04 08:21:06 +08:00
Clean-up gcc warnings, such as -Werror=misleading-indentation -Werror=catch-value -Werror=class-memaccess -Werror=unused-variable -Werror=unused-but-set-variable
720 lines
24 KiB
C++
720 lines
24 KiB
C++
/*========================== begin_copyright_notice ============================
|
|
|
|
Copyright (C) 2017-2021 Intel Corporation
|
|
|
|
SPDX-License-Identifier: MIT
|
|
|
|
============================= end_copyright_notice ===========================*/
|
|
|
|
#include "SpillCode.h"
|
|
#include "BuildIR.h"
|
|
#include "FlowGraph.h"
|
|
#include "PointsToAnalysis.h"
|
|
#include <vector>
|
|
|
|
#ifdef _DEBUG
|
|
#define _DEBUG_SPILL
|
|
#endif
|
|
|
|
using namespace vISA;
|
|
|
|
void splice(G4_BB *bb, INST_LIST_ITER iter, INST_LIST &instList,
|
|
unsigned int CISAOff);
|
|
|
|
//
|
|
// create a declare to hold the spill value of var
|
|
//
|
|
G4_Declare *SpillManager::createNewSpillLocDeclare(G4_Declare *dcl) {
|
|
|
|
if (dcl->getRegFile() == G4_FLAG) {
|
|
vISA_ASSERT(dcl->getElemType() == Type_UW || dcl->getElemType() == Type_W,
|
|
"flag reg's type should be UW");
|
|
vISA_ASSERT(dcl->getNumElems() <= builder.getNumFlagRegisters(),
|
|
"Flag reg Spill size exceeds limit");
|
|
} else if (dcl->getRegFile() == G4_ADDRESS) {
|
|
// if we are dealing with type other than UW, e.g., B, then we need to
|
|
// take care different data type reg moves of spill code. For now, just
|
|
// assume data types of addr reg are UW
|
|
//
|
|
[[maybe_unused]] G4_Type type = dcl->getElemType();
|
|
vISA_ASSERT(type == Type_UW || type == Type_W || type == Type_UD ||
|
|
type == Type_D,
|
|
"addr reg's type should be UW or UD");
|
|
vISA_ASSERT(dcl->getNumElems() <= builder.getNumAddrRegisters(),
|
|
"Addr reg Spill size exceeds limit");
|
|
}
|
|
G4_Declare *sp = dcl->getSpilledDeclare();
|
|
if (sp == NULL) // not yet created
|
|
{
|
|
sp = builder.createAddrFlagSpillLoc(dcl);
|
|
gra.setBBId(sp, bbId);
|
|
}
|
|
|
|
return sp;
|
|
}
|
|
|
|
//
|
|
// replicate dcl for temporary use (loading value from SPILL location)
|
|
//
|
|
G4_Declare *SpillManager::createNewTempAddrDeclare(G4_Declare *dcl) {
|
|
const char *name = builder.getNameString(16, "Temp_ADDR_%d", tempDclId++);
|
|
|
|
vISA_ASSERT(dcl->getElemType() == Type_UW || dcl->getElemType() == Type_W,
|
|
"addr reg's type should be UW");
|
|
vISA_ASSERT(dcl->getNumRows() == 1, "Temp_ADDR should be only 1 row");
|
|
vISA_ASSERT(dcl->getNumElems() <= builder.getNumAddrRegisters(),
|
|
"Temp_ADDR element number exceeds maximum value");
|
|
G4_Declare *sp = builder.createDeclare(name, G4_ADDRESS, dcl->getNumElems(),
|
|
1, // 1 row
|
|
Type_UW);
|
|
gra.setBBId(sp, bbId);
|
|
// Live range of new temp addrs is short so that there is no point spilling
|
|
// them. indicate this is for newly created addr temp so that RA won't spill
|
|
// it in subsequent RA allocation
|
|
gra.addAddrFlagSpillDcl(sp);
|
|
|
|
return sp;
|
|
}
|
|
|
|
G4_Declare *SpillManager::createNewTempFlagDeclare(G4_Declare *dcl) {
|
|
const char *name = builder.getNameString(32, "Temp_FSPILL_%d", tempDclId++);
|
|
|
|
vISA_ASSERT(dcl->getRegFile() == G4_FLAG, "dcl should be a flag");
|
|
G4_Declare *sp = builder.createFlag(dcl->getNumberFlagElements(), name);
|
|
gra.setBBId(sp, bbId);
|
|
sp->copyAlign(dcl);
|
|
gra.copyAlignment(sp, dcl);
|
|
gra.addAddrFlagSpillDcl(sp);
|
|
|
|
return sp;
|
|
}
|
|
|
|
//
|
|
// replicate dcl for temporary use (loading value from SPILL location)
|
|
//
|
|
G4_Declare *SpillManager::createNewTempAddrDeclare(G4_Declare *dcl,
|
|
uint16_t num_reg) {
|
|
const char *name = builder.getNameString(16, "Temp_ADDR_%d", tempDclId++);
|
|
|
|
G4_Type type = dcl->getElemType();
|
|
vISA_ASSERT(type == Type_UW || type == Type_W || type == Type_UD ||
|
|
type == Type_D,
|
|
"addr reg's type should be UW or UD");
|
|
vISA_ASSERT(dcl->getNumRows() == 1, "Temp_ADDR should be only 1 row");
|
|
vISA_ASSERT(dcl->getNumElems() <= builder.getNumAddrRegisters(),
|
|
"Temp_ADDR exceeds 16 bytes");
|
|
G4_Declare *sp = builder.createDeclare(name, G4_ADDRESS, num_reg,
|
|
1, // 1 row
|
|
type);
|
|
gra.setBBId(sp, bbId);
|
|
// Live range of new temp addrs is short so that there is no point spilling
|
|
// them. indicate this is for newly created addr temp so that RA won't spill
|
|
// it in subsequent RA allocation
|
|
gra.addAddrFlagSpillDcl(sp);
|
|
|
|
return sp;
|
|
}
|
|
|
|
G4_Declare *SpillManager::createNewTempScalarDeclare(G4_Declare *dcl) {
|
|
const char *name = builder.getNameString(32, "Temp_SCALAR_%d", tempDclId++);
|
|
G4_Declare *sp =
|
|
builder.createDeclare(name, G4_SCALAR, 1, 1, dcl->getElemType());
|
|
gra.setBBId(sp, bbId);
|
|
sp->copyAlign(dcl);
|
|
auto subAlign = Get_G4_SubRegAlign_From_Size((uint16_t)dcl->getElemSize(),
|
|
builder.getPlatform(),
|
|
builder.getGRFAlign());
|
|
sp->setSubRegAlign(subAlign);
|
|
gra.addAddrFlagSpillDcl(sp);
|
|
|
|
return sp;
|
|
}
|
|
|
|
//
|
|
// generate a reg to reg mov inst for addr/flag spill
|
|
// mov dst(dRegOff,dSubRegOff)<1> src(sRegOff,sSubRegOff)<nRegs;nRegs,1>
|
|
//
|
|
void SpillManager::genRegMov(G4_BB *bb, INST_LIST_ITER it, G4_VarBase *src,
|
|
unsigned short sSubRegOff, G4_VarBase *dst,
|
|
unsigned nRegs, bool useNoMask = true) {
|
|
builder.instList.clear();
|
|
|
|
uint16_t dSubRegOff = 0;
|
|
for (uint16_t i = builder.getNumAddrRegisters(); i != 0 && nRegs != 0;
|
|
i >>= 1) // 16, 8, 4, 2, 1
|
|
{
|
|
if (nRegs >= i) {
|
|
//
|
|
// create loc(0,locOff)<nRegs;nRegs,1> operand
|
|
//
|
|
/*
|
|
Flag registers should always be scalar regions
|
|
*/
|
|
G4_Type type = Type_W;
|
|
const RegionDesc *srcRgn = NULL;
|
|
G4_ExecSize execSize{i};
|
|
if (src->isFlag() || dst->isFlag()) {
|
|
|
|
type = Type_UW;
|
|
if (i == 2) {
|
|
type = Type_UD;
|
|
execSize = g4::SIMD1;
|
|
} else if (i > 2) {
|
|
vISA_ASSERT(false, "unsupported flag width");
|
|
}
|
|
|
|
srcRgn = builder.getRegionScalar();
|
|
} else {
|
|
srcRgn =
|
|
(i == 1) ? builder.getRegionScalar() : builder.getRegionStride1();
|
|
}
|
|
|
|
G4_SrcRegRegion *s = builder.createSrc(src, 0, sSubRegOff, srcRgn, type);
|
|
//
|
|
// create a0.aOff<1>
|
|
//
|
|
G4_DstRegRegion *d = builder.createDst(dst, 0, dSubRegOff, 1, type);
|
|
|
|
if (execSize != kernel.getSimdSize()) {
|
|
// NoMask must be used in this case
|
|
useNoMask = true;
|
|
}
|
|
// mov (nRegs) a0.aOff<1> loc(0,locOff)<4;4,1>
|
|
builder.createMov(execSize, d, s,
|
|
useNoMask ? InstOpt_WriteEnable : InstOpt_NoOpt, true);
|
|
|
|
sSubRegOff += i;
|
|
dSubRegOff += i;
|
|
|
|
nRegs -= i;
|
|
}
|
|
}
|
|
vISA_ASSERT(nRegs == 0, ERROR_SPILLCODE);
|
|
|
|
if (gra.EUFusionNoMaskWANeeded()) {
|
|
for (auto inst : builder.instList) {
|
|
if (inst->isWriteEnableInst()) {
|
|
gra.addEUFusionNoMaskWAInst(bb, inst);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// insert newly created insts from builder to instList
|
|
//
|
|
splice(bb, it, builder.instList, currCISAOffset);
|
|
}
|
|
//
|
|
// check if dst is spilled & insert spill code
|
|
//
|
|
void SpillManager::replaceSpilledDst(
|
|
G4_BB *bb,
|
|
INST_LIST_ITER it, // where new insts will be inserted
|
|
G4_INST *inst, std::vector<G4_Operand *> &operands_analyzed,
|
|
std::vector<G4_Declare *> &declares_created) {
|
|
G4_DstRegRegion *dst = inst->getDst();
|
|
if (dst == NULL)
|
|
return;
|
|
|
|
if (dst->getBase()->isRegAllocPartaker() &&
|
|
dst->getBase()->asRegVar()->getDeclare()->getSpilledDeclare() !=
|
|
NULL) // spilled base
|
|
{
|
|
// create a dst region with spill loc
|
|
// original dst region V100_uw(0,0)<1>:uw ==>
|
|
// new dst region SP_uw(0,0)<1>:uw
|
|
G4_Declare *spDcl =
|
|
dst->getBase()->asRegVar()->getDeclare()->getSpilledDeclare();
|
|
if (dst->getRegAccess() == Direct) {
|
|
|
|
G4_DstRegRegion rgn(builder, *dst,
|
|
spDcl->getRegVar()); // using spDcl as new base
|
|
if (rgn.getHorzStride() == UNDEFINED_SHORT && dst->isFlag()) {
|
|
// Flag as destination has undefined hstride
|
|
// For replacing it with spill range, make hstride 1
|
|
rgn.setHorzStride(1);
|
|
}
|
|
G4_DstRegRegion *d = builder.createDstRegRegion(rgn);
|
|
inst->setDest(d);
|
|
} else if (dst->getRegAccess() == IndirGRF) {
|
|
// add (1) r[V100_uw(0,0),0]<1>:f V124_f(0,0)<0;1,0>:f 1
|
|
// indirect access' base must be addr reg so we need to create a temp addr
|
|
// live range to load value from V100's spill loc e.g., mov (1)
|
|
// T_uw(0,0)<1>:uw SPILL_LOC_V100_uw(0,0)<0;1,0>:uw
|
|
// add (1) r[T_uw(0,0),0]<1>:f V124_f(0,0)<0;1,0>:f 1
|
|
//
|
|
// create declare for temp addr live range
|
|
//
|
|
G4_Declare *tmpDcl = NULL;
|
|
bool match_found = false;
|
|
|
|
for (unsigned int j = 0, je = operands_analyzed.size(); j < je; j++) {
|
|
G4_SrcRegRegion *analyzed_src =
|
|
static_cast<G4_SrcRegRegion *>(operands_analyzed[j]);
|
|
if (analyzed_src != NULL &&
|
|
analyzed_src->getBase()->asRegVar()->getDeclare() ==
|
|
dst->getBase()->asRegVar()->getDeclare() &&
|
|
analyzed_src->getSubRegOff() == dst->getSubRegOff() &&
|
|
!analyzed_src->getRegion()->isRegionWH()) {
|
|
tmpDcl = declares_created[j];
|
|
match_found = true;
|
|
}
|
|
}
|
|
|
|
if (!match_found) {
|
|
tmpDcl = createNewTempAddrDeclare(spDcl);
|
|
//
|
|
// generate mov Tmp(0,0)<1> SPILL_LOC_V100(0,0)
|
|
//
|
|
genRegMov(bb, it, spDcl->getRegVar(), 0, tmpDcl->getRegVar(),
|
|
tmpDcl->getNumElems());
|
|
}
|
|
|
|
G4_DstRegRegion rgn(builder, *dst,
|
|
tmpDcl->getRegVar()); // using tmpDcl as new base
|
|
G4_DstRegRegion *d = match_found
|
|
? builder.createDstWithNewSubRegOff(&rgn, 0)
|
|
: builder.createDstRegRegion(rgn);
|
|
inst->setDest(d);
|
|
|
|
if (!match_found) {
|
|
pointsToAnalysis.insertAndMergeFilledAddr(dst->getBase()->asRegVar(),
|
|
tmpDcl->getRegVar());
|
|
}
|
|
} else
|
|
vISA_ASSERT(false, "Unknown reg access");
|
|
}
|
|
}
|
|
//
|
|
// check if src is spilled and insert spill code to load spilled value
|
|
//
|
|
void SpillManager::replaceSpilledSrc(
|
|
G4_BB *bb,
|
|
INST_LIST_ITER it, // where new insts will be inserted
|
|
G4_INST *inst, unsigned i, std::vector<G4_Operand *> &operands_analyzed,
|
|
std::vector<G4_Declare *> &declares_created) {
|
|
G4_Operand *src = inst->getSrc(i);
|
|
if (src == NULL)
|
|
return;
|
|
//
|
|
// go ahead replace src (addr reg) with spill GRF
|
|
//
|
|
|
|
if (src->isSrcRegRegion() &&
|
|
src->asSrcRegRegion()->getBase()->isRegAllocPartaker() &&
|
|
src->asSrcRegRegion()
|
|
->getBase()
|
|
->asRegVar()
|
|
->getDeclare()
|
|
->getSpilledDeclare() != NULL) // spilled base
|
|
{
|
|
// create a src region with spill loc
|
|
// original src region V100_uw(0,0)<0;1,0>:uw
|
|
// new src region SP_uw(0,0)<0;1,0>:uw
|
|
G4_SrcRegRegion *ss = src->asSrcRegRegion();
|
|
G4_Declare *srcDcl = ss->getBase()->asRegVar()->getDeclare();
|
|
G4_Declare *spDcl = srcDcl->getSpilledDeclare();
|
|
if (ss->getRegAccess() == Direct) {
|
|
G4_SrcRegRegion *s;
|
|
if (inst->isSplitSend() && i == 3) {
|
|
G4_Declare *tmpDcl = createNewTempAddrDeclare(spDcl, 1);
|
|
tmpDcl->setSubRegAlign(Four_Word);
|
|
gra.setSubRegAlign(tmpDcl, Four_Word);
|
|
// (W) mov (1) tmpDcl<1>:ud spDcl<0;1,0>:ud
|
|
auto movSrc =
|
|
builder.createSrcRegRegion(spDcl, builder.getRegionScalar());
|
|
auto movDst = builder.createDstRegRegion(tmpDcl, 1);
|
|
G4_INST *movInst = builder.createMov(g4::SIMD1, movDst, movSrc,
|
|
InstOpt_WriteEnable, false);
|
|
bb->insertBefore(it, movInst);
|
|
|
|
if (gra.EUFusionNoMaskWANeeded()) {
|
|
gra.addEUFusionNoMaskWAInst(bb, movInst);
|
|
}
|
|
|
|
s = builder.createSrc(tmpDcl->getRegVar(), 0, 0, ss->getRegion(),
|
|
spDcl->getElemType());
|
|
inst->setSrc(s, i);
|
|
} else {
|
|
s = builder.createSrcWithNewBase(
|
|
ss, spDcl->getRegVar()); // using spDcl as new base
|
|
}
|
|
inst->setSrc(s, i);
|
|
} else if (ss->getRegAccess() == IndirGRF) {
|
|
// add (2) V124_f(0,0)<1>:f r[V100_uw(0,0),0]<4;2,2>:f 1
|
|
// indirect access' base must be addr reg so we need to create a temp addr
|
|
// live range to load value from V100's spill loc e.g., mov (1)
|
|
// T(0,0)<1>:uw SPILL_LOC_V100_uw(0,0)<0;1,0>:uw
|
|
// add (2) V124_f(0,0)<1>:f r[T(0,0),0]<4;2,2>:f 1
|
|
//
|
|
// create declare for temp addr live range
|
|
//
|
|
|
|
uint16_t num_reg = 1;
|
|
// if access is VxH copy number of addresses based on execution size of
|
|
// instruction
|
|
if (ss->getRegion()->isRegionWH()) {
|
|
num_reg = inst->getExecSize();
|
|
}
|
|
|
|
G4_Declare *tmpDcl = NULL;
|
|
bool match_found = false;
|
|
|
|
for (unsigned int j = 0; j < i; j++) {
|
|
G4_SrcRegRegion *analyzed_src = (G4_SrcRegRegion *)operands_analyzed[j];
|
|
if (analyzed_src != NULL &&
|
|
analyzed_src->getBase()->asRegVar()->getDeclare() ==
|
|
ss->getBase()->asRegVar()->getDeclare() &&
|
|
analyzed_src->getSubRegOff() == ss->getSubRegOff()) {
|
|
tmpDcl = declares_created[j];
|
|
match_found = true;
|
|
}
|
|
}
|
|
|
|
if (!match_found) {
|
|
tmpDcl = createNewTempAddrDeclare(spDcl, num_reg);
|
|
operands_analyzed[i] = ss;
|
|
declares_created[i] = tmpDcl;
|
|
bool isNoMask = (inst->getOption() & InstOpt_WriteEnable) != 0;
|
|
//
|
|
// generate mov Tmp(0,0)<1> SPILL_LOC_V100(0,0)
|
|
//
|
|
genRegMov(bb, it, spDcl->getRegVar(), ss->getSubRegOff(),
|
|
tmpDcl->getRegVar(), tmpDcl->getNumElems(),
|
|
isNoMask);
|
|
auto pseudoKill =
|
|
builder.createPseudoKill(tmpDcl, PseudoKillType::Other, false);
|
|
bb->insertBefore(std::prev(it), pseudoKill);
|
|
}
|
|
|
|
// create new src from the temp address variable, with offset 0
|
|
auto s = builder.createIndirectSrc(ss->getModifier(), tmpDcl->getRegVar(),
|
|
ss->getRegOff(), 0, ss->getRegion(),
|
|
ss->getType(), ss->getAddrImm());
|
|
inst->setSrc(s, i);
|
|
if (!match_found) {
|
|
pointsToAnalysis.insertAndMergeFilledAddr(ss->getBase()->asRegVar(),
|
|
tmpDcl->getRegVar());
|
|
}
|
|
} else
|
|
vISA_ASSERT(false, "Unknown reg access");
|
|
}
|
|
}
|
|
|
|
//
|
|
// check if predicate is spilled & insert fill code
|
|
//
|
|
void SpillManager::replaceSpilledPredicate(
|
|
G4_BB *bb,
|
|
INST_LIST_ITER it, // where new insts will be inserted
|
|
G4_INST *inst) {
|
|
G4_Predicate *predicate = inst->getPredicate();
|
|
if (predicate == NULL)
|
|
return;
|
|
|
|
G4_VarBase *flagReg = predicate->getBase();
|
|
if (flagReg->asRegVar()->isRegAllocPartaker()) {
|
|
G4_Declare *flagDcl = flagReg->asRegVar()->getDeclare();
|
|
G4_Declare *spDcl = flagDcl->getSpilledDeclare();
|
|
if (spDcl != NULL) {
|
|
G4_Declare *tmpDcl = createNewTempFlagDeclare(flagDcl);
|
|
genRegMov(bb, it, spDcl->getRegVar(), 0, tmpDcl->getRegVar(),
|
|
tmpDcl->getNumElems());
|
|
G4_Predicate *new_pred =
|
|
builder.createPredicate(predicate->getState(), tmpDcl->getRegVar(), 0,
|
|
predicate->getControl());
|
|
inst->setPredicate(new_pred);
|
|
++numFlagSpillLoad;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool SpillManager::checkDefUseDomRel(G4_Operand *dst, G4_BB *defBB) {
|
|
auto dcl = dst->getTopDcl();
|
|
|
|
// check whether this def dominates all its uses
|
|
auto uses = refs.getUses(dcl);
|
|
|
|
for (auto &use : *uses) {
|
|
auto useBB = std::get<1>(use);
|
|
|
|
// check if def dominates use
|
|
if (!defBB->dominates(useBB))
|
|
return false;
|
|
|
|
if (defBB == useBB) {
|
|
// defBB dominates useBB since its the same BB.
|
|
// ensure def instruction appears lexically before use BB.
|
|
auto useInst = std::get<0>(use);
|
|
if (dst->getInst()->getLexicalId() > useInst->getLexicalId())
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// if def is in loop then ensure all uses are in same loop level
|
|
// or inner loop nest of def's closest loop.
|
|
auto defLoop = gra.kernel.fg.getLoops().getInnerMostLoop(defBB);
|
|
if (defLoop) {
|
|
// since def is in loop, check whether uses are also in same loop.
|
|
for (auto &use : *uses) {
|
|
auto useBB = std::get<1>(use);
|
|
auto useLoop = gra.kernel.fg.getLoops().getInnerMostLoop(useBB);
|
|
if (!useLoop)
|
|
return false;
|
|
|
|
if (!useLoop->fullSubset(defLoop))
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SpillManager::isDominatingDef(G4_Operand *opnd, G4_BB *bb) {
|
|
// return true if this opnd is dominates all other defs
|
|
auto dcl = opnd->getTopDcl();
|
|
|
|
auto defs = refs.getDefs(dcl);
|
|
|
|
for (auto &def : *defs) {
|
|
auto otherDefBB = std::get<1>(def);
|
|
|
|
if (!bb->dominates(otherDefBB))
|
|
return false;
|
|
|
|
if (bb == otherDefBB) {
|
|
auto otherDefInst = std::get<0>(def);
|
|
if (opnd->getInst()->getLexicalId() > otherDefInst->getLexicalId())
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// update RMW information for flag operands
|
|
void SpillManager::updateRMWNeeded() {
|
|
if (!gra.kernel.getOption(vISA_SkipRedundantFillInRMW))
|
|
return;
|
|
|
|
auto isRMWNeededForSpill = [&](G4_BB *bb, G4_Operand *spilledRegion) {
|
|
bool isUniqueDef = (refs.getDefCount(spilledRegion->getTopDcl()) < 2);
|
|
|
|
// Check0 : Def is NoMask, -- checked before inserting RMW fill already
|
|
// Check1 : Def is unique def OR def is dominating all other defs,
|
|
// Check2 : Def is in loop L and all use(s) of dcl are in loop L or it's
|
|
// inner loop nest Check3 : Flowgraph is reducible RMW_Not_Needed = Check0
|
|
// || (Check1 && Check2 && Check3)
|
|
bool RMW_Needed = true;
|
|
|
|
if ((isUniqueDef || isDominatingDef(spilledRegion, bb)) &&
|
|
kernel.fg.isReducible() && checkDefUseDomRel(spilledRegion, bb)) {
|
|
RMW_Needed = false;
|
|
}
|
|
|
|
return RMW_Needed;
|
|
};
|
|
|
|
auto isOpndSpilled = [&](G4_Operand *opnd) {
|
|
auto base = opnd->getBase();
|
|
if (base && base->isRegVar() && base->asRegVar()->isRegAllocPartaker()) {
|
|
auto dstRegVar = base->asRegVar();
|
|
if (dstRegVar && base->asRegVar()->getDeclare()->getSpilledDeclare())
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
// update rmw set if opnd is spilled, nop if opnd isnt spilled.
|
|
auto updateRMW = [&](G4_BB *bb, G4_Operand *opnd) {
|
|
auto RMW_Needed = isRMWNeededForSpill(bb, opnd);
|
|
if (!RMW_Needed) {
|
|
// Any spilled dst region that doesnt need RMW
|
|
// is added to noRMWNeeded set. This set is later
|
|
// checked when inserting spill/fill code.
|
|
noRMWNeeded.insert(opnd);
|
|
}
|
|
};
|
|
|
|
// First pass to setup lexical ids of instruction so dominator relation can be
|
|
// computed correctly intra-BB.
|
|
unsigned int lexId = 0;
|
|
for (auto bb : gra.kernel.fg.getBBList()) {
|
|
for (auto inst : bb->getInstList()) {
|
|
inst->setLexicalId(lexId++);
|
|
}
|
|
}
|
|
|
|
for (auto bb : gra.kernel.fg.getBBList()) {
|
|
for (auto inst : bb->getInstList()) {
|
|
if (inst->isPseudoKill())
|
|
continue;
|
|
|
|
// flags are used only as cond modifiers with non-NoMask
|
|
auto condMod = inst->getCondMod();
|
|
if (condMod && isOpndSpilled(condMod)) {
|
|
updateRMW(bb, condMod);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// check if flag dst is spilled and insert spill code
|
|
//
|
|
void SpillManager::replaceSpilledFlagCondMod(
|
|
G4_BB *bb,
|
|
INST_LIST_ITER it, // where new insts will be inserted
|
|
G4_INST *inst) {
|
|
G4_CondMod *mod = inst->getCondMod();
|
|
if (mod == NULL)
|
|
return;
|
|
|
|
G4_VarBase *flagReg = mod->getBase();
|
|
if (flagReg != NULL && flagReg->asRegVar()->isRegAllocPartaker()) {
|
|
G4_Declare *flagDcl = flagReg->asRegVar()->getDeclare();
|
|
G4_Declare *spDcl = flagDcl->getSpilledDeclare();
|
|
if (spDcl != NULL) {
|
|
G4_Declare *tmpDcl;
|
|
G4_Predicate *predicate = inst->getPredicate();
|
|
|
|
if (predicate != NULL) {
|
|
G4_VarBase *flagReg = predicate->getBase();
|
|
tmpDcl = flagReg->asRegVar()->getDeclare();
|
|
} else {
|
|
tmpDcl = createNewTempFlagDeclare(flagDcl);
|
|
}
|
|
|
|
// Need to pre-load the spill GRF if the inst isn't going to write the
|
|
// full spilled GRF variable.
|
|
if (flagDcl->getNumberFlagElements() > inst->getExecSize() ||
|
|
(!bb->isAllLaneActive() && !inst->isWriteEnableInst())) {
|
|
// Conditional modifier must use same flag register as predicate.
|
|
// So if conditional modifier needs pre-fill, the prediciate must be
|
|
// filled already.
|
|
if (noRMWNeeded.find(mod) == noRMWNeeded.end() && predicate == NULL) {
|
|
genRegMov(bb, it, spDcl->getRegVar(), 0, tmpDcl->getRegVar(),
|
|
tmpDcl->getNumElems());
|
|
++numFlagSpillLoad;
|
|
} else {
|
|
// insert kill for temp flag
|
|
auto pseudoKill =
|
|
builder.createPseudoKill(tmpDcl, PseudoKillType::Other, false);
|
|
bb->insertBefore(it, pseudoKill);
|
|
}
|
|
}
|
|
|
|
G4_CondMod *newCondMod =
|
|
builder.createCondMod(mod->getMod(), tmpDcl->getRegVar(), 0);
|
|
|
|
inst->setCondMod(newCondMod);
|
|
|
|
genRegMov(bb, ++it, tmpDcl->getRegVar(), 0, spDcl->getRegVar(),
|
|
tmpDcl->getNumElems());
|
|
++numFlagSpillStore;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// go over all declares and allocate spill locations
|
|
//
|
|
void SpillManager::createSpillLocations(const G4_Kernel &kernel) {
|
|
// set spill flag to indicate which vars are spilled
|
|
for (const LiveRange *lr : spilledLRs) {
|
|
G4_Declare *dcl = lr->getVar()->getDeclare();
|
|
dcl->setSpillFlag();
|
|
vISA_ASSERT(lr->getPhyReg() == NULL,
|
|
"Spilled Live Range shouldn't have physical reg");
|
|
vISA_ASSERT(lr->getSpillCost() < MAXSPILLCOST,
|
|
"ERROR: spill live range with infinite spill cost");
|
|
// create spill loc for holding spilled addr regs
|
|
createNewSpillLocDeclare(dcl);
|
|
}
|
|
// take care of alias declares
|
|
for (G4_Declare *dcl : kernel.Declares) {
|
|
if (!dcl->getRegVar()->isRegAllocPartaker()) // skip non reg alloc candidate
|
|
continue;
|
|
|
|
if (dcl->getAliasDeclare() != NULL && // dcl is not a representative declare
|
|
dcl->getAliasDeclare()
|
|
->isSpilled()) // dcl's representative decl is spilled
|
|
{
|
|
G4_Declare *sp = createNewSpillLocDeclare(dcl);
|
|
// when doing RA multiple times (due to spill code), we don't want to set
|
|
// alias information more than once
|
|
if (sp->getAliasDeclare() == NULL) {
|
|
sp->setAliasDeclare(dcl->getAliasDeclare()->getSpilledDeclare(),
|
|
dcl->getAliasOffset());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool isSpillCandidateForLifetimeOpRemoval(G4_INST *inst) {
|
|
if (inst->isPseudoKill()) {
|
|
return inst->getDst()->isSpilled();
|
|
} else if (inst->isLifeTimeEnd()) {
|
|
return inst->getSrc(0)->asSrcRegRegion()->isSpilled();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void SpillManager::insertSpillCode() {
|
|
//
|
|
// create spill locations
|
|
//
|
|
createSpillLocations(kernel);
|
|
|
|
updateRMWNeeded();
|
|
|
|
for (G4_BB *bb : kernel.fg) {
|
|
bbId = bb->getId();
|
|
//
|
|
// handle spill code for the current BB
|
|
//
|
|
|
|
// In one iteration remove all spilled lifetime.start/end
|
|
// ops.
|
|
bb->erase(std::remove_if(bb->begin(), bb->end(),
|
|
isSpillCandidateForLifetimeOpRemoval),
|
|
bb->end());
|
|
|
|
for (INST_LIST_ITER inst_it = bb->begin(); inst_it != bb->end();) {
|
|
G4_INST *inst = *inst_it;
|
|
|
|
currCISAOffset = inst->getVISAId();
|
|
|
|
const unsigned numSrc = inst->getNumSrc();
|
|
std::vector<G4_Operand *> operands_analyzed(numSrc, nullptr);
|
|
std::vector<G4_Declare *> declares_created(numSrc, nullptr);
|
|
// insert spill inst for spilled srcs
|
|
for (unsigned i = 0; i < numSrc; i++) {
|
|
replaceSpilledSrc(bb, inst_it, inst, i, operands_analyzed,
|
|
declares_created);
|
|
}
|
|
// insert spill inst for spilled dst
|
|
replaceSpilledDst(bb, inst_it, inst, operands_analyzed, declares_created);
|
|
|
|
//
|
|
// Process predicate
|
|
//
|
|
G4_Predicate *predicate = inst->getPredicate();
|
|
if (predicate != NULL) {
|
|
replaceSpilledPredicate(bb, inst_it, inst);
|
|
}
|
|
|
|
//
|
|
// Process condMod
|
|
//
|
|
G4_CondMod *mod = inst->getCondMod();
|
|
if (mod != NULL && mod->getBase() != NULL) {
|
|
replaceSpilledFlagCondMod(bb, inst_it, inst);
|
|
}
|
|
inst_it++;
|
|
}
|
|
bbId = UINT_MAX;
|
|
}
|
|
}
|