File: GenXNumbering.h

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 (145 lines) | stat: -rw-r--r-- 6,247 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
/*========================== begin_copyright_notice ============================

Copyright (C) 2017-2021 Intel Corporation

SPDX-License-Identifier: MIT

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

//
/// GenXNumbering
/// -------------
///
/// GenXNumbering is an analysis that provides a numbering of the instructions
/// for use by live ranges.
///
/// The numbering is done such that slots are reserved for where GenXCoalescing
/// might need to insert copies.
///
/// Generally, an instruction gets a slot in the numbering for itself, and
/// another slot just before, in case it is a two address instruction where
/// GenXCoalescing might want to insert a copy.
///
/// Every instruction gets a number, even if it is baled in. However, for the
/// purposes of live range segments, every instruction in a bale is assumed
/// to have the same number as the head instruction of the bale.
///
/// A non-intrinsic call has N slots reserved
/// before it for pre-copies, where N is the number of SimpleValues in the
/// (possibly struct) args, allowing for extra args that might be added later by
/// GenXArgIndirection.
///
/// Similarly, a non-intrinsic call has N slots reserved after it for
/// post-copies, where N is the number of SimpleValues in the (possibly struct)
/// return value. The definition of each SimpleValue in the result of the call
/// is considered to be in its slot, and the corresponding SimpleValue in the
/// unified return value has an extra segment of live range from the call up to
/// that slot.
///
/// A return instruction in a subroutine has N slots reserved before it for
/// pre-copies, where N is the number of SimpleValues in the (possibly struct)
/// return value. The use of each SimpleValue in the return is considered to be
/// in its slot, and the corresponding SimpleValue in the unified return value
/// has an extra segment of live range from the slot up to the return.
///
/// A kernel has a slot for each kernel arg copy. A copy is inserted into such a slot in
/// GenXCoalescing if the kernel arg offset is not aligned enough for the uses
/// of the value.
///
/// **IR restriction**: After this pass, it is very difficult to modify code
/// other than by inserting copies in the reserved slots above, as it would
/// disturb the numbering.
///
//===----------------------------------------------------------------------===//
#ifndef GENXNUMBERING_H
#define GENXNUMBERING_H

#include "FunctionGroup.h"
#include "IgnoreRAUWValueMap.h"
#include "llvm/IR/Value.h"

#include <unordered_map>

namespace llvm {

class CallInst;
class GenXBaling;
class PHINode;
class ReturnInst;

class GenXNumbering : public FGPassImplInterface,
                      public IDMixin<GenXNumbering> {
  FunctionGroup *FG = nullptr;
  GenXBaling *Baling = nullptr;
  struct BBNumber {
    unsigned Index; // 0-based index in list of basic blocks
    unsigned PhiNumber; // instruction number of first phi node in successor
    unsigned EndNumber; // instruction number of end of block
  };
  // BBNumbers : The 0-based number (index) of each basic block.
  ValueMap<const BasicBlock *, BBNumber,
          IgnoreRAUWValueMapConfig<const BasicBlock *>> BBNumbers;
  // Numbers : The map of instruction numbers.
  ValueMap<const Value *, unsigned,
          IgnoreRAUWValueMapConfig<const Value *>> Numbers;
  // StartNumbers : for a CallInst, the start number of where arg pre-copies
  // are considered to be. This is stored, instead of being calculated from
  // the CallInst's number, so that a CallInst can change number of args, as
  // happens in GenXArgIndirection.
  ValueMap<const Value *, unsigned,
          IgnoreRAUWValueMapConfig<const Value *>> StartNumbers;
  // NumberToPhiIncomingMap : map from instruction number to the phi incoming
  // (phi node plus incoming index) it represents. We assume that a phi node is
  //  never deleted after GenXNumbering. It is implemented as multimap because
  //  several Phis may refer to the same PHYCPY segment.
  std::unordered_multimap<unsigned, std::pair<PHINode *, unsigned>>
      NumberToPhiIncomingMap;

  // The number for the entire fucntion group. All live ranges are included in
  // live-range [0, LastNum].
  unsigned LastNum = 0;

public:
  explicit GenXNumbering() : Baling(0) {}
  static StringRef getPassName() { return "GenX numbering"; }
  static void getAnalysisUsage(AnalysisUsage &AU);
  bool runOnFunctionGroup(FunctionGroup &FG) override;
  // get BBNumber struct for a basic block
  const BBNumber *getBBNumber(BasicBlock *BB) { return &BBNumbers[BB]; }
  // get and set instruction number
  unsigned getBaleNumber(Instruction *Inst);
  unsigned getNumber(Value *V) const;
  unsigned getLastNumber() const { return LastNum; }
  void setNumber(Value *V, unsigned Number);
  // get and set "start instruction number" for a CallInst
  unsigned getStartNumber(Value *V) { return StartNumbers[V]; }
  void setStartNumber(Value *V, unsigned Number) { StartNumbers[V] = Number; }
  // get number for kernel arg copy, arg pre-copy, ret pre-copy and ret post-copy sites
  unsigned getArgIndirectionNumber(CallInst *CI, unsigned OperandNum, unsigned Index);
  unsigned getKernelArgCopyNumber(Argument *Arg);
  unsigned getArgPreCopyNumber(CallInst *CI, unsigned OperandNum, unsigned Index);
  unsigned getRetPreCopyNumber(ReturnInst *RI, unsigned Index);
  unsigned getRetPostCopyNumber(CallInst *CI, unsigned Index);
  // get the number of a phi incoming, where its copy will be inserted
  // if necessary
  unsigned getPhiNumber(PHINode *Phi, BasicBlock *BB) const;
  unsigned getPhiNumber(PHINode *Phi, BasicBlock *BB);
  // getPhiIncomingFromNumber : get the phi incoming for a number returned from getPhiNumber
  std::unordered_map<PHINode *, unsigned>
  getPhiIncomingFromNumber(unsigned Number);
  // Debug dump
  void print(raw_ostream &OS) const;
  void dump();

  void releaseMemory() override;

private:
  unsigned numberInstructionsInFunc(Function *Func, unsigned Num);
  unsigned getPhiOffset(PHINode *Phi) const;
};

void initializeGenXNumberingWrapperPass(PassRegistry &);
using GenXNumberingWrapper = FunctionGroupWrapperPass<GenXNumbering>;

} // end namespace llvm
#endif //ndef GENXNUMBERING_H