Add gfx950 mfma instructions to ROCDL dialect (#123361)
[llvm-project.git] / llvm / lib / Target / Hexagon / HexagonTfrCleanup.cpp
blob8a995f671895e87492e1d7306cc44b17a8e3c258
1 //===------- HexagonTfrCleanup.cpp - Hexagon Transfer Cleanup Pass -------===//
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 // This pass is to address a situation that appears after register allocaion
9 // evey now and then, namely a register copy from a source that was defined
10 // as an immediate value in the same block (usually just before the copy).
12 // Here is an example of actual code emitted that shows this problem:
14 // .LBB0_5:
15 // {
16 // r5 = zxtb(r8)
17 // r6 = or(r6, ##12345)
18 // }
19 // {
20 // r3 = xor(r1, r2)
21 // r1 = #0 <-- r1 set to #0
22 // }
23 // {
24 // r7 = r1 <-- r7 set to r1
25 // r0 = zxtb(r3)
26 // }
28 #define DEBUG_TYPE "tfr-cleanup"
29 #include "HexagonTargetMachine.h"
31 #include "llvm/CodeGen/LiveIntervals.h"
32 #include "llvm/CodeGen/MachineFunction.h"
33 #include "llvm/CodeGen/MachineInstrBuilder.h"
34 #include "llvm/CodeGen/Passes.h"
35 #include "llvm/CodeGen/TargetInstrInfo.h"
36 #include "llvm/CodeGen/TargetRegisterInfo.h"
38 using namespace llvm;
40 namespace llvm {
41 FunctionPass *createHexagonTfrCleanup();
42 void initializeHexagonTfrCleanupPass(PassRegistry &);
43 } // namespace llvm
45 namespace {
46 class HexagonTfrCleanup : public MachineFunctionPass {
47 public:
48 static char ID;
49 HexagonTfrCleanup() : MachineFunctionPass(ID), HII(0), TRI(0) {
50 PassRegistry &R = *PassRegistry::getPassRegistry();
51 initializeHexagonTfrCleanupPass(R);
53 StringRef getPassName() const override { return "Hexagon TFR Cleanup"; }
54 void getAnalysisUsage(AnalysisUsage &AU) const override {
55 AU.setPreservesAll();
56 MachineFunctionPass::getAnalysisUsage(AU);
58 bool runOnMachineFunction(MachineFunction &MF) override;
60 private:
61 const HexagonInstrInfo *HII;
62 const TargetRegisterInfo *TRI;
64 typedef DenseMap<unsigned, uint64_t> ImmediateMap;
66 bool isIntReg(unsigned Reg, bool &Is32);
67 void setReg(unsigned R32, uint32_t V32, ImmediateMap &IMap);
68 bool getReg(unsigned Reg, uint64_t &Val, ImmediateMap &IMap);
69 bool updateImmMap(MachineInstr *MI, ImmediateMap &IMap);
70 bool rewriteIfImm(MachineInstr *MI, ImmediateMap &IMap, SlotIndexes *Indexes);
71 bool eraseIfRedundant(MachineInstr *MI, SlotIndexes *Indexes);
73 } // namespace
75 char HexagonTfrCleanup::ID = 0;
77 namespace llvm {
78 char &HexagonTfrCleanupID = HexagonTfrCleanup::ID;
81 bool HexagonTfrCleanup::isIntReg(unsigned Reg, bool &Is32) {
82 Is32 = Hexagon::IntRegsRegClass.contains(Reg);
83 return Is32 || Hexagon::DoubleRegsRegClass.contains(Reg);
86 // Assign given value V32 to the specified the register R32 in the map. Only
87 // 32-bit registers are valid arguments.
88 void HexagonTfrCleanup::setReg(unsigned R32, uint32_t V32, ImmediateMap &IMap) {
89 IMap[R32] = V32;
92 // Retrieve a value of the provided register Reg and store it into Val.
93 // Return "true" if a value was found, "false" otherwise.
94 bool HexagonTfrCleanup::getReg(unsigned Reg, uint64_t &Val,
95 ImmediateMap &IMap) {
96 bool Is32;
97 if (!isIntReg(Reg, Is32))
98 return false;
100 if (Is32) {
101 ImmediateMap::iterator F = IMap.find(Reg);
102 if (F == IMap.end())
103 return false;
104 Val = F->second;
105 return true;
108 // For 64-bit registers, compose the value from the values of its
109 // subregisters.
110 unsigned SubL = TRI->getSubReg(Reg, Hexagon::isub_lo);
111 unsigned SubH = TRI->getSubReg(Reg, Hexagon::isub_hi);
112 ImmediateMap::iterator FL = IMap.find(SubL), FH = IMap.find(SubH);
113 if (FL == IMap.end() || FH == IMap.end())
114 return false;
115 Val = (FH->second << 32) | FL->second;
116 return true;
119 // Process an instruction and record the relevant information in the imme-
120 // diate map.
121 bool HexagonTfrCleanup::updateImmMap(MachineInstr *MI, ImmediateMap &IMap) {
122 using namespace Hexagon;
124 if (MI->isCall()) {
125 IMap.clear();
126 return true;
129 // If this is an instruction that loads a constant into a register,
130 // record this information in IMap.
131 unsigned Opc = MI->getOpcode();
132 if (Opc == A2_tfrsi || Opc == A2_tfrpi) {
133 unsigned DefR = MI->getOperand(0).getReg();
134 bool Is32;
135 if (!isIntReg(DefR, Is32))
136 return false;
137 if (!MI->getOperand(1).isImm()) {
138 if (!Is32) {
139 IMap.erase(TRI->getSubReg(DefR, isub_lo));
140 IMap.erase(TRI->getSubReg(DefR, isub_hi));
141 } else {
142 IMap.erase(DefR);
144 return false;
146 uint64_t Val = MI->getOperand(1).getImm();
147 // If it's a 64-bit register, break it up into subregisters.
148 if (!Is32) {
149 uint32_t VH = (Val >> 32), VL = (Val & 0xFFFFFFFFU);
150 setReg(TRI->getSubReg(DefR, isub_lo), VL, IMap);
151 setReg(TRI->getSubReg(DefR, isub_hi), VH, IMap);
152 } else {
153 setReg(DefR, Val, IMap);
155 return true;
158 // Not a A2_tfr[sp]i. Invalidate all modified registers in IMap.
159 for (MachineInstr::mop_iterator Mo = MI->operands_begin(),
160 E = MI->operands_end();
161 Mo != E; ++Mo) {
162 if (Mo->isRegMask()) {
163 IMap.clear();
164 return true;
166 if (!Mo->isReg() || !Mo->isDef())
167 continue;
168 unsigned R = Mo->getReg();
169 for (MCRegAliasIterator AR(R, TRI, true); AR.isValid(); ++AR) {
170 ImmediateMap::iterator F = IMap.find(*AR);
171 if (F != IMap.end())
172 IMap.erase(F);
175 return true;
178 // Rewrite the instruction as A2_tfrsi/A2_tfrpi, it is a copy of a source that
179 // has a known constant value.
180 bool HexagonTfrCleanup::rewriteIfImm(MachineInstr *MI, ImmediateMap &IMap,
181 SlotIndexes *Indexes) {
182 using namespace Hexagon;
183 unsigned Opc = MI->getOpcode();
184 switch (Opc) {
185 case A2_tfr:
186 case A2_tfrp:
187 case COPY:
188 break;
189 default:
190 return false;
193 unsigned DstR = MI->getOperand(0).getReg();
194 unsigned SrcR = MI->getOperand(1).getReg();
195 bool Tmp, Is32;
196 if (!isIntReg(DstR, Is32) || !isIntReg(SrcR, Tmp))
197 return false;
198 assert(Tmp == Is32 && "Register size mismatch");
199 uint64_t Val;
200 bool Found = getReg(SrcR, Val, IMap);
201 if (!Found)
202 return false;
204 MachineBasicBlock &B = *MI->getParent();
205 DebugLoc DL = MI->getDebugLoc();
206 int64_t SVal = Is32 ? int32_t(Val) : Val;
207 auto &HST = B.getParent()->getSubtarget<HexagonSubtarget>();
208 MachineInstr *NewMI;
209 if (Is32)
210 NewMI = BuildMI(B, MI, DL, HII->get(A2_tfrsi), DstR).addImm(SVal);
211 else if (isInt<8>(SVal))
212 NewMI = BuildMI(B, MI, DL, HII->get(A2_tfrpi), DstR).addImm(SVal);
213 else if (isInt<8>(SVal >> 32) && isInt<8>(int32_t(Val & 0xFFFFFFFFLL)))
214 NewMI = BuildMI(B, MI, DL, HII->get(A2_combineii), DstR)
215 .addImm(int32_t(SVal >> 32))
216 .addImm(int32_t(Val & 0xFFFFFFFFLL));
217 else if (HST.isTinyCore())
218 // Disable generating CONST64 since it requires load resource.
219 return false;
220 else
221 NewMI = BuildMI(B, MI, DL, HII->get(CONST64), DstR).addImm(Val);
223 // Replace the MI to reuse the same slot index
224 if (Indexes)
225 Indexes->replaceMachineInstrInMaps(*MI, *NewMI);
226 MI->eraseFromParent();
227 return true;
230 // Remove the instruction if it is a self-assignment.
231 bool HexagonTfrCleanup::eraseIfRedundant(MachineInstr *MI,
232 SlotIndexes *Indexes) {
233 unsigned Opc = MI->getOpcode();
234 unsigned DefR, SrcR;
235 bool IsUndef = false;
236 switch (Opc) {
237 case Hexagon::A2_tfr:
238 // Rd = Rd
239 DefR = MI->getOperand(0).getReg();
240 SrcR = MI->getOperand(1).getReg();
241 IsUndef = MI->getOperand(1).isUndef();
242 break;
243 case Hexagon::A2_tfrt:
244 case Hexagon::A2_tfrf:
245 // if ([!]Pu) Rd = Rd
246 DefR = MI->getOperand(0).getReg();
247 SrcR = MI->getOperand(2).getReg();
248 IsUndef = MI->getOperand(2).isUndef();
249 break;
250 default:
251 return false;
253 if (DefR != SrcR)
254 return false;
255 if (IsUndef) {
256 MachineBasicBlock &B = *MI->getParent();
257 DebugLoc DL = MI->getDebugLoc();
258 auto DefI = BuildMI(B, MI, DL, HII->get(TargetOpcode::IMPLICIT_DEF), DefR);
259 for (auto &Op : MI->operands())
260 if (Op.isReg() && Op.isDef() && Op.isImplicit())
261 DefI->addOperand(Op);
264 if (Indexes)
265 Indexes->removeMachineInstrFromMaps(*MI);
266 MI->eraseFromParent();
267 return true;
270 bool HexagonTfrCleanup::runOnMachineFunction(MachineFunction &MF) {
271 bool Changed = false;
272 // Map: 32-bit register -> immediate value.
273 // 64-bit registers are stored through their subregisters.
274 ImmediateMap IMap;
275 auto *SIWrapper = getAnalysisIfAvailable<SlotIndexesWrapperPass>();
276 SlotIndexes *Indexes = SIWrapper ? &SIWrapper->getSI() : nullptr;
278 auto &HST = MF.getSubtarget<HexagonSubtarget>();
279 HII = HST.getInstrInfo();
280 TRI = HST.getRegisterInfo();
282 for (MachineBasicBlock &B : MF) {
283 MachineBasicBlock::iterator J, F, NextJ;
284 IMap.clear();
285 bool Inserted = false, Erased = false;
286 for (J = B.begin(), F = B.end(); J != F; J = NextJ) {
287 NextJ = std::next(J);
288 MachineInstr *MI = &*J;
289 bool E = eraseIfRedundant(MI, Indexes);
290 Erased |= E;
291 if (E)
292 continue;
293 Inserted |= rewriteIfImm(MI, IMap, Indexes);
294 MachineBasicBlock::iterator NewJ = std::prev(NextJ);
295 updateImmMap(&*NewJ, IMap);
297 bool BlockC = Inserted | Erased;
298 Changed |= BlockC;
299 if (BlockC && Indexes)
300 Indexes->repairIndexesInRange(&B, B.begin(), B.end());
303 return Changed;
306 //===----------------------------------------------------------------------===//
307 // Public Constructor Functions
308 //===----------------------------------------------------------------------===//
309 INITIALIZE_PASS(HexagonTfrCleanup, "tfr-cleanup", "Hexagon TFR Cleanup", false,
310 false)
312 FunctionPass *llvm::createHexagonTfrCleanup() {
313 return new HexagonTfrCleanup();