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 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
|
/*========================== begin_copyright_notice ============================
Copyright (C) 2017-2021 Intel Corporation
SPDX-License-Identifier: MIT
============================= end_copyright_notice ===========================*/
//
/// GenXLiveRanges
/// --------------
///
/// GenXLiveRanges calculates the actual live range information (the segments)
/// on the LiveRange object for each value. See the comment at the top of
/// GenXLiveness.h for details of how the live range information works. This
/// pass calls GenXLiveness::buildLiveRange to do the work for each value.
///
/// The LiveRange object for each value already existed before this pass, as it
/// was created by GenXCategory. In the case of a value that we can now see does
/// not want a LiveRange, because it is an Instruction baled in to something,
/// we erase the LiveRange here.
///
//===----------------------------------------------------------------------===//
#include "FunctionGroup.h"
#include "GenX.h"
#include "GenXBaling.h"
#include "GenXIntrinsics.h"
#include "GenXLiveness.h"
#include "GenXNumbering.h"
#include "vc/Support/BackendConfig.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/Debug.h"
#include "Probe/Assertion.h"
#define DEBUG_TYPE "GENX_LIVERANGES"
using namespace llvm;
using namespace genx;
namespace {
class GenXLiveRanges : public FGPassImplInterface,
public IDMixin<GenXLiveRanges> {
FunctionGroup *FG = nullptr;
GenXBaling *Baling = nullptr;
GenXLiveness *Liveness = nullptr;
public:
explicit GenXLiveRanges() {}
static StringRef getPassName() { return "GenX live ranges analysis"; }
static void getAnalysisUsage(AnalysisUsage &AU);
bool runOnFunctionGroup(FunctionGroup &FG) override;
private:
void buildLiveRanges();
bool isPredefinedVariable(Value *) const;
};
/***********************************************************************
* Local function for testing one assertion statement.
* Check we don't have any leftover empty live ranges. If we do, it means
* that a pass between GenXCategory and here has erased a value and failed
* to erase its LiveRange, or alternatively this pass has failed to erase
* the LiveRange for a value that does not need it because it is a baled
* in instruction.
*/
bool testDuplicates(/*const*/ llvm::GenXLiveness& Liveness) {
if (std::any_of(Liveness.begin(), Liveness.end(),
[](const auto &X) { return X.second == nullptr; })) {
llvm::errs() << "Liveness contains NULL live ranges\n";
return false;
}
auto testRange = [](const auto &X) {
auto HasSegment = (X.second->size() > 0);
auto UndefVal = isa<UndefValue>(X.first.getValue());
return !(HasSegment || UndefVal);
};
auto WrongLR = std::find_if(Liveness.begin(), Liveness.end(), testRange);
if (WrongLR != Liveness.end()) {
llvm::errs() << "Bad live range\n";
WrongLR->second->print(llvm::errs(), true);
llvm::errs() << "\nWhole liveness:\n";
Liveness.dump();
llvm::errs() << "\n";
return false;
}
return true;
}
} // end anonymous namespace
namespace llvm {
void initializeGenXLiveRangesWrapperPass(PassRegistry &);
using GenXLiveRangesWrapper = FunctionGroupWrapperPass<GenXLiveRanges>;
} // namespace llvm
INITIALIZE_PASS_BEGIN(GenXLiveRangesWrapper, "GenXLiveRangesWrapper",
"GenXLiveRangesWrapper", false, false)
INITIALIZE_PASS_DEPENDENCY(GenXGroupBalingWrapper)
INITIALIZE_PASS_DEPENDENCY(GenXLivenessWrapper)
INITIALIZE_PASS_DEPENDENCY(GenXNumberingWrapper)
INITIALIZE_PASS_DEPENDENCY(FunctionGroupAnalysis)
INITIALIZE_PASS_END(GenXLiveRangesWrapper, "GenXLiveRangesWrapper",
"GenXLiveRangesWrapper", false, false)
ModulePass *llvm::createGenXLiveRangesWrapperPass() {
initializeGenXLiveRangesWrapperPass(*PassRegistry::getPassRegistry());
return new GenXLiveRangesWrapper();
}
void GenXLiveRanges::getAnalysisUsage(AnalysisUsage &AU) {
AU.addRequired<GenXGroupBaling>();
AU.addRequired<GenXLiveness>();
AU.addRequired<GenXNumbering>();
AU.addRequired<GenXBackendConfig>();
AU.addRequired<FunctionGroupAnalysis>();
AU.setPreservesAll();
}
/***********************************************************************
* runOnFunctionGroup : run the liveness analysis for this FunctionGroup
*/
bool GenXLiveRanges::runOnFunctionGroup(FunctionGroup &ArgFG)
{
FG = &ArgFG;
const auto &BC = getAnalysis<GenXBackendConfig>();
Baling = &getAnalysis<GenXGroupBaling>();
Liveness = &getAnalysis<GenXLiveness>();
Liveness->setNoCoalescingMode(BC.disableLiveRangesCoalescing());
Liveness->setBaling(Baling);
Liveness->setNumbering(&getAnalysis<GenXNumbering>());
// Build the live ranges.
Liveness->buildSubroutineLRs();
buildLiveRanges();
IGC_ASSERT(testDuplicates(*Liveness));
return false;
}
/***********************************************************************
* isPredefinedVariable : check if it's tranlated into predefined
* variables in vISA.
*/
bool GenXLiveRanges::isPredefinedVariable(Value *V) const {
switch (GenXIntrinsic::getGenXIntrinsicID(V)) {
case GenXIntrinsic::genx_predefined_surface:
case GenXIntrinsic::genx_read_predef_reg:
case GenXIntrinsic::genx_write_predef_reg:
return true;
default:
break;
}
return false;
}
/***********************************************************************
* buildLiveRanges : build live ranges for all args and instructions
*/
void GenXLiveRanges::buildLiveRanges()
{
// Build live ranges for global variables;
for (auto &G : FG->getModule()->globals())
Liveness->buildLiveRange(&G);
for (auto i = FG->begin(), e = FG->end(); i != e; ++i) {
Function *Func = *i;
// Build live ranges for args.
for (auto fi = Func->arg_begin(), fe = Func->arg_end(); fi != fe; ++fi)
Liveness->buildLiveRange(&*fi);
if (!Func->getReturnType()->isVoidTy()) {
// Build live range(s) for unified return value.
Liveness->buildLiveRange(Liveness->getUnifiedRet(Func));
}
// Build live ranges for code.
for (Function::iterator fi = Func->begin(), fe = Func->end(); fi != fe; ++fi) {
BasicBlock *BB = &*fi;
for (BasicBlock::iterator bi = BB->begin(), be = BB->end(); bi != be; ++bi) {
Instruction *Inst = &*bi;
// Skip building live range for instructions
// - has no destination
// - is already baled, or
// - is predefined variable in vISA.
if (!Inst->getType()->isVoidTy() && !Baling->isBaled(Inst) &&
!isPredefinedVariable(Inst)) {
// Instruction is not baled in to anything.
// First check if the result is unused and it is an intrinsic whose
// result is marked RAW_NULLALLOWED. If so, don't create a live range,
// so no register gets allocated.
if (Inst->use_empty()) {
unsigned IID = vc::getAnyIntrinsicID(Inst);
switch (IID) {
case GenXIntrinsic::not_any_intrinsic:
case GenXIntrinsic::genx_rdregioni:
case GenXIntrinsic::genx_rdregionf:
case GenXIntrinsic::genx_wrregioni:
case GenXIntrinsic::genx_wrregionf:
case GenXIntrinsic::genx_wrconstregion:
break;
default: {
GenXIntrinsicInfo::ArgInfo AI
= GenXIntrinsicInfo(IID).getRetInfo();
if (AI.isRaw() && AI.rawNullAllowed()) {
// Unused RAW_NULLALLOWED result.
Liveness->eraseLiveRange(Inst);
continue;
}
break;
}
}
}
// Build its live range.
Liveness->buildLiveRange(Inst);
} else {
// Instruction is baled in to something. Erase its live range so the
// register allocator does not try and allocate it something.
Liveness->eraseLiveRange(Inst);
}
}
}
}
}
|