File: GenXGlobalUniform.cpp

package info (click to toggle)
intel-graphics-compiler 1.0.17791.18-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 102,312 kB
  • sloc: cpp: 935,343; lisp: 286,143; ansic: 16,196; python: 3,279; yacc: 2,487; lex: 1,642; pascal: 300; sh: 174; makefile: 27
file content (133 lines) | stat: -rw-r--r-- 3,980 bytes parent folder | download | duplicates (2)
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
/*========================== begin_copyright_notice ============================

Copyright (C) 2023 Intel Corporation

SPDX-License-Identifier: MIT

============================= end_copyright_notice ===========================*/
#include "GenXGlobalUniform.h"
#include "GenXUtil.h"
#include "GenX.h"

#include "llvm/IR/InstIterator.h"
#include "llvm/InitializePasses.h"

#include <stack>

#define DEBUG_TYPE "GENX_GLOBAL_UNIFORM"

using namespace llvm;

static cl::opt<bool>
    PrintGlobalUniform("print-global-uniform-info", cl::init(false), cl::Hidden,
                       cl::desc("Print GenXGlobalUniform analysis results"));

char GenXGlobalUniformAnalysis::ID = 0;

INITIALIZE_PASS_BEGIN(GenXGlobalUniformAnalysis, "GenXGlobalUniformAnalysis",
                      "GenXGlobalUniformAnalysis", false, true)
INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)
INITIALIZE_PASS_END(GenXGlobalUniformAnalysis, "GenXGlobalUniformAnalysis",
                    "GenXGlobalUniformAnalysis", false, true)

FunctionPass *llvm::createGenXGlobalUniformAnalysisPass() {
  initializeGenXGlobalUniformAnalysisPass(*PassRegistry::getPassRegistry());
  return new GenXGlobalUniformAnalysis();
}

void GenXGlobalUniformAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
  FunctionPass::getAnalysisUsage(AU);
  AU.addRequired<PostDominatorTreeWrapperPass>();
  AU.setPreservesCFG();
}

void GenXGlobalUniformAnalysis::print(raw_ostream &OS) const {
  OS << "Non-uniform basic blocks:\n";
  for (auto *BB : m_Divergent)
    OS << "\t" << BB->getName() << "\n";
}

void GenXGlobalUniformAnalysis::analyzeDivergentCFG(
    IGCLLVM::TerminatorInst *TI) {
  BasicBlock *StartBB = TI->getParent();
  if (m_Divergent.find(StartBB) != m_Divergent.end())
    return;

  // Get immediate post dominator - the basic block where CFG joins again.
  // It could be null in case when the function has multiple exits
  BasicBlock *IPD = PDT->getNode(StartBB)->getIDom()->getBlock();

  std::stack<BasicBlock *> Stack;
  Stack.push(StartBB);

  DenseSet<BasicBlock *> Visited;

  // Mark as divergent all the basic blocks from the start till the IPD
  while (!Stack.empty()) {
    auto *BB = Stack.top();
    Stack.pop();
    Visited.insert(BB);
    for (auto *Succ : successors(BB)) {
      if (Succ == IPD)
        continue;
      if (Visited.find(Succ) != Visited.end())
        continue;
      m_Divergent.insert(Succ);
      Stack.push(Succ);
    }
  }
}

bool GenXGlobalUniformAnalysis::runOnFunction(Function &F) {
  this->F = &F;
  PDT = &getAnalysis<PostDominatorTreeWrapperPass>().getPostDomTree();

  std::stack<Value *> Stack;

  // Find all the non-uniform values in function
  // First check the arguments
  for (auto &Arg : F.args()) {
    if (Arg.getName() == "impl.arg.llvm.genx.local.id16" ||
        Arg.getName() == "impl.arg.llvm.genx.local.id")
      Stack.push(cast<Value>(&Arg));
  }

  // Do the initial instrucion scan
  for (auto &Inst : instructions(F)) {
    unsigned IID = vc::getAnyIntrinsicID(&Inst);
    switch (IID) {
    case GenXIntrinsic::genx_group_id_x:
    case GenXIntrinsic::genx_group_id_y:
    case GenXIntrinsic::genx_group_id_z:
    case GenXIntrinsic::genx_local_id:
    case GenXIntrinsic::genx_local_id16:
      Stack.push(cast<Value>(&Inst));
      break;
    }
  }

  DenseSet<Value *> Visited;

  // Traverse the use-def chain for found non-uniform values
  // and mark every user of non-uniform value also as non-uniform
  while (!Stack.empty()) {
    auto *V = Stack.top();
    Stack.pop();
    Visited.insert(V);
    for (auto *U : V->users()) {
      if (Visited.find(cast<Value>(U)) != Visited.end())
        continue;
      auto *Inst = dyn_cast<Instruction>(U);
      if (Inst && Inst->isTerminator()) {
        // Non-uniform terminator found. This means the start of divergent CFG
        analyzeDivergentCFG(Inst);
      }
      Stack.push(cast<Value>(U));
    }
  }

  if (PrintGlobalUniform)
    print(outs());

  return false;
}