/src/llvm-project/llvm/lib/Target/Hexagon/BitTracker.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===- BitTracker.h ---------------------------------------------*- C++ -*-===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | |
9 | | #ifndef LLVM_LIB_TARGET_HEXAGON_BITTRACKER_H |
10 | | #define LLVM_LIB_TARGET_HEXAGON_BITTRACKER_H |
11 | | |
12 | | #include "llvm/ADT/DenseSet.h" |
13 | | #include "llvm/ADT/SetVector.h" |
14 | | #include "llvm/ADT/SmallVector.h" |
15 | | #include "llvm/CodeGen/MachineInstr.h" |
16 | | #include "llvm/CodeGen/MachineOperand.h" |
17 | | #include <cassert> |
18 | | #include <cstdint> |
19 | | #include <map> |
20 | | #include <queue> |
21 | | #include <set> |
22 | | #include <utility> |
23 | | |
24 | | namespace llvm { |
25 | | |
26 | | class BitVector; |
27 | | class ConstantInt; |
28 | | class MachineRegisterInfo; |
29 | | class MachineBasicBlock; |
30 | | class MachineFunction; |
31 | | class raw_ostream; |
32 | | class TargetRegisterClass; |
33 | | class TargetRegisterInfo; |
34 | | |
35 | | struct BitTracker { |
36 | | struct BitRef; |
37 | | struct RegisterRef; |
38 | | struct BitValue; |
39 | | struct BitMask; |
40 | | struct RegisterCell; |
41 | | struct MachineEvaluator; |
42 | | |
43 | | using BranchTargetList = SetVector<const MachineBasicBlock *>; |
44 | | using CellMapType = std::map<unsigned, RegisterCell>; |
45 | | |
46 | | BitTracker(const MachineEvaluator &E, MachineFunction &F); |
47 | | ~BitTracker(); |
48 | | |
49 | | void run(); |
50 | 8.46k | void trace(bool On = false) { Trace = On; } |
51 | | bool has(unsigned Reg) const; |
52 | | const RegisterCell &lookup(unsigned Reg) const; |
53 | | RegisterCell get(RegisterRef RR) const; |
54 | | void put(RegisterRef RR, const RegisterCell &RC); |
55 | | void subst(RegisterRef OldRR, RegisterRef NewRR); |
56 | | bool reached(const MachineBasicBlock *B) const; |
57 | | void visit(const MachineInstr &MI); |
58 | | |
59 | | void print_cells(raw_ostream &OS) const; |
60 | | |
61 | | private: |
62 | | void visitPHI(const MachineInstr &PI); |
63 | | void visitNonBranch(const MachineInstr &MI); |
64 | | void visitBranchesFrom(const MachineInstr &BI); |
65 | | void visitUsesOf(Register Reg); |
66 | | |
67 | | using CFGEdge = std::pair<int, int>; |
68 | | using EdgeSetType = std::set<CFGEdge>; |
69 | | using InstrSetType = std::set<const MachineInstr *>; |
70 | | using EdgeQueueType = std::queue<CFGEdge>; |
71 | | |
72 | | // Priority queue of instructions using modified registers, ordered by |
73 | | // their relative position in a basic block. |
74 | | struct UseQueueType { |
75 | 25.4k | UseQueueType() : Uses(Dist) {} |
76 | | |
77 | 1.69M | unsigned size() const { |
78 | 1.69M | return Uses.size(); |
79 | 1.69M | } |
80 | 1.69M | bool empty() const { |
81 | 1.69M | return size() == 0; |
82 | 1.69M | } |
83 | 3.23M | MachineInstr *front() const { |
84 | 3.23M | return Uses.top(); |
85 | 3.23M | } |
86 | 2.21M | void push(MachineInstr *MI) { |
87 | 2.21M | if (Set.insert(MI).second) |
88 | 1.61M | Uses.push(MI); |
89 | 2.21M | } |
90 | 1.61M | void pop() { |
91 | 1.61M | Set.erase(front()); |
92 | 1.61M | Uses.pop(); |
93 | 1.61M | } |
94 | 34.9k | void reset() { |
95 | 34.9k | Dist.clear(); |
96 | 34.9k | } |
97 | | private: |
98 | | struct Cmp { |
99 | 25.4k | Cmp(DenseMap<const MachineInstr*,unsigned> &Map) : Dist(Map) {} |
100 | | bool operator()(const MachineInstr *MI, const MachineInstr *MJ) const; |
101 | | DenseMap<const MachineInstr*,unsigned> &Dist; |
102 | | }; |
103 | | std::priority_queue<MachineInstr*, std::vector<MachineInstr*>, Cmp> Uses; |
104 | | DenseSet<const MachineInstr*> Set; // Set to avoid adding duplicate entries. |
105 | | DenseMap<const MachineInstr*,unsigned> Dist; |
106 | | }; |
107 | | |
108 | | void reset(); |
109 | | void runEdgeQueue(BitVector &BlockScanned); |
110 | | void runUseQueue(); |
111 | | |
112 | | const MachineEvaluator &ME; |
113 | | MachineFunction &MF; |
114 | | MachineRegisterInfo &MRI; |
115 | | CellMapType ⤅ |
116 | | |
117 | | EdgeSetType EdgeExec; // Executable flow graph edges. |
118 | | InstrSetType InstrExec; // Executable instructions. |
119 | | UseQueueType UseQ; // Work queue of register uses. |
120 | | EdgeQueueType FlowQ; // Work queue of CFG edges. |
121 | | DenseSet<unsigned> ReachedBB; // Cache of reached blocks. |
122 | | bool Trace; // Enable tracing for debugging. |
123 | | }; |
124 | | |
125 | | // Abstraction of a reference to bit at position Pos from a register Reg. |
126 | | struct BitTracker::BitRef { |
127 | 712M | BitRef(unsigned R = 0, uint16_t P = 0) : Reg(R), Pos(P) {} |
128 | | |
129 | 35.3M | bool operator== (const BitRef &BR) const { |
130 | | // If Reg is 0, disregard Pos. |
131 | 35.3M | return Reg == BR.Reg && (Reg == 0 || Pos == BR.Pos); |
132 | 35.3M | } |
133 | | |
134 | | Register Reg; |
135 | | uint16_t Pos; |
136 | | }; |
137 | | |
138 | | // Abstraction of a register reference in MachineOperand. It contains the |
139 | | // register number and the subregister index. |
140 | | // FIXME: Consolidate duplicate definitions of RegisterRef |
141 | | struct BitTracker::RegisterRef { |
142 | 15.8M | RegisterRef(Register R = 0, unsigned S = 0) : Reg(R), Sub(S) {} |
143 | | RegisterRef(const MachineOperand &MO) |
144 | 14.1M | : Reg(MO.getReg()), Sub(MO.getSubReg()) {} |
145 | | |
146 | | Register Reg; |
147 | | unsigned Sub; |
148 | | }; |
149 | | |
150 | | // Value that a single bit can take. This is outside of the context of |
151 | | // any register, it is more of an abstraction of the two-element set of |
152 | | // possible bit values. One extension here is the "Ref" type, which |
153 | | // indicates that this bit takes the same value as the bit described by |
154 | | // RefInfo. |
155 | | struct BitTracker::BitValue { |
156 | | enum ValueType { |
157 | | Top, // Bit not yet defined. |
158 | | Zero, // Bit = 0. |
159 | | One, // Bit = 1. |
160 | | Ref // Bit value same as the one described in RefI. |
161 | | // Conceptually, there is no explicit "bottom" value: the lattice's |
162 | | // bottom will be expressed as a "ref to itself", which, in the context |
163 | | // of registers, could be read as "this value of this bit is defined by |
164 | | // this bit". |
165 | | // The ordering is: |
166 | | // x <= Top, |
167 | | // Self <= x, where "Self" is "ref to itself". |
168 | | // This makes the value lattice different for each virtual register |
169 | | // (even for each bit in the same virtual register), since the "bottom" |
170 | | // for one register will be a simple "ref" for another register. |
171 | | // Since we do not store the "Self" bit and register number, the meet |
172 | | // operation will need to take it as a parameter. |
173 | | // |
174 | | // In practice there is a special case for values that are not associa- |
175 | | // ted with any specific virtual register. An example would be a value |
176 | | // corresponding to a bit of a physical register, or an intermediate |
177 | | // value obtained in some computation (such as instruction evaluation). |
178 | | // Such cases are identical to the usual Ref type, but the register |
179 | | // number is 0. In such case the Pos field of the reference is ignored. |
180 | | // |
181 | | // What is worthy of notice is that in value V (that is a "ref"), as long |
182 | | // as the RefI.Reg is not 0, it may actually be the same register as the |
183 | | // one in which V will be contained. If the RefI.Pos refers to the posi- |
184 | | // tion of V, then V is assumed to be "bottom" (as a "ref to itself"), |
185 | | // otherwise V is taken to be identical to the referenced bit of the |
186 | | // same register. |
187 | | // If RefI.Reg is 0, however, such a reference to the same register is |
188 | | // not possible. Any value V that is a "ref", and whose RefI.Reg is 0 |
189 | | // is treated as "bottom". |
190 | | }; |
191 | | ValueType Type; |
192 | | BitRef RefI; |
193 | | |
194 | 504M | BitValue(ValueType T = Top) : Type(T) {} |
195 | 34.8M | BitValue(bool B) : Type(B ? One : Zero) {} |
196 | 94.6M | BitValue(unsigned Reg, uint16_t Pos) : Type(Ref), RefI(Reg, Pos) {} |
197 | | |
198 | 145M | bool operator== (const BitValue &V) const { |
199 | 145M | if (Type != V.Type) |
200 | 74.6M | return false; |
201 | 70.7M | if (Type == Ref && !(RefI == V.RefI)) |
202 | 25.3M | return false; |
203 | 45.3M | return true; |
204 | 70.7M | } |
205 | 29.0M | bool operator!= (const BitValue &V) const { |
206 | 29.0M | return !operator==(V); |
207 | 29.0M | } |
208 | | |
209 | 80.0M | bool is(unsigned T) const { |
210 | 80.0M | assert(T == 0 || T == 1); |
211 | 80.0M | return T == 0 ? Type == Zero |
212 | 80.0M | : (T == 1 ? Type == One : false); |
213 | 80.0M | } |
214 | | |
215 | | // The "meet" operation is the "." operation in a semilattice (L, ., T, B): |
216 | | // (1) x.x = x |
217 | | // (2) x.y = y.x |
218 | | // (3) x.(y.z) = (x.y).z |
219 | | // (4) x.T = x (i.e. T = "top") |
220 | | // (5) x.B = B (i.e. B = "bottom") |
221 | | // |
222 | | // This "meet" function will update the value of the "*this" object with |
223 | | // the newly calculated one, and return "true" if the value of *this has |
224 | | // changed, and "false" otherwise. |
225 | | // To prove that it satisfies the conditions (1)-(5), it is sufficient |
226 | | // to show that a relation |
227 | | // x <= y <=> x.y = x |
228 | | // defines a partial order (i.e. that "meet" is same as "infimum"). |
229 | 11.3M | bool meet(const BitValue &V, const BitRef &Self) { |
230 | | // First, check the cases where there is nothing to be done. |
231 | 11.3M | if (Type == Ref && RefI == Self) // Bottom.meet(V) = Bottom (i.e. This) |
232 | 0 | return false; |
233 | 11.3M | if (V.Type == Top) // This.meet(Top) = This |
234 | 0 | return false; |
235 | 11.3M | if (*this == V) // This.meet(This) = This |
236 | 10.3M | return false; |
237 | | |
238 | | // At this point, we know that the value of "this" will change. |
239 | | // If it is Top, it will become the same as V, otherwise it will |
240 | | // become "bottom" (i.e. Self). |
241 | 1.00M | if (Type == Top) { |
242 | 0 | Type = V.Type; |
243 | 0 | RefI = V.RefI; // This may be irrelevant, but copy anyway. |
244 | 0 | return true; |
245 | 0 | } |
246 | | // Become "bottom". |
247 | 1.00M | Type = Ref; |
248 | 1.00M | RefI = Self; |
249 | 1.00M | return true; |
250 | 1.00M | } |
251 | | |
252 | | // Create a reference to the bit value V. |
253 | | static BitValue ref(const BitValue &V); |
254 | | // Create a "self". |
255 | | static BitValue self(const BitRef &Self = BitRef()); |
256 | | |
257 | 2.01M | bool num() const { |
258 | 2.01M | return Type == Zero || Type == One; |
259 | 2.01M | } |
260 | | |
261 | 228k | operator bool() const { |
262 | 228k | assert(Type == Zero || Type == One); |
263 | 0 | return Type == One; |
264 | 228k | } |
265 | | |
266 | | friend raw_ostream &operator<<(raw_ostream &OS, const BitValue &BV); |
267 | | }; |
268 | | |
269 | | // This operation must be idempotent, i.e. ref(ref(V)) == ref(V). |
270 | | inline BitTracker::BitValue |
271 | 80.1M | BitTracker::BitValue::ref(const BitValue &V) { |
272 | 80.1M | if (V.Type != Ref) |
273 | 32.2M | return BitValue(V.Type); |
274 | 47.9M | if (V.RefI.Reg != 0) |
275 | 45.5M | return BitValue(V.RefI.Reg, V.RefI.Pos); |
276 | 2.37M | return self(); |
277 | 47.9M | } |
278 | | |
279 | | inline BitTracker::BitValue |
280 | 49.0M | BitTracker::BitValue::self(const BitRef &Self) { |
281 | 49.0M | return BitValue(Self.Reg, Self.Pos); |
282 | 49.0M | } |
283 | | |
284 | | // A sequence of bits starting from index B up to and including index E. |
285 | | // If E < B, the mask represents two sections: [0..E] and [B..W) where |
286 | | // W is the width of the register. |
287 | | struct BitTracker::BitMask { |
288 | | BitMask() = default; |
289 | 1.03M | BitMask(uint16_t b, uint16_t e) : B(b), E(e) {} |
290 | | |
291 | 1.03M | uint16_t first() const { return B; } |
292 | 1.03M | uint16_t last() const { return E; } |
293 | | |
294 | | private: |
295 | | uint16_t B = 0; |
296 | | uint16_t E = 0; |
297 | | }; |
298 | | |
299 | | // Representation of a register: a list of BitValues. |
300 | | struct BitTracker::RegisterCell { |
301 | 11.5M | RegisterCell(uint16_t Width = DefaultBitN) : Bits(Width) {} |
302 | | |
303 | 49.0M | uint16_t width() const { |
304 | 49.0M | return Bits.size(); |
305 | 49.0M | } |
306 | | |
307 | 311M | const BitValue &operator[](uint16_t BitN) const { |
308 | 311M | assert(BitN < Bits.size()); |
309 | 0 | return Bits[BitN]; |
310 | 311M | } |
311 | 379M | BitValue &operator[](uint16_t BitN) { |
312 | 379M | assert(BitN < Bits.size()); |
313 | 0 | return Bits[BitN]; |
314 | 379M | } |
315 | | |
316 | | bool meet(const RegisterCell &RC, Register SelfR); |
317 | | RegisterCell &insert(const RegisterCell &RC, const BitMask &M); |
318 | | RegisterCell extract(const BitMask &M) const; // Returns a new cell. |
319 | | RegisterCell &rol(uint16_t Sh); // Rotate left. |
320 | | RegisterCell &fill(uint16_t B, uint16_t E, const BitValue &V); |
321 | | RegisterCell &cat(const RegisterCell &RC); // Concatenate. |
322 | | uint16_t cl(bool B) const; |
323 | | uint16_t ct(bool B) const; |
324 | | |
325 | | bool operator== (const RegisterCell &RC) const; |
326 | 114k | bool operator!= (const RegisterCell &RC) const { |
327 | 114k | return !operator==(RC); |
328 | 114k | } |
329 | | |
330 | | // Replace the ref-to-reg-0 bit values with the given register. |
331 | | RegisterCell ®ify(unsigned R); |
332 | | |
333 | | // Generate a "ref" cell for the corresponding register. In the resulting |
334 | | // cell each bit will be described as being the same as the corresponding |
335 | | // bit in register Reg (i.e. the cell is "defined" by register Reg). |
336 | | static RegisterCell self(unsigned Reg, uint16_t Width); |
337 | | // Generate a "top" cell of given size. |
338 | | static RegisterCell top(uint16_t Width); |
339 | | // Generate a cell that is a "ref" to another cell. |
340 | | static RegisterCell ref(const RegisterCell &C); |
341 | | |
342 | | private: |
343 | | // The DefaultBitN is here only to avoid frequent reallocation of the |
344 | | // memory in the vector. |
345 | | static const unsigned DefaultBitN = 32; |
346 | | using BitValueList = SmallVector<BitValue, DefaultBitN>; |
347 | | BitValueList Bits; |
348 | | |
349 | | friend raw_ostream &operator<<(raw_ostream &OS, const RegisterCell &RC); |
350 | | }; |
351 | | |
352 | 14.3M | inline bool BitTracker::has(unsigned Reg) const { |
353 | 14.3M | return Map.find(Reg) != Map.end(); |
354 | 14.3M | } |
355 | | |
356 | | inline const BitTracker::RegisterCell& |
357 | 14.8M | BitTracker::lookup(unsigned Reg) const { |
358 | 14.8M | CellMapType::const_iterator F = Map.find(Reg); |
359 | 14.8M | assert(F != Map.end()); |
360 | 0 | return F->second; |
361 | 14.8M | } |
362 | | |
363 | | inline BitTracker::RegisterCell |
364 | 662k | BitTracker::RegisterCell::self(unsigned Reg, uint16_t Width) { |
365 | 662k | RegisterCell RC(Width); |
366 | 23.9M | for (uint16_t i = 0; i < Width; ++i) |
367 | 23.2M | RC.Bits[i] = BitValue::self(BitRef(Reg, i)); |
368 | 662k | return RC; |
369 | 662k | } |
370 | | |
371 | | inline BitTracker::RegisterCell |
372 | 1.58M | BitTracker::RegisterCell::top(uint16_t Width) { |
373 | 1.58M | RegisterCell RC(Width); |
374 | 61.8M | for (uint16_t i = 0; i < Width; ++i) |
375 | 60.2M | RC.Bits[i] = BitValue(BitValue::Top); |
376 | 1.58M | return RC; |
377 | 1.58M | } |
378 | | |
379 | | inline BitTracker::RegisterCell |
380 | 2.14M | BitTracker::RegisterCell::ref(const RegisterCell &C) { |
381 | 2.14M | uint16_t W = C.width(); |
382 | 2.14M | RegisterCell RC(W); |
383 | 77.6M | for (unsigned i = 0; i < W; ++i) |
384 | 75.4M | RC[i] = BitValue::ref(C[i]); |
385 | 2.14M | return RC; |
386 | 2.14M | } |
387 | | |
388 | | // A class to evaluate target's instructions and update the cell maps. |
389 | | // This is used internally by the bit tracker. A target that wants to |
390 | | // utilize this should implement the evaluation functions (noted below) |
391 | | // in a subclass of this class. |
392 | | struct BitTracker::MachineEvaluator { |
393 | | MachineEvaluator(const TargetRegisterInfo &T, MachineRegisterInfo &M) |
394 | 25.4k | : TRI(T), MRI(M) {} |
395 | 25.4k | virtual ~MachineEvaluator() = default; |
396 | | |
397 | | uint16_t getRegBitWidth(const RegisterRef &RR) const; |
398 | | |
399 | | RegisterCell getCell(const RegisterRef &RR, const CellMapType &M) const; |
400 | | void putCell(const RegisterRef &RR, RegisterCell RC, CellMapType &M) const; |
401 | | |
402 | | // A result of any operation should use refs to the source cells, not |
403 | | // the cells directly. This function is a convenience wrapper to quickly |
404 | | // generate a ref for a cell corresponding to a register reference. |
405 | 0 | RegisterCell getRef(const RegisterRef &RR, const CellMapType &M) const { |
406 | 0 | RegisterCell RC = getCell(RR, M); |
407 | 0 | return RegisterCell::ref(RC); |
408 | 0 | } |
409 | | |
410 | | // Helper functions. |
411 | | // Check if a cell is an immediate value (i.e. all bits are either 0 or 1). |
412 | | bool isInt(const RegisterCell &A) const; |
413 | | // Convert cell to an immediate value. |
414 | | uint64_t toInt(const RegisterCell &A) const; |
415 | | |
416 | | // Generate cell from an immediate value. |
417 | | RegisterCell eIMM(int64_t V, uint16_t W) const; |
418 | | RegisterCell eIMM(const ConstantInt *CI) const; |
419 | | |
420 | | // Arithmetic. |
421 | | RegisterCell eADD(const RegisterCell &A1, const RegisterCell &A2) const; |
422 | | RegisterCell eSUB(const RegisterCell &A1, const RegisterCell &A2) const; |
423 | | RegisterCell eMLS(const RegisterCell &A1, const RegisterCell &A2) const; |
424 | | RegisterCell eMLU(const RegisterCell &A1, const RegisterCell &A2) const; |
425 | | |
426 | | // Shifts. |
427 | | RegisterCell eASL(const RegisterCell &A1, uint16_t Sh) const; |
428 | | RegisterCell eLSR(const RegisterCell &A1, uint16_t Sh) const; |
429 | | RegisterCell eASR(const RegisterCell &A1, uint16_t Sh) const; |
430 | | |
431 | | // Logical. |
432 | | RegisterCell eAND(const RegisterCell &A1, const RegisterCell &A2) const; |
433 | | RegisterCell eORL(const RegisterCell &A1, const RegisterCell &A2) const; |
434 | | RegisterCell eXOR(const RegisterCell &A1, const RegisterCell &A2) const; |
435 | | RegisterCell eNOT(const RegisterCell &A1) const; |
436 | | |
437 | | // Set bit, clear bit. |
438 | | RegisterCell eSET(const RegisterCell &A1, uint16_t BitN) const; |
439 | | RegisterCell eCLR(const RegisterCell &A1, uint16_t BitN) const; |
440 | | |
441 | | // Count leading/trailing bits (zeros/ones). |
442 | | RegisterCell eCLB(const RegisterCell &A1, bool B, uint16_t W) const; |
443 | | RegisterCell eCTB(const RegisterCell &A1, bool B, uint16_t W) const; |
444 | | |
445 | | // Sign/zero extension. |
446 | | RegisterCell eSXT(const RegisterCell &A1, uint16_t FromN) const; |
447 | | RegisterCell eZXT(const RegisterCell &A1, uint16_t FromN) const; |
448 | | |
449 | | // Extract/insert |
450 | | // XTR R,b,e: extract bits from A1 starting at bit b, ending at e-1. |
451 | | // INS R,S,b: take R and replace bits starting from b with S. |
452 | | RegisterCell eXTR(const RegisterCell &A1, uint16_t B, uint16_t E) const; |
453 | | RegisterCell eINS(const RegisterCell &A1, const RegisterCell &A2, |
454 | | uint16_t AtN) const; |
455 | | |
456 | | // User-provided functions for individual targets: |
457 | | |
458 | | // Return a sub-register mask that indicates which bits in Reg belong |
459 | | // to the subregister Sub. These bits are assumed to be contiguous in |
460 | | // the super-register, and have the same ordering in the sub-register |
461 | | // as in the super-register. It is valid to call this function with |
462 | | // Sub == 0, in this case, the function should return a mask that spans |
463 | | // the entire register Reg (which is what the default implementation |
464 | | // does). |
465 | | virtual BitMask mask(Register Reg, unsigned Sub) const; |
466 | | // Indicate whether a given register class should be tracked. |
467 | 7.19M | virtual bool track(const TargetRegisterClass *RC) const { return true; } |
468 | | // Evaluate a non-branching machine instruction, given the cell map with |
469 | | // the input values. Place the results in the Outputs map. Return "true" |
470 | | // if evaluation succeeded, "false" otherwise. |
471 | | virtual bool evaluate(const MachineInstr &MI, const CellMapType &Inputs, |
472 | | CellMapType &Outputs) const; |
473 | | // Evaluate a branch, given the cell map with the input values. Fill out |
474 | | // a list of all possible branch targets and indicate (through a flag) |
475 | | // whether the branch could fall-through. Return "true" if this information |
476 | | // has been successfully computed, "false" otherwise. |
477 | | virtual bool evaluate(const MachineInstr &BI, const CellMapType &Inputs, |
478 | | BranchTargetList &Targets, bool &FallsThru) const = 0; |
479 | | // Given a register class RC, return a register class that should be assumed |
480 | | // when a register from class RC is used with a subregister of index Idx. |
481 | | virtual const TargetRegisterClass& |
482 | 0 | composeWithSubRegIndex(const TargetRegisterClass &RC, unsigned Idx) const { |
483 | 0 | if (Idx == 0) |
484 | 0 | return RC; |
485 | 0 | llvm_unreachable("Unimplemented composeWithSubRegIndex"); |
486 | 0 | } |
487 | | // Return the size in bits of the physical register Reg. |
488 | | virtual uint16_t getPhysRegBitWidth(MCRegister Reg) const; |
489 | | |
490 | | const TargetRegisterInfo &TRI; |
491 | | MachineRegisterInfo &MRI; |
492 | | }; |
493 | | |
494 | | } // end namespace llvm |
495 | | |
496 | | #endif // LLVM_LIB_TARGET_HEXAGON_BITTRACKER_H |