xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVMakeCompressible.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
1*81ad6265SDimitry Andric //===-- RISCVMakeCompressible.cpp - Make more instructions compressible ---===//
2*81ad6265SDimitry Andric //
3*81ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*81ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*81ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*81ad6265SDimitry Andric //
7*81ad6265SDimitry Andric //===----------------------------------------------------------------------===//
8*81ad6265SDimitry Andric //
9*81ad6265SDimitry Andric // This pass searches for instructions that are prevented from being compressed
10*81ad6265SDimitry Andric // by one of the following:
11*81ad6265SDimitry Andric //
12*81ad6265SDimitry Andric //   1. The use of a single uncompressed register.
13*81ad6265SDimitry Andric //   2. A base register + offset where the offset is too large to be compressed
14*81ad6265SDimitry Andric //   and the base register may or may not be compressed.
15*81ad6265SDimitry Andric //
16*81ad6265SDimitry Andric //
17*81ad6265SDimitry Andric // For case 1, if a compressed register is available, then the uncompressed
18*81ad6265SDimitry Andric // register is copied to the compressed register and its uses are replaced.
19*81ad6265SDimitry Andric //
20*81ad6265SDimitry Andric // For example, storing zero uses the uncompressible zero register:
21*81ad6265SDimitry Andric //   sw zero, 0(a0)   # if zero
22*81ad6265SDimitry Andric //   sw zero, 8(a0)   # if zero
23*81ad6265SDimitry Andric //   sw zero, 4(a0)   # if zero
24*81ad6265SDimitry Andric //   sw zero, 24(a0)   # if zero
25*81ad6265SDimitry Andric //
26*81ad6265SDimitry Andric // If a compressed register (e.g. a1) is available, the above can be transformed
27*81ad6265SDimitry Andric // to the following to improve code size:
28*81ad6265SDimitry Andric //   li a1, 0
29*81ad6265SDimitry Andric //   c.sw a1, 0(a0)
30*81ad6265SDimitry Andric //   c.sw a1, 8(a0)
31*81ad6265SDimitry Andric //   c.sw a1, 4(a0)
32*81ad6265SDimitry Andric //   c.sw a1, 24(a0)
33*81ad6265SDimitry Andric //
34*81ad6265SDimitry Andric //
35*81ad6265SDimitry Andric // For case 2, if a compressed register is available, then the original base
36*81ad6265SDimitry Andric // is copied and adjusted such that:
37*81ad6265SDimitry Andric //
38*81ad6265SDimitry Andric //   new_base_register = base_register + adjustment
39*81ad6265SDimitry Andric //   base_register + large_offset = new_base_register + small_offset
40*81ad6265SDimitry Andric //
41*81ad6265SDimitry Andric // For example, the following offsets are too large for c.sw:
42*81ad6265SDimitry Andric //   lui a2, 983065
43*81ad6265SDimitry Andric //   sw  a1, -236(a2)
44*81ad6265SDimitry Andric //   sw  a1, -240(a2)
45*81ad6265SDimitry Andric //   sw  a1, -244(a2)
46*81ad6265SDimitry Andric //   sw  a1, -248(a2)
47*81ad6265SDimitry Andric //   sw  a1, -252(a2)
48*81ad6265SDimitry Andric //   sw  a0, -256(a2)
49*81ad6265SDimitry Andric //
50*81ad6265SDimitry Andric // If a compressed register is available (e.g. a3), a new base could be created
51*81ad6265SDimitry Andric // such that the addresses can accessed with a compressible offset, thus
52*81ad6265SDimitry Andric // improving code size:
53*81ad6265SDimitry Andric //   lui a2, 983065
54*81ad6265SDimitry Andric //   addi  a3, a2, -256
55*81ad6265SDimitry Andric //   c.sw  a1, 20(a3)
56*81ad6265SDimitry Andric //   c.sw  a1, 16(a3)
57*81ad6265SDimitry Andric //   c.sw  a1, 12(a3)
58*81ad6265SDimitry Andric //   c.sw  a1, 8(a3)
59*81ad6265SDimitry Andric //   c.sw  a1, 4(a3)
60*81ad6265SDimitry Andric //   c.sw  a0, 0(a3)
61*81ad6265SDimitry Andric //
62*81ad6265SDimitry Andric //
63*81ad6265SDimitry Andric // This optimization is only applied if there are enough uses of the copied
64*81ad6265SDimitry Andric // register for code size to be reduced.
65*81ad6265SDimitry Andric //
66*81ad6265SDimitry Andric //===----------------------------------------------------------------------===//
67*81ad6265SDimitry Andric 
68*81ad6265SDimitry Andric #include "RISCV.h"
69*81ad6265SDimitry Andric #include "RISCVSubtarget.h"
70*81ad6265SDimitry Andric #include "llvm/CodeGen/Passes.h"
71*81ad6265SDimitry Andric #include "llvm/CodeGen/RegisterScavenging.h"
72*81ad6265SDimitry Andric #include "llvm/MC/TargetRegistry.h"
73*81ad6265SDimitry Andric #include "llvm/Support/Debug.h"
74*81ad6265SDimitry Andric 
75*81ad6265SDimitry Andric using namespace llvm;
76*81ad6265SDimitry Andric 
77*81ad6265SDimitry Andric #define DEBUG_TYPE "riscv-make-compressible"
78*81ad6265SDimitry Andric #define RISCV_COMPRESS_INSTRS_NAME "RISCV Make Compressible"
79*81ad6265SDimitry Andric 
80*81ad6265SDimitry Andric namespace {
81*81ad6265SDimitry Andric 
82*81ad6265SDimitry Andric struct RISCVMakeCompressibleOpt : public MachineFunctionPass {
83*81ad6265SDimitry Andric   static char ID;
84*81ad6265SDimitry Andric 
85*81ad6265SDimitry Andric   bool runOnMachineFunction(MachineFunction &Fn) override;
86*81ad6265SDimitry Andric 
87*81ad6265SDimitry Andric   RISCVMakeCompressibleOpt() : MachineFunctionPass(ID) {
88*81ad6265SDimitry Andric     initializeRISCVMakeCompressibleOptPass(*PassRegistry::getPassRegistry());
89*81ad6265SDimitry Andric   }
90*81ad6265SDimitry Andric 
91*81ad6265SDimitry Andric   StringRef getPassName() const override { return RISCV_COMPRESS_INSTRS_NAME; }
92*81ad6265SDimitry Andric };
93*81ad6265SDimitry Andric } // namespace
94*81ad6265SDimitry Andric 
95*81ad6265SDimitry Andric char RISCVMakeCompressibleOpt::ID = 0;
96*81ad6265SDimitry Andric INITIALIZE_PASS(RISCVMakeCompressibleOpt, "riscv-make-compressible",
97*81ad6265SDimitry Andric                 RISCV_COMPRESS_INSTRS_NAME, false, false)
98*81ad6265SDimitry Andric 
99*81ad6265SDimitry Andric // Return log2(widthInBytes) of load/store done by Opcode.
100*81ad6265SDimitry Andric static unsigned log2LdstWidth(unsigned Opcode) {
101*81ad6265SDimitry Andric   switch (Opcode) {
102*81ad6265SDimitry Andric   default:
103*81ad6265SDimitry Andric     llvm_unreachable("Unexpected opcode");
104*81ad6265SDimitry Andric   case RISCV::LW:
105*81ad6265SDimitry Andric   case RISCV::SW:
106*81ad6265SDimitry Andric   case RISCV::FLW:
107*81ad6265SDimitry Andric   case RISCV::FSW:
108*81ad6265SDimitry Andric     return 2;
109*81ad6265SDimitry Andric   case RISCV::LD:
110*81ad6265SDimitry Andric   case RISCV::SD:
111*81ad6265SDimitry Andric   case RISCV::FLD:
112*81ad6265SDimitry Andric   case RISCV::FSD:
113*81ad6265SDimitry Andric     return 3;
114*81ad6265SDimitry Andric   }
115*81ad6265SDimitry Andric }
116*81ad6265SDimitry Andric 
117*81ad6265SDimitry Andric // Return a mask for the offset bits of a non-stack-pointer based compressed
118*81ad6265SDimitry Andric // load/store.
119*81ad6265SDimitry Andric static uint8_t compressedLDSTOffsetMask(unsigned Opcode) {
120*81ad6265SDimitry Andric   return 0x1f << log2LdstWidth(Opcode);
121*81ad6265SDimitry Andric }
122*81ad6265SDimitry Andric 
123*81ad6265SDimitry Andric // Return true if Offset fits within a compressed stack-pointer based
124*81ad6265SDimitry Andric // load/store.
125*81ad6265SDimitry Andric static bool compressibleSPOffset(int64_t Offset, unsigned Opcode) {
126*81ad6265SDimitry Andric   return log2LdstWidth(Opcode) == 2 ? isShiftedUInt<6, 2>(Offset)
127*81ad6265SDimitry Andric                                     : isShiftedUInt<6, 3>(Offset);
128*81ad6265SDimitry Andric }
129*81ad6265SDimitry Andric 
130*81ad6265SDimitry Andric // Given an offset for a load/store, return the adjustment required to the base
131*81ad6265SDimitry Andric // register such that the address can be accessed with a compressible offset.
132*81ad6265SDimitry Andric // This will return 0 if the offset is already compressible.
133*81ad6265SDimitry Andric static int64_t getBaseAdjustForCompression(int64_t Offset, unsigned Opcode) {
134*81ad6265SDimitry Andric   // Return the excess bits that do not fit in a compressible offset.
135*81ad6265SDimitry Andric   return Offset & ~compressedLDSTOffsetMask(Opcode);
136*81ad6265SDimitry Andric }
137*81ad6265SDimitry Andric 
138*81ad6265SDimitry Andric // Return true if Reg is in a compressed register class.
139*81ad6265SDimitry Andric static bool isCompressedReg(Register Reg) {
140*81ad6265SDimitry Andric   return RISCV::GPRCRegClass.contains(Reg) ||
141*81ad6265SDimitry Andric          RISCV::FPR32CRegClass.contains(Reg) ||
142*81ad6265SDimitry Andric          RISCV::FPR64CRegClass.contains(Reg);
143*81ad6265SDimitry Andric }
144*81ad6265SDimitry Andric 
145*81ad6265SDimitry Andric // Return true if MI is a load for which there exists a compressed version.
146*81ad6265SDimitry Andric static bool isCompressibleLoad(const MachineInstr &MI) {
147*81ad6265SDimitry Andric   const RISCVSubtarget &STI = MI.getMF()->getSubtarget<RISCVSubtarget>();
148*81ad6265SDimitry Andric   const unsigned Opcode = MI.getOpcode();
149*81ad6265SDimitry Andric 
150*81ad6265SDimitry Andric   return Opcode == RISCV::LW || (!STI.is64Bit() && Opcode == RISCV::FLW) ||
151*81ad6265SDimitry Andric          Opcode == RISCV::LD || Opcode == RISCV::FLD;
152*81ad6265SDimitry Andric }
153*81ad6265SDimitry Andric 
154*81ad6265SDimitry Andric // Return true if MI is a store for which there exists a compressed version.
155*81ad6265SDimitry Andric static bool isCompressibleStore(const MachineInstr &MI) {
156*81ad6265SDimitry Andric   const RISCVSubtarget &STI = MI.getMF()->getSubtarget<RISCVSubtarget>();
157*81ad6265SDimitry Andric   const unsigned Opcode = MI.getOpcode();
158*81ad6265SDimitry Andric 
159*81ad6265SDimitry Andric   return Opcode == RISCV::SW || (!STI.is64Bit() && Opcode == RISCV::FSW) ||
160*81ad6265SDimitry Andric          Opcode == RISCV::SD || Opcode == RISCV::FSD;
161*81ad6265SDimitry Andric }
162*81ad6265SDimitry Andric 
163*81ad6265SDimitry Andric // Find a single register and/or large offset which, if compressible, would
164*81ad6265SDimitry Andric // allow the given instruction to be compressed.
165*81ad6265SDimitry Andric //
166*81ad6265SDimitry Andric // Possible return values:
167*81ad6265SDimitry Andric //
168*81ad6265SDimitry Andric //   {Reg, 0}               - Uncompressed Reg needs replacing with a compressed
169*81ad6265SDimitry Andric //                            register.
170*81ad6265SDimitry Andric //   {Reg, N}               - Reg needs replacing with a compressed register and
171*81ad6265SDimitry Andric //                            N needs adding to the new register. (Reg may be
172*81ad6265SDimitry Andric //                            compressed or uncompressed).
173*81ad6265SDimitry Andric //   {RISCV::NoRegister, 0} - No suitable optimization found for this
174*81ad6265SDimitry Andric //   instruction.
175*81ad6265SDimitry Andric static RegImmPair getRegImmPairPreventingCompression(const MachineInstr &MI) {
176*81ad6265SDimitry Andric   const unsigned Opcode = MI.getOpcode();
177*81ad6265SDimitry Andric 
178*81ad6265SDimitry Andric   if (isCompressibleLoad(MI) || isCompressibleStore(MI)) {
179*81ad6265SDimitry Andric     const MachineOperand &MOImm = MI.getOperand(2);
180*81ad6265SDimitry Andric     if (!MOImm.isImm())
181*81ad6265SDimitry Andric       return RegImmPair(RISCV::NoRegister, 0);
182*81ad6265SDimitry Andric 
183*81ad6265SDimitry Andric     int64_t Offset = MOImm.getImm();
184*81ad6265SDimitry Andric     int64_t NewBaseAdjust = getBaseAdjustForCompression(Offset, Opcode);
185*81ad6265SDimitry Andric     Register Base = MI.getOperand(1).getReg();
186*81ad6265SDimitry Andric 
187*81ad6265SDimitry Andric     // Memory accesses via the stack pointer do not have a requirement for
188*81ad6265SDimitry Andric     // either of the registers to be compressible and can take a larger offset.
189*81ad6265SDimitry Andric     if (RISCV::SPRegClass.contains(Base)) {
190*81ad6265SDimitry Andric       if (!compressibleSPOffset(Offset, Opcode) && NewBaseAdjust)
191*81ad6265SDimitry Andric         return RegImmPair(Base, NewBaseAdjust);
192*81ad6265SDimitry Andric     } else {
193*81ad6265SDimitry Andric       Register SrcDest = MI.getOperand(0).getReg();
194*81ad6265SDimitry Andric       bool SrcDestCompressed = isCompressedReg(SrcDest);
195*81ad6265SDimitry Andric       bool BaseCompressed = isCompressedReg(Base);
196*81ad6265SDimitry Andric 
197*81ad6265SDimitry Andric       // If only Base and/or offset prevent compression, then return Base and
198*81ad6265SDimitry Andric       // any adjustment required to make the offset compressible.
199*81ad6265SDimitry Andric       if ((!BaseCompressed || NewBaseAdjust) && SrcDestCompressed)
200*81ad6265SDimitry Andric         return RegImmPair(Base, NewBaseAdjust);
201*81ad6265SDimitry Andric 
202*81ad6265SDimitry Andric       // For loads, we can only change the base register since dest is defined
203*81ad6265SDimitry Andric       // rather than used.
204*81ad6265SDimitry Andric       //
205*81ad6265SDimitry Andric       // For stores, we can change SrcDest (and Base if SrcDest == Base) but
206*81ad6265SDimitry Andric       // cannot resolve an uncompressible offset in this case.
207*81ad6265SDimitry Andric       if (isCompressibleStore(MI)) {
208*81ad6265SDimitry Andric         if (!SrcDestCompressed && (BaseCompressed || SrcDest == Base) &&
209*81ad6265SDimitry Andric             !NewBaseAdjust)
210*81ad6265SDimitry Andric           return RegImmPair(SrcDest, NewBaseAdjust);
211*81ad6265SDimitry Andric       }
212*81ad6265SDimitry Andric     }
213*81ad6265SDimitry Andric   }
214*81ad6265SDimitry Andric   return RegImmPair(RISCV::NoRegister, 0);
215*81ad6265SDimitry Andric }
216*81ad6265SDimitry Andric 
217*81ad6265SDimitry Andric // Check all uses after FirstMI of the given register, keeping a vector of
218*81ad6265SDimitry Andric // instructions that would be compressible if the given register (and offset if
219*81ad6265SDimitry Andric // applicable) were compressible.
220*81ad6265SDimitry Andric //
221*81ad6265SDimitry Andric // If there are enough uses for this optimization to improve code size and a
222*81ad6265SDimitry Andric // compressed register is available, return that compressed register.
223*81ad6265SDimitry Andric static Register analyzeCompressibleUses(MachineInstr &FirstMI,
224*81ad6265SDimitry Andric                                         RegImmPair RegImm,
225*81ad6265SDimitry Andric                                         SmallVectorImpl<MachineInstr *> &MIs) {
226*81ad6265SDimitry Andric   MachineBasicBlock &MBB = *FirstMI.getParent();
227*81ad6265SDimitry Andric   const TargetRegisterInfo *TRI =
228*81ad6265SDimitry Andric       MBB.getParent()->getSubtarget().getRegisterInfo();
229*81ad6265SDimitry Andric 
230*81ad6265SDimitry Andric   RegScavenger RS;
231*81ad6265SDimitry Andric   RS.enterBasicBlock(MBB);
232*81ad6265SDimitry Andric 
233*81ad6265SDimitry Andric   for (MachineBasicBlock::instr_iterator I = FirstMI.getIterator(),
234*81ad6265SDimitry Andric                                          E = MBB.instr_end();
235*81ad6265SDimitry Andric        I != E; ++I) {
236*81ad6265SDimitry Andric     MachineInstr &MI = *I;
237*81ad6265SDimitry Andric 
238*81ad6265SDimitry Andric     // Determine if this is an instruction which would benefit from using the
239*81ad6265SDimitry Andric     // new register.
240*81ad6265SDimitry Andric     RegImmPair CandidateRegImm = getRegImmPairPreventingCompression(MI);
241*81ad6265SDimitry Andric     if (CandidateRegImm.Reg == RegImm.Reg &&
242*81ad6265SDimitry Andric         CandidateRegImm.Imm == RegImm.Imm) {
243*81ad6265SDimitry Andric       // Advance tracking since the value in the new register must be live for
244*81ad6265SDimitry Andric       // this instruction too.
245*81ad6265SDimitry Andric       RS.forward(I);
246*81ad6265SDimitry Andric 
247*81ad6265SDimitry Andric       MIs.push_back(&MI);
248*81ad6265SDimitry Andric     }
249*81ad6265SDimitry Andric 
250*81ad6265SDimitry Andric     // If RegImm.Reg is modified by this instruction, then we cannot optimize
251*81ad6265SDimitry Andric     // past this instruction. If the register is already compressed, then it may
252*81ad6265SDimitry Andric     // possible to optimize a large offset in the current instruction - this
253*81ad6265SDimitry Andric     // will have been detected by the preceeding call to
254*81ad6265SDimitry Andric     // getRegImmPairPreventingCompression.
255*81ad6265SDimitry Andric     if (MI.modifiesRegister(RegImm.Reg, TRI))
256*81ad6265SDimitry Andric       break;
257*81ad6265SDimitry Andric   }
258*81ad6265SDimitry Andric 
259*81ad6265SDimitry Andric   // Adjusting the base costs one new uncompressed addi and therefore three uses
260*81ad6265SDimitry Andric   // are required for a code size reduction. If no base adjustment is required,
261*81ad6265SDimitry Andric   // then copying the register costs one new c.mv (or c.li Rd, 0 for "copying"
262*81ad6265SDimitry Andric   // the zero register) and therefore two uses are required for a code size
263*81ad6265SDimitry Andric   // reduction.
264*81ad6265SDimitry Andric   if (MIs.size() < 2 || (RegImm.Imm != 0 && MIs.size() < 3))
265*81ad6265SDimitry Andric     return RISCV::NoRegister;
266*81ad6265SDimitry Andric 
267*81ad6265SDimitry Andric   // Find a compressible register which will be available from the first
268*81ad6265SDimitry Andric   // instruction we care about to the last.
269*81ad6265SDimitry Andric   const TargetRegisterClass *RCToScavenge;
270*81ad6265SDimitry Andric 
271*81ad6265SDimitry Andric   // Work out the compressed register class from which to scavenge.
272*81ad6265SDimitry Andric   if (RISCV::GPRRegClass.contains(RegImm.Reg))
273*81ad6265SDimitry Andric     RCToScavenge = &RISCV::GPRCRegClass;
274*81ad6265SDimitry Andric   else if (RISCV::FPR32RegClass.contains(RegImm.Reg))
275*81ad6265SDimitry Andric     RCToScavenge = &RISCV::FPR32CRegClass;
276*81ad6265SDimitry Andric   else if (RISCV::FPR64RegClass.contains(RegImm.Reg))
277*81ad6265SDimitry Andric     RCToScavenge = &RISCV::FPR64CRegClass;
278*81ad6265SDimitry Andric   else
279*81ad6265SDimitry Andric     return RISCV::NoRegister;
280*81ad6265SDimitry Andric 
281*81ad6265SDimitry Andric   return RS.scavengeRegisterBackwards(*RCToScavenge, FirstMI.getIterator(),
282*81ad6265SDimitry Andric                                       /*RestoreAfter=*/false, /*SPAdj=*/0,
283*81ad6265SDimitry Andric                                       /*AllowSpill=*/false);
284*81ad6265SDimitry Andric }
285*81ad6265SDimitry Andric 
286*81ad6265SDimitry Andric // Update uses of the old register in the given instruction to the new register.
287*81ad6265SDimitry Andric static void updateOperands(MachineInstr &MI, RegImmPair OldRegImm,
288*81ad6265SDimitry Andric                            Register NewReg) {
289*81ad6265SDimitry Andric   unsigned Opcode = MI.getOpcode();
290*81ad6265SDimitry Andric 
291*81ad6265SDimitry Andric   // If this pass is extended to support more instructions, the check for
292*81ad6265SDimitry Andric   // definedness may need to be strengthened.
293*81ad6265SDimitry Andric   assert((isCompressibleLoad(MI) || isCompressibleStore(MI)) &&
294*81ad6265SDimitry Andric          "Unsupported instruction for this optimization.");
295*81ad6265SDimitry Andric 
296*81ad6265SDimitry Andric   // Update registers
297*81ad6265SDimitry Andric   for (MachineOperand &MO : MI.operands())
298*81ad6265SDimitry Andric     if (MO.isReg() && MO.getReg() == OldRegImm.Reg) {
299*81ad6265SDimitry Andric       // Do not update operands that define the old register.
300*81ad6265SDimitry Andric       //
301*81ad6265SDimitry Andric       // The new register was scavenged for the range of instructions that are
302*81ad6265SDimitry Andric       // being updated, therefore it should not be defined within this range
303*81ad6265SDimitry Andric       // except possibly in the final instruction.
304*81ad6265SDimitry Andric       if (MO.isDef()) {
305*81ad6265SDimitry Andric         assert(isCompressibleLoad(MI));
306*81ad6265SDimitry Andric         continue;
307*81ad6265SDimitry Andric       }
308*81ad6265SDimitry Andric       // Update reg
309*81ad6265SDimitry Andric       MO.setReg(NewReg);
310*81ad6265SDimitry Andric     }
311*81ad6265SDimitry Andric 
312*81ad6265SDimitry Andric   // Update offset
313*81ad6265SDimitry Andric   MachineOperand &MOImm = MI.getOperand(2);
314*81ad6265SDimitry Andric   int64_t NewOffset = MOImm.getImm() & compressedLDSTOffsetMask(Opcode);
315*81ad6265SDimitry Andric   MOImm.setImm(NewOffset);
316*81ad6265SDimitry Andric }
317*81ad6265SDimitry Andric 
318*81ad6265SDimitry Andric bool RISCVMakeCompressibleOpt::runOnMachineFunction(MachineFunction &Fn) {
319*81ad6265SDimitry Andric   // This is a size optimization.
320*81ad6265SDimitry Andric   if (skipFunction(Fn.getFunction()) || !Fn.getFunction().hasMinSize())
321*81ad6265SDimitry Andric     return false;
322*81ad6265SDimitry Andric 
323*81ad6265SDimitry Andric   const RISCVSubtarget &STI = Fn.getSubtarget<RISCVSubtarget>();
324*81ad6265SDimitry Andric   const RISCVInstrInfo &TII = *STI.getInstrInfo();
325*81ad6265SDimitry Andric 
326*81ad6265SDimitry Andric   // This optimization only makes sense if compressed instructions are emitted.
327*81ad6265SDimitry Andric   if (!STI.hasStdExtC())
328*81ad6265SDimitry Andric     return false;
329*81ad6265SDimitry Andric 
330*81ad6265SDimitry Andric   for (MachineBasicBlock &MBB : Fn) {
331*81ad6265SDimitry Andric     LLVM_DEBUG(dbgs() << "MBB: " << MBB.getName() << "\n");
332*81ad6265SDimitry Andric     for (MachineInstr &MI : MBB) {
333*81ad6265SDimitry Andric       // Determine if this instruction would otherwise be compressed if not for
334*81ad6265SDimitry Andric       // an uncompressible register or offset.
335*81ad6265SDimitry Andric       RegImmPair RegImm = getRegImmPairPreventingCompression(MI);
336*81ad6265SDimitry Andric       if (!RegImm.Reg && RegImm.Imm == 0)
337*81ad6265SDimitry Andric         continue;
338*81ad6265SDimitry Andric 
339*81ad6265SDimitry Andric       // Determine if there is a set of instructions for which replacing this
340*81ad6265SDimitry Andric       // register with a compressed register (and compressible offset if
341*81ad6265SDimitry Andric       // applicable) is possible and will allow compression.
342*81ad6265SDimitry Andric       SmallVector<MachineInstr *, 8> MIs;
343*81ad6265SDimitry Andric       Register NewReg = analyzeCompressibleUses(MI, RegImm, MIs);
344*81ad6265SDimitry Andric       if (!NewReg)
345*81ad6265SDimitry Andric         continue;
346*81ad6265SDimitry Andric 
347*81ad6265SDimitry Andric       // Create the appropriate copy and/or offset.
348*81ad6265SDimitry Andric       if (RISCV::GPRRegClass.contains(RegImm.Reg)) {
349*81ad6265SDimitry Andric         assert(isInt<12>(RegImm.Imm));
350*81ad6265SDimitry Andric         BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(RISCV::ADDI), NewReg)
351*81ad6265SDimitry Andric             .addReg(RegImm.Reg)
352*81ad6265SDimitry Andric             .addImm(RegImm.Imm);
353*81ad6265SDimitry Andric       } else {
354*81ad6265SDimitry Andric         // If we are looking at replacing an FPR register we don't expect to
355*81ad6265SDimitry Andric         // have any offset. The only compressible FP instructions with an offset
356*81ad6265SDimitry Andric         // are loads and stores, for which the offset applies to the GPR operand
357*81ad6265SDimitry Andric         // not the FPR operand.
358*81ad6265SDimitry Andric         assert(RegImm.Imm == 0);
359*81ad6265SDimitry Andric         unsigned Opcode = RISCV::FPR32RegClass.contains(RegImm.Reg)
360*81ad6265SDimitry Andric                               ? RISCV::FSGNJ_S
361*81ad6265SDimitry Andric                               : RISCV::FSGNJ_D;
362*81ad6265SDimitry Andric         BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(Opcode), NewReg)
363*81ad6265SDimitry Andric             .addReg(RegImm.Reg)
364*81ad6265SDimitry Andric             .addReg(RegImm.Reg);
365*81ad6265SDimitry Andric       }
366*81ad6265SDimitry Andric 
367*81ad6265SDimitry Andric       // Update the set of instructions to use the compressed register and
368*81ad6265SDimitry Andric       // compressible offset instead. These instructions should now be
369*81ad6265SDimitry Andric       // compressible.
370*81ad6265SDimitry Andric       // TODO: Update all uses if RegImm.Imm == 0? Not just those that are
371*81ad6265SDimitry Andric       // expected to become compressible.
372*81ad6265SDimitry Andric       for (MachineInstr *UpdateMI : MIs)
373*81ad6265SDimitry Andric         updateOperands(*UpdateMI, RegImm, NewReg);
374*81ad6265SDimitry Andric     }
375*81ad6265SDimitry Andric   }
376*81ad6265SDimitry Andric   return true;
377*81ad6265SDimitry Andric }
378*81ad6265SDimitry Andric 
379*81ad6265SDimitry Andric /// Returns an instance of the Make Compressible Optimization pass.
380*81ad6265SDimitry Andric FunctionPass *llvm::createRISCVMakeCompressibleOptPass() {
381*81ad6265SDimitry Andric   return new RISCVMakeCompressibleOpt();
382*81ad6265SDimitry Andric }
383