File: DeSSA.hpp

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 (326 lines) | stat: -rw-r--r-- 13,331 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
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
/*========================== begin_copyright_notice ============================

Copyright (C) 2017-2021 Intel Corporation

SPDX-License-Identifier: MIT

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

/*========================== begin_copyright_notice ============================

This file is distributed under the University of Illinois Open Source License.
See LICENSE.TXT for details.

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

//===-------- DeSSA.hpp - divide phi variables into congruent class -------===//
//
//  Intel Extention to LLVM core
//===----------------------------------------------------------------------===//
//
// This pass is originated from the StrongPHIElimination on the machine-ir.
// We have adopted it to work on llvm-ir. Also note that we have changed it
// from a transformation to an analysis, meaning which only divides phi-vars
// into congruent classes, and does NOT insert the copies. A separate code-gen
// pass can use this analysis to emit non-ssa target code.
//
//===----------------------------------------------------------------------===//

#pragma once

#include "Compiler/CISACodeGen/LiveVars.hpp"
#include "Compiler/CISACodeGen/WIAnalysis.hpp"
#include "Compiler/CISACodeGen/PatternMatchPass.hpp"
#include "Compiler/MetaDataUtilsWrapper.h"
#include "common/LLVMWarningsPush.hpp"
#include <llvm/Pass.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Instruction.h>
#include <llvm/IR/Instructions.h>
#include <llvm/Support/Allocator.h>
#include <llvm/IR/CFG.h>
#include <llvm/Support/Debug.h>
#include <llvm/IR/Dominators.h>
#include <llvm/ADT/DenseMap.h>
#include <llvm/ADT/MapVector.h>
#include <llvm/ADT/SetVector.h>
#include <llvm/ADT/SmallSet.h>
#include <llvm/ADT/SmallVector.h>
#include <llvm/ADT/DenseSet.h>
#include "common/LLVMWarningsPop.hpp"
#include <map>
#include "Probe/Assertion.h"

namespace IGC {

    class CShader;
    class CVariable;
    class CodeGenPatternMatch;
    class CodeGenContextWrapper;

    class DeSSA : public llvm::FunctionPass {
    public:
        static char ID; // Pass identification, replacement for typeid

        DeSSA();
        virtual void getAnalysisUsage(llvm::AnalysisUsage& AU) const override {
            AU.setPreservesAll();
            AU.addRequired<llvm::DominatorTreeWrapperPass>();
            AU.addRequired<WIAnalysis>();
            AU.addRequired<LiveVarsAnalysis>();
            AU.addRequired<CodeGenPatternMatch>();
            AU.addRequired<llvm::LoopInfoWrapperPass>();
            AU.addRequired<MetaDataUtilsWrapper>();
            AU.addRequired<CodeGenContextWrapper>();
        }
        bool runOnFunction(llvm::Function&) override;

        virtual void releaseMemory() override {
            Allocator.Reset();
            PHISrcDefs.clear();
            PHISrcArgs.clear();
            RegNodeMap.clear();
            InsEltMap.clear();
            AliasMap.clear();
        }

        virtual llvm::StringRef getPassName() const  override {
            return "DeSSA";
        }

        /// Look at the phi-union and insert-element union, find the root value.
        /// return 0 if reg is isolated, and not in any insert-element union
        llvm::Value* getRootValue(llvm::Value*, e_alignment* pAlign = 0) const;

        bool isIsolated(llvm::Value*) const;

        bool isUniform(llvm::Value* v) const {
            return (WIA->isUniform(v));
        }

        void getAllValuesInCongruentClass(
            llvm::Value* V,
            llvm::SmallVector<llvm::Value*, 8> & ValsInCC);

        /// print - print partitions in human readable form
        virtual void print(llvm::raw_ostream& OS, const llvm::Module* = 0) const override;

        /// dump - Dump the partitions to dbgs().
        void dump() const;

    private:
        /// This struct represents a single node in the union-find data structure
        /// representing the variable congruence classes. There is one difference
        /// from a normal union-find data structure. We steal two bits from the parent
        /// pointer . One of these bits is used to represent whether the register
        /// itself has been isolated, and the other is used to represent whether the
        /// PHI with that register as its destination has been isolated.
        ///
        /// Note that this leads to the strange situation where the leader of a
        /// congruence class may no longer logically be a member, due to being
        /// isolated.
        struct Node {
            Node(llvm::Value* v, int c, e_alignment align)
                : parent(this), next(this), prev(this), value(v)
                , rank(0), alignment(align), color(c)
            {
            }

            /// Find leader (representative of a congruent class) by path halving
            Node* getLeader();

            Node* parent;
            // double-linked circular list. All values are in the same congruent class
            // except those that have been isolated.
            Node* next;
            Node* prev;
            llvm::Value* value;
            unsigned rank;
            e_alignment alignment;

            // Unique one for each node. Used to represent the color
            // (in another word, id or label) of a congruent class.
            // Start from 1
            int color;
        };

        /// Get the union-root of a register. The root is 0 if the register has been
        /// isolated.
        llvm::Value* getRegRoot(llvm::Value*, e_alignment* pAlign = 0) const;

        // Return color (>0) if V is in a congruent class; return 0 otherwise.
        // (This is needed during traversal of algo. The color is used as the
        // reprentative of a congruent class that remains unchanged during traversal.)
        int getRootColor(llvm::Value* V);

        // Isolate a register.
        void isolateReg(llvm::Value*);

        /// Is it isolated (single-valued congruent class)
        bool isIsolated(Node* N) const { return (N == N->next); }

        // Split node from its existing congurent class, and
        // node itself becomes a new single-value congruent class
        void splitNode(Node* ND);

        /// Traverses a basic block, splitting any interferences found between
        /// registers in the same congruence class. It takes two DenseMaps as
        /// arguments that it also updates: CurrentDominatingParent, which maps
        /// a color to the register in that congruence class whose definition was
        /// most recently seen, and ImmediateDominatingParent, which maps a register
        /// to the register in the same congruence class that most immediately
        /// dominates it.
        ///
        /// This function assumes that it is being called in a depth-first traversal
        /// of the dominator tree.
        void SplitInterferencesForBasicBlock(
            llvm::BasicBlock*,
            llvm::DenseMap<int, llvm::Value*>& CurrentDominatingParent,
            llvm::DenseMap<llvm::Value*, llvm::Value*>& ImmediateDominatingParent);

        void SplitInterferencesForArgument(
            llvm::DenseMap<int, llvm::Value*>& CurrentDominatingParent,
            llvm::DenseMap<llvm::Value*, llvm::Value*>& ImmediateDominatingParent);

        void SplitInterferencesForAlignment();

        llvm::DominatorTree* DT;
        LiveVars* LV;
        WIAnalysis* WIA;
        llvm::LoopInfo* LI;
        CodeGenPatternMatch* CG;
        const llvm::DataLayout* DL;
        CodeGenContext* CTX;
        llvm::Function* m_F;  // Current Function

        llvm::BumpPtrAllocator Allocator;

        // Color (label) assigned to each congruent class
        // start from 1. Make sure each Node has a different
        // color number.
        int CurrColor;

    public:
        LiveVars* getLiveVars() const { return LV; }

        llvm::MapVector<llvm::Value*, Node*> RegNodeMap;

        // Maps a basic block to a list of its defs of registers that appear as PHI
        // sources.
        llvm::DenseMap<llvm::BasicBlock*, std::vector<llvm::Instruction*> > PHISrcDefs;
        llvm::SetVector<llvm::Value*> PHISrcArgs;

        // Maps a color to a pair of a llvm::Instruction* and a virtual register, which
        // is the operand of that PHI corresponding to the current basic block.
        llvm::DenseMap<int, std::pair<llvm::Instruction*, llvm::Value*> > CurrentPHIForColor;

        // Implement reuse for InsertElement only
        // Hierarchical coalescing:
        // - step 1, union insert-elements into trees, update the liveness
        // - step 2, build phi-union, the root of the InsElt-union-tree can be added to the phi-union.
        // - step 3, detect interferences of every phi-union, a set of insert-elements are associated
        //           with a single-node in phi-union. When being isolated, they are isolated together
        llvm::MapVector<llvm::Value*, llvm::Value*> InsEltMap;

        // Value Alias map
        //   This is used for maitaining aliases among values. It maps a value, called 'aliaser',
        //   to its 'aliasee' (denoted as alias(aliaer, aliasee). This map has the following
        //   properties:
        //       1. No alias chain, that is, the map does not have both alias(v0, v1) and
        //          alias(v1, v2) with v0 != V1 != v2.
        //
        //          Note that for each aliasee, say V,  alias(V, V) is in map for convenience to
        //          indicate V is aliasee and to help setup aliasing entry of the map.
        //       2. The aliasee's liveness info has been updated to be the union of all its aliasers.
        //          In this way, only aliasee will be used in DeSSA node.
        //
        // The DeSSA/Coalescing procedure:
        //   1. Follow Dominance tree to set up alias map. While setting up alias map,
        //      update liveness for aliasee.
        //   2. Make sure InsEltMap only use aliasee
        //   3. Make sure DeSSA node only use aliasee.
        llvm::DenseMap<llvm::Value*, llvm::Value*> AliasMap;

        // If an inst is an aliaser and no need to generate code
        // due to aliasing, it will be added in this map.
        llvm::DenseMap<llvm::Value*, int> NoopAliasMap;

        /// If there is no node for Val, create a new one.
        void addReg(llvm::Value* Val, e_alignment Align);

        int getGRFSize() const { return CTX->platform.getGRFSize(); }

        /// union-by-rank:
        ///   Join the congruence classes of two registers by attaching
        ///   a shorter tree to a taller tree. If they have the same height,
        ///   attaching Val2 to Val1. Note that unionRegs() expects that
        ///   nodes for Val1 and Val2 have been created already.
        void unionRegs(llvm::Value* Val1, llvm::Value* Val2) {
            unionRegs(RegNodeMap[Val1], RegNodeMap[Val2]);
        }

        // For a value, return its representative value that is used
        // to create dessa node, which is its aliasee's InsElt root.
        llvm::Value* getNodeValue(llvm::Value* V) const {
            llvm::Value* aliasee = getAliasee(V);
            return getInsEltRoot(aliasee);
        }

        llvm::Value* getInsEltRoot(llvm::Value* Val) const;
        llvm::Value* getAliasee(llvm::Value* V) const;
        bool isAliasee(llvm::Value* V) const;
        bool isAliaser(llvm::Value* V) const;
        bool isNoopAliaser(llvm::Value* V) const;
        bool isSingleValued(llvm::Value* V) const;
        bool interfere(llvm::Value* V0, llvm::Value* V1);
        bool aliasInterfere(llvm::Value* V0, llvm::Value* V1);
        bool alignInterfere(e_alignment a1, e_alignment a2);

    private:
        void CoalesceInsertElementsForBasicBlock(llvm::BasicBlock* blk);

        void InsEltMapAddValue(llvm::Value* Val) {
            if (InsEltMap.find(Val) == InsEltMap.end()) {
                InsEltMap[Val] = Val;
            }
        }
        void InsEltMapUnionValue(llvm::Value* SrcVal, llvm::Value* DefVal) {
            IGC_ASSERT(InsEltMap.find(SrcVal) != InsEltMap.end());
            InsEltMap[DefVal] = InsEltMap[SrcVal];
        }

        void unionRegs(Node* N1, Node* N2);
        void CoalesceAliasInstForBasicBlock(llvm::BasicBlock* Blk);
        int checkInsertElementAlias(
            llvm::InsertElementInst* IEI,
            llvm::SmallVector<llvm::Value*, 16> & AllIEIs);

        // Add Val->Val into aliasMap if it is not in the map yet.
        // Return Val's aliasee.
        void AddAlias(llvm::Value* Val) {
            if (AliasMap.find(Val) == AliasMap.end())
                AliasMap[Val] = Val;
        }

        // If V is an arg or a needed inst (by patternmatch),
        // return true; otherwise, return false;
        bool isArgOrNeededInst(llvm::Value* V) {
            if (llvm::Instruction * I = llvm::dyn_cast<llvm::Instruction>(V))
            {
                return CG->NeedInstruction(*I);
            }
            return llvm::isa<llvm::Argument>(V);
        }
    };

    struct MIIndexCompare {
        MIIndexCompare(LiveVars* _lv) : LV(_lv) { }

        bool operator()(const llvm::Instruction* LHS, const llvm::Instruction* RHS) const {
            return LV->getDistance(LHS) < LV->getDistance(RHS);
        }

        LiveVars* LV;
    };

} // End CISA namespace