1 | //===- DetectDeadLanes.cpp - SubRegister Lane Usage Analysis --*- 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 | /// \file |
10 | /// Analysis that tracks defined/used subregister lanes across COPY instructions |
11 | /// and instructions that get lowered to a COPY (PHI, REG_SEQUENCE, |
12 | /// INSERT_SUBREG, EXTRACT_SUBREG). |
13 | /// The information is used to detect dead definitions and the usage of |
14 | /// (completely) undefined values and mark the operands as such. |
15 | /// This pass is necessary because the dead/undef status is not obvious anymore |
16 | /// when subregisters are involved. |
17 | /// |
18 | /// Example: |
19 | /// %0 = some definition |
20 | /// %1 = IMPLICIT_DEF |
21 | /// %2 = REG_SEQUENCE %0, sub0, %1, sub1 |
22 | /// %3 = EXTRACT_SUBREG %2, sub1 |
23 | /// = use %3 |
24 | /// The %0 definition is dead and %3 contains an undefined value. |
25 | // |
26 | //===----------------------------------------------------------------------===// |
27 | |
28 | #include "llvm/CodeGen/DetectDeadLanes.h" |
29 | #include "llvm/CodeGen/MachineFunctionPass.h" |
30 | #include "llvm/CodeGen/MachineRegisterInfo.h" |
31 | #include "llvm/CodeGen/TargetRegisterInfo.h" |
32 | #include "llvm/InitializePasses.h" |
33 | #include "llvm/Pass.h" |
34 | #include "llvm/Support/Debug.h" |
35 | #include "llvm/Support/raw_ostream.h" |
36 | |
37 | using namespace llvm; |
38 | |
39 | #define DEBUG_TYPE "detect-dead-lanes" |
40 | |
41 | DeadLaneDetector::DeadLaneDetector(const MachineRegisterInfo *MRI, |
42 | const TargetRegisterInfo *TRI) |
43 | : MRI(MRI), TRI(TRI) { |
44 | unsigned NumVirtRegs = MRI->getNumVirtRegs(); |
45 | VRegInfos = std::unique_ptr<VRegInfo[]>(new VRegInfo[NumVirtRegs]); |
46 | WorklistMembers.resize(N: NumVirtRegs); |
47 | DefinedByCopy.resize(N: NumVirtRegs); |
48 | } |
49 | |
50 | /// Returns true if \p MI will get lowered to a series of COPY instructions. |
51 | /// We call this a COPY-like instruction. |
52 | static bool lowersToCopies(const MachineInstr &MI) { |
53 | // Note: We could support instructions with MCInstrDesc::isRegSequenceLike(), |
54 | // isExtractSubRegLike(), isInsertSubregLike() in the future even though they |
55 | // are not lowered to a COPY. |
56 | switch (MI.getOpcode()) { |
57 | case TargetOpcode::COPY: |
58 | case TargetOpcode::PHI: |
59 | case TargetOpcode::INSERT_SUBREG: |
60 | case TargetOpcode::REG_SEQUENCE: |
61 | case TargetOpcode::EXTRACT_SUBREG: |
62 | return true; |
63 | } |
64 | return false; |
65 | } |
66 | |
67 | static bool isCrossCopy(const MachineRegisterInfo &MRI, |
68 | const MachineInstr &MI, |
69 | const TargetRegisterClass *DstRC, |
70 | const MachineOperand &MO) { |
71 | assert(lowersToCopies(MI)); |
72 | Register SrcReg = MO.getReg(); |
73 | const TargetRegisterClass *SrcRC = MRI.getRegClass(Reg: SrcReg); |
74 | if (DstRC == SrcRC) |
75 | return false; |
76 | |
77 | unsigned SrcSubIdx = MO.getSubReg(); |
78 | |
79 | const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo(); |
80 | unsigned DstSubIdx = 0; |
81 | switch (MI.getOpcode()) { |
82 | case TargetOpcode::INSERT_SUBREG: |
83 | if (MO.getOperandNo() == 2) |
84 | DstSubIdx = MI.getOperand(i: 3).getImm(); |
85 | break; |
86 | case TargetOpcode::REG_SEQUENCE: { |
87 | unsigned OpNum = MO.getOperandNo(); |
88 | DstSubIdx = MI.getOperand(i: OpNum+1).getImm(); |
89 | break; |
90 | } |
91 | case TargetOpcode::EXTRACT_SUBREG: { |
92 | unsigned SubReg = MI.getOperand(i: 2).getImm(); |
93 | SrcSubIdx = TRI.composeSubRegIndices(a: SubReg, b: SrcSubIdx); |
94 | } |
95 | } |
96 | |
97 | unsigned PreA, PreB; // Unused. |
98 | if (SrcSubIdx && DstSubIdx) |
99 | return !TRI.getCommonSuperRegClass(RCA: SrcRC, SubA: SrcSubIdx, RCB: DstRC, SubB: DstSubIdx, PreA, |
100 | PreB); |
101 | if (SrcSubIdx) |
102 | return !TRI.getMatchingSuperRegClass(A: SrcRC, B: DstRC, Idx: SrcSubIdx); |
103 | if (DstSubIdx) |
104 | return !TRI.getMatchingSuperRegClass(A: DstRC, B: SrcRC, Idx: DstSubIdx); |
105 | return !TRI.getCommonSubClass(A: SrcRC, B: DstRC); |
106 | } |
107 | |
108 | void DeadLaneDetector::addUsedLanesOnOperand(const MachineOperand &MO, |
109 | LaneBitmask UsedLanes) { |
110 | if (!MO.readsReg()) |
111 | return; |
112 | Register MOReg = MO.getReg(); |
113 | if (!MOReg.isVirtual()) |
114 | return; |
115 | |
116 | unsigned MOSubReg = MO.getSubReg(); |
117 | if (MOSubReg != 0) |
118 | UsedLanes = TRI->composeSubRegIndexLaneMask(IdxA: MOSubReg, Mask: UsedLanes); |
119 | UsedLanes &= MRI->getMaxLaneMaskForVReg(Reg: MOReg); |
120 | |
121 | unsigned MORegIdx = Register::virtReg2Index(Reg: MOReg); |
122 | DeadLaneDetector::VRegInfo &MORegInfo = VRegInfos[MORegIdx]; |
123 | LaneBitmask PrevUsedLanes = MORegInfo.UsedLanes; |
124 | // Any change at all? |
125 | if ((UsedLanes & ~PrevUsedLanes).none()) |
126 | return; |
127 | |
128 | // Set UsedLanes and remember instruction for further propagation. |
129 | MORegInfo.UsedLanes = PrevUsedLanes | UsedLanes; |
130 | if (DefinedByCopy.test(Idx: MORegIdx)) |
131 | PutInWorklist(RegIdx: MORegIdx); |
132 | } |
133 | |
134 | void DeadLaneDetector::transferUsedLanesStep(const MachineInstr &MI, |
135 | LaneBitmask UsedLanes) { |
136 | for (const MachineOperand &MO : MI.uses()) { |
137 | if (!MO.isReg() || !MO.getReg().isVirtual()) |
138 | continue; |
139 | LaneBitmask UsedOnMO = transferUsedLanes(MI, UsedLanes, MO); |
140 | addUsedLanesOnOperand(MO, UsedLanes: UsedOnMO); |
141 | } |
142 | } |
143 | |
144 | LaneBitmask |
145 | DeadLaneDetector::transferUsedLanes(const MachineInstr &MI, |
146 | LaneBitmask UsedLanes, |
147 | const MachineOperand &MO) const { |
148 | unsigned OpNum = MO.getOperandNo(); |
149 | assert(lowersToCopies(MI) && |
150 | DefinedByCopy[Register::virtReg2Index(MI.getOperand(0).getReg())]); |
151 | |
152 | switch (MI.getOpcode()) { |
153 | case TargetOpcode::COPY: |
154 | case TargetOpcode::PHI: |
155 | return UsedLanes; |
156 | case TargetOpcode::REG_SEQUENCE: { |
157 | assert(OpNum % 2 == 1); |
158 | unsigned SubIdx = MI.getOperand(i: OpNum + 1).getImm(); |
159 | return TRI->reverseComposeSubRegIndexLaneMask(IdxA: SubIdx, LaneMask: UsedLanes); |
160 | } |
161 | case TargetOpcode::INSERT_SUBREG: { |
162 | unsigned SubIdx = MI.getOperand(i: 3).getImm(); |
163 | LaneBitmask MO2UsedLanes = |
164 | TRI->reverseComposeSubRegIndexLaneMask(IdxA: SubIdx, LaneMask: UsedLanes); |
165 | if (OpNum == 2) |
166 | return MO2UsedLanes; |
167 | |
168 | const MachineOperand &Def = MI.getOperand(i: 0); |
169 | Register DefReg = Def.getReg(); |
170 | const TargetRegisterClass *RC = MRI->getRegClass(Reg: DefReg); |
171 | LaneBitmask MO1UsedLanes; |
172 | if (RC->CoveredBySubRegs) |
173 | MO1UsedLanes = UsedLanes & ~TRI->getSubRegIndexLaneMask(SubIdx); |
174 | else |
175 | MO1UsedLanes = RC->LaneMask; |
176 | |
177 | assert(OpNum == 1); |
178 | return MO1UsedLanes; |
179 | } |
180 | case TargetOpcode::EXTRACT_SUBREG: { |
181 | assert(OpNum == 1); |
182 | unsigned SubIdx = MI.getOperand(i: 2).getImm(); |
183 | return TRI->composeSubRegIndexLaneMask(IdxA: SubIdx, Mask: UsedLanes); |
184 | } |
185 | default: |
186 | llvm_unreachable("function must be called with COPY-like instruction" ); |
187 | } |
188 | } |
189 | |
190 | void DeadLaneDetector::transferDefinedLanesStep(const MachineOperand &Use, |
191 | LaneBitmask DefinedLanes) { |
192 | if (!Use.readsReg()) |
193 | return; |
194 | // Check whether the operand writes a vreg and is part of a COPY-like |
195 | // instruction. |
196 | const MachineInstr &MI = *Use.getParent(); |
197 | if (MI.getDesc().getNumDefs() != 1) |
198 | return; |
199 | // FIXME: PATCHPOINT instructions announce a Def that does not always exist, |
200 | // they really need to be modeled differently! |
201 | if (MI.getOpcode() == TargetOpcode::PATCHPOINT) |
202 | return; |
203 | const MachineOperand &Def = *MI.defs().begin(); |
204 | Register DefReg = Def.getReg(); |
205 | if (!DefReg.isVirtual()) |
206 | return; |
207 | unsigned DefRegIdx = Register::virtReg2Index(Reg: DefReg); |
208 | if (!DefinedByCopy.test(Idx: DefRegIdx)) |
209 | return; |
210 | |
211 | unsigned OpNum = Use.getOperandNo(); |
212 | DefinedLanes = |
213 | TRI->reverseComposeSubRegIndexLaneMask(IdxA: Use.getSubReg(), LaneMask: DefinedLanes); |
214 | DefinedLanes = transferDefinedLanes(Def, OpNum, DefinedLanes); |
215 | |
216 | VRegInfo &RegInfo = VRegInfos[DefRegIdx]; |
217 | LaneBitmask PrevDefinedLanes = RegInfo.DefinedLanes; |
218 | // Any change at all? |
219 | if ((DefinedLanes & ~PrevDefinedLanes).none()) |
220 | return; |
221 | |
222 | RegInfo.DefinedLanes = PrevDefinedLanes | DefinedLanes; |
223 | PutInWorklist(RegIdx: DefRegIdx); |
224 | } |
225 | |
226 | LaneBitmask DeadLaneDetector::transferDefinedLanes( |
227 | const MachineOperand &Def, unsigned OpNum, LaneBitmask DefinedLanes) const { |
228 | const MachineInstr &MI = *Def.getParent(); |
229 | // Translate DefinedLanes if necessary. |
230 | switch (MI.getOpcode()) { |
231 | case TargetOpcode::REG_SEQUENCE: { |
232 | unsigned SubIdx = MI.getOperand(i: OpNum + 1).getImm(); |
233 | DefinedLanes = TRI->composeSubRegIndexLaneMask(IdxA: SubIdx, Mask: DefinedLanes); |
234 | DefinedLanes &= TRI->getSubRegIndexLaneMask(SubIdx); |
235 | break; |
236 | } |
237 | case TargetOpcode::INSERT_SUBREG: { |
238 | unsigned SubIdx = MI.getOperand(i: 3).getImm(); |
239 | if (OpNum == 2) { |
240 | DefinedLanes = TRI->composeSubRegIndexLaneMask(IdxA: SubIdx, Mask: DefinedLanes); |
241 | DefinedLanes &= TRI->getSubRegIndexLaneMask(SubIdx); |
242 | } else { |
243 | assert(OpNum == 1 && "INSERT_SUBREG must have two operands" ); |
244 | // Ignore lanes defined by operand 2. |
245 | DefinedLanes &= ~TRI->getSubRegIndexLaneMask(SubIdx); |
246 | } |
247 | break; |
248 | } |
249 | case TargetOpcode::EXTRACT_SUBREG: { |
250 | unsigned SubIdx = MI.getOperand(i: 2).getImm(); |
251 | assert(OpNum == 1 && "EXTRACT_SUBREG must have one register operand only" ); |
252 | DefinedLanes = TRI->reverseComposeSubRegIndexLaneMask(IdxA: SubIdx, LaneMask: DefinedLanes); |
253 | break; |
254 | } |
255 | case TargetOpcode::COPY: |
256 | case TargetOpcode::PHI: |
257 | break; |
258 | default: |
259 | llvm_unreachable("function must be called with COPY-like instruction" ); |
260 | } |
261 | |
262 | assert(Def.getSubReg() == 0 && |
263 | "Should not have subregister defs in machine SSA phase" ); |
264 | DefinedLanes &= MRI->getMaxLaneMaskForVReg(Reg: Def.getReg()); |
265 | return DefinedLanes; |
266 | } |
267 | |
268 | LaneBitmask DeadLaneDetector::determineInitialDefinedLanes(unsigned Reg) { |
269 | // Live-In or unused registers have no definition but are considered fully |
270 | // defined. |
271 | if (!MRI->hasOneDef(RegNo: Reg)) |
272 | return LaneBitmask::getAll(); |
273 | |
274 | const MachineOperand &Def = *MRI->def_begin(RegNo: Reg); |
275 | const MachineInstr &DefMI = *Def.getParent(); |
276 | if (lowersToCopies(MI: DefMI)) { |
277 | // Start optimisatically with no used or defined lanes for copy |
278 | // instructions. The following dataflow analysis will add more bits. |
279 | unsigned RegIdx = Register::virtReg2Index(Reg); |
280 | DefinedByCopy.set(RegIdx); |
281 | PutInWorklist(RegIdx); |
282 | |
283 | if (Def.isDead()) |
284 | return LaneBitmask::getNone(); |
285 | |
286 | // COPY/PHI can copy across unrelated register classes (example: float/int) |
287 | // with incompatible subregister structure. Do not include these in the |
288 | // dataflow analysis since we cannot transfer lanemasks in a meaningful way. |
289 | const TargetRegisterClass *DefRC = MRI->getRegClass(Reg); |
290 | |
291 | // Determine initially DefinedLanes. |
292 | LaneBitmask DefinedLanes; |
293 | for (const MachineOperand &MO : DefMI.uses()) { |
294 | if (!MO.isReg() || !MO.readsReg()) |
295 | continue; |
296 | Register MOReg = MO.getReg(); |
297 | if (!MOReg) |
298 | continue; |
299 | |
300 | LaneBitmask MODefinedLanes; |
301 | if (MOReg.isPhysical()) { |
302 | MODefinedLanes = LaneBitmask::getAll(); |
303 | } else if (isCrossCopy(MRI: *MRI, MI: DefMI, DstRC: DefRC, MO)) { |
304 | MODefinedLanes = LaneBitmask::getAll(); |
305 | } else { |
306 | assert(MOReg.isVirtual()); |
307 | if (MRI->hasOneDef(RegNo: MOReg)) { |
308 | const MachineOperand &MODef = *MRI->def_begin(RegNo: MOReg); |
309 | const MachineInstr &MODefMI = *MODef.getParent(); |
310 | // Bits from copy-like operations will be added later. |
311 | if (lowersToCopies(MI: MODefMI) || MODefMI.isImplicitDef()) |
312 | continue; |
313 | } |
314 | unsigned MOSubReg = MO.getSubReg(); |
315 | MODefinedLanes = MRI->getMaxLaneMaskForVReg(Reg: MOReg); |
316 | MODefinedLanes = TRI->reverseComposeSubRegIndexLaneMask( |
317 | IdxA: MOSubReg, LaneMask: MODefinedLanes); |
318 | } |
319 | |
320 | unsigned OpNum = MO.getOperandNo(); |
321 | DefinedLanes |= transferDefinedLanes(Def, OpNum, DefinedLanes: MODefinedLanes); |
322 | } |
323 | return DefinedLanes; |
324 | } |
325 | if (DefMI.isImplicitDef() || Def.isDead()) |
326 | return LaneBitmask::getNone(); |
327 | |
328 | assert(Def.getSubReg() == 0 && |
329 | "Should not have subregister defs in machine SSA phase" ); |
330 | return MRI->getMaxLaneMaskForVReg(Reg); |
331 | } |
332 | |
333 | LaneBitmask DeadLaneDetector::determineInitialUsedLanes(unsigned Reg) { |
334 | LaneBitmask UsedLanes = LaneBitmask::getNone(); |
335 | for (const MachineOperand &MO : MRI->use_nodbg_operands(Reg)) { |
336 | if (!MO.readsReg()) |
337 | continue; |
338 | |
339 | const MachineInstr &UseMI = *MO.getParent(); |
340 | if (UseMI.isKill()) |
341 | continue; |
342 | |
343 | unsigned SubReg = MO.getSubReg(); |
344 | if (lowersToCopies(MI: UseMI)) { |
345 | assert(UseMI.getDesc().getNumDefs() == 1); |
346 | const MachineOperand &Def = *UseMI.defs().begin(); |
347 | Register DefReg = Def.getReg(); |
348 | // The used lanes of COPY-like instruction operands are determined by the |
349 | // following dataflow analysis. |
350 | if (DefReg.isVirtual()) { |
351 | // But ignore copies across incompatible register classes. |
352 | bool CrossCopy = false; |
353 | if (lowersToCopies(MI: UseMI)) { |
354 | const TargetRegisterClass *DstRC = MRI->getRegClass(Reg: DefReg); |
355 | CrossCopy = isCrossCopy(MRI: *MRI, MI: UseMI, DstRC, MO); |
356 | if (CrossCopy) |
357 | LLVM_DEBUG(dbgs() << "Copy across incompatible classes: " << UseMI); |
358 | } |
359 | |
360 | if (!CrossCopy) |
361 | continue; |
362 | } |
363 | } |
364 | |
365 | // Shortcut: All lanes are used. |
366 | if (SubReg == 0) |
367 | return MRI->getMaxLaneMaskForVReg(Reg); |
368 | |
369 | UsedLanes |= TRI->getSubRegIndexLaneMask(SubIdx: SubReg); |
370 | } |
371 | return UsedLanes; |
372 | } |
373 | |
374 | namespace { |
375 | |
376 | class DetectDeadLanes : public MachineFunctionPass { |
377 | public: |
378 | bool runOnMachineFunction(MachineFunction &MF) override; |
379 | |
380 | static char ID; |
381 | DetectDeadLanes() : MachineFunctionPass(ID) {} |
382 | |
383 | StringRef getPassName() const override { return "Detect Dead Lanes" ; } |
384 | |
385 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
386 | AU.setPreservesCFG(); |
387 | MachineFunctionPass::getAnalysisUsage(AU); |
388 | } |
389 | |
390 | private: |
391 | /// update the operand status. |
392 | /// The first return value shows whether MF been changed. |
393 | /// The second return value indicates we need to call |
394 | /// DeadLaneDetector::computeSubRegisterLaneBitInfo and this function again |
395 | /// to propagate changes. |
396 | std::pair<bool, bool> |
397 | modifySubRegisterOperandStatus(const DeadLaneDetector &DLD, |
398 | MachineFunction &MF); |
399 | |
400 | bool isUndefRegAtInput(const MachineOperand &MO, |
401 | const DeadLaneDetector::VRegInfo &RegInfo) const; |
402 | |
403 | bool isUndefInput(const DeadLaneDetector &DLD, const MachineOperand &MO, |
404 | bool *CrossCopy) const; |
405 | |
406 | const MachineRegisterInfo *MRI = nullptr; |
407 | const TargetRegisterInfo *TRI = nullptr; |
408 | }; |
409 | |
410 | } // end anonymous namespace |
411 | |
412 | char DetectDeadLanes::ID = 0; |
413 | char &llvm::DetectDeadLanesID = DetectDeadLanes::ID; |
414 | |
415 | INITIALIZE_PASS(DetectDeadLanes, DEBUG_TYPE, "Detect Dead Lanes" , false, false) |
416 | |
417 | bool DetectDeadLanes::isUndefRegAtInput( |
418 | const MachineOperand &MO, const DeadLaneDetector::VRegInfo &RegInfo) const { |
419 | unsigned SubReg = MO.getSubReg(); |
420 | LaneBitmask Mask = TRI->getSubRegIndexLaneMask(SubIdx: SubReg); |
421 | return (RegInfo.DefinedLanes & RegInfo.UsedLanes & Mask).none(); |
422 | } |
423 | |
424 | bool DetectDeadLanes::isUndefInput(const DeadLaneDetector &DLD, |
425 | const MachineOperand &MO, |
426 | bool *CrossCopy) const { |
427 | if (!MO.isUse()) |
428 | return false; |
429 | const MachineInstr &MI = *MO.getParent(); |
430 | if (!lowersToCopies(MI)) |
431 | return false; |
432 | const MachineOperand &Def = MI.getOperand(i: 0); |
433 | Register DefReg = Def.getReg(); |
434 | if (!DefReg.isVirtual()) |
435 | return false; |
436 | unsigned DefRegIdx = Register::virtReg2Index(Reg: DefReg); |
437 | if (!DLD.isDefinedByCopy(RegIdx: DefRegIdx)) |
438 | return false; |
439 | |
440 | const DeadLaneDetector::VRegInfo &DefRegInfo = DLD.getVRegInfo(RegIdx: DefRegIdx); |
441 | LaneBitmask UsedLanes = DLD.transferUsedLanes(MI, UsedLanes: DefRegInfo.UsedLanes, MO); |
442 | if (UsedLanes.any()) |
443 | return false; |
444 | |
445 | Register MOReg = MO.getReg(); |
446 | if (MOReg.isVirtual()) { |
447 | const TargetRegisterClass *DstRC = MRI->getRegClass(Reg: DefReg); |
448 | *CrossCopy = isCrossCopy(MRI: *MRI, MI, DstRC, MO); |
449 | } |
450 | return true; |
451 | } |
452 | |
453 | void DeadLaneDetector::computeSubRegisterLaneBitInfo() { |
454 | // First pass: Populate defs/uses of vregs with initial values |
455 | unsigned NumVirtRegs = MRI->getNumVirtRegs(); |
456 | for (unsigned RegIdx = 0; RegIdx < NumVirtRegs; ++RegIdx) { |
457 | Register Reg = Register::index2VirtReg(Index: RegIdx); |
458 | |
459 | // Determine used/defined lanes and add copy instructions to worklist. |
460 | VRegInfo &Info = VRegInfos[RegIdx]; |
461 | Info.DefinedLanes = determineInitialDefinedLanes(Reg); |
462 | Info.UsedLanes = determineInitialUsedLanes(Reg); |
463 | } |
464 | |
465 | // Iterate as long as defined lanes/used lanes keep changing. |
466 | while (!Worklist.empty()) { |
467 | unsigned RegIdx = Worklist.front(); |
468 | Worklist.pop_front(); |
469 | WorklistMembers.reset(Idx: RegIdx); |
470 | VRegInfo &Info = VRegInfos[RegIdx]; |
471 | Register Reg = Register::index2VirtReg(Index: RegIdx); |
472 | |
473 | // Transfer UsedLanes to operands of DefMI (backwards dataflow). |
474 | MachineOperand &Def = *MRI->def_begin(RegNo: Reg); |
475 | const MachineInstr &MI = *Def.getParent(); |
476 | transferUsedLanesStep(MI, UsedLanes: Info.UsedLanes); |
477 | // Transfer DefinedLanes to users of Reg (forward dataflow). |
478 | for (const MachineOperand &MO : MRI->use_nodbg_operands(Reg)) |
479 | transferDefinedLanesStep(Use: MO, DefinedLanes: Info.DefinedLanes); |
480 | } |
481 | |
482 | LLVM_DEBUG({ |
483 | dbgs() << "Defined/Used lanes:\n" ; |
484 | for (unsigned RegIdx = 0; RegIdx < NumVirtRegs; ++RegIdx) { |
485 | Register Reg = Register::index2VirtReg(RegIdx); |
486 | const VRegInfo &Info = VRegInfos[RegIdx]; |
487 | dbgs() << printReg(Reg, nullptr) |
488 | << " Used: " << PrintLaneMask(Info.UsedLanes) |
489 | << " Def: " << PrintLaneMask(Info.DefinedLanes) << '\n'; |
490 | } |
491 | dbgs() << "\n" ; |
492 | }); |
493 | } |
494 | |
495 | std::pair<bool, bool> |
496 | DetectDeadLanes::modifySubRegisterOperandStatus(const DeadLaneDetector &DLD, |
497 | MachineFunction &MF) { |
498 | bool Changed = false; |
499 | bool Again = false; |
500 | // Mark operands as dead/unused. |
501 | for (MachineBasicBlock &MBB : MF) { |
502 | for (MachineInstr &MI : MBB) { |
503 | for (MachineOperand &MO : MI.operands()) { |
504 | if (!MO.isReg()) |
505 | continue; |
506 | Register Reg = MO.getReg(); |
507 | if (!Reg.isVirtual()) |
508 | continue; |
509 | unsigned RegIdx = Register::virtReg2Index(Reg); |
510 | const DeadLaneDetector::VRegInfo &RegInfo = DLD.getVRegInfo(RegIdx); |
511 | if (MO.isDef() && !MO.isDead() && RegInfo.UsedLanes.none()) { |
512 | LLVM_DEBUG(dbgs() |
513 | << "Marking operand '" << MO << "' as dead in " << MI); |
514 | MO.setIsDead(); |
515 | Changed = true; |
516 | } |
517 | if (MO.readsReg()) { |
518 | bool CrossCopy = false; |
519 | if (isUndefRegAtInput(MO, RegInfo)) { |
520 | LLVM_DEBUG(dbgs() |
521 | << "Marking operand '" << MO << "' as undef in " << MI); |
522 | MO.setIsUndef(); |
523 | Changed = true; |
524 | } else if (isUndefInput(DLD, MO, CrossCopy: &CrossCopy)) { |
525 | LLVM_DEBUG(dbgs() |
526 | << "Marking operand '" << MO << "' as undef in " << MI); |
527 | MO.setIsUndef(); |
528 | Changed = true; |
529 | if (CrossCopy) |
530 | Again = true; |
531 | } |
532 | } |
533 | } |
534 | } |
535 | } |
536 | |
537 | return std::make_pair(x&: Changed, y&: Again); |
538 | } |
539 | |
540 | bool DetectDeadLanes::runOnMachineFunction(MachineFunction &MF) { |
541 | // Don't bother if we won't track subregister liveness later. This pass is |
542 | // required for correctness if subregister liveness is enabled because the |
543 | // register coalescer cannot deal with hidden dead defs. However without |
544 | // subregister liveness enabled, the expected benefits of this pass are small |
545 | // so we safe the compile time. |
546 | MRI = &MF.getRegInfo(); |
547 | if (!MRI->subRegLivenessEnabled()) { |
548 | LLVM_DEBUG(dbgs() << "Skipping Detect dead lanes pass\n" ); |
549 | return false; |
550 | } |
551 | |
552 | TRI = MRI->getTargetRegisterInfo(); |
553 | |
554 | DeadLaneDetector DLD(MRI, TRI); |
555 | |
556 | bool Changed = false; |
557 | bool Again; |
558 | do { |
559 | DLD.computeSubRegisterLaneBitInfo(); |
560 | bool LocalChanged; |
561 | std::tie(args&: LocalChanged, args&: Again) = modifySubRegisterOperandStatus(DLD, MF); |
562 | Changed |= LocalChanged; |
563 | } while (Again); |
564 | |
565 | return Changed; |
566 | } |
567 | |