From 587bac637cd8b8de6a0c0dc793dfbcd19901d106 Mon Sep 17 00:00:00 2001 From: Sudharsan Veeravalli Date: Tue, 13 Jan 2026 06:34:18 +0530 Subject: [PATCH] [RISCV] Adjust base cost for Xqcilo loads/stores in RISCVMakeCompressible (#175572) We only need two uses in Xqcilo load/store instructions for the base adjustment to be profitable as compared to three uses in the base load/store instructions. --- .../Target/RISCV/RISCVMakeCompressible.cpp | 45 +++++++++++++--- .../CodeGen/RISCV/make-compressible-xqci.mir | 53 +++++++++++++++++-- 2 files changed, 86 insertions(+), 12 deletions(-) diff --git a/llvm/lib/Target/RISCV/RISCVMakeCompressible.cpp b/llvm/lib/Target/RISCV/RISCVMakeCompressible.cpp index 4666ddc4c3d0..0c4f22e4f433 100644 --- a/llvm/lib/Target/RISCV/RISCVMakeCompressible.cpp +++ b/llvm/lib/Target/RISCV/RISCVMakeCompressible.cpp @@ -326,6 +326,21 @@ static RegImmPair getRegImmPairPreventingCompression(const MachineInstr &MI) { return RegImmPair(Register(), 0); } +static bool isXqciloLdSt(const MachineInstr &MI) { + switch (MI.getOpcode()) { + default: + return false; + case RISCV::QC_E_SB: + case RISCV::QC_E_SH: + case RISCV::QC_E_SW: + case RISCV::QC_E_LBU: + case RISCV::QC_E_LH: + case RISCV::QC_E_LHU: + case RISCV::QC_E_LW: + return true; + } +} + // 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. @@ -338,6 +353,7 @@ static Register analyzeCompressibleUses(MachineInstr &FirstMI, MachineBasicBlock &MBB = *FirstMI.getParent(); const TargetRegisterInfo *TRI = MBB.getParent()->getSubtarget().getRegisterInfo(); + bool XqciloLdSt = false; for (MachineBasicBlock::instr_iterator I = FirstMI.getIterator(), E = MBB.instr_end(); @@ -347,8 +363,11 @@ static Register analyzeCompressibleUses(MachineInstr &FirstMI, // Determine if this is an instruction which would benefit from using the // new register. RegImmPair CandidateRegImm = getRegImmPairPreventingCompression(MI); - if (CandidateRegImm.Reg == RegImm.Reg && CandidateRegImm.Imm == RegImm.Imm) + if (CandidateRegImm.Reg == RegImm.Reg && + CandidateRegImm.Imm == RegImm.Imm) { + XqciloLdSt |= isXqciloLdSt(MI); MIs.push_back(&MI); + } // If RegImm.Reg is modified by this instruction, then we cannot optimize // past this instruction. If the register is already compressed, then it may @@ -359,14 +378,26 @@ static Register analyzeCompressibleUses(MachineInstr &FirstMI, break; } - // Adjusting the base costs one new uncompressed addi and therefore three uses - // are required for a code size reduction. If no base adjustment is required, - // then copying the register costs one new c.mv (or c.li Rd, 0 for "copying" - // the zero register) and therefore two uses are required for a code size - // reduction. For GPR pairs, we need 2 ADDIs to copy so we need three users. + // Adjusting the base costs: + // a. --> addi (uncompressed 4 bytes) + // lw/sw (4 bytes) --> compressed to 2 bytes + // lw/sw (4 bytes) --> compressed to 2 bytes + // lw/sw (4 bytes) --> compressed to 2 bytes + // at least three lw/sw instructions for code size reduction. + // + // b. --> qc.e.addi (uncompressed 6 bytes) + // qc.e.lw/sw (6 bytes) --> compressed to 2 bytes + // qc.e.lw/sw (6 bytes) --> compressed to 2 bytes + // at least two qc.e.lw/sw instructions for code size reduction. + // + // If no base adjustment is required, then copying the register costs one new + // c.mv (or c.li Rd, 0 for "copying" the zero register) and therefore two uses + // are required for a code size reduction. For GPR pairs, we need 2 ADDIs to + // copy so we need three users. + unsigned BaseCost = XqciloLdSt ? 2 : 3; unsigned CopyCost = RISCV::GPRPairRegClass.contains(RegImm.Reg) ? 2 : 1; assert((RegImm.Imm == 0 || CopyCost == 1) && "GPRPair should have zero imm"); - if (MIs.size() <= CopyCost || (RegImm.Imm != 0 && MIs.size() <= 2)) + if (MIs.size() <= CopyCost || (RegImm.Imm != 0 && MIs.size() < BaseCost)) return Register(); // Find a compressible register which will be available from the first diff --git a/llvm/test/CodeGen/RISCV/make-compressible-xqci.mir b/llvm/test/CodeGen/RISCV/make-compressible-xqci.mir index 09183c57fe0d..949aa892e058 100644 --- a/llvm/test/CodeGen/RISCV/make-compressible-xqci.mir +++ b/llvm/test/CodeGen/RISCV/make-compressible-xqci.mir @@ -28,6 +28,8 @@ define void @store_large_offset_no_opt(ptr %p) #0 { ret void } + define void @store_large_offset_two_uses(ptr %p) #0 { ret void } + attributes #0 = { minsize } ... @@ -504,8 +506,6 @@ body: | ; RV32XQCI-NEXT: {{ $}} ; RV32XQCI-NEXT: renamable $x11 = ADDI $x0, 1 ; RV32XQCI-NEXT: QC_E_SW killed renamable $x11, renamable $x10, 4000 :: (volatile store (s32)) - ; RV32XQCI-NEXT: renamable $x11 = ADDI $x0, 3 - ; RV32XQCI-NEXT: QC_E_SW killed renamable $x11, killed renamable $x10, 4004 :: (volatile store (s32)) ; RV32XQCI-NEXT: PseudoRET ; ; RV32XQCI_ZCB-LABEL: name: store_large_offset_no_opt @@ -513,8 +513,6 @@ body: | ; RV32XQCI_ZCB-NEXT: {{ $}} ; RV32XQCI_ZCB-NEXT: renamable $x11 = ADDI $x0, 1 ; RV32XQCI_ZCB-NEXT: QC_E_SW killed renamable $x11, renamable $x10, 4000 :: (volatile store (s32)) - ; RV32XQCI_ZCB-NEXT: renamable $x11 = ADDI $x0, 3 - ; RV32XQCI_ZCB-NEXT: QC_E_SW killed renamable $x11, killed renamable $x10, 4004 :: (volatile store (s32)) ; RV32XQCI_ZCB-NEXT: PseudoRET ; ; RV32XQCI_NOXQCILIA-LABEL: name: store_large_offset_no_opt @@ -522,11 +520,56 @@ body: | ; RV32XQCI_NOXQCILIA-NEXT: {{ $}} ; RV32XQCI_NOXQCILIA-NEXT: renamable $x11 = ADDI $x0, 1 ; RV32XQCI_NOXQCILIA-NEXT: QC_E_SW killed renamable $x11, renamable $x10, 4000 :: (volatile store (s32)) + ; RV32XQCI_NOXQCILIA-NEXT: PseudoRET + ; + ; RV32XQCI_ZCB_NOXQCILIA-LABEL: name: store_large_offset_no_opt + ; RV32XQCI_ZCB_NOXQCILIA: liveins: $x10 + ; RV32XQCI_ZCB_NOXQCILIA-NEXT: {{ $}} + ; RV32XQCI_ZCB_NOXQCILIA-NEXT: renamable $x11 = ADDI $x0, 1 + ; RV32XQCI_ZCB_NOXQCILIA-NEXT: QC_E_SW killed renamable $x11, renamable $x10, 4000 :: (volatile store (s32)) + ; RV32XQCI_ZCB_NOXQCILIA-NEXT: PseudoRET + renamable $x11 = ADDI $x0, 1 + QC_E_SW killed renamable $x11, renamable $x10, 4000 :: (volatile store (s32)) + PseudoRET + +... +--- +name: store_large_offset_two_uses +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10 + + ; RV32XQCI-LABEL: name: store_large_offset_two_uses + ; RV32XQCI: liveins: $x10 + ; RV32XQCI-NEXT: {{ $}} + ; RV32XQCI-NEXT: renamable $x11 = ADDI $x0, 1 + ; RV32XQCI-NEXT: $x12 = QC_E_ADDI $x10, 3968 + ; RV32XQCI-NEXT: QC_E_SW killed renamable $x11, $x12, 32 :: (volatile store (s32)) + ; RV32XQCI-NEXT: renamable $x11 = ADDI $x0, 3 + ; RV32XQCI-NEXT: QC_E_SW killed renamable $x11, killed $x12, 36 :: (volatile store (s32)) + ; RV32XQCI-NEXT: PseudoRET + ; + ; RV32XQCI_ZCB-LABEL: name: store_large_offset_two_uses + ; RV32XQCI_ZCB: liveins: $x10 + ; RV32XQCI_ZCB-NEXT: {{ $}} + ; RV32XQCI_ZCB-NEXT: renamable $x11 = ADDI $x0, 1 + ; RV32XQCI_ZCB-NEXT: $x12 = QC_E_ADDI $x10, 3968 + ; RV32XQCI_ZCB-NEXT: QC_E_SW killed renamable $x11, $x12, 32 :: (volatile store (s32)) + ; RV32XQCI_ZCB-NEXT: renamable $x11 = ADDI $x0, 3 + ; RV32XQCI_ZCB-NEXT: QC_E_SW killed renamable $x11, killed $x12, 36 :: (volatile store (s32)) + ; RV32XQCI_ZCB-NEXT: PseudoRET + ; + ; RV32XQCI_NOXQCILIA-LABEL: name: store_large_offset_two_uses + ; RV32XQCI_NOXQCILIA: liveins: $x10 + ; RV32XQCI_NOXQCILIA-NEXT: {{ $}} + ; RV32XQCI_NOXQCILIA-NEXT: renamable $x11 = ADDI $x0, 1 + ; RV32XQCI_NOXQCILIA-NEXT: QC_E_SW killed renamable $x11, renamable $x10, 4000 :: (volatile store (s32)) ; RV32XQCI_NOXQCILIA-NEXT: renamable $x11 = ADDI $x0, 3 ; RV32XQCI_NOXQCILIA-NEXT: QC_E_SW killed renamable $x11, killed renamable $x10, 4004 :: (volatile store (s32)) ; RV32XQCI_NOXQCILIA-NEXT: PseudoRET ; - ; RV32XQCI_ZCB_NOXQCILIA-LABEL: name: store_large_offset_no_opt + ; RV32XQCI_ZCB_NOXQCILIA-LABEL: name: store_large_offset_two_uses ; RV32XQCI_ZCB_NOXQCILIA: liveins: $x10 ; RV32XQCI_ZCB_NOXQCILIA-NEXT: {{ $}} ; RV32XQCI_ZCB_NOXQCILIA-NEXT: renamable $x11 = ADDI $x0, 1