//===-- RISCVMakeCompressible.cpp - Make more instructions compressible ---===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This pass searches for instructions that are prevented from being compressed // by one of the following: // // 1. The use of a single uncompressed register. // 2. A base register + offset where the offset is too large to be compressed // and the base register may or may not be compressed. // // // For case 1, if a compressed register is available, then the uncompressed // register is copied to the compressed register and its uses are replaced. // // For example, storing zero uses the uncompressible zero register: // sw zero, 0(a0) # if zero // sw zero, 8(a0) # if zero // sw zero, 4(a0) # if zero // sw zero, 24(a0) # if zero // // If a compressed register (e.g. a1) is available, the above can be transformed // to the following to improve code size: // li a1, 0 // c.sw a1, 0(a0) // c.sw a1, 8(a0) // c.sw a1, 4(a0) // c.sw a1, 24(a0) // // // For case 2, if a compressed register is available, then the original base // is copied and adjusted such that: // // new_base_register = base_register + adjustment // base_register + large_offset = new_base_register + small_offset // // For example, the following offsets are too large for c.sw: // lui a2, 983065 // sw a1, -236(a2) // sw a1, -240(a2) // sw a1, -244(a2) // sw a1, -248(a2) // sw a1, -252(a2) // sw a0, -256(a2) // // If a compressed register is available (e.g. a3), a new base could be created // such that the addresses can accessed with a compressible offset, thus // improving code size: // lui a2, 983065 // addi a3, a2, -256 // c.sw a1, 20(a3) // c.sw a1, 16(a3) // c.sw a1, 12(a3) // c.sw a1, 8(a3) // c.sw a1, 4(a3) // c.sw a0, 0(a3) // // // This optimization is only applied if there are enough uses of the copied // register for code size to be reduced. // //===----------------------------------------------------------------------===// #include "RISCV.h" #include "RISCVSubtarget.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/RegisterScavenging.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/Debug.h" usingnamespacellvm; #define DEBUG_TYPE … #define RISCV_COMPRESS_INSTRS_NAME … namespace { struct RISCVMakeCompressibleOpt : public MachineFunctionPass { … }; } // namespace char RISCVMakeCompressibleOpt::ID = …; INITIALIZE_PASS(…) // Return log2(widthInBytes) of load/store done by Opcode. static unsigned log2LdstWidth(unsigned Opcode) { … } // Return bit field size of immediate operand of Opcode. static unsigned offsetMask(unsigned Opcode) { … } // Return a mask for the offset bits of a non-stack-pointer based compressed // load/store. static uint8_t compressedLDSTOffsetMask(unsigned Opcode) { … } // Return true if Offset fits within a compressed stack-pointer based // load/store. static bool compressibleSPOffset(int64_t Offset, unsigned Opcode) { … } // Given an offset for a load/store, return the adjustment required to the base // register such that the address can be accessed with a compressible offset. // This will return 0 if the offset is already compressible. static int64_t getBaseAdjustForCompression(int64_t Offset, unsigned Opcode) { … } // Return true if Reg is in a compressed register class. static bool isCompressedReg(Register Reg) { … } // Return true if MI is a load for which there exists a compressed version. static bool isCompressibleLoad(const MachineInstr &MI) { … } // Return true if MI is a store for which there exists a compressed version. static bool isCompressibleStore(const MachineInstr &MI) { … } // Find a single register and/or large offset which, if compressible, would // allow the given instruction to be compressed. // // Possible return values: // // {Reg, 0} - Uncompressed Reg needs replacing with a compressed // register. // {Reg, N} - Reg needs replacing with a compressed register and // N needs adding to the new register. (Reg may be // compressed or uncompressed). // {RISCV::NoRegister, 0} - No suitable optimization found for this // instruction. static RegImmPair getRegImmPairPreventingCompression(const MachineInstr &MI) { … } // Check all uses after FirstMI of the given register, keeping a vector of // instructions that would be compressible if the given register (and offset if // applicable) were compressible. // // If there are enough uses for this optimization to improve code size and a // compressed register is available, return that compressed register. static Register analyzeCompressibleUses(MachineInstr &FirstMI, RegImmPair RegImm, SmallVectorImpl<MachineInstr *> &MIs) { … } // Update uses of the old register in the given instruction to the new register. static void updateOperands(MachineInstr &MI, RegImmPair OldRegImm, Register NewReg) { … } bool RISCVMakeCompressibleOpt::runOnMachineFunction(MachineFunction &Fn) { … } /// Returns an instance of the Make Compressible Optimization pass. FunctionPass *llvm::createRISCVMakeCompressibleOptPass() { … }