-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[RISCV] Xqccmp Code Generation #128815
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RISCV] Xqccmp Code Generation #128815
Conversation
Xqccmp is a new spec by Qualcomm that makes a vendor-specific effort to solve the push/pop + frame pointers issue. Broadly, it takes the Zcmp instructions and reverse the order they push/pop registers in, which ends up matching the frame pointer convention. This extension adds a new instruction not present in Xqccmp, `qc.cm.pushfp`, which will set `fp` to the incoming `sp` value after it has pushed the registers in rlist. This change duplicates the Zcmp implementation, with minor changes to mnemonics (for the `qc.` prefix), predicates, and the addition of `qc.cm.pushfp`. There is also new logic to prevent combining Xqccmp and Zcmp. Xqccmp is kept separate to Xqci for decoding/encoding etc, as the specs are separate today. Specification: https://github.com/quic/riscv-unified-db/releases/tag/Xqccmp_extension-0.1.0
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 instructions. - 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.
@llvm/pr-subscribers-backend-risc-v @llvm/pr-subscribers-clang Author: Sam Elliott (lenary) ChangesThis adds support for Xqccmp to the following passes:
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:
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]
|
@llvm/pr-subscribers-clang-driver Author: Sam Elliott (lenary) ChangesThis adds support for Xqccmp to the following passes:
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:
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]
|
@llvm/pr-subscribers-mc Author: Sam Elliott (lenary) ChangesThis adds support for Xqccmp to the following passes:
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:
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]
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
✅ With the latest revision this PR passed the C/C++ code formatter. |
@topperc the two useful changes since you last reviewed are:
|
RI->adjustReg(MBB, MBBI, DL, FPReg, SPReg, | ||
StackOffset::getFixed(RealStackSize - RVFI->getVarArgsSaveSize()), | ||
MachineInstr::FrameSetup, getStackAlign()); | ||
// Xqxxmp with hasFP will update FP using `qc.cm.pushfp`, so we don't need |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Xqccmp*
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, sorted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
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 adds support for Xqccmp to the following passes:
qc.
variants of the double-move instructions.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.