File: GenXLiveElements.h

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 (204 lines) | stat: -rw-r--r-- 7,057 bytes parent folder | download
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
/*========================== begin_copyright_notice ============================

Copyright (C) 2023 Intel Corporation

SPDX-License-Identifier: MIT

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

//
/// GenXLiveElements
/// --------------------
///
/// GenXLiveElements is an analysis pass that stores information about
/// live (i.e. possibly used in future) lanes of vector instructions and
/// their uses inside a function. Pass starts its work from root instructions
/// (terminators and side-effect instructions) and propagates this information
/// backwards until some stable point is not reached. Propagation function for
/// each instruction gets live elements of its result and estimates what
/// elements in operands are required to it. For unknown types of instructions
/// there is a safe fallback to estimate "all-live" result, but this can be
/// improved in future to get more precise results
//===----------------------------------------------------------------------===//
#ifndef GENXLIVEELEMENTS_H
#define GENXLIVEELEMENTS_H

#include "FunctionGroup.h"

#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/ValueMap.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"

namespace llvm {
namespace genx {

// LiveElements is an utility class to represent information about used elements
// inside some type, possibly aggregate. It contains bit masks for each simple
// (scalar or vector) value in flattened order for complex nested types. The
// special case is void type, which doesn't have any bit mask (even empty). Such
// empty LiveElements is treated as always used

class LiveElements {
private:
  using LiveElementsTy = SmallVector<SmallBitVector, 2>;
  LiveElementsTy LiveElems;

public:
  using size_type = LiveElementsTy::size_type;
  using iterator = LiveElementsTy::iterator;
  using const_iterator = LiveElementsTy::const_iterator;
  using reference = LiveElementsTy::reference;
  using const_reference = LiveElementsTy::const_reference;

  LiveElements() = default;
  LiveElements(Type *Ty, bool IsLive = false);
  LiveElements(const ArrayRef<SmallBitVector> LE)
      : LiveElems(LE.begin(), LE.end()) {}
  LiveElements(SmallBitVector &&LE) : LiveElems({std::move(LE)}) {}
  LiveElements(const SmallBitVector &LE) = delete;
  LiveElements &operator=(const SmallBitVector &) = delete;

  iterator begin() { return LiveElems.begin(); }
  const_iterator begin() const { return LiveElems.begin(); }
  iterator end() { return LiveElems.end(); }
  const_iterator end() const { return LiveElems.end(); }
  reference operator[](size_type Idx) { return LiveElems[Idx]; }
  const_reference operator[](size_type Idx) const { return LiveElems[Idx]; }
  size_type size() const { return LiveElems.size(); }

  bool isAllDead() const {
    return !LiveElems.empty() && all_of(LiveElems, [](const auto &LiveBits) {
      return !LiveBits.empty() && LiveBits.none();
    });
  }

  bool isAnyDead() const {
    return !LiveElems.empty() && any_of(LiveElems, [](const auto &LiveBits) {
      return !LiveBits.empty() && !LiveBits.all();
    });
  }

  bool operator==(const LiveElements &Rhs) const {
    return LiveElems == Rhs.LiveElems;
  }

  bool operator!=(const LiveElements &Rhs) const { return !(*this == Rhs); }

  LiveElements operator|=(const LiveElements &Rhs);

  void print(raw_ostream &OS) const;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
  void dump() const;
#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
};

inline LiveElements operator|(const LiveElements &Lhs,
                              const LiveElements &Rhs) {
  LiveElements Res(Lhs);
  Res |= Rhs;
  return Res;
}

inline raw_ostream &operator<<(raw_ostream &OS, const LiveElements &LE) {
  LE.print(OS);
  return OS;
}
} // namespace genx

// GenXLiveElements - analysis that can give information for 2 types of
// queries:
// 1. What elements of instruction result or function argument are live (i.e.
//    can be used later)
// 2. What elements of value are live in some particular use. This gives
//    more precise result that live elements of whole value, because
//    multiple uses of same value can use different elements
class GenXLiveElements {
public:
  void processFunction(const Function &F);
  void clear() { LiveMap.clear(); }

  genx::LiveElements getLiveElements(const Value *V) const;
  genx::LiveElements getLiveElements(const Use *U) const;

private:
  ValueMap<const Value *, genx::LiveElements> LiveMap;

  genx::LiveElements
  getBitCastLiveElements(const BitCastInst *BCI,
                         const genx::LiveElements &InstLiveElems) const;
  genx::LiveElements
  getExtractValueLiveElements(const ExtractValueInst *EVI, unsigned OperandNo,
                              const genx::LiveElements &InstLiveElems) const;
  genx::LiveElements
  getInsertValueLiveElements(const InsertValueInst *IVI, unsigned OperandNo,
                             const genx::LiveElements &InstLiveElems) const;
  genx::LiveElements
  getRdRegionLiveElements(const Instruction *RdR, unsigned OperandNo,
                          const genx::LiveElements &InstLiveElems) const;
  genx::LiveElements
  getWrRegionLiveElements(const Instruction *WrR, unsigned OperandNo,
                          const genx::LiveElements &InstLiveElems) const;
  genx::LiveElements
  getTwoDstInstLiveElements(const genx::LiveElements &InstLiveElems) const;
  genx::LiveElements
  getOperandLiveElements(const Instruction *Inst, unsigned OperandNo,
                         const genx::LiveElements &InstLiveElems) const;
};

// Function pass wrapper for GenXLiveElements
class GenXFuncLiveElements : public FunctionPass,
                             public GenXLiveElements {
public:
  static char ID;

  explicit GenXFuncLiveElements() : FunctionPass(ID) {}

  StringRef getPassName() const override {
    return "GenX live elements analysis for a function";
  }

  void releaseMemory() override { clear(); }

  void getAnalysisUsage(AnalysisUsage &AU) const override {
    AU.setPreservesAll();
  }

  bool runOnFunction(Function &F) override {
    clear();
    processFunction(F);
    return false;
  }
};

void initializeGenXFuncLiveElementsPass(PassRegistry &);

// FunctionGroup pass wrapper for GenXLiveElements
class GenXGroupLiveElements : public FGPassImplInterface,
                              public IDMixin<GenXGroupLiveElements>,
                              public GenXLiveElements {
public:
  static StringRef getPassName() {
    return "GenX live elements analysis for a function group";
  }

  void releaseMemory() override { clear(); }

  static void getAnalysisUsage(AnalysisUsage &AU) { AU.setPreservesAll(); }

  bool runOnFunctionGroup(FunctionGroup &FG) override {
    clear();
    for (auto &F : FG)
      processFunction(*F);
    return false;
  }
};

void initializeGenXGroupLiveElementsWrapperPass(PassRegistry &);

using GenXGroupLiveElementsWrapper =
    FunctionGroupWrapperPass<GenXGroupLiveElements>;
} // namespace llvm

#endif