[clang] [llvm] [RISCV] Xqccmp Code Generation (PR #128815)

via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 25 20:23:19 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-risc-v

@llvm/pr-subscribers-clang

Author: Sam Elliott (lenary)

<details>
<summary>Changes</summary>

This adds support for Xqccmp to the following passes:
- Prolog Epilog Insertion - reusing much of the existing push/pop logic, but extending it to cope with frame pointers and reorder the CFI information correctly.
- Move Merger - extending it to support the `qc.` variants of the double-move instructions.
- Push/Pop Optimizer - extending it to support the `qc.` variants of the pop instructions.

The testing is based on existing Zcmp tests, but I have put them in separate files as some of the Zcmp tests were getting quite long.

---

This is stacked on #<!-- -->128731.

---

Patch is 293.87 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/128815.diff


26 Files Affected:

- (modified) clang/test/Driver/print-supported-extensions-riscv.c (+1) 
- (modified) llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp (+12-1) 
- (modified) llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp (+3) 
- (modified) llvm/lib/Target/RISCV/RISCVFeatures.td (+8) 
- (modified) llvm/lib/Target/RISCV/RISCVFrameLowering.cpp (+59-8) 
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfo.td (+1) 
- (added) llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td (+95) 
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfoZc.td (-2) 
- (modified) llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.h (+32-3) 
- (modified) llvm/lib/Target/RISCV/RISCVMoveMerger.cpp (+54-12) 
- (modified) llvm/lib/Target/RISCV/RISCVPushPopOptimizer.cpp (+27-8) 
- (modified) llvm/lib/TargetParser/RISCVISAInfo.cpp (+5) 
- (modified) llvm/test/CodeGen/RISCV/attributes.ll (+5) 
- (added) llvm/test/CodeGen/RISCV/xqccmp-additional-stack.ll (+54) 
- (added) llvm/test/CodeGen/RISCV/xqccmp-callee-saved-gprs.ll (+1171) 
- (added) llvm/test/CodeGen/RISCV/xqccmp-cm-popretz.mir (+66) 
- (added) llvm/test/CodeGen/RISCV/xqccmp-cm-push-pop.mir (+92) 
- (added) llvm/test/CodeGen/RISCV/xqccmp-push-pop-popret.ll (+3889) 
- (added) llvm/test/CodeGen/RISCV/xqccmp-with-float.ll (+90) 
- (added) llvm/test/CodeGen/RISCV/xqccmp_mvas_mvsa.mir (+28) 
- (added) llvm/test/MC/RISCV/rv32xqccmp-invalid.s (+35) 
- (added) llvm/test/MC/RISCV/rv32xqccmp-valid.s (+353) 
- (added) llvm/test/MC/RISCV/rv64e-xqccmp-valid.s (+85) 
- (added) llvm/test/MC/RISCV/rv64xqccmp-invalid.s (+35) 
- (added) llvm/test/MC/RISCV/rv64xqccmp-valid.s (+181) 
- (modified) llvm/unittests/TargetParser/RISCVISAInfoTest.cpp (+6) 


``````````diff
diff --git a/clang/test/Driver/print-supported-extensions-riscv.c b/clang/test/Driver/print-supported-extensions-riscv.c
index fcd820464e2d1..1c29ae98c96f0 100644
--- a/clang/test/Driver/print-supported-extensions-riscv.c
+++ b/clang/test/Driver/print-supported-extensions-riscv.c
@@ -193,6 +193,7 @@
 // CHECK-NEXT:     smctr                1.0       'Smctr' (Control Transfer Records Machine Level)
 // CHECK-NEXT:     ssctr                1.0       'Ssctr' (Control Transfer Records Supervisor Level)
 // CHECK-NEXT:     svukte               0.3       'Svukte' (Address-Independent Latency of User-Mode Faults to Supervisor Addresses)
+// CHECK-NEXT:     xqccmp               0.1       'Xqccmp' (Qualcomm 16-bit Push/Pop and Double Moves)
 // CHECK-NEXT:     xqcia                0.2       'Xqcia' (Qualcomm uC Arithmetic Extension)
 // CHECK-NEXT:     xqciac               0.3       'Xqciac' (Qualcomm uC Load-Store Address Calculation Extension)
 // CHECK-NEXT:     xqcicli              0.2       'Xqcicli' (Qualcomm uC Conditional Load Immediate Extension)
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 650ad48e50de0..fb0ff9a73159d 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -1682,6 +1682,17 @@ bool RISCVAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
   case Match_InvalidRnumArg: {
     return generateImmOutOfRangeError(Operands, ErrorInfo, 0, 10);
   }
+  case Match_InvalidStackAdj: {
+    SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
+    StringRef SpecName = "Zc";
+    if (getSTI().hasFeature(RISCV::FeatureVendorXqccmp))
+      SpecName = "Xqccmp";
+
+    return Error(
+        ErrorLoc,
+        "stack adjustment is invalid for this instruction and register list; "
+        "refer to " + SpecName + " spec for a detailed range of stack adjustment");
+  }
   }
 
   if (const char *MatchDiag = getMatchKindDiag((RISCVMatchResultTy)Result)) {
@@ -3640,7 +3651,7 @@ bool RISCVAsmParser::validateInstruction(MCInst &Inst,
     }
   }
 
-  if (Opcode == RISCV::CM_MVSA01) {
+  if (Opcode == RISCV::CM_MVSA01 || Opcode == RISCV::QC_CM_MVSA01) {
     MCRegister Rd1 = Inst.getOperand(0).getReg();
     MCRegister Rd2 = Inst.getOperand(1).getReg();
     if (Rd1 == Rd2) {
diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
index 8c07d87680d65..7beed1d157024 100644
--- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -745,6 +745,9 @@ DecodeStatus RISCVDisassembler::getInstruction16(MCInst &MI, uint64_t &Size,
                         "Qualcomm uC Conditional Move 16bit");
   TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXqciint, DecoderTableXqciint16,
                         "Qualcomm uC Interrupts 16bit");
+  TRY_TO_DECODE_FEATURE(
+      RISCV::FeatureVendorXqccmp, DecoderTableXqccmp16,
+      "Xqccmp (Qualcomm 16-bit Push/Pop & Double Move Instructions)");
   TRY_TO_DECODE_AND_ADD_SP(STI.hasFeature(RISCV::FeatureVendorXwchc),
                            DecoderTableXwchc16, "WCH QingKe XW");
   TRY_TO_DECODE_AND_ADD_SP(true, DecoderTable16,
diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index 1a93371a4d92f..2b5b7173f2a68 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -1374,6 +1374,14 @@ def HasVendorXqcilo
       AssemblerPredicate<(all_of FeatureVendorXqcilo),
                          "'Xqcilo' (Qualcomm uC Large Offset Load Store Extension)">;
 
+def FeatureVendorXqccmp
+    : RISCVExperimentalExtension<0, 1,
+                                 "Qualcomm 16-bit Push/Pop and Double Moves",
+                                 [FeatureStdExtZca]>;
+def HasVendorXqccmp : Predicate<"Subtarget->hasVendorXqccmp()">,
+                      AssemblerPredicate<(all_of FeatureVendorXqccmp),
+                        "'Xqccmp' (Qualcomm 16-bit Push/Pop and Double Moves)">;
+
 // Rivos Extension(s)
 
 def FeatureVendorXRivosVizip
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 32834a6b84f10..6526390f38abd 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -783,6 +783,54 @@ void RISCVFrameLowering::allocateStack(MachineBasicBlock &MBB,
   }
 }
 
+static bool isPush(unsigned Opcode) {
+  switch (Opcode) {
+  case RISCV::CM_PUSH:
+  case RISCV::QC_CM_PUSH:
+  case RISCV::QC_CM_PUSHFP:
+    return true;
+  default:
+    return false;
+  }
+}
+
+static bool isPop(unsigned Opcode) {
+  // There are other pops but these are the only ones introduced during this
+  // pass.
+  switch (Opcode) {
+  case RISCV::CM_POP:
+  case RISCV::QC_CM_POP:
+    return true;
+  default:
+    return false;
+  }
+}
+
+static unsigned getPushOpcode(RISCVMachineFunctionInfo::PushKind Kind,
+                              bool hasFP) {
+  switch (Kind) {
+  case RISCVMachineFunctionInfo::PushKind::StdExtZcmp:
+    return RISCV::CM_PUSH;
+  case RISCVMachineFunctionInfo::PushKind::VendorXqccmp:
+    return hasFP ? RISCV::QC_CM_PUSHFP : RISCV::QC_CM_PUSH;
+  default:
+    llvm_unreachable("Unhandled PushKind");
+  }
+}
+
+static unsigned getPopOpcode(RISCVMachineFunctionInfo::PushKind Kind) {
+  // There are other pops but they are introduced later by the Push/Pop
+  // Optimizer.
+  switch (Kind) {
+  case RISCVMachineFunctionInfo::PushKind::StdExtZcmp:
+    return RISCV::CM_POP;
+  case llvm::RISCVMachineFunctionInfo::PushKind::VendorXqccmp:
+    return RISCV::CM_POP;
+  default:
+    llvm_unreachable("Unhandled Push Kind");
+  }
+}
+
 void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
                                       MachineBasicBlock &MBB) const {
   MachineFrameInfo &MFI = MF.getFrameInfo();
@@ -882,7 +930,7 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
   }
 
   if (RVFI->isPushable(MF) && FirstFrameSetup != MBB.end() &&
-      FirstFrameSetup->getOpcode() == RISCV::CM_PUSH) {
+      isPush(FirstFrameSetup->getOpcode())) {
     // Use available stack adjustment in push instruction to allocate additional
     // stack space. Align the stack size down to a multiple of 16. This is
     // needed for RVE.
@@ -926,7 +974,8 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
   emitCFIForCSI<CFISaveRegisterEmitter>(MBB, MBBI, getUnmanagedCSI(MF, CSI));
 
   // Generate new FP.
-  if (hasFP(MF)) {
+  if (hasFP(MF) && RVFI->getPushKind(MF) !=
+                       RISCVMachineFunctionInfo::PushKind::VendorXqccmp) {
     if (STI.isRegisterReservedByUser(FPReg))
       MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{
           MF.getFunction(), "Frame pointer required, but has been reserved."});
@@ -1193,9 +1242,7 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
   // Recover callee-saved registers.
   emitCFIForCSI<CFIRestoreRegisterEmitter>(MBB, MBBI, getUnmanagedCSI(MF, CSI));
 
-  bool ApplyPop = RVFI->isPushable(MF) && MBBI != MBB.end() &&
-                  MBBI->getOpcode() == RISCV::CM_POP;
-  if (ApplyPop) {
+  if (RVFI->isPushable(MF) && MBBI != MBB.end() && isPop(MBBI->getOpcode())) {
     // Use available stack adjustment in pop instruction to deallocate stack
     // space. Align the stack size down to a multiple of 16. This is needed for
     // RVE.
@@ -1816,7 +1863,8 @@ bool RISCVFrameLowering::assignCalleeSavedSpillSlots(
           FixedCSRFIMap, [&](auto P) { return P.first == CS.getReg(); });
       if (FII != std::end(FixedCSRFIMap)) {
         int64_t Offset;
-        if (RVFI->isPushable(MF))
+        if (RVFI->getPushKind(MF) ==
+            RISCVMachineFunctionInfo::PushKind::StdExtZcmp)
           Offset = -((FII->second + RVFI->getRVPushRegs() + 1) * (int64_t)Size);
         else
           Offset = FII->second * (int64_t)Size;
@@ -1881,8 +1929,10 @@ bool RISCVFrameLowering::spillCalleeSavedRegisters(
     if (PushedRegNum > 0) {
       // Use encoded number to represent registers to spill.
       int RegEnc = RVFI->getRVPushRlist();
+
+      unsigned Opcode = getPushOpcode(RVFI->getPushKind(*MF), hasFP(*MF));
       MachineInstrBuilder PushBuilder =
-          BuildMI(MBB, MI, DL, TII.get(RISCV::CM_PUSH))
+          BuildMI(MBB, MI, DL, TII.get(Opcode))
               .setMIFlag(MachineInstr::FrameSetup);
       PushBuilder.addImm((int64_t)RegEnc);
       PushBuilder.addImm(0);
@@ -2035,8 +2085,9 @@ bool RISCVFrameLowering::restoreCalleeSavedRegisters(
   if (RVFI->isPushable(*MF)) {
     int RegEnc = RVFI->getRVPushRlist();
     if (RegEnc != llvm::RISCVZC::RLISTENCODE::INVALID_RLIST) {
+      unsigned Opcode = getPopOpcode(RVFI->getPushKind(*MF));
       MachineInstrBuilder PopBuilder =
-          BuildMI(MBB, MI, DL, TII.get(RISCV::CM_POP))
+          BuildMI(MBB, MI, DL, TII.get(Opcode))
               .setMIFlag(MachineInstr::FrameDestroy);
       // Use encoded number to represent registers to restore.
       PopBuilder.addImm(RegEnc);
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index a962e64581797..c84caa76b1b4d 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -2147,6 +2147,7 @@ include "RISCVInstrInfoSFB.td"
 include "RISCVInstrInfoXCV.td"
 include "RISCVInstrInfoXwch.td"
 include "RISCVInstrInfoXqci.td"
+include "RISCVInstrInfoXqccmp.td"
 include "RISCVInstrInfoXMips.td"
 include "RISCVInstrInfoXRivos.td"
 
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td
new file mode 100644
index 0000000000000..5bb9c1e4b228b
--- /dev/null
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqccmp.td
@@ -0,0 +1,95 @@
+//===---------------- RISCVInstrInfoXqccmp.td --------------*- tablegen -*-===//
+//
+// 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 file describes Qualcomm's Xqccmp extension.
+//
+// Xqccmp is broadly equivalent to (and incompatible with) Zcmp except the
+// following changes:
+//
+// - The registers are pushed in the opposite order, so `ra` and `fp` are
+//   closest to the incoming stack pointer (to be compatible with the
+//   frame-pointer convention), and
+//
+// - There is a new `qc.cm.pushfp` instruction which is `qc.cm.push` but it sets
+//   `fp` to the incoming stack pointer value, as expected by the frame-pointer
+//   convention.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Operand and SDNode transformation definitions.
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Instruction Formats
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Instruction Class Templates
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Instructions
+//===----------------------------------------------------------------------===//
+
+let DecoderNamespace = "Xqccmp", Predicates = [HasVendorXqccmp] in {
+
+let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
+let Defs = [X10, X11] in
+def QC_CM_MVA01S : RVInst16CA<0b101011, 0b11, 0b10, (outs),
+                              (ins SR07:$rs1, SR07:$rs2), "qc.cm.mva01s", "$rs1, $rs2">,
+                   Sched<[WriteIALU, WriteIALU, ReadIALU, ReadIALU]>;
+
+let Uses = [X10, X11] in
+def QC_CM_MVSA01 : RVInst16CA<0b101011, 0b01, 0b10, (outs SR07:$rs1, SR07:$rs2),
+                              (ins), "qc.cm.mvsa01", "$rs1, $rs2">,
+                   Sched<[WriteIALU, WriteIALU, ReadIALU, ReadIALU]>;
+} // hasSideEffects = 0, mayLoad = 0, mayStore = 0
+
+let hasSideEffects = 0, mayLoad = 0, mayStore = 1, Uses = [X2], Defs = [X2] in
+def QC_CM_PUSH : RVInstZcCPPP<0b11000, "qc.cm.push", negstackadj>,
+                 Sched<[WriteIALU, ReadIALU, ReadStoreData, ReadStoreData,
+                        ReadStoreData, ReadStoreData, ReadStoreData, ReadStoreData,
+                        ReadStoreData, ReadStoreData, ReadStoreData, ReadStoreData,
+                        ReadStoreData, ReadStoreData, ReadStoreData]>;
+
+let hasSideEffects = 0, mayLoad = 0, mayStore = 1, Uses = [X2], Defs = [X2, X8] in
+def QC_CM_PUSHFP : RVInstZcCPPP<0b11001, "qc.cm.pushfp", negstackadj>,
+                   Sched<[WriteIALU, WriteIALU, ReadIALU, ReadStoreData, ReadStoreData,
+                          ReadStoreData, ReadStoreData, ReadStoreData, ReadStoreData,
+                          ReadStoreData, ReadStoreData, ReadStoreData, ReadStoreData,
+                          ReadStoreData, ReadStoreData, ReadStoreData]>;
+
+let hasSideEffects = 0, mayLoad = 1, mayStore = 0, isReturn = 1,
+    Uses = [X2], Defs = [X2] in
+def QC_CM_POPRET : RVInstZcCPPP<0b11110, "qc.cm.popret">,
+                   Sched<[WriteIALU, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
+                          WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
+                          WriteLDW, WriteLDW, WriteLDW, WriteLDW, ReadIALU]>;
+
+let hasSideEffects = 0, mayLoad = 1, mayStore = 0, isReturn = 1,
+    Uses = [X2], Defs = [X2, X10] in
+def QC_CM_POPRETZ : RVInstZcCPPP<0b11100, "qc.cm.popretz">,
+                    Sched<[WriteIALU, WriteIALU, WriteLDW, WriteLDW, WriteLDW,
+                           WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
+                           WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
+                           ReadIALU]>;
+
+let hasSideEffects = 0, mayLoad = 1, mayStore = 0,
+    Uses = [X2], Defs = [X2] in
+def QC_CM_POP : RVInstZcCPPP<0b11010, "qc.cm.pop">,
+                Sched<[WriteIALU, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
+                       WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
+                       WriteLDW, WriteLDW, WriteLDW, ReadIALU]>;
+
+} // DecoderNamespace = "Xqccmp", Predicates = [HasVendorXqccmp]
+
+//===----------------------------------------------------------------------===//
+// Aliases
+//===----------------------------------------------------------------------===//
+
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td
index 9dfbcf678d6eb..4944e85cbbcbb 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td
@@ -46,8 +46,6 @@ def StackAdjAsmOperand : AsmOperandClass {
   let Name = "StackAdj";
   let ParserMethod = "parseZcmpStackAdj";
   let DiagnosticType = "InvalidStackAdj";
-  let DiagnosticString = "stack adjustment is invalid for this instruction and register list; "
-        "refer to Zc spec for a detailed range of stack adjustment";
   let PredicateMethod = "isSpimm";
   let RenderMethod = "addSpimmOperands";
 }
diff --git a/llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.h b/llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.h
index 27a13bb7cace1..e8744a0dcb5cb 100644
--- a/llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.h
+++ b/llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.h
@@ -141,9 +141,38 @@ class RISCVMachineFunctionInfo : public MachineFunctionInfo {
     // We cannot use fixed locations for the callee saved spill slots if the
     // function uses a varargs save area.
     // TODO: Use a separate placement for vararg registers to enable Zcmp.
-    return MF.getSubtarget<RISCVSubtarget>().hasStdExtZcmp() &&
-           !MF.getTarget().Options.DisableFramePointerElim(MF) &&
-           VarArgsSaveSize == 0;
+    if (VarArgsSaveSize != 0)
+      return false;
+
+    // Zcmp is not compatible with the frame pointer convention.
+    if (MF.getSubtarget<RISCVSubtarget>().hasStdExtZcmp())
+      return !MF.getTarget().Options.DisableFramePointerElim(MF);
+
+    // Xqccmp is Zcmp but has a push order compatible with the frame-pointer
+    // convention.
+    if (MF.getSubtarget<RISCVSubtarget>().hasVendorXqccmp())
+      return true;
+
+    return false;
+  }
+
+  enum class PushKind { None = 0, StdExtZcmp, VendorXqccmp };
+
+  PushKind getPushKind(const MachineFunction &MF) const {
+    if (VarArgsSaveSize != 0)
+      return PushKind::None;
+
+    // Zcmp is not compatible with the frame pointer convention.
+    if (MF.getSubtarget<RISCVSubtarget>().hasStdExtZcmp() &&
+        !MF.getTarget().Options.DisableFramePointerElim(MF))
+      return PushKind::StdExtZcmp;
+
+    // Xqccmp is Zcmp but has a push order compatible with the frame-pointer
+    // convention.
+    if (MF.getSubtarget<RISCVSubtarget>().hasVendorXqccmp())
+      return PushKind::VendorXqccmp;
+
+    return PushKind::None;
   }
 
   int getRVPushRlist() const { return RVPushRlist; }
diff --git a/llvm/lib/Target/RISCV/RISCVMoveMerger.cpp b/llvm/lib/Target/RISCV/RISCVMoveMerger.cpp
index 3c5462057b280..7a2541a652b58 100644
--- a/llvm/lib/Target/RISCV/RISCVMoveMerger.cpp
+++ b/llvm/lib/Target/RISCV/RISCVMoveMerger.cpp
@@ -9,10 +9,12 @@
 // This file contains a pass that performs move related peephole optimizations
 // as Zcmp has specified. This pass should be run after register allocation.
 //
+// This pass also supports Xqccmp, which has identical instructions.
+//
 //===----------------------------------------------------------------------===//
 
 #include "RISCVInstrInfo.h"
-#include "RISCVMachineFunctionInfo.h"
+#include "RISCVSubtarget.h"
 
 using namespace llvm;
 
@@ -43,7 +45,7 @@ struct RISCVMoveMerge : public MachineFunctionPass {
   MachineBasicBlock::iterator
   findMatchingInst(MachineBasicBlock::iterator &MBBI, unsigned InstOpcode,
                    const DestSourcePair &RegPair);
-  bool mergeMoveSARegPair(MachineBasicBlock &MBB);
+  bool mergeMoveSARegPair(const RISCVSubtarget &STI, MachineBasicBlock &MBB);
   bool runOnMachineFunction(MachineFunction &Fn) override;
 
   StringRef getPassName() const override { return RISCV_MOVE_MERGE_NAME; }
@@ -56,6 +58,46 @@ char RISCVMoveMerge::ID = 0;
 INITIALIZE_PASS(RISCVMoveMerge, "riscv-move-merge", RISCV_MOVE_MERGE_NAME,
                 false, false)
 
+static bool isMoveFromAToS(unsigned Opcode) {
+  switch (Opcode) {
+  case RISCV::CM_MVA01S:
+  case RISCV::QC_CM_MVA01S:
+    return true;
+  default:
+    return false;
+  }
+}
+
+static unsigned getMoveFromAToSOpcode(const RISCVSubtarget &STI) {
+  if (STI.hasStdExtZcmp())
+    return RISCV::CM_MVA01S;
+
+  if (STI.hasVendorXqccmp())
+    return RISCV::QC_CM_MVA01S;
+
+  llvm_unreachable("Unhandled subtarget with paired A to S move.");
+}
+
+static bool isMoveFromSToA(unsigned Opcode) {
+  switch (Opcode) {
+  case RISCV::CM_MVSA01:
+  case RISCV::QC_CM_MVSA01:
+    return true;
+  default:
+    return false;
+  }
+}
+
+static unsigned getMoveFromSToAOpcode(const RISCVSubtarget &STI) {
+  if (STI.hasStdExtZcmp())
+    return RISCV::CM_MVSA01;
+
+  if (STI.hasVendorXqccmp())
+    return RISCV::QC_CM_MVSA01;
+
+  llvm_unreachable("Unhandled subtarget with paired S to A move");
+}
+
 // Check if registers meet CM.MVA01S constraints.
 bool RISCVMoveMerge::isCandidateToMergeMVA01S(const DestSourcePair &RegPair) {
   Register Destination = RegPair.Destination->getReg();
@@ -87,7 +129,7 @@ RISCVMoveMerge::mergePairedInsns(MachineBasicBlock::iterator I,
   MachineBasicBlock::iterator NextI = next_nodbg(I, E);
   DestSourcePair FirstPair = TII->isCopyInstrImpl(*I).value();
   DestSourcePair PairedRegs = TII->isCopyInstrImpl(*Paired).value();
-  Register ARegInFirstPair = Opcode == RISCV::CM_MVA01S
+  Register ARegInFirstPair = isMoveFromAToS(Opcode)
                                  ? FirstPair.Destination->getReg()
                                  : FirstPair.Source->getReg();
 
@@ -104,7 +146,7 @@ RISCVMoveMerge::mergePairedInsns(MachineBasicBlock::iterator I,
   //   mv a0, s2
   //   mv a1, s1    =>  cm.mva01s s2,s1
   bool StartWithX10 = ARegInFirstPa...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/128815


More information about the llvm-commits mailing list