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 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
|
/*========================== begin_copyright_notice ============================
Copyright (C) 2017-2021 Intel Corporation
SPDX-License-Identifier: MIT
============================= end_copyright_notice ===========================*/
//
// GenXNumbering is an analysis that provides a numbering of the instructions
// for use by live range segments. See GenXNumbering.h.
//
//===----------------------------------------------------------------------===//
#include "GenXNumbering.h"
#include "GenX.h"
#include "GenXBaling.h"
#include "GenXLiveness.h"
#include "vc/Utils/GenX/KernelInfo.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Function.h"
#include "llvmWrapper/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/Support/Debug.h"
#include "llvmWrapper/IR/InstrTypes.h"
#include "Probe/Assertion.h"
#define DEBUG_TYPE "GENX_NUMBERING"
using namespace llvm;
using namespace genx;
INITIALIZE_PASS_BEGIN(GenXNumberingWrapper, "GenXNumberingWrapper",
"GenXNumberingWrapper", false, false)
INITIALIZE_PASS_DEPENDENCY(GenXGroupBalingWrapper)
INITIALIZE_PASS_END(GenXNumberingWrapper, "GenXNumberingWrapper",
"GenXNumberingWrapper", false, false)
ModulePass *llvm::createGenXNumberingWrapperPass() {
initializeGenXNumberingWrapperPass(*PassRegistry::getPassRegistry());
return new GenXNumberingWrapper();
}
void GenXNumbering::getAnalysisUsage(AnalysisUsage &AU) {
AU.addRequired<GenXGroupBaling>();
AU.setPreservesAll();
}
/***********************************************************************
* runOnFunctionGroup : run pass
*/
bool GenXNumbering::runOnFunctionGroup(FunctionGroup &ArgFG)
{
FG = &ArgFG;
Baling = &getAnalysis<GenXGroupBaling>();
unsigned Num = 0;
for (auto fgi = FG->begin(), fge = FG->end(); fgi != fge; ++fgi)
Num = numberInstructionsInFunc(*fgi, Num);
LastNum = Num;
return false;
}
/***********************************************************************
* releaseMemory : clear the GenXNumbering
*/
void GenXNumbering::releaseMemory() {
BBNumbers.clear();
Numbers.clear();
NumberToPhiIncomingMap.clear();
}
/***********************************************************************
* numberInstructionsInFunc : number the instructions in a function
*/
unsigned GenXNumbering::numberInstructionsInFunc(Function *Func, unsigned Num)
{
// Number the function, reserving one number for the args.
Numbers[Func] = Num++;
for (Function::iterator fi = Func->begin(), fe = Func->end(); fi != fe; ++fi) {
BasicBlock *Block = &*fi;
// Number the basic block.
auto BBNumber = &BBNumbers[Block];
BBNumber->Index = BBNumbers.size() - 1;
Numbers[Block] = Num++;
// If this is the first block of a kernel, reserve kernel arg copy slots.
if (Block == &Func->front() && vc::isKernel(Func))
for (auto ai = Func->arg_begin(), ae = Func->arg_end(); ai != ae; ++ai)
++Num;
// Iterate the instructions.
Instruction *Inst;
for (BasicBlock::iterator bi = Block->begin(); ; ++bi) {
Inst = &*bi;
if (Inst->isTerminator())
break;
// For most instructions, reserve one number for any pre-copy that
// coalescing needs to insert, and nothing after.
unsigned PreReserve = 1, PostReserve = 0;
if (auto CI = dyn_cast<CallInst>(Inst)) {
if (!GenXIntrinsic::isAnyNonTrivialIntrinsic(CI) &&
!CI->isInlineAsm()) {
// For a non-intrinsic call, reserve enough numbers before the call
// for:
// - a slot for each element of the args, two numbers per element:
// 1. one for the address setup in case it is an address arg added
// by arg indirection (as returned by getArgIndirectionNumber());
// 2. one for a pre-copy inserted if coalescing fails (as returned
// by getArgPreCopyNumber());
//
// - a similar slot with two numbers for any address arg added by
// arg indirection (also as returned by getArgIndirectionNumber()
// and getArgPreCopyNumber()).
//
// Reserve enough numbers after the call for:
// - post-copies of (elements of) the return value, as returned by
// getRetPostCopyNumber().
//
// Note that numbers get wasted because most call args do not need
// two slots, and most calls never have address args added by arg
// indirection. But treating all call args the same is easier, and
// wasting numbers does not really matter.
PreReserve = 2 * IndexFlattener::getNumArgElements(
CI->getFunctionType());
PreReserve += 2 * IGCLLVM::getNumArgOperands(CI); // extra for pre-copy addresses of args
unsigned NumRetVals = IndexFlattener::getNumElements(CI->getType());
PreReserve += NumRetVals; // extra for pre-copy addresses of retvals
PostReserve = NumRetVals;
// Set the start number of the call so users of numbering can work out
// where the pre-copies are assumed to start, even if the call gets
// modified later by GenXArgIndirection.
setStartNumber(CI, Num);
}
}
// Number the instruction, reserving PreReserve.
Num += PreReserve;
Numbers[Inst] = Num;
Num += 1 + PostReserve;
}
// We have reached the terminator instruction but not yet numbered it.
// Reserve a number for each phi node in the successor. If there is
// more than one successor (this is a critical edge), then allow for
// whichever successor has the most phi nodes.
BBNumber->PhiNumber = Num;
auto TI = cast<IGCLLVM::TerminatorInst>(Block->getTerminator());
unsigned MaxPhis = 0;
for (unsigned i = 0, e = TI->getNumSuccessors(); i != e; ++i) {
BasicBlock *Succ = TI->getSuccessor(i);
unsigned NumPhis = 0;
for (BasicBlock::iterator sbi = Succ->begin(), sbe = Succ->end(); sbi != sbe; ++sbi) {
if (!isa<PHINode>(&*sbi))
break;
NumPhis++;
}
if (NumPhis > MaxPhis)
MaxPhis = NumPhis;
}
Num += MaxPhis;
// Now number the terminator instruction. Doing it here ensures that any
// input to the terminator instruction interferes with the results of the
// phi nodes of the successor.
unsigned PreReserve = 1;
if (isa<ReturnInst>(Inst)) {
// For a return, reserve enough numbers before for pre-copies of
// (elements of) the return value.
PreReserve = IndexFlattener::getNumElements(Func->getReturnType());
}
Num += PreReserve;
Numbers[Inst] = Num++;
BBNumber->EndNumber = Num;
}
return Num;
}
/***********************************************************************
* getBaleNumber : get instruction number for head of bale, 0 if none
*/
unsigned GenXNumbering::getBaleNumber(Instruction *Inst)
{
Inst = Baling->getBaleHead(Inst);
return getNumber(Inst);
}
/***********************************************************************
* getNumber : get instruction number, or 0 if none
*/
unsigned GenXNumbering::getNumber(Value *V) const {
auto i = Numbers.find(V), e = Numbers.end();
if (i == e)
return 0;
return i->second;
}
/***********************************************************************
* setNumber : get instruction number
*/
void GenXNumbering::setNumber(Value *V, unsigned Number)
{
Numbers[V] = Number;
}
/***********************************************************************
* getArgIndirectionNumber : get number of arg indirection slot for call arg
*
* Enter: CI = CallInst
* OperandNum = operand (arg) number
* Index = flattened index in the struct
*
* Each flattened index in each call arg has an arg indirection slot before the
* call instruction, where a copy will be inserted if coalescing fails. Each
* slot in fact has two numbers, and this returns the first one. (The second
* one is used for arg pre-copy when coalescing fails.)
*/
unsigned GenXNumbering::getArgIndirectionNumber(CallInst *CI, unsigned OperandNum,
unsigned Index)
{
auto FT = cast<FunctionType>(CI->getFunctionType());
return getStartNumber(CI) + 2 * (IndexFlattener::flattenArg(FT, OperandNum)
+ Index);
}
/***********************************************************************
* getKernelArgCopyNumber : get number of kernel arg copy slot
*/
unsigned GenXNumbering::getKernelArgCopyNumber(Argument *Arg)
{
IGC_ASSERT(vc::isKernel(Arg->getParent()));
return Numbers[&Arg->getParent()->front()] + 1 + Arg->getArgNo();
}
/***********************************************************************
* getArgPreCopyNumber : get number of pre-copy slot for call arg
*
* Enter: CI = CallInst
* OperandNum = operand (arg) number
* Index = flattened index in the struct
*
* Each flattened index in each call arg has an arg pre-copy slot before the
* call instruction, where a copy will be inserted if coalescing fails. Each
* slot in fact has two numbers, and this returns the second one. (The first
* one is used for address loading in arg indirection.)
*/
unsigned GenXNumbering::getArgPreCopyNumber(CallInst *CI, unsigned OperandNum,
unsigned Index)
{
return getArgIndirectionNumber(CI, OperandNum, Index) + 1;
}
/***********************************************************************
* getRetPreCopyNumber : get number of pre-copy slot for return value
*
* Enter: RI = ReturnInst
* Index = flattened index in the struct
*
* For each flattened index in the return type, there is one slot before the
* return instruction.
*/
unsigned GenXNumbering::getRetPreCopyNumber(ReturnInst *RI, unsigned Index)
{
return getNumber(RI)
- IndexFlattener::getNumElements(RI->getOperand(0)->getType()) + Index;
}
/***********************************************************************
* getRetPostCopyNumber : get number of post-copy slot for return value
*
* Enter: CI = CallInst
* Index = flattened index in the struct
*
* For each flattened index in the return type, there is one slot after the call
* instruction.
*/
unsigned GenXNumbering::getRetPostCopyNumber(CallInst *CI, unsigned Index)
{
return getNumber(CI) + 1 + Index;
}
/***********************************************************************
* getPhiNumber : get instruction number for phi node for particular predecessor
*
* The non-const version caches the result in NumberToPhiIncomingMap, for the
* later use of getPhiIncomingFromNumber.
*/
unsigned GenXNumbering::getPhiNumber(PHINode *Phi, BasicBlock *BB) const
{
// The instruction number is the count of phi nodes before it added to the
// PhiNumber for the predecessor.
return BBNumbers.find(BB)->second.PhiNumber + getPhiOffset(Phi);
}
unsigned GenXNumbering::getPhiNumber(PHINode *Phi, BasicBlock *BB)
{
unsigned Number = ((const GenXNumbering *)this)->getPhiNumber(Phi, BB);
NumberToPhiIncomingMap.emplace(
Number, std::make_pair(Phi, Phi->getBasicBlockIndex(BB)));
return Number;
}
/***********************************************************************
* getPhiIncomingFromNumber : get the phi incoming for a number returned from
* getPhiNumber
*
* This returns the phi node and incoming index corresponding to the supplied
* instruction number.
*/
std::unordered_map<PHINode *, unsigned>
GenXNumbering::getPhiIncomingFromNumber(unsigned Number) {
auto Range = NumberToPhiIncomingMap.equal_range(Number);
std::unordered_map<PHINode *, unsigned> PHIs;
PHIs.reserve(std::distance(Range.first, Range.second));
std::transform(Range.first, Range.second, std::inserter(PHIs, PHIs.begin()),
[](auto It) { return It.second; });
return PHIs;
}
/***********************************************************************
* getPhiOffset : get phi node offset (the 0 based index within its block)
*/
unsigned GenXNumbering::getPhiOffset(PHINode *Phi) const
{
// Count phi nodes from start of basic block to here.
unsigned Count = 0;
for (BasicBlock::const_iterator bi = Phi->getParent()->begin(); &*bi != Phi; ++bi)
++Count;
return Count;
}
/***********************************************************************
* dump, print : dump the instruction numbering
*/
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void GenXNumbering::dump()
{
print(errs()); errs() << '\n';
}
#endif
void GenXNumbering::print(raw_ostream &OS) const
{
OS << "GenXNumbering for FunctionGroup " << FG->getName() << "\n";
for (auto fgi = FG->begin(), fge = FG->end(); fgi != fge; ++fgi) {
Function *Func = *fgi;
if (FG->size() != 1)
OS << Func->getName() << ":\n";
for (Function::iterator fi = Func->begin(), fe = Func->end(); fi != fe; ++fi) {
BasicBlock *BB = &*fi;
OS << "\n" << Numbers.find(BB)->second << " " << BB->getName() << ":\n";
for (BasicBlock::iterator bi = BB->begin(), be = BB->end(); bi != be; ++bi) {
Instruction *Inst = &*bi;
if (Numbers.find(Inst) == Numbers.end())
OS << " - ";
else
OS << Numbers.find(Inst)->second;
OS << " ";
Inst->print(OS);
OS << "\n";
}
auto TI = cast<IGCLLVM::TerminatorInst>(BB->getTerminator());
if (TI->getNumSuccessors()) {
BasicBlock *Succ = TI->getSuccessor(0);
for (BasicBlock::iterator sbi = Succ->begin(), sbe = Succ->end(); sbi != sbe; ++sbi) {
if (PHINode *Phi = dyn_cast<PHINode>(&*sbi)) {
OS << "(" << getPhiNumber(Phi, BB) << ") ";
Phi->print(OS);
OS << "\n";
} else
break;
}
}
}
}
OS << "\n";
}
|