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