File: GenXModule.cpp

package info (click to toggle)
intel-graphics-compiler 1.0.12504.6-1%2Bdeb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 83,912 kB
  • sloc: cpp: 910,147; lisp: 202,655; ansic: 15,197; python: 4,025; yacc: 2,241; lex: 1,570; pascal: 244; sh: 104; makefile: 25
file content (216 lines) | stat: -rw-r--r-- 8,072 bytes parent folder | download | duplicates (3)
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
/*========================== begin_copyright_notice ============================

Copyright (C) 2017-2021 Intel Corporation

SPDX-License-Identifier: MIT

============================= end_copyright_notice ===========================*/

//
// GenXModule is a module pass whose purpose is to store information
// about the GenX module being written, such as the built kernels and functions.
// See the comment in GenXModule.h.
//
//===----------------------------------------------------------------------===//
#include "GenXModule.h"
#include "FunctionGroup.h"
#include "GenX.h"
#include "GenXSubtarget.h"
#include "GenXTargetMachine.h"

#include "vc/Utils/GenX/ImplicitArgsBuffer.h"
#include "vc/Utils/GenX/KernelInfo.h"
#include "vc/Utils/General/DebugInfo.h"

#include <llvm/CodeGen/TargetPassConfig.h>
#include <llvm/GenXIntrinsics/GenXMetadata.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Instructions.h>
#include <llvm/Support/Debug.h>
#include <llvm/Transforms/Utils/Cloning.h>

#include <set>
#include "Probe/Assertion.h"

#define DEBUG_TYPE "GENX_MODULE"

using namespace llvm;

char GenXModule::ID = 0;
INITIALIZE_PASS_BEGIN(GenXModule, "GenXModule", "GenXModule", false,
                      true /*analysis*/)
INITIALIZE_PASS_DEPENDENCY(FunctionGroupAnalysis)
INITIALIZE_PASS_DEPENDENCY(GenXBackendConfig)
INITIALIZE_PASS_END(GenXModule, "GenXModule", "GenXModule", false,
                    true /*analysis*/)

ModulePass *llvm::createGenXModulePass() {
  initializeGenXModulePass(*PassRegistry::getPassRegistry());
  return new GenXModule;
}

void GenXModule::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<FunctionGroupAnalysis>();
  AU.addRequired<GenXBackendConfig>();
  AU.addRequired<TargetPassConfig>();
  AU.setPreservesAll();
}

bool GenXModule::CheckForInlineAsm(Module &M) const {
  for (auto &F : M)
    for (auto &BB : F)
      for (auto &I : BB) {
        CallInst *CI = dyn_cast<CallInst>(&I);
        if (CI && CI->isInlineAsm())
          return true;
      }
  return false;
}

static bool isImplicitArgsBufferUsed(const Module &M) {
  return llvm::any_of(vc::kernels(M), [](const Function &F) {
    return F.hasFnAttribute(vc::ImplicitArgs::KernelAttr);
  });
}

/***********************************************************************
 * runOnModule : run GenXModule analysis
 *
 * This populates FunctionGroupAnalysis such that each FunctionGroup
 * corresponds to a GenX kernel/function and its subroutines. If any
 * subroutine would be used in more than one FunctionGroup, it is
 * cloned.
 *
 * The FunctionGroup is populated in an order such that a function appears
 * after all its callers.
 */
bool GenXModule::runOnModule(Module &M) {
  auto FGA = &getAnalysis<FunctionGroupAnalysis>();
  const auto &TM = getAnalysis<TargetPassConfig>().getTM<GenXTargetMachine>();

  ST = &TM.getGenXSubtarget();
  Ctx = &M.getContext();
  BC = &getAnalysis<GenXBackendConfig>();

  InlineAsm = CheckForInlineAsm(M);

  DisableFinalizerOpts = TM.getOptLevel() == CodeGenOpt::Level::None;
  EmitDebugInformation =
      BC->emitDWARFDebugInfo() && vc::DIBuilder::checkIfModuleHasDebugInfo(M);
  ImplicitArgsBufferIsUsed = isImplicitArgsBufferUsed(M);

  bool ModuleModified = FGA->legalizeGroups();
  FGA->buildGroups();
  return ModuleModified;
}

using MappingT = genx::di::VisaMapping::Mapping;

void GenXModule::updateVisaMapping(const Function *K, const Instruction *Inst,
                                   unsigned VisaIndex, StringRef Reason) {
  // NOTE: K stands for "kernel function". That is the function that is
  // for the currently generated vISA object
  IGC_ASSERT(K);

  auto PrevCounter = VisaCounter[K];
  VisaCounter[K] = VisaIndex;
  if (!Inst) {
    LLVM_DEBUG(dbgs() << "visaCounter update <" << K->getName() << ">:{"
                      << PrevCounter << "->" << VisaIndex
                      << "}, src: " << Reason << "\n");
    return;
  }

  const auto *F = Inst->getFunction();
  LLVM_DEBUG(dbgs() << "visaCounter update <" << K->getName() << "/"
                    << ((F == K) ? StringRef(".") : F->getName()) << ">: {"
                    << PrevCounter << "->" << VisaIndex << "}, inst: " << *Inst
                    << "\n");

  // Unfortunately, our CISA builder routines are not very consistent with
  // respect to the interfaces used to emit vISA.
  // There may be situations when the debug information for instruction is
  // updated several times (like when we emit an additional VISALifeTime
  // instruction)
  // This check is a workaround for a problem when we may emit an auxiliary
  // visa instruction using the interface which requires us to update the
  // "current instruction" without actually doing so.
  auto &Map = VisaMapping[F];
  const Instruction *LastInst =
      Map.V2I.empty() ? nullptr : Map.V2I.rbegin()->Inst;
  if (LastInst != Inst) {
    bool IsDbgInst = isa<DbgInfoIntrinsic>(Inst);
    Map.V2I.emplace_back(MappingT{VisaIndex, Inst, 0 /*Count*/, IsDbgInst});
    LLVM_DEBUG(dbgs() << "Added :" << VisaIndex << ": " << *Inst << " \n");
  }
  if (!Map.V2I.empty())
    LLVM_DEBUG(dbgs() << "Last element <"
                      << " id =" << Map.V2I.rbegin()->VisaIdx
                      << " count =" << Map.V2I.rbegin()->VisaCount
                      << " inst: " << *(Map.V2I.rbegin()->Inst) << "\n");
}

void GenXModule::updateVisaCountMapping(const Function *K,
                                        const Instruction *Inst,
                                        unsigned VisaIndex, StringRef Reason) {
  IGC_ASSERT(K);
  IGC_ASSERT(Inst);
  auto PrevCounter = VisaCounter[K];
  VisaCounter[K] = VisaIndex;
  const auto *F = Inst->getFunction();
  auto &Map = VisaMapping[F];
  if (Map.V2I.empty())
    return;

  // Update instruction size or remove instruction mapping, if there is
  // no visa instruction found for it.
  auto LastElement = Map.V2I.rbegin();
  // Do not fill mapping for instructions with empty elements
  // update counter does not called for debug-instructions
  if (LastElement->VisaIdx == VisaIndex && LastElement->VisaCount == 0 &&
      LastElement->Inst == Inst) {
    LLVM_DEBUG(dbgs() << "Remove empty mapping for ");
    LLVM_DEBUG(LastElement->Inst->dump());
    Map.V2I.pop_back();
  } else if (!LastElement->IsDbgInst) {
    IGC_ASSERT(VisaIndex - PrevCounter >= 0);
    LastElement->VisaCount = VisaIndex - LastElement->VisaIdx;
    LLVM_DEBUG(dbgs() << "visaCounter update Map <" << K->getName() << "/"
                      << ((F == K) ? StringRef(".") : F->getName())
                      << "> for :{" << PrevCounter << " count = "
                      << LastElement->VisaCount << " in_inst =" << *Inst
                      << "}, src: End " << Reason << "\n");
  } else {
    IGC_ASSERT(!isa<DbgInfoIntrinsic>(Inst));
    LLVM_DEBUG(dbgs() << "remove unused instruction from Map <" << K->getName()
                      << "/" << ((F == K) ? StringRef(".") : F->getName())
                      << "> for :{" << PrevCounter << " -> " << VisaIndex
                      << "} inst =" << *Inst << ", src: Lost " << Reason
                      << "\n");
    Map.V2I.emplace_back(MappingT{PrevCounter, Inst, VisaIndex - PrevCounter,
                                  false /*Not dbg inst!*/});
  }

  if (!Map.V2I.empty())
    LLVM_DEBUG(dbgs() << "Last element <" << Map.V2I.rbegin()->VisaIdx
                      << " id = "
                      << " inst: " << *(Map.V2I.rbegin()->Inst) << "\n");
}

const genx::di::VisaMapping *
GenXModule::getVisaMapping(const Function *F) const {
  IGC_ASSERT(VisaMapping.count(F));
  return &VisaMapping.at(F);
}

GenXModule::InfoForFinalizer GenXModule::getInfoForFinalizer() const {
  InfoForFinalizer Info;
  Info.EmitDebugInformation = EmitDebugInformation;
  Info.DisableFinalizerOpts = DisableFinalizerOpts;
  IGC_ASSERT_MESSAGE(
      ST,
      "GenXSubtarget must be defined to call GenXModule::getInfoForFinalizer");
  Info.EmitCrossThreadOffsetRelocation =
      ST->hasThreadPayloadInMemory() && ImplicitArgsBufferIsUsed;
  return Info;
}