Skip to content

Commit aaf0cc9

Browse files
committed
[RISCV] Initial ISel support for the experimental zacas extension
1 parent 26fbdff commit aaf0cc9

7 files changed

+3957
-343
lines changed

llvm/lib/Target/RISCV/RISCVExpandAtomicPseudoInsts.cpp

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ class RISCVExpandAtomicPseudo : public MachineFunctionPass {
5959
bool expandAtomicCmpXchg(MachineBasicBlock &MBB,
6060
MachineBasicBlock::iterator MBBI, bool IsMasked,
6161
int Width, MachineBasicBlock::iterator &NextMBBI);
62+
bool expandAMOCAS(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
63+
bool IsPaired, int Width,
64+
MachineBasicBlock::iterator &NextMBBI);
6265
#ifndef NDEBUG
6366
unsigned getInstSizeInBytes(const MachineFunction &MF) const {
6467
unsigned Size = 0;
@@ -145,6 +148,14 @@ bool RISCVExpandAtomicPseudo::expandMI(MachineBasicBlock &MBB,
145148
return expandAtomicCmpXchg(MBB, MBBI, false, 64, NextMBBI);
146149
case RISCV::PseudoMaskedCmpXchg32:
147150
return expandAtomicCmpXchg(MBB, MBBI, true, 32, NextMBBI);
151+
case RISCV::PseudoAMOCAS_W:
152+
return expandAMOCAS(MBB, MBBI, false, 32, NextMBBI);
153+
case RISCV::PseudoAMOCAS_D_RV64:
154+
return expandAMOCAS(MBB, MBBI, false, 64, NextMBBI);
155+
case RISCV::PseudoAMOCAS_D_RV32:
156+
return expandAMOCAS(MBB, MBBI, true, 64, NextMBBI);
157+
case RISCV::PseudoAMOCAS_Q:
158+
return expandAMOCAS(MBB, MBBI, true, 128, NextMBBI);
148159
}
149160

150161
return false;
@@ -256,6 +267,74 @@ static unsigned getSCForRMW(AtomicOrdering Ordering, int Width,
256267
llvm_unreachable("Unexpected SC width\n");
257268
}
258269

270+
static unsigned getAMOCASForRMW32(AtomicOrdering Ordering,
271+
const RISCVSubtarget *Subtarget) {
272+
if (Subtarget->hasStdExtZtso())
273+
return RISCV::AMOCAS_W;
274+
switch (Ordering) {
275+
default:
276+
llvm_unreachable("Unexpected AtomicOrdering");
277+
case AtomicOrdering::Monotonic:
278+
return RISCV::AMOCAS_W;
279+
case AtomicOrdering::Acquire:
280+
return RISCV::AMOCAS_W_AQ;
281+
case AtomicOrdering::Release:
282+
return RISCV::AMOCAS_W_RL;
283+
case AtomicOrdering::AcquireRelease:
284+
case AtomicOrdering::SequentiallyConsistent:
285+
return RISCV::AMOCAS_W_AQ_RL;
286+
}
287+
}
288+
289+
static unsigned getAMOCASForRMW64(AtomicOrdering Ordering,
290+
const RISCVSubtarget *Subtarget) {
291+
if (Subtarget->hasStdExtZtso())
292+
return RISCV::AMOCAS_D;
293+
switch (Ordering) {
294+
default:
295+
llvm_unreachable("Unexpected AtomicOrdering");
296+
case AtomicOrdering::Monotonic:
297+
return RISCV::AMOCAS_D;
298+
case AtomicOrdering::Acquire:
299+
return RISCV::AMOCAS_D_AQ;
300+
case AtomicOrdering::Release:
301+
return RISCV::AMOCAS_D_RL;
302+
case AtomicOrdering::AcquireRelease:
303+
case AtomicOrdering::SequentiallyConsistent:
304+
return RISCV::AMOCAS_D_AQ_RL;
305+
}
306+
}
307+
308+
static unsigned getAMOCASForRMW128(AtomicOrdering Ordering,
309+
const RISCVSubtarget *Subtarget) {
310+
if (Subtarget->hasStdExtZtso())
311+
return RISCV::AMOCAS_Q;
312+
switch (Ordering) {
313+
default:
314+
llvm_unreachable("Unexpected AtomicOrdering");
315+
case AtomicOrdering::Monotonic:
316+
return RISCV::AMOCAS_Q;
317+
case AtomicOrdering::Acquire:
318+
return RISCV::AMOCAS_Q_AQ;
319+
case AtomicOrdering::Release:
320+
return RISCV::AMOCAS_Q_RL;
321+
case AtomicOrdering::AcquireRelease:
322+
case AtomicOrdering::SequentiallyConsistent:
323+
return RISCV::AMOCAS_Q_AQ_RL;
324+
}
325+
}
326+
327+
static unsigned getAMOCASForRMW(AtomicOrdering Ordering, int Width,
328+
const RISCVSubtarget *Subtarget) {
329+
if (Width == 32)
330+
return getAMOCASForRMW32(Ordering, Subtarget);
331+
if (Width == 64)
332+
return getAMOCASForRMW64(Ordering, Subtarget);
333+
if (Width == 128)
334+
return getAMOCASForRMW128(Ordering, Subtarget);
335+
llvm_unreachable("Unexpected AMOCAS width\n");
336+
}
337+
259338
static void doAtomicBinOpExpansion(const RISCVInstrInfo *TII, MachineInstr &MI,
260339
DebugLoc DL, MachineBasicBlock *ThisMBB,
261340
MachineBasicBlock *LoopMBB,
@@ -728,6 +807,38 @@ bool RISCVExpandAtomicPseudo::expandAtomicCmpXchg(
728807
return true;
729808
}
730809

810+
static Register getGPRPairEvenReg(Register PairedReg) {
811+
assert(PairedReg >= RISCV::X0_PD && PairedReg <= RISCV::X30_PD &&
812+
"Invalid GPR pair");
813+
return (PairedReg - RISCV::X0_PD) * 2 + RISCV::X0;
814+
}
815+
816+
bool RISCVExpandAtomicPseudo::expandAMOCAS(
817+
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, bool IsPaired,
818+
int Width, MachineBasicBlock::iterator &NextMBBI) {
819+
MachineInstr &MI = *MBBI;
820+
DebugLoc DL = MI.getDebugLoc();
821+
822+
Register DestReg = MI.getOperand(0).getReg();
823+
if (IsPaired)
824+
DestReg = getGPRPairEvenReg(DestReg);
825+
Register AddrReg = MI.getOperand(1).getReg();
826+
Register NewValReg = MI.getOperand(3).getReg();
827+
if (IsPaired)
828+
NewValReg = getGPRPairEvenReg(NewValReg);
829+
AtomicOrdering Ordering =
830+
static_cast<AtomicOrdering>(MI.getOperand(4).getImm());
831+
832+
MachineInstr *NewMI =
833+
BuildMI(MBB, MBBI, DL, TII->get(getAMOCASForRMW(Ordering, Width, STI)))
834+
.addReg(DestReg, RegState::Define)
835+
.addReg(AddrReg)
836+
.addReg(NewValReg);
837+
838+
MI.eraseFromParent();
839+
return true;
840+
}
841+
731842
} // end of anonymous namespace
732843

733844
INITIALIZE_PASS(RISCVExpandAtomicPseudo, "riscv-expand-atomic-pseudo",

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,10 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
621621
}
622622

623623
if (Subtarget.hasStdExtA()) {
624-
setMaxAtomicSizeInBitsSupported(Subtarget.getXLen());
624+
if (Subtarget.hasStdExtZacas())
625+
setMaxAtomicSizeInBitsSupported(Subtarget.getXLen() * 2);
626+
else
627+
setMaxAtomicSizeInBitsSupported(Subtarget.getXLen());
625628
setMinCmpXchgSizeInBits(32);
626629
} else if (Subtarget.hasForcedAtomics()) {
627630
setMaxAtomicSizeInBitsSupported(Subtarget.getXLen());
@@ -1339,6 +1342,12 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
13391342
XLenVT, LibCall);
13401343
}
13411344

1345+
// Set atomic_cmp_swap operations to expand to AMOCAS.D (RV32) and AMOCAS.Q
1346+
// (RV64).
1347+
if (Subtarget.hasStdExtZacas())
1348+
setOperationAction(ISD::ATOMIC_CMP_SWAP,
1349+
Subtarget.is64Bit() ? MVT::i128 : MVT::i64, Custom);
1350+
13421351
if (Subtarget.hasVendorXTHeadMemIdx()) {
13431352
for (unsigned im = (unsigned)ISD::PRE_INC; im != (unsigned)ISD::POST_DEC;
13441353
++im) {
@@ -11075,13 +11084,67 @@ static SDValue customLegalizeToWOpWithSExt(SDNode *N, SelectionDAG &DAG) {
1107511084
return DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, NewRes);
1107611085
}
1107711086

11087+
// Create an even/odd pair of X registers holding integer value V.
11088+
static SDValue createGPRPairNode(SelectionDAG &DAG, SDValue V, MVT VT,
11089+
MVT SubRegVT) {
11090+
SDLoc DL(V.getNode());
11091+
auto [VLo, VHi] = DAG.SplitScalar(V, DL, SubRegVT, SubRegVT);
11092+
SDValue RegClass =
11093+
DAG.getTargetConstant(RISCV::GPRPairRegClassID, DL, MVT::i32);
11094+
SDValue SubReg0 = DAG.getTargetConstant(RISCV::sub_32, DL, MVT::i32);
11095+
SDValue SubReg1 = DAG.getTargetConstant(RISCV::sub_32_hi, DL, MVT::i32);
11096+
const SDValue Ops[] = {RegClass, VLo, SubReg0, VHi, SubReg1};
11097+
return SDValue(
11098+
DAG.getMachineNode(TargetOpcode::REG_SEQUENCE, DL, MVT::Untyped, Ops), 0);
11099+
}
11100+
11101+
static void ReplaceCMP_SWAP_2XLenResults(SDNode *N,
11102+
SmallVectorImpl<SDValue> &Results,
11103+
SelectionDAG &DAG,
11104+
const RISCVSubtarget &Subtarget) {
11105+
MVT VT = N->getSimpleValueType(0);
11106+
assert(N->getValueType(0) == (Subtarget.is64Bit() ? MVT::i128 : MVT::i64) &&
11107+
"AtomicCmpSwap on types less than 2*XLen should be legal");
11108+
assert(Subtarget.hasStdExtZacas());
11109+
MVT XLenVT = Subtarget.getXLenVT();
11110+
11111+
SDLoc DL(N);
11112+
MachineMemOperand *MemOp = cast<MemSDNode>(N)->getMemOperand();
11113+
AtomicOrdering Ordering = MemOp->getMergedOrdering();
11114+
SDValue Ops[] = {
11115+
N->getOperand(1), // Ptr
11116+
createGPRPairNode(DAG, N->getOperand(2), VT, XLenVT), // Compare value
11117+
createGPRPairNode(DAG, N->getOperand(3), VT, XLenVT), // Store value
11118+
DAG.getTargetConstant(static_cast<unsigned>(Ordering), DL,
11119+
MVT::i32), // Ordering
11120+
N->getOperand(0), // Chain in
11121+
};
11122+
11123+
unsigned Opcode =
11124+
(VT == MVT::i64 ? RISCV::PseudoAMOCAS_D_RV32 : RISCV::PseudoAMOCAS_Q);
11125+
MachineSDNode *CmpSwap = DAG.getMachineNode(
11126+
Opcode, DL, DAG.getVTList(MVT::Untyped, MVT::Other), Ops);
11127+
DAG.setNodeMemRefs(CmpSwap, {MemOp});
11128+
11129+
unsigned SubReg1 = RISCV::sub_32, SubReg2 = RISCV::sub_32_hi;
11130+
SDValue Lo =
11131+
DAG.getTargetExtractSubreg(SubReg1, DL, XLenVT, SDValue(CmpSwap, 0));
11132+
SDValue Hi =
11133+
DAG.getTargetExtractSubreg(SubReg2, DL, XLenVT, SDValue(CmpSwap, 0));
11134+
Results.push_back(DAG.getNode(ISD::BUILD_PAIR, DL, VT, Lo, Hi));
11135+
Results.push_back(SDValue(CmpSwap, 1));
11136+
}
11137+
1107811138
void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
1107911139
SmallVectorImpl<SDValue> &Results,
1108011140
SelectionDAG &DAG) const {
1108111141
SDLoc DL(N);
1108211142
switch (N->getOpcode()) {
1108311143
default:
1108411144
llvm_unreachable("Don't know how to custom type legalize this operation!");
11145+
case ISD::ATOMIC_CMP_SWAP:
11146+
ReplaceCMP_SWAP_2XLenResults(N, Results, DAG, Subtarget);
11147+
break;
1108511148
case ISD::STRICT_FP_TO_SINT:
1108611149
case ISD::STRICT_FP_TO_UINT:
1108711150
case ISD::FP_TO_SINT:

llvm/lib/Target/RISCV/RISCVInstrInfoA.td

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,28 @@ multiclass PseudoCmpXchgPat<string Op, Pseudo CmpXchgInst,
295295
(CmpXchgInst GPR:$addr, GPR:$cmp, GPR:$new, 7)>;
296296
}
297297

298+
let Predicates = [HasStdExtZacas] in {
299+
class PseudoAMOCAS<RegisterClass RC = GPR>
300+
: Pseudo<(outs RC:$res),
301+
(ins GPR:$addr, RC:$cmpval, RC:$newval, ixlenimm:$ordering), []> {
302+
let Constraints = "$res = $cmpval";
303+
let mayLoad = 1;
304+
let mayStore = 1;
305+
let hasSideEffects = 0;
306+
}
307+
def PseudoAMOCAS_W: PseudoAMOCAS;
308+
defm : PseudoCmpXchgPat<"atomic_cmp_swap_32", PseudoAMOCAS_W>;
309+
310+
let Predicates = [HasStdExtZacas, IsRV32] in
311+
def PseudoAMOCAS_D_RV32: PseudoAMOCAS<GPRPair>;
312+
313+
let Predicates = [HasStdExtZacas, IsRV64] in {
314+
def PseudoAMOCAS_D_RV64: PseudoAMOCAS;
315+
defm : PseudoCmpXchgPat<"atomic_cmp_swap_64", PseudoAMOCAS_D_RV64>;
316+
def PseudoAMOCAS_Q: PseudoAMOCAS<GPRPair>;
317+
}
318+
}
319+
298320
def PseudoCmpXchg32 : PseudoCmpXchg;
299321
defm : PseudoCmpXchgPat<"atomic_cmp_swap_32", PseudoCmpXchg32>;
300322

llvm/lib/Target/RISCV/RISCVRegisterInfo.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,16 @@ def GPRPF64 : RegisterClass<"RISCV", [f64], 64, (add
571571
X0_PD, X2_PD, X4_PD
572572
)>;
573573

574+
let RegInfos = RegInfoByHwMode<[RV32, RV64], [RegInfo<32, 32, 32>, RegInfo<64, 64, 64>]> in
575+
def GPRPair : RegisterClass<"RISCV", [untyped], 64, (add
576+
X10_PD, X12_PD, X14_PD, X16_PD,
577+
X6_PD,
578+
X28_PD, X30_PD,
579+
X8_PD,
580+
X18_PD, X20_PD, X22_PD, X24_PD, X26_PD,
581+
X0_PD, X2_PD, X4_PD
582+
)>;
583+
574584
// The register class is added for inline assembly for vector mask types.
575585
def VM : VReg<VMaskVTs,
576586
(add (sequence "V%u", 8, 31),

0 commit comments

Comments
 (0)