1 //===------- HexagonTfrCleanup.cpp - Hexagon Transfer Cleanup Pass -------===//
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
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:
17 // r6 = or(r6, ##12345)
21 // r1 = #0 <-- r1 set to #0
24 // r7 = r1 <-- r7 set to r1
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"
41 FunctionPass
*createHexagonTfrCleanup();
42 void initializeHexagonTfrCleanupPass(PassRegistry
&);
46 class HexagonTfrCleanup
: public MachineFunctionPass
{
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
{
56 MachineFunctionPass::getAnalysisUsage(AU
);
58 bool runOnMachineFunction(MachineFunction
&MF
) override
;
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
);
75 char HexagonTfrCleanup::ID
= 0;
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
) {
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
,
97 if (!isIntReg(Reg
, Is32
))
101 ImmediateMap::iterator F
= IMap
.find(Reg
);
108 // For 64-bit registers, compose the value from the values of its
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())
115 Val
= (FH
->second
<< 32) | FL
->second
;
119 // Process an instruction and record the relevant information in the imme-
121 bool HexagonTfrCleanup::updateImmMap(MachineInstr
*MI
, ImmediateMap
&IMap
) {
122 using namespace Hexagon
;
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();
135 if (!isIntReg(DefR
, Is32
))
137 if (!MI
->getOperand(1).isImm()) {
139 IMap
.erase(TRI
->getSubReg(DefR
, isub_lo
));
140 IMap
.erase(TRI
->getSubReg(DefR
, isub_hi
));
146 uint64_t Val
= MI
->getOperand(1).getImm();
147 // If it's a 64-bit register, break it up into subregisters.
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
);
153 setReg(DefR
, Val
, IMap
);
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();
162 if (Mo
->isRegMask()) {
166 if (!Mo
->isReg() || !Mo
->isDef())
168 unsigned R
= Mo
->getReg();
169 for (MCRegAliasIterator
AR(R
, TRI
, true); AR
.isValid(); ++AR
) {
170 ImmediateMap::iterator F
= IMap
.find(*AR
);
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();
193 unsigned DstR
= MI
->getOperand(0).getReg();
194 unsigned SrcR
= MI
->getOperand(1).getReg();
196 if (!isIntReg(DstR
, Is32
) || !isIntReg(SrcR
, Tmp
))
198 assert(Tmp
== Is32
&& "Register size mismatch");
200 bool Found
= getReg(SrcR
, Val
, IMap
);
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
>();
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.
221 NewMI
= BuildMI(B
, MI
, DL
, HII
->get(CONST64
), DstR
).addImm(Val
);
223 // Replace the MI to reuse the same slot index
225 Indexes
->replaceMachineInstrInMaps(*MI
, *NewMI
);
226 MI
->eraseFromParent();
230 // Remove the instruction if it is a self-assignment.
231 bool HexagonTfrCleanup::eraseIfRedundant(MachineInstr
*MI
,
232 SlotIndexes
*Indexes
) {
233 unsigned Opc
= MI
->getOpcode();
235 bool IsUndef
= false;
237 case Hexagon::A2_tfr
:
239 DefR
= MI
->getOperand(0).getReg();
240 SrcR
= MI
->getOperand(1).getReg();
241 IsUndef
= MI
->getOperand(1).isUndef();
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();
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
);
265 Indexes
->removeMachineInstrFromMaps(*MI
);
266 MI
->eraseFromParent();
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.
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
;
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
);
293 Inserted
|= rewriteIfImm(MI
, IMap
, Indexes
);
294 MachineBasicBlock::iterator NewJ
= std::prev(NextJ
);
295 updateImmMap(&*NewJ
, IMap
);
297 bool BlockC
= Inserted
| Erased
;
299 if (BlockC
&& Indexes
)
300 Indexes
->repairIndexesInRange(&B
, B
.begin(), B
.end());
306 //===----------------------------------------------------------------------===//
307 // Public Constructor Functions
308 //===----------------------------------------------------------------------===//
309 INITIALIZE_PASS(HexagonTfrCleanup
, "tfr-cleanup", "Hexagon TFR Cleanup", false,
312 FunctionPass
*llvm::createHexagonTfrCleanup() {
313 return new HexagonTfrCleanup();