xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVMakeCompressible.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
181ad6265SDimitry Andric //===-- RISCVMakeCompressible.cpp - Make more instructions compressible ---===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // This pass searches for instructions that are prevented from being compressed
1081ad6265SDimitry Andric // by one of the following:
1181ad6265SDimitry Andric //
1281ad6265SDimitry Andric //   1. The use of a single uncompressed register.
1381ad6265SDimitry Andric //   2. A base register + offset where the offset is too large to be compressed
1481ad6265SDimitry Andric //   and the base register may or may not be compressed.
1581ad6265SDimitry Andric //
1681ad6265SDimitry Andric //
1781ad6265SDimitry Andric // For case 1, if a compressed register is available, then the uncompressed
1881ad6265SDimitry Andric // register is copied to the compressed register and its uses are replaced.
1981ad6265SDimitry Andric //
2081ad6265SDimitry Andric // For example, storing zero uses the uncompressible zero register:
2181ad6265SDimitry Andric //   sw zero, 0(a0)   # if zero
2281ad6265SDimitry Andric //   sw zero, 8(a0)   # if zero
2381ad6265SDimitry Andric //   sw zero, 4(a0)   # if zero
2481ad6265SDimitry Andric //   sw zero, 24(a0)   # if zero
2581ad6265SDimitry Andric //
2681ad6265SDimitry Andric // If a compressed register (e.g. a1) is available, the above can be transformed
2781ad6265SDimitry Andric // to the following to improve code size:
2881ad6265SDimitry Andric //   li a1, 0
2981ad6265SDimitry Andric //   c.sw a1, 0(a0)
3081ad6265SDimitry Andric //   c.sw a1, 8(a0)
3181ad6265SDimitry Andric //   c.sw a1, 4(a0)
3281ad6265SDimitry Andric //   c.sw a1, 24(a0)
3381ad6265SDimitry Andric //
3481ad6265SDimitry Andric //
3581ad6265SDimitry Andric // For case 2, if a compressed register is available, then the original base
3681ad6265SDimitry Andric // is copied and adjusted such that:
3781ad6265SDimitry Andric //
3881ad6265SDimitry Andric //   new_base_register = base_register + adjustment
3981ad6265SDimitry Andric //   base_register + large_offset = new_base_register + small_offset
4081ad6265SDimitry Andric //
4181ad6265SDimitry Andric // For example, the following offsets are too large for c.sw:
4281ad6265SDimitry Andric //   lui a2, 983065
4381ad6265SDimitry Andric //   sw  a1, -236(a2)
4481ad6265SDimitry Andric //   sw  a1, -240(a2)
4581ad6265SDimitry Andric //   sw  a1, -244(a2)
4681ad6265SDimitry Andric //   sw  a1, -248(a2)
4781ad6265SDimitry Andric //   sw  a1, -252(a2)
4881ad6265SDimitry Andric //   sw  a0, -256(a2)
4981ad6265SDimitry Andric //
5081ad6265SDimitry Andric // If a compressed register is available (e.g. a3), a new base could be created
5181ad6265SDimitry Andric // such that the addresses can accessed with a compressible offset, thus
5281ad6265SDimitry Andric // improving code size:
5381ad6265SDimitry Andric //   lui a2, 983065
5481ad6265SDimitry Andric //   addi  a3, a2, -256
5581ad6265SDimitry Andric //   c.sw  a1, 20(a3)
5681ad6265SDimitry Andric //   c.sw  a1, 16(a3)
5781ad6265SDimitry Andric //   c.sw  a1, 12(a3)
5881ad6265SDimitry Andric //   c.sw  a1, 8(a3)
5981ad6265SDimitry Andric //   c.sw  a1, 4(a3)
6081ad6265SDimitry Andric //   c.sw  a0, 0(a3)
6181ad6265SDimitry Andric //
6281ad6265SDimitry Andric //
6381ad6265SDimitry Andric // This optimization is only applied if there are enough uses of the copied
6481ad6265SDimitry Andric // register for code size to be reduced.
6581ad6265SDimitry Andric //
6681ad6265SDimitry Andric //===----------------------------------------------------------------------===//
6781ad6265SDimitry Andric 
6881ad6265SDimitry Andric #include "RISCV.h"
6981ad6265SDimitry Andric #include "RISCVSubtarget.h"
7081ad6265SDimitry Andric #include "llvm/CodeGen/Passes.h"
7181ad6265SDimitry Andric #include "llvm/CodeGen/RegisterScavenging.h"
7281ad6265SDimitry Andric #include "llvm/MC/TargetRegistry.h"
7381ad6265SDimitry Andric #include "llvm/Support/Debug.h"
7481ad6265SDimitry Andric 
7581ad6265SDimitry Andric using namespace llvm;
7681ad6265SDimitry Andric 
7781ad6265SDimitry Andric #define DEBUG_TYPE "riscv-make-compressible"
7806c3fb27SDimitry Andric #define RISCV_COMPRESS_INSTRS_NAME "RISC-V Make Compressible"
7981ad6265SDimitry Andric 
8081ad6265SDimitry Andric namespace {
8181ad6265SDimitry Andric 
8281ad6265SDimitry Andric struct RISCVMakeCompressibleOpt : public MachineFunctionPass {
8381ad6265SDimitry Andric   static char ID;
8481ad6265SDimitry Andric 
8581ad6265SDimitry Andric   bool runOnMachineFunction(MachineFunction &Fn) override;
8681ad6265SDimitry Andric 
875f757f3fSDimitry Andric   RISCVMakeCompressibleOpt() : MachineFunctionPass(ID) {}
8881ad6265SDimitry Andric 
8981ad6265SDimitry Andric   StringRef getPassName() const override { return RISCV_COMPRESS_INSTRS_NAME; }
9081ad6265SDimitry Andric };
9181ad6265SDimitry Andric } // namespace
9281ad6265SDimitry Andric 
9381ad6265SDimitry Andric char RISCVMakeCompressibleOpt::ID = 0;
9481ad6265SDimitry Andric INITIALIZE_PASS(RISCVMakeCompressibleOpt, "riscv-make-compressible",
9581ad6265SDimitry Andric                 RISCV_COMPRESS_INSTRS_NAME, false, false)
9681ad6265SDimitry Andric 
9781ad6265SDimitry Andric // Return log2(widthInBytes) of load/store done by Opcode.
9881ad6265SDimitry Andric static unsigned log2LdstWidth(unsigned Opcode) {
9981ad6265SDimitry Andric   switch (Opcode) {
10081ad6265SDimitry Andric   default:
10181ad6265SDimitry Andric     llvm_unreachable("Unexpected opcode");
102*0fca6ea1SDimitry Andric   case RISCV::LBU:
103*0fca6ea1SDimitry Andric   case RISCV::SB:
104*0fca6ea1SDimitry Andric     return 0;
105*0fca6ea1SDimitry Andric   case RISCV::LH:
106*0fca6ea1SDimitry Andric   case RISCV::LHU:
107*0fca6ea1SDimitry Andric   case RISCV::SH:
108*0fca6ea1SDimitry Andric     return 1;
10981ad6265SDimitry Andric   case RISCV::LW:
11081ad6265SDimitry Andric   case RISCV::SW:
11181ad6265SDimitry Andric   case RISCV::FLW:
11281ad6265SDimitry Andric   case RISCV::FSW:
11381ad6265SDimitry Andric     return 2;
11481ad6265SDimitry Andric   case RISCV::LD:
11581ad6265SDimitry Andric   case RISCV::SD:
11681ad6265SDimitry Andric   case RISCV::FLD:
11781ad6265SDimitry Andric   case RISCV::FSD:
11881ad6265SDimitry Andric     return 3;
11981ad6265SDimitry Andric   }
12081ad6265SDimitry Andric }
12181ad6265SDimitry Andric 
122*0fca6ea1SDimitry Andric // Return bit field size of immediate operand of Opcode.
123*0fca6ea1SDimitry Andric static unsigned offsetMask(unsigned Opcode) {
124*0fca6ea1SDimitry Andric   switch (Opcode) {
125*0fca6ea1SDimitry Andric   default:
126*0fca6ea1SDimitry Andric     llvm_unreachable("Unexpected opcode");
127*0fca6ea1SDimitry Andric   case RISCV::LBU:
128*0fca6ea1SDimitry Andric   case RISCV::SB:
129*0fca6ea1SDimitry Andric     return maskTrailingOnes<unsigned>(2U);
130*0fca6ea1SDimitry Andric   case RISCV::LH:
131*0fca6ea1SDimitry Andric   case RISCV::LHU:
132*0fca6ea1SDimitry Andric   case RISCV::SH:
133*0fca6ea1SDimitry Andric     return maskTrailingOnes<unsigned>(1U);
134*0fca6ea1SDimitry Andric   case RISCV::LW:
135*0fca6ea1SDimitry Andric   case RISCV::SW:
136*0fca6ea1SDimitry Andric   case RISCV::FLW:
137*0fca6ea1SDimitry Andric   case RISCV::FSW:
138*0fca6ea1SDimitry Andric   case RISCV::LD:
139*0fca6ea1SDimitry Andric   case RISCV::SD:
140*0fca6ea1SDimitry Andric   case RISCV::FLD:
141*0fca6ea1SDimitry Andric   case RISCV::FSD:
142*0fca6ea1SDimitry Andric     return maskTrailingOnes<unsigned>(5U);
143*0fca6ea1SDimitry Andric   }
144*0fca6ea1SDimitry Andric }
145*0fca6ea1SDimitry Andric 
14681ad6265SDimitry Andric // Return a mask for the offset bits of a non-stack-pointer based compressed
14781ad6265SDimitry Andric // load/store.
14881ad6265SDimitry Andric static uint8_t compressedLDSTOffsetMask(unsigned Opcode) {
149*0fca6ea1SDimitry Andric   return offsetMask(Opcode) << log2LdstWidth(Opcode);
15081ad6265SDimitry Andric }
15181ad6265SDimitry Andric 
15281ad6265SDimitry Andric // Return true if Offset fits within a compressed stack-pointer based
15381ad6265SDimitry Andric // load/store.
15481ad6265SDimitry Andric static bool compressibleSPOffset(int64_t Offset, unsigned Opcode) {
155*0fca6ea1SDimitry Andric   // Compressed sp-based loads and stores only work for 32/64 bits.
156*0fca6ea1SDimitry Andric   switch (log2LdstWidth(Opcode)) {
157*0fca6ea1SDimitry Andric   case 2:
158*0fca6ea1SDimitry Andric     return isShiftedUInt<6, 2>(Offset);
159*0fca6ea1SDimitry Andric   case 3:
160*0fca6ea1SDimitry Andric     return isShiftedUInt<6, 3>(Offset);
161*0fca6ea1SDimitry Andric   }
162*0fca6ea1SDimitry Andric   return false;
16381ad6265SDimitry Andric }
16481ad6265SDimitry Andric 
16581ad6265SDimitry Andric // Given an offset for a load/store, return the adjustment required to the base
16681ad6265SDimitry Andric // register such that the address can be accessed with a compressible offset.
16781ad6265SDimitry Andric // This will return 0 if the offset is already compressible.
16881ad6265SDimitry Andric static int64_t getBaseAdjustForCompression(int64_t Offset, unsigned Opcode) {
16981ad6265SDimitry Andric   // Return the excess bits that do not fit in a compressible offset.
17081ad6265SDimitry Andric   return Offset & ~compressedLDSTOffsetMask(Opcode);
17181ad6265SDimitry Andric }
17281ad6265SDimitry Andric 
17381ad6265SDimitry Andric // Return true if Reg is in a compressed register class.
17481ad6265SDimitry Andric static bool isCompressedReg(Register Reg) {
17581ad6265SDimitry Andric   return RISCV::GPRCRegClass.contains(Reg) ||
17681ad6265SDimitry Andric          RISCV::FPR32CRegClass.contains(Reg) ||
17781ad6265SDimitry Andric          RISCV::FPR64CRegClass.contains(Reg);
17881ad6265SDimitry Andric }
17981ad6265SDimitry Andric 
18081ad6265SDimitry Andric // Return true if MI is a load for which there exists a compressed version.
18181ad6265SDimitry Andric static bool isCompressibleLoad(const MachineInstr &MI) {
18281ad6265SDimitry Andric   const RISCVSubtarget &STI = MI.getMF()->getSubtarget<RISCVSubtarget>();
18381ad6265SDimitry Andric 
184*0fca6ea1SDimitry Andric   switch (MI.getOpcode()) {
185*0fca6ea1SDimitry Andric   default:
186*0fca6ea1SDimitry Andric     return false;
187*0fca6ea1SDimitry Andric   case RISCV::LBU:
188*0fca6ea1SDimitry Andric   case RISCV::LH:
189*0fca6ea1SDimitry Andric   case RISCV::LHU:
190*0fca6ea1SDimitry Andric     return STI.hasStdExtZcb();
191*0fca6ea1SDimitry Andric   case RISCV::LW:
192*0fca6ea1SDimitry Andric   case RISCV::LD:
193*0fca6ea1SDimitry Andric     return STI.hasStdExtCOrZca();
194*0fca6ea1SDimitry Andric   case RISCV::FLW:
195*0fca6ea1SDimitry Andric     return !STI.is64Bit() && STI.hasStdExtCOrZcfOrZce();
196*0fca6ea1SDimitry Andric   case RISCV::FLD:
197*0fca6ea1SDimitry Andric     return STI.hasStdExtCOrZcd();
198*0fca6ea1SDimitry Andric   }
19981ad6265SDimitry Andric }
20081ad6265SDimitry Andric 
20181ad6265SDimitry Andric // Return true if MI is a store for which there exists a compressed version.
20281ad6265SDimitry Andric static bool isCompressibleStore(const MachineInstr &MI) {
20381ad6265SDimitry Andric   const RISCVSubtarget &STI = MI.getMF()->getSubtarget<RISCVSubtarget>();
20481ad6265SDimitry Andric 
205*0fca6ea1SDimitry Andric   switch (MI.getOpcode()) {
206*0fca6ea1SDimitry Andric   default:
207*0fca6ea1SDimitry Andric     return false;
208*0fca6ea1SDimitry Andric   case RISCV::SB:
209*0fca6ea1SDimitry Andric   case RISCV::SH:
210*0fca6ea1SDimitry Andric     return STI.hasStdExtZcb();
211*0fca6ea1SDimitry Andric   case RISCV::SW:
212*0fca6ea1SDimitry Andric   case RISCV::SD:
213*0fca6ea1SDimitry Andric     return STI.hasStdExtCOrZca();
214*0fca6ea1SDimitry Andric   case RISCV::FSW:
215*0fca6ea1SDimitry Andric     return !STI.is64Bit() && STI.hasStdExtCOrZcfOrZce();
216*0fca6ea1SDimitry Andric   case RISCV::FSD:
217*0fca6ea1SDimitry Andric     return STI.hasStdExtCOrZcd();
218*0fca6ea1SDimitry Andric   }
21981ad6265SDimitry Andric }
22081ad6265SDimitry Andric 
22181ad6265SDimitry Andric // Find a single register and/or large offset which, if compressible, would
22281ad6265SDimitry Andric // allow the given instruction to be compressed.
22381ad6265SDimitry Andric //
22481ad6265SDimitry Andric // Possible return values:
22581ad6265SDimitry Andric //
22681ad6265SDimitry Andric //   {Reg, 0}               - Uncompressed Reg needs replacing with a compressed
22781ad6265SDimitry Andric //                            register.
22881ad6265SDimitry Andric //   {Reg, N}               - Reg needs replacing with a compressed register and
22981ad6265SDimitry Andric //                            N needs adding to the new register. (Reg may be
23081ad6265SDimitry Andric //                            compressed or uncompressed).
23181ad6265SDimitry Andric //   {RISCV::NoRegister, 0} - No suitable optimization found for this
23281ad6265SDimitry Andric //   instruction.
23381ad6265SDimitry Andric static RegImmPair getRegImmPairPreventingCompression(const MachineInstr &MI) {
23481ad6265SDimitry Andric   const unsigned Opcode = MI.getOpcode();
23581ad6265SDimitry Andric 
23681ad6265SDimitry Andric   if (isCompressibleLoad(MI) || isCompressibleStore(MI)) {
23781ad6265SDimitry Andric     const MachineOperand &MOImm = MI.getOperand(2);
23881ad6265SDimitry Andric     if (!MOImm.isImm())
23981ad6265SDimitry Andric       return RegImmPair(RISCV::NoRegister, 0);
24081ad6265SDimitry Andric 
24181ad6265SDimitry Andric     int64_t Offset = MOImm.getImm();
24281ad6265SDimitry Andric     int64_t NewBaseAdjust = getBaseAdjustForCompression(Offset, Opcode);
24381ad6265SDimitry Andric     Register Base = MI.getOperand(1).getReg();
24481ad6265SDimitry Andric 
24581ad6265SDimitry Andric     // Memory accesses via the stack pointer do not have a requirement for
24681ad6265SDimitry Andric     // either of the registers to be compressible and can take a larger offset.
24781ad6265SDimitry Andric     if (RISCV::SPRegClass.contains(Base)) {
24881ad6265SDimitry Andric       if (!compressibleSPOffset(Offset, Opcode) && NewBaseAdjust)
24981ad6265SDimitry Andric         return RegImmPair(Base, NewBaseAdjust);
25081ad6265SDimitry Andric     } else {
25181ad6265SDimitry Andric       Register SrcDest = MI.getOperand(0).getReg();
25281ad6265SDimitry Andric       bool SrcDestCompressed = isCompressedReg(SrcDest);
25381ad6265SDimitry Andric       bool BaseCompressed = isCompressedReg(Base);
25481ad6265SDimitry Andric 
25581ad6265SDimitry Andric       // If only Base and/or offset prevent compression, then return Base and
25681ad6265SDimitry Andric       // any adjustment required to make the offset compressible.
25781ad6265SDimitry Andric       if ((!BaseCompressed || NewBaseAdjust) && SrcDestCompressed)
25881ad6265SDimitry Andric         return RegImmPair(Base, NewBaseAdjust);
25981ad6265SDimitry Andric 
26081ad6265SDimitry Andric       // For loads, we can only change the base register since dest is defined
26181ad6265SDimitry Andric       // rather than used.
26281ad6265SDimitry Andric       //
26381ad6265SDimitry Andric       // For stores, we can change SrcDest (and Base if SrcDest == Base) but
26481ad6265SDimitry Andric       // cannot resolve an uncompressible offset in this case.
26581ad6265SDimitry Andric       if (isCompressibleStore(MI)) {
26681ad6265SDimitry Andric         if (!SrcDestCompressed && (BaseCompressed || SrcDest == Base) &&
26781ad6265SDimitry Andric             !NewBaseAdjust)
26881ad6265SDimitry Andric           return RegImmPair(SrcDest, NewBaseAdjust);
26981ad6265SDimitry Andric       }
27081ad6265SDimitry Andric     }
27181ad6265SDimitry Andric   }
27281ad6265SDimitry Andric   return RegImmPair(RISCV::NoRegister, 0);
27381ad6265SDimitry Andric }
27481ad6265SDimitry Andric 
27581ad6265SDimitry Andric // Check all uses after FirstMI of the given register, keeping a vector of
27681ad6265SDimitry Andric // instructions that would be compressible if the given register (and offset if
27781ad6265SDimitry Andric // applicable) were compressible.
27881ad6265SDimitry Andric //
27981ad6265SDimitry Andric // If there are enough uses for this optimization to improve code size and a
28081ad6265SDimitry Andric // compressed register is available, return that compressed register.
28181ad6265SDimitry Andric static Register analyzeCompressibleUses(MachineInstr &FirstMI,
28281ad6265SDimitry Andric                                         RegImmPair RegImm,
28381ad6265SDimitry Andric                                         SmallVectorImpl<MachineInstr *> &MIs) {
28481ad6265SDimitry Andric   MachineBasicBlock &MBB = *FirstMI.getParent();
28581ad6265SDimitry Andric   const TargetRegisterInfo *TRI =
28681ad6265SDimitry Andric       MBB.getParent()->getSubtarget().getRegisterInfo();
28781ad6265SDimitry Andric 
28881ad6265SDimitry Andric   for (MachineBasicBlock::instr_iterator I = FirstMI.getIterator(),
28981ad6265SDimitry Andric                                          E = MBB.instr_end();
29081ad6265SDimitry Andric        I != E; ++I) {
29181ad6265SDimitry Andric     MachineInstr &MI = *I;
29281ad6265SDimitry Andric 
29381ad6265SDimitry Andric     // Determine if this is an instruction which would benefit from using the
29481ad6265SDimitry Andric     // new register.
29581ad6265SDimitry Andric     RegImmPair CandidateRegImm = getRegImmPairPreventingCompression(MI);
29606c3fb27SDimitry Andric     if (CandidateRegImm.Reg == RegImm.Reg && CandidateRegImm.Imm == RegImm.Imm)
29781ad6265SDimitry Andric       MIs.push_back(&MI);
29881ad6265SDimitry Andric 
29981ad6265SDimitry Andric     // If RegImm.Reg is modified by this instruction, then we cannot optimize
30081ad6265SDimitry Andric     // past this instruction. If the register is already compressed, then it may
30181ad6265SDimitry Andric     // possible to optimize a large offset in the current instruction - this
30281ad6265SDimitry Andric     // will have been detected by the preceeding call to
30381ad6265SDimitry Andric     // getRegImmPairPreventingCompression.
30481ad6265SDimitry Andric     if (MI.modifiesRegister(RegImm.Reg, TRI))
30581ad6265SDimitry Andric       break;
30681ad6265SDimitry Andric   }
30781ad6265SDimitry Andric 
30881ad6265SDimitry Andric   // Adjusting the base costs one new uncompressed addi and therefore three uses
30981ad6265SDimitry Andric   // are required for a code size reduction. If no base adjustment is required,
31081ad6265SDimitry Andric   // then copying the register costs one new c.mv (or c.li Rd, 0 for "copying"
31181ad6265SDimitry Andric   // the zero register) and therefore two uses are required for a code size
31281ad6265SDimitry Andric   // reduction.
31381ad6265SDimitry Andric   if (MIs.size() < 2 || (RegImm.Imm != 0 && MIs.size() < 3))
31481ad6265SDimitry Andric     return RISCV::NoRegister;
31581ad6265SDimitry Andric 
31681ad6265SDimitry Andric   // Find a compressible register which will be available from the first
31781ad6265SDimitry Andric   // instruction we care about to the last.
31881ad6265SDimitry Andric   const TargetRegisterClass *RCToScavenge;
31981ad6265SDimitry Andric 
32081ad6265SDimitry Andric   // Work out the compressed register class from which to scavenge.
32181ad6265SDimitry Andric   if (RISCV::GPRRegClass.contains(RegImm.Reg))
32281ad6265SDimitry Andric     RCToScavenge = &RISCV::GPRCRegClass;
32381ad6265SDimitry Andric   else if (RISCV::FPR32RegClass.contains(RegImm.Reg))
32481ad6265SDimitry Andric     RCToScavenge = &RISCV::FPR32CRegClass;
32581ad6265SDimitry Andric   else if (RISCV::FPR64RegClass.contains(RegImm.Reg))
32681ad6265SDimitry Andric     RCToScavenge = &RISCV::FPR64CRegClass;
32781ad6265SDimitry Andric   else
32881ad6265SDimitry Andric     return RISCV::NoRegister;
32981ad6265SDimitry Andric 
33006c3fb27SDimitry Andric   RegScavenger RS;
33106c3fb27SDimitry Andric   RS.enterBasicBlockEnd(MBB);
3325f757f3fSDimitry Andric   RS.backward(std::next(MIs.back()->getIterator()));
33381ad6265SDimitry Andric   return RS.scavengeRegisterBackwards(*RCToScavenge, FirstMI.getIterator(),
33481ad6265SDimitry Andric                                       /*RestoreAfter=*/false, /*SPAdj=*/0,
33581ad6265SDimitry Andric                                       /*AllowSpill=*/false);
33681ad6265SDimitry Andric }
33781ad6265SDimitry Andric 
33881ad6265SDimitry Andric // Update uses of the old register in the given instruction to the new register.
33981ad6265SDimitry Andric static void updateOperands(MachineInstr &MI, RegImmPair OldRegImm,
34081ad6265SDimitry Andric                            Register NewReg) {
34181ad6265SDimitry Andric   unsigned Opcode = MI.getOpcode();
34281ad6265SDimitry Andric 
34381ad6265SDimitry Andric   // If this pass is extended to support more instructions, the check for
34481ad6265SDimitry Andric   // definedness may need to be strengthened.
34581ad6265SDimitry Andric   assert((isCompressibleLoad(MI) || isCompressibleStore(MI)) &&
34681ad6265SDimitry Andric          "Unsupported instruction for this optimization.");
34781ad6265SDimitry Andric 
348753f127fSDimitry Andric   int SkipN = 0;
349753f127fSDimitry Andric 
350753f127fSDimitry Andric   // Skip the first (value) operand to a store instruction (except if the store
351753f127fSDimitry Andric   // offset is zero) in order to avoid an incorrect transformation.
352753f127fSDimitry Andric   // e.g. sd a0, 808(a0) to addi a2, a0, 768; sd a2, 40(a2)
353753f127fSDimitry Andric   if (isCompressibleStore(MI) && OldRegImm.Imm != 0)
354753f127fSDimitry Andric     SkipN = 1;
355753f127fSDimitry Andric 
35681ad6265SDimitry Andric   // Update registers
357753f127fSDimitry Andric   for (MachineOperand &MO : drop_begin(MI.operands(), SkipN))
35881ad6265SDimitry Andric     if (MO.isReg() && MO.getReg() == OldRegImm.Reg) {
35981ad6265SDimitry Andric       // Do not update operands that define the old register.
36081ad6265SDimitry Andric       //
36181ad6265SDimitry Andric       // The new register was scavenged for the range of instructions that are
36281ad6265SDimitry Andric       // being updated, therefore it should not be defined within this range
36381ad6265SDimitry Andric       // except possibly in the final instruction.
36481ad6265SDimitry Andric       if (MO.isDef()) {
36581ad6265SDimitry Andric         assert(isCompressibleLoad(MI));
36681ad6265SDimitry Andric         continue;
36781ad6265SDimitry Andric       }
36881ad6265SDimitry Andric       // Update reg
36981ad6265SDimitry Andric       MO.setReg(NewReg);
37081ad6265SDimitry Andric     }
37181ad6265SDimitry Andric 
37281ad6265SDimitry Andric   // Update offset
37381ad6265SDimitry Andric   MachineOperand &MOImm = MI.getOperand(2);
37481ad6265SDimitry Andric   int64_t NewOffset = MOImm.getImm() & compressedLDSTOffsetMask(Opcode);
37581ad6265SDimitry Andric   MOImm.setImm(NewOffset);
37681ad6265SDimitry Andric }
37781ad6265SDimitry Andric 
37881ad6265SDimitry Andric bool RISCVMakeCompressibleOpt::runOnMachineFunction(MachineFunction &Fn) {
37981ad6265SDimitry Andric   // This is a size optimization.
38081ad6265SDimitry Andric   if (skipFunction(Fn.getFunction()) || !Fn.getFunction().hasMinSize())
38181ad6265SDimitry Andric     return false;
38281ad6265SDimitry Andric 
38381ad6265SDimitry Andric   const RISCVSubtarget &STI = Fn.getSubtarget<RISCVSubtarget>();
38481ad6265SDimitry Andric   const RISCVInstrInfo &TII = *STI.getInstrInfo();
38581ad6265SDimitry Andric 
38681ad6265SDimitry Andric   // This optimization only makes sense if compressed instructions are emitted.
387*0fca6ea1SDimitry Andric   if (!STI.hasStdExtCOrZca())
38881ad6265SDimitry Andric     return false;
38981ad6265SDimitry Andric 
39081ad6265SDimitry Andric   for (MachineBasicBlock &MBB : Fn) {
39181ad6265SDimitry Andric     LLVM_DEBUG(dbgs() << "MBB: " << MBB.getName() << "\n");
39281ad6265SDimitry Andric     for (MachineInstr &MI : MBB) {
39381ad6265SDimitry Andric       // Determine if this instruction would otherwise be compressed if not for
39481ad6265SDimitry Andric       // an uncompressible register or offset.
39581ad6265SDimitry Andric       RegImmPair RegImm = getRegImmPairPreventingCompression(MI);
39681ad6265SDimitry Andric       if (!RegImm.Reg && RegImm.Imm == 0)
39781ad6265SDimitry Andric         continue;
39881ad6265SDimitry Andric 
39981ad6265SDimitry Andric       // Determine if there is a set of instructions for which replacing this
40081ad6265SDimitry Andric       // register with a compressed register (and compressible offset if
40181ad6265SDimitry Andric       // applicable) is possible and will allow compression.
40281ad6265SDimitry Andric       SmallVector<MachineInstr *, 8> MIs;
40381ad6265SDimitry Andric       Register NewReg = analyzeCompressibleUses(MI, RegImm, MIs);
40481ad6265SDimitry Andric       if (!NewReg)
40581ad6265SDimitry Andric         continue;
40681ad6265SDimitry Andric 
40781ad6265SDimitry Andric       // Create the appropriate copy and/or offset.
40881ad6265SDimitry Andric       if (RISCV::GPRRegClass.contains(RegImm.Reg)) {
40981ad6265SDimitry Andric         assert(isInt<12>(RegImm.Imm));
41081ad6265SDimitry Andric         BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(RISCV::ADDI), NewReg)
41181ad6265SDimitry Andric             .addReg(RegImm.Reg)
41281ad6265SDimitry Andric             .addImm(RegImm.Imm);
41381ad6265SDimitry Andric       } else {
41481ad6265SDimitry Andric         // If we are looking at replacing an FPR register we don't expect to
41581ad6265SDimitry Andric         // have any offset. The only compressible FP instructions with an offset
41681ad6265SDimitry Andric         // are loads and stores, for which the offset applies to the GPR operand
41781ad6265SDimitry Andric         // not the FPR operand.
41881ad6265SDimitry Andric         assert(RegImm.Imm == 0);
41981ad6265SDimitry Andric         unsigned Opcode = RISCV::FPR32RegClass.contains(RegImm.Reg)
42081ad6265SDimitry Andric                               ? RISCV::FSGNJ_S
42181ad6265SDimitry Andric                               : RISCV::FSGNJ_D;
42281ad6265SDimitry Andric         BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(Opcode), NewReg)
42381ad6265SDimitry Andric             .addReg(RegImm.Reg)
42481ad6265SDimitry Andric             .addReg(RegImm.Reg);
42581ad6265SDimitry Andric       }
42681ad6265SDimitry Andric 
42781ad6265SDimitry Andric       // Update the set of instructions to use the compressed register and
42881ad6265SDimitry Andric       // compressible offset instead. These instructions should now be
42981ad6265SDimitry Andric       // compressible.
43081ad6265SDimitry Andric       // TODO: Update all uses if RegImm.Imm == 0? Not just those that are
43181ad6265SDimitry Andric       // expected to become compressible.
43281ad6265SDimitry Andric       for (MachineInstr *UpdateMI : MIs)
43381ad6265SDimitry Andric         updateOperands(*UpdateMI, RegImm, NewReg);
43481ad6265SDimitry Andric     }
43581ad6265SDimitry Andric   }
43681ad6265SDimitry Andric   return true;
43781ad6265SDimitry Andric }
43881ad6265SDimitry Andric 
43981ad6265SDimitry Andric /// Returns an instance of the Make Compressible Optimization pass.
44081ad6265SDimitry Andric FunctionPass *llvm::createRISCVMakeCompressibleOptPass() {
44181ad6265SDimitry Andric   return new RISCVMakeCompressibleOpt();
44281ad6265SDimitry Andric }
443