1 /*========================== begin_copyright_notice ============================
2 
3 Copyright (C) 2017-2021 Intel Corporation
4 
5 SPDX-License-Identifier: MIT
6 
7 ============================= end_copyright_notice ===========================*/
8 
9 #ifndef _IGA_SWSBSETTER_H_
10 #define _IGA_SWSBSETTER_H_
11 
12 #include "Instruction.hpp"
13 #include "Block.hpp"
14 #include "Kernel.hpp"
15 #include "Operand.hpp"
16 #include "../ErrorHandler.hpp"
17 #include "RegDeps.hpp"
18 
19 namespace iga
20 {
21     // Bucket represents a GRF and maps to all instructions that access it
22     class Bucket
23     {
24     public:
Bucket()25         Bucket() { dependencies.reserve(5); }
clearDependency()26         void clearDependency() { dependencies.clear(); }
isEmpty() const27         bool isEmpty() const { return dependencies.empty(); }
getNumDependencies() const28         size_t getNumDependencies() const { return dependencies.size(); }
getDepSet(uint32_t index)29         DepSet * getDepSet(uint32_t index) { return dependencies[index]; }
clearDepSet(uint32_t index)30         void clearDepSet(uint32_t index) { dependencies[index] = nullptr; }
31         //Most of the time dependecy vector will have 1 or two entries
addDepSet(DepSet * dep)32         void addDepSet(DepSet *dep) {
33             bool depSet = false;
34             for (size_t i = 0; i < dependencies.size(); ++i)
35             {
36                 if (!dependencies[i])
37                 {
38                     dependencies[i] = dep;
39                     depSet = true;
40                     break;
41                 }
42             }
43             if (!depSet)
44             {
45                 dependencies.push_back(dep);
46             }
47         }
48     private:
49         std::vector<DepSet*> dependencies;
50     };
51 
52     class SWSBAnalyzer
53     {
54     public:
55         typedef DepSet::InstIDs InstIDs;
56     public:
57         //Blocks have already been created
SWSBAnalyzer(Kernel & k,ErrorHandler & errHandler,SWSB_ENCODE_MODE encode_mode,int sbid_count)58         SWSBAnalyzer(Kernel &k, ErrorHandler &errHandler,
59             SWSB_ENCODE_MODE encode_mode, int sbid_count)
60                       : m_kernel(k),
61                         m_errorHandler(errHandler),
62                         m_SBIDRRCounter(0),
63                         m_initPoint(false),
64                         MAX_VALID_DISTANCE(k.getModel().getSWSBMaxValidDistance())
65         {
66             // Set SWSB_ENCODE_MODE
67             if (encode_mode != SWSB_ENCODE_MODE::SWSBInvalidMode)
68                 m_swsbMode = encode_mode;
69             else
70                 m_swsbMode = k.getModel().getSWSBEncodeMode();
71 
72             if (m_swsbMode == SWSB_ENCODE_MODE::FourDistPipeReduction
73                 ) {
74                 m_LatencyLong64Pipe = 12;
75             }
76 
77             m_DB = new DepSetBuilder(k.getModel());
78             m_buckets = new Bucket[m_DB->getTOTAL_BUCKETS()];
79 
80             // set sbid count to 16 if not given
81             if (sbid_count)
82                 m_SBIDCount = sbid_count;
83             else
84                 m_SBIDCount = 16;
85             m_freeSBIDList.resize(m_SBIDCount);
86         }
87 
~SWSBAnalyzer()88         ~SWSBAnalyzer()
89         {
90             delete m_DB;
91             delete[] m_buckets;
92         }
93 
94         void run();
95 
96         // getNumOfDistPipe - get number of in-order distance pipes of the given mode
97         static uint32_t getNumOfDistPipe(SWSB_ENCODE_MODE mode);
98 
99     private:
100         // postProcess - last step of "run"
101         void postProcess();
102 
103     private:
104         // activeSBID: input list that the sbid this dep has dependency on will be added into. This list
105         // will later on be pass to processActiveSBID to set the swsb id dependency to inst accordingly
106         // needSyncForShootDownInst: if the sync to the sbid on the instruction is required. If the instruction
107         // is possiblely being shoot down, we have to add a sync to the id is synced with because we will
108         // clear the dependency
109         void calculateDependence(DepSet &dep,
110                                  SWSB &distanceDependency,
111                                  const Instruction &currInst,
112                                  std::vector<SBID> &activeSBID,
113                                  bool &needSyncForShootDownInst);
114         void processActiveSBID(SWSB &distanceDependency,
115                                const DepSet* input,
116                                Block *bb,
117                                InstList::iterator iter,
118                                std::vector<SBID>& activeSBID);
119 
120         // helper function to pick a free SBID and set it to distanceDependency.
121         // This function only set SBID to distanceDependency, will not assign distanceDependency to
122         // the inst
123         SBID& assignSBID(DepSet* input, DepSet* output, Instruction& inst, SWSB& distanceDependency,
124             InstList::iterator insertPoint, Block *curBB, bool needSyncForShootDown);
125 
126         // helper fuction to set out-of-order dependecy. Called by calculateDependence.
127         // This function create SBID with depedency to given dep, and add it to activeSBID
128         // it also set needSyncForShootDownInst if required.
129         void setSbidDependency(DepSet& dep, const Instruction& currInst,
130             bool& needSyncForShootDownInst, std::vector<SBID>& activeSBID);
131 
132         // clear dependency of the given dep
133         void clearDepBuckets(DepSet &dep);
134         // clear all sbid, set ids to all free and insert sync to sync with all pipes
135         void clearSBIDDependence(InstList::iterator insertPoint, Instruction *lastInst, Block *bb);
136         // clear given input and output dependency in the buckets (for in-order pipes only)
137         void clearBuckets(DepSet* input, DepSet* output);
138 
139         // helper function to insert sync.allrd and sync.allwr before the given inserPoint of given bb
140         void insertSyncAllRdWr(InstList::iterator insertPoint, Block *bb);
141 
142         // a helper function to increase inst id counter based on the current encoding mode
143         void advanceInorderInstCounter(DEP_PIPE dep_pipe);
144 
145         // get number of dist pipe according to SWSB_ENCODE_MODE
146         uint32_t getNumOfDistPipe();
147 
148         // addRMWDependencyIfReqruied - add read dependnecy to input DepSet if the instruction has RMW
149         // behavior, which is, has byte type dst
150         // XeHPC+ feature
151         void addRMWDependencyIfReqruied(DepSet& input, DepSet& output);
152 
153         // add swsb into instruction, insert sync if the added swsb is not compatible
154         // with the existed swsb in the inst
155         void addSWSBToInst(Instruction& inst, const SWSB& swsb,
156                            Block& block, InstListIterator inst_it);
157 
158     private:
159         const uint32_t MAX_GRF_BUCKETS = 128;
160         // Instruction having 64-bit type destination having 14 latency
161         // All the other instructions having 10 latency
162         int m_LatencyLong64Pipe = 14;
163         int m_LatencyInOrderMath = 18;
164         int m_LatencyInOrderPipe = 10;
165 
166     private:
167         // m_SBIDCound - number of SBID can be used
168         uint32_t m_SBIDCount;
169 
170         // m_InstIdCounter - record the current instruction state
171         InstIDs m_InstIdCounter;
172 
173         Kernel &m_kernel;
174         ErrorHandler &m_errorHandler;
175 
176         Bucket* m_buckets = nullptr;
177         DepSetBuilder* m_DB = nullptr;
178 
179         // This is the list to recored all sbid, if it's free or not
180         std::vector<SBID> m_freeSBIDList;
181 
182         // m_SBIDRRCounter - the round robin counter for SB id reuse
183         unsigned int m_SBIDRRCounter;
184 
185         // id to dep set mapping, this tracks for which instructions' dependency that this id
186         // is currently on. While we're re-using id, we clean up the dependency
187         std::map<uint32_t, std::pair<DepSet*, DepSet*>> m_IdToDepSetMap;
188 
189         // m_distanceTracker - Track the DepSet of in-order instructions to see if their latency
190         // is satisfied. If the distance to current instruction is larger then the latency, then
191         // we no need to track the dependency anymore, remove the node from m_distanceTracker
192         struct distanceTrackerNode {
distanceTrackerNodeiga::SWSBAnalyzer::distanceTrackerNode193             distanceTrackerNode(DepSet *in, DepSet *out)
194                 : input(in), output(out)
195             {}
196             DepSet *input;
197             DepSet *output;
198         };
199         std::list<distanceTrackerNode> m_distanceTracker;
200 
201         bool m_initPoint;
202 
203         SWSB_ENCODE_MODE m_swsbMode;
204 
205         const int MAX_VALID_DISTANCE;
206     };
207 }
208 #endif
209