Skip to content

Commit e49180d

Browse files
authored
[RISCV] Xqccmp Code Generation (#128815)
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.
1 parent 9f0a912 commit e49180d

14 files changed

+5641
-43
lines changed

llvm/docs/ReleaseNotes.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,9 @@ Changes to the RISC-V Backend
109109

110110
* Adds experimental assembler support for the Qualcomm uC 'Xqcilia` (Large Immediate Arithmetic)
111111
extension.
112-
* Adds experimental assembler support for the Qualcomm 'Xqccmp' extension, which
113-
is a frame-pointer convention compatible version of Zcmp.
112+
* Adds experimental assembler and code generation support for the Qualcomm
113+
'Xqccmp' extension, which is a frame-pointer convention compatible version of
114+
Zcmp.
114115
* Added non-quadratic ``log-vrgather`` cost model for ``vrgather.vv`` instruction
115116

116117
Changes to the WebAssembly Backend

llvm/lib/Target/RISCV/RISCVFrameLowering.cpp

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,54 @@ void RISCVFrameLowering::allocateStack(MachineBasicBlock &MBB,
750750
}
751751
}
752752

753+
static bool isPush(unsigned Opcode) {
754+
switch (Opcode) {
755+
case RISCV::CM_PUSH:
756+
case RISCV::QC_CM_PUSH:
757+
case RISCV::QC_CM_PUSHFP:
758+
return true;
759+
default:
760+
return false;
761+
}
762+
}
763+
764+
static bool isPop(unsigned Opcode) {
765+
// There are other pops but these are the only ones introduced during this
766+
// pass.
767+
switch (Opcode) {
768+
case RISCV::CM_POP:
769+
case RISCV::QC_CM_POP:
770+
return true;
771+
default:
772+
return false;
773+
}
774+
}
775+
776+
static unsigned getPushOpcode(RISCVMachineFunctionInfo::PushPopKind Kind,
777+
bool HasFP) {
778+
switch (Kind) {
779+
case RISCVMachineFunctionInfo::PushPopKind::StdExtZcmp:
780+
return RISCV::CM_PUSH;
781+
case RISCVMachineFunctionInfo::PushPopKind::VendorXqccmp:
782+
return HasFP ? RISCV::QC_CM_PUSHFP : RISCV::QC_CM_PUSH;
783+
default:
784+
llvm_unreachable("Unhandled PushPopKind");
785+
}
786+
}
787+
788+
static unsigned getPopOpcode(RISCVMachineFunctionInfo::PushPopKind Kind) {
789+
// There are other pops but they are introduced later by the Push/Pop
790+
// Optimizer.
791+
switch (Kind) {
792+
case RISCVMachineFunctionInfo::PushPopKind::StdExtZcmp:
793+
return RISCV::CM_POP;
794+
case RISCVMachineFunctionInfo::PushPopKind::VendorXqccmp:
795+
return RISCV::QC_CM_POP;
796+
default:
797+
llvm_unreachable("Unhandled PushPopKind");
798+
}
799+
}
800+
753801
void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
754802
MachineBasicBlock &MBB) const {
755803
MachineFrameInfo &MFI = MF.getFrameInfo();
@@ -849,7 +897,7 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
849897
}
850898

851899
if (RVFI->isPushable(MF) && FirstFrameSetup != MBB.end() &&
852-
FirstFrameSetup->getOpcode() == RISCV::CM_PUSH) {
900+
isPush(FirstFrameSetup->getOpcode())) {
853901
// Use available stack adjustment in push instruction to allocate additional
854902
// stack space. Align the stack size down to a multiple of 16. This is
855903
// needed for RVE.
@@ -900,9 +948,15 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
900948
// The frame pointer does need to be reserved from register allocation.
901949
assert(MF.getRegInfo().isReserved(FPReg) && "FP not reserved");
902950

903-
RI->adjustReg(MBB, MBBI, DL, FPReg, SPReg,
904-
StackOffset::getFixed(RealStackSize - RVFI->getVarArgsSaveSize()),
905-
MachineInstr::FrameSetup, getStackAlign());
951+
// Xqccmp with hasFP will update FP using `qc.cm.pushfp`, so we don't need
952+
// to update it again, but we do need to emit the `.cfi_def_cfa` below.
953+
if (RVFI->getPushPopKind(MF) !=
954+
RISCVMachineFunctionInfo::PushPopKind::VendorXqccmp) {
955+
RI->adjustReg(
956+
MBB, MBBI, DL, FPReg, SPReg,
957+
StackOffset::getFixed(RealStackSize - RVFI->getVarArgsSaveSize()),
958+
MachineInstr::FrameSetup, getStackAlign());
959+
}
906960

907961
// Emit ".cfi_def_cfa $fp, RVFI->getVarArgsSaveSize()"
908962
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfa(
@@ -1160,9 +1214,7 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
11601214
// Recover callee-saved registers.
11611215
emitCFIForCSI<CFIRestoreRegisterEmitter>(MBB, MBBI, getUnmanagedCSI(MF, CSI));
11621216

1163-
bool ApplyPop = RVFI->isPushable(MF) && MBBI != MBB.end() &&
1164-
MBBI->getOpcode() == RISCV::CM_POP;
1165-
if (ApplyPop) {
1217+
if (RVFI->isPushable(MF) && MBBI != MBB.end() && isPop(MBBI->getOpcode())) {
11661218
// Use available stack adjustment in pop instruction to deallocate stack
11671219
// space. Align the stack size down to a multiple of 16. This is needed for
11681220
// RVE.
@@ -1781,7 +1833,8 @@ bool RISCVFrameLowering::assignCalleeSavedSpillSlots(
17811833

17821834
if (FII != std::end(FixedCSRFIMap)) {
17831835
int64_t Offset;
1784-
if (RVFI->isPushable(MF))
1836+
if (RVFI->getPushPopKind(MF) ==
1837+
RISCVMachineFunctionInfo::PushPopKind::StdExtZcmp)
17851838
Offset = -int64_t(RVFI->getRVPushRegs() - RegNum) * Size;
17861839
else
17871840
Offset = -int64_t(RegNum + 1) * Size;
@@ -1845,9 +1898,10 @@ bool RISCVFrameLowering::spillCalleeSavedRegisters(
18451898
unsigned PushedRegNum = RVFI->getRVPushRegs();
18461899
if (PushedRegNum > 0) {
18471900
// Use encoded number to represent registers to spill.
1901+
unsigned Opcode = getPushOpcode(RVFI->getPushPopKind(*MF), hasFP(*MF));
18481902
unsigned RegEnc = RISCVZC::encodeRlistNumRegs(PushedRegNum);
18491903
MachineInstrBuilder PushBuilder =
1850-
BuildMI(MBB, MI, DL, TII.get(RISCV::CM_PUSH))
1904+
BuildMI(MBB, MI, DL, TII.get(Opcode))
18511905
.setMIFlag(MachineInstr::FrameSetup);
18521906
PushBuilder.addImm(RegEnc);
18531907
PushBuilder.addImm(0);
@@ -2000,9 +2054,10 @@ bool RISCVFrameLowering::restoreCalleeSavedRegisters(
20002054
if (RVFI->isPushable(*MF)) {
20012055
unsigned PushedRegNum = RVFI->getRVPushRegs();
20022056
if (PushedRegNum > 0) {
2057+
unsigned Opcode = getPopOpcode(RVFI->getPushPopKind(*MF));
20032058
unsigned RegEnc = RISCVZC::encodeRlistNumRegs(PushedRegNum);
20042059
MachineInstrBuilder PopBuilder =
2005-
BuildMI(MBB, MI, DL, TII.get(RISCV::CM_POP))
2060+
BuildMI(MBB, MI, DL, TII.get(Opcode))
20062061
.setMIFlag(MachineInstr::FrameDestroy);
20072062
// Use encoded number to represent registers to restore.
20082063
PopBuilder.addImm(RegEnc);

llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,27 @@ void yaml::RISCVMachineFunctionInfo::mappingImpl(yaml::IO &YamlIO) {
6060
MappingTraits<RISCVMachineFunctionInfo>::mapping(YamlIO, *this);
6161
}
6262

63+
RISCVMachineFunctionInfo::PushPopKind
64+
RISCVMachineFunctionInfo::getPushPopKind(const MachineFunction &MF) const {
65+
// We cannot use fixed locations for the callee saved spill slots if the
66+
// function uses a varargs save area.
67+
// TODO: Use a separate placement for vararg registers to enable Zcmp.
68+
if (VarArgsSaveSize != 0)
69+
return PushPopKind::None;
70+
71+
// Zcmp is not compatible with the frame pointer convention.
72+
if (MF.getSubtarget<RISCVSubtarget>().hasStdExtZcmp() &&
73+
!MF.getTarget().Options.DisableFramePointerElim(MF))
74+
return PushPopKind::StdExtZcmp;
75+
76+
// Xqccmp is Zcmp but has a push order compatible with the frame-pointer
77+
// convention.
78+
if (MF.getSubtarget<RISCVSubtarget>().hasVendorXqccmp())
79+
return PushPopKind::VendorXqccmp;
80+
81+
return PushPopKind::None;
82+
}
83+
6384
void RISCVMachineFunctionInfo::initializeBaseYamlFields(
6485
const yaml::RISCVMachineFunctionInfo &YamlMFI) {
6586
VarArgsFrameIndex = YamlMFI.VarArgsFrameIndex;

llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.h

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -136,13 +136,12 @@ class RISCVMachineFunctionInfo : public MachineFunctionInfo {
136136
unsigned getCalleeSavedStackSize() const { return CalleeSavedStackSize; }
137137
void setCalleeSavedStackSize(unsigned Size) { CalleeSavedStackSize = Size; }
138138

139+
enum class PushPopKind { None = 0, StdExtZcmp, VendorXqccmp };
140+
141+
PushPopKind getPushPopKind(const MachineFunction &MF) const;
142+
139143
bool isPushable(const MachineFunction &MF) const {
140-
// We cannot use fixed locations for the callee saved spill slots if the
141-
// function uses a varargs save area.
142-
// TODO: Use a separate placement for vararg registers to enable Zcmp.
143-
return MF.getSubtarget<RISCVSubtarget>().hasStdExtZcmp() &&
144-
!MF.getTarget().Options.DisableFramePointerElim(MF) &&
145-
VarArgsSaveSize == 0;
144+
return getPushPopKind(MF) != PushPopKind::None;
146145
}
147146

148147
unsigned getRVPushRegs() const { return RVPushRegs; }

llvm/lib/Target/RISCV/RISCVMoveMerger.cpp

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99
// This file contains a pass that performs move related peephole optimizations
1010
// as Zcmp has specified. This pass should be run after register allocation.
1111
//
12+
// This pass also supports Xqccmp, which has identical instructions.
13+
//
1214
//===----------------------------------------------------------------------===//
1315

1416
#include "RISCVInstrInfo.h"
15-
#include "RISCVMachineFunctionInfo.h"
17+
#include "RISCVSubtarget.h"
1618

1719
using namespace llvm;
1820

@@ -43,7 +45,7 @@ struct RISCVMoveMerge : public MachineFunctionPass {
4345
MachineBasicBlock::iterator
4446
findMatchingInst(MachineBasicBlock::iterator &MBBI, unsigned InstOpcode,
4547
const DestSourcePair &RegPair);
46-
bool mergeMoveSARegPair(MachineBasicBlock &MBB);
48+
bool mergeMoveSARegPair(const RISCVSubtarget &STI, MachineBasicBlock &MBB);
4749
bool runOnMachineFunction(MachineFunction &Fn) override;
4850

4951
StringRef getPassName() const override { return RISCV_MOVE_MERGE_NAME; }
@@ -56,6 +58,46 @@ char RISCVMoveMerge::ID = 0;
5658
INITIALIZE_PASS(RISCVMoveMerge, "riscv-move-merge", RISCV_MOVE_MERGE_NAME,
5759
false, false)
5860

61+
static bool isMoveFromAToS(unsigned Opcode) {
62+
switch (Opcode) {
63+
case RISCV::CM_MVA01S:
64+
case RISCV::QC_CM_MVA01S:
65+
return true;
66+
default:
67+
return false;
68+
}
69+
}
70+
71+
static unsigned getMoveFromAToSOpcode(const RISCVSubtarget &STI) {
72+
if (STI.hasStdExtZcmp())
73+
return RISCV::CM_MVA01S;
74+
75+
if (STI.hasVendorXqccmp())
76+
return RISCV::QC_CM_MVA01S;
77+
78+
llvm_unreachable("Unhandled subtarget with paired A to S move.");
79+
}
80+
81+
static bool isMoveFromSToA(unsigned Opcode) {
82+
switch (Opcode) {
83+
case RISCV::CM_MVSA01:
84+
case RISCV::QC_CM_MVSA01:
85+
return true;
86+
default:
87+
return false;
88+
}
89+
}
90+
91+
static unsigned getMoveFromSToAOpcode(const RISCVSubtarget &STI) {
92+
if (STI.hasStdExtZcmp())
93+
return RISCV::CM_MVSA01;
94+
95+
if (STI.hasVendorXqccmp())
96+
return RISCV::QC_CM_MVSA01;
97+
98+
llvm_unreachable("Unhandled subtarget with paired S to A move");
99+
}
100+
59101
// Check if registers meet CM.MVA01S constraints.
60102
bool RISCVMoveMerge::isCandidateToMergeMVA01S(const DestSourcePair &RegPair) {
61103
Register Destination = RegPair.Destination->getReg();
@@ -87,7 +129,7 @@ RISCVMoveMerge::mergePairedInsns(MachineBasicBlock::iterator I,
87129
MachineBasicBlock::iterator NextI = next_nodbg(I, E);
88130
DestSourcePair FirstPair = TII->isCopyInstrImpl(*I).value();
89131
DestSourcePair PairedRegs = TII->isCopyInstrImpl(*Paired).value();
90-
Register ARegInFirstPair = Opcode == RISCV::CM_MVA01S
132+
Register ARegInFirstPair = isMoveFromAToS(Opcode)
91133
? FirstPair.Destination->getReg()
92134
: FirstPair.Source->getReg();
93135

@@ -104,7 +146,7 @@ RISCVMoveMerge::mergePairedInsns(MachineBasicBlock::iterator I,
104146
// mv a0, s2
105147
// mv a1, s1 => cm.mva01s s2,s1
106148
bool StartWithX10 = ARegInFirstPair == RISCV::X10;
107-
if (Opcode == RISCV::CM_MVA01S) {
149+
if (isMoveFromAToS(Opcode)) {
108150
Sreg1 = StartWithX10 ? FirstPair.Source : PairedRegs.Source;
109151
Sreg2 = StartWithX10 ? PairedRegs.Source : FirstPair.Source;
110152
} else {
@@ -139,8 +181,7 @@ RISCVMoveMerge::findMatchingInst(MachineBasicBlock::iterator &MBBI,
139181
Register SourceReg = SecondPair->Source->getReg();
140182
Register DestReg = SecondPair->Destination->getReg();
141183

142-
if (InstOpcode == RISCV::CM_MVA01S &&
143-
isCandidateToMergeMVA01S(*SecondPair)) {
184+
if (isMoveFromAToS(InstOpcode) && isCandidateToMergeMVA01S(*SecondPair)) {
144185
// If register pair is valid and destination registers are different.
145186
if ((RegPair.Destination->getReg() == DestReg))
146187
return E;
@@ -154,7 +195,7 @@ RISCVMoveMerge::findMatchingInst(MachineBasicBlock::iterator &MBBI,
154195
return E;
155196

156197
return I;
157-
} else if (InstOpcode == RISCV::CM_MVSA01 &&
198+
} else if (isMoveFromSToA(InstOpcode) &&
158199
isCandidateToMergeMVSA01(*SecondPair)) {
159200
if ((RegPair.Source->getReg() == SourceReg) ||
160201
(RegPair.Destination->getReg() == DestReg))
@@ -176,7 +217,8 @@ RISCVMoveMerge::findMatchingInst(MachineBasicBlock::iterator &MBBI,
176217

177218
// Finds instructions, which could be represented as C.MV instructions and
178219
// merged into CM.MVA01S or CM.MVSA01.
179-
bool RISCVMoveMerge::mergeMoveSARegPair(MachineBasicBlock &MBB) {
220+
bool RISCVMoveMerge::mergeMoveSARegPair(const RISCVSubtarget &STI,
221+
MachineBasicBlock &MBB) {
180222
bool Modified = false;
181223

182224
for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
@@ -188,9 +230,9 @@ bool RISCVMoveMerge::mergeMoveSARegPair(MachineBasicBlock &MBB) {
188230
unsigned Opcode = 0;
189231

190232
if (isCandidateToMergeMVA01S(*RegPair))
191-
Opcode = RISCV::CM_MVA01S;
233+
Opcode = getMoveFromAToSOpcode(STI);
192234
else if (isCandidateToMergeMVSA01(*RegPair))
193-
Opcode = RISCV::CM_MVSA01;
235+
Opcode = getMoveFromSToAOpcode(STI);
194236
else {
195237
++MBBI;
196238
continue;
@@ -215,7 +257,7 @@ bool RISCVMoveMerge::runOnMachineFunction(MachineFunction &Fn) {
215257
return false;
216258

217259
const RISCVSubtarget *Subtarget = &Fn.getSubtarget<RISCVSubtarget>();
218-
if (!Subtarget->hasStdExtZcmp())
260+
if (!(Subtarget->hasStdExtZcmp() || Subtarget->hasVendorXqccmp()))
219261
return false;
220262

221263
TII = Subtarget->getInstrInfo();
@@ -227,7 +269,7 @@ bool RISCVMoveMerge::runOnMachineFunction(MachineFunction &Fn) {
227269
UsedRegUnits.init(*TRI);
228270
bool Modified = false;
229271
for (auto &MBB : Fn)
230-
Modified |= mergeMoveSARegPair(MBB);
272+
Modified |= mergeMoveSARegPair(*Subtarget, MBB);
231273
return Modified;
232274
}
233275

0 commit comments

Comments
 (0)