Skip to content

Commit 66d9a75

Browse files
committed
[RISCV] Implement codegen for cmpxchg on RV32IA
Utilise a similar ('late') lowering strategy to D47882. The changes to AtomicExpandPass allow this strategy to be utilised by other targets which implement shouldExpandAtomicCmpXchgInIR. All cmpxchg are lowered as 'strong' currently and failure ordering is ignored. This is conservative but correct. Differential Revision: https://reviews.llvm.org/D48131 llvm-svn: 347914
1 parent 7eb1c28 commit 66d9a75

File tree

7 files changed

+984
-3
lines changed

7 files changed

+984
-3
lines changed

llvm/include/llvm/IR/IntrinsicsRISCV.td

+5
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,9 @@ def int_riscv_masked_atomicrmw_min_i32 : MaskedAtomicRMW32WithSextIntrinsic;
3636
def int_riscv_masked_atomicrmw_umax_i32 : MaskedAtomicRMW32Intrinsic;
3737
def int_riscv_masked_atomicrmw_umin_i32 : MaskedAtomicRMW32Intrinsic;
3838

39+
def int_riscv_masked_cmpxchg_i32
40+
: Intrinsic<[llvm_i32_ty], [llvm_anyptr_ty, llvm_i32_ty, llvm_i32_ty,
41+
llvm_i32_ty, llvm_i32_ty],
42+
[IntrArgMemOnly, NoCapture<0>]>;
43+
3944
} // TargetPrefix = "riscv"

llvm/lib/CodeGen/AtomicExpandPass.cpp

+32-2
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ namespace {
9191
AtomicRMWInst *widenPartwordAtomicRMW(AtomicRMWInst *AI);
9292
void expandPartwordCmpXchg(AtomicCmpXchgInst *I);
9393
void expandAtomicRMWToMaskedIntrinsic(AtomicRMWInst *AI);
94+
void expandAtomicCmpXchgToMaskedIntrinsic(AtomicCmpXchgInst *CI);
9495

9596
AtomicCmpXchgInst *convertCmpXchgToIntegerType(AtomicCmpXchgInst *CI);
9697
static Value *insertRMWCmpXchgLoop(
@@ -944,6 +945,35 @@ void AtomicExpand::expandAtomicRMWToMaskedIntrinsic(AtomicRMWInst *AI) {
944945
AI->eraseFromParent();
945946
}
946947

948+
void AtomicExpand::expandAtomicCmpXchgToMaskedIntrinsic(AtomicCmpXchgInst *CI) {
949+
IRBuilder<> Builder(CI);
950+
951+
PartwordMaskValues PMV = createMaskInstrs(
952+
Builder, CI, CI->getCompareOperand()->getType(), CI->getPointerOperand(),
953+
TLI->getMinCmpXchgSizeInBits() / 8);
954+
955+
Value *CmpVal_Shifted = Builder.CreateShl(
956+
Builder.CreateZExt(CI->getCompareOperand(), PMV.WordType), PMV.ShiftAmt,
957+
"CmpVal_Shifted");
958+
Value *NewVal_Shifted = Builder.CreateShl(
959+
Builder.CreateZExt(CI->getNewValOperand(), PMV.WordType), PMV.ShiftAmt,
960+
"NewVal_Shifted");
961+
Value *OldVal = TLI->emitMaskedAtomicCmpXchgIntrinsic(
962+
Builder, CI, PMV.AlignedAddr, CmpVal_Shifted, NewVal_Shifted, PMV.Mask,
963+
CI->getSuccessOrdering());
964+
Value *FinalOldVal = Builder.CreateTrunc(
965+
Builder.CreateLShr(OldVal, PMV.ShiftAmt), PMV.ValueType);
966+
967+
Value *Res = UndefValue::get(CI->getType());
968+
Res = Builder.CreateInsertValue(Res, FinalOldVal, 0);
969+
Value *Success = Builder.CreateICmpEQ(
970+
CmpVal_Shifted, Builder.CreateAnd(OldVal, PMV.Mask), "Success");
971+
Res = Builder.CreateInsertValue(Res, Success, 1);
972+
973+
CI->replaceAllUsesWith(Res);
974+
CI->eraseFromParent();
975+
}
976+
947977
Value *AtomicExpand::insertRMWLLSCLoop(
948978
IRBuilder<> &Builder, Type *ResultTy, Value *Addr,
949979
AtomicOrdering MemOpOrder,
@@ -1366,8 +1396,8 @@ bool AtomicExpand::tryExpandAtomicCmpXchg(AtomicCmpXchgInst *CI) {
13661396
return expandAtomicCmpXchg(CI);
13671397
}
13681398
case TargetLoweringBase::AtomicExpansionKind::MaskedIntrinsic:
1369-
llvm_unreachable(
1370-
"MaskedIntrinsic expansion of cmpxhg not yet implemented");
1399+
expandAtomicCmpXchgToMaskedIntrinsic(CI);
1400+
return true;
13711401
}
13721402
}
13731403

llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp

+104
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ class RISCVExpandPseudo : public MachineFunctionPass {
5252
MachineBasicBlock::iterator MBBI,
5353
AtomicRMWInst::BinOp, bool IsMasked, int Width,
5454
MachineBasicBlock::iterator &NextMBBI);
55+
bool expandAtomicCmpXchg(MachineBasicBlock &MBB,
56+
MachineBasicBlock::iterator MBBI, bool IsMasked,
57+
int Width, MachineBasicBlock::iterator &NextMBBI);
5558
};
5659

5760
char RISCVExpandPseudo::ID = 0;
@@ -106,6 +109,10 @@ bool RISCVExpandPseudo::expandMI(MachineBasicBlock &MBB,
106109
case RISCV::PseudoMaskedAtomicLoadUMin32:
107110
return expandAtomicMinMaxOp(MBB, MBBI, AtomicRMWInst::UMin, true, 32,
108111
NextMBBI);
112+
case RISCV::PseudoCmpXchg32:
113+
return expandAtomicCmpXchg(MBB, MBBI, false, 32, NextMBBI);
114+
case RISCV::PseudoMaskedCmpXchg32:
115+
return expandAtomicCmpXchg(MBB, MBBI, true, 32, NextMBBI);
109116
}
110117

111118
return false;
@@ -441,6 +448,103 @@ bool RISCVExpandPseudo::expandAtomicMinMaxOp(
441448
return true;
442449
}
443450

451+
bool RISCVExpandPseudo::expandAtomicCmpXchg(
452+
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, bool IsMasked,
453+
int Width, MachineBasicBlock::iterator &NextMBBI) {
454+
assert(Width == 32 && "RV64 atomic expansion currently unsupported");
455+
MachineInstr &MI = *MBBI;
456+
DebugLoc DL = MI.getDebugLoc();
457+
MachineFunction *MF = MBB.getParent();
458+
auto LoopHeadMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
459+
auto LoopTailMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
460+
auto DoneMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
461+
462+
// Insert new MBBs.
463+
MF->insert(++MBB.getIterator(), LoopHeadMBB);
464+
MF->insert(++LoopHeadMBB->getIterator(), LoopTailMBB);
465+
MF->insert(++LoopTailMBB->getIterator(), DoneMBB);
466+
467+
// Set up successors and transfer remaining instructions to DoneMBB.
468+
LoopHeadMBB->addSuccessor(LoopTailMBB);
469+
LoopHeadMBB->addSuccessor(DoneMBB);
470+
LoopTailMBB->addSuccessor(DoneMBB);
471+
LoopTailMBB->addSuccessor(LoopHeadMBB);
472+
DoneMBB->splice(DoneMBB->end(), &MBB, MI, MBB.end());
473+
DoneMBB->transferSuccessors(&MBB);
474+
MBB.addSuccessor(LoopHeadMBB);
475+
476+
unsigned DestReg = MI.getOperand(0).getReg();
477+
unsigned ScratchReg = MI.getOperand(1).getReg();
478+
unsigned AddrReg = MI.getOperand(2).getReg();
479+
unsigned CmpValReg = MI.getOperand(3).getReg();
480+
unsigned NewValReg = MI.getOperand(4).getReg();
481+
AtomicOrdering Ordering =
482+
static_cast<AtomicOrdering>(MI.getOperand(IsMasked ? 6 : 5).getImm());
483+
484+
if (!IsMasked) {
485+
// .loophead:
486+
// lr.w dest, (addr)
487+
// bne dest, cmpval, done
488+
BuildMI(LoopHeadMBB, DL, TII->get(getLRForRMW32(Ordering)), DestReg)
489+
.addReg(AddrReg);
490+
BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BNE))
491+
.addReg(DestReg)
492+
.addReg(CmpValReg)
493+
.addMBB(DoneMBB);
494+
// .looptail:
495+
// sc.w scratch, newval, (addr)
496+
// bnez scratch, loophead
497+
BuildMI(LoopTailMBB, DL, TII->get(getSCForRMW32(Ordering)), ScratchReg)
498+
.addReg(AddrReg)
499+
.addReg(NewValReg);
500+
BuildMI(LoopTailMBB, DL, TII->get(RISCV::BNE))
501+
.addReg(ScratchReg)
502+
.addReg(RISCV::X0)
503+
.addMBB(LoopHeadMBB);
504+
} else {
505+
// .loophead:
506+
// lr.w dest, (addr)
507+
// and scratch, dest, mask
508+
// bne scratch, cmpval, done
509+
unsigned MaskReg = MI.getOperand(5).getReg();
510+
BuildMI(LoopHeadMBB, DL, TII->get(getLRForRMW32(Ordering)), DestReg)
511+
.addReg(AddrReg);
512+
BuildMI(LoopHeadMBB, DL, TII->get(RISCV::AND), ScratchReg)
513+
.addReg(DestReg)
514+
.addReg(MaskReg);
515+
BuildMI(LoopHeadMBB, DL, TII->get(RISCV::BNE))
516+
.addReg(ScratchReg)
517+
.addReg(CmpValReg)
518+
.addMBB(DoneMBB);
519+
520+
// .looptail:
521+
// xor scratch, dest, newval
522+
// and scratch, scratch, mask
523+
// xor scratch, dest, scratch
524+
// sc.w scratch, scratch, (adrr)
525+
// bnez scratch, loophead
526+
insertMaskedMerge(TII, DL, LoopTailMBB, ScratchReg, DestReg, NewValReg,
527+
MaskReg, ScratchReg);
528+
BuildMI(LoopTailMBB, DL, TII->get(getSCForRMW32(Ordering)), ScratchReg)
529+
.addReg(AddrReg)
530+
.addReg(ScratchReg);
531+
BuildMI(LoopTailMBB, DL, TII->get(RISCV::BNE))
532+
.addReg(ScratchReg)
533+
.addReg(RISCV::X0)
534+
.addMBB(LoopHeadMBB);
535+
}
536+
537+
NextMBBI = MBB.end();
538+
MI.eraseFromParent();
539+
540+
LivePhysRegs LiveRegs;
541+
computeAndAddLiveIns(LiveRegs, *LoopHeadMBB);
542+
computeAndAddLiveIns(LiveRegs, *LoopTailMBB);
543+
computeAndAddLiveIns(LiveRegs, *DoneMBB);
544+
545+
return true;
546+
}
547+
444548
} // end of anonymous namespace
445549

446550
INITIALIZE_PASS(RISCVExpandPseudo, "riscv-expand-pseudo",

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ bool RISCVTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
186186
case Intrinsic::riscv_masked_atomicrmw_min_i32:
187187
case Intrinsic::riscv_masked_atomicrmw_umax_i32:
188188
case Intrinsic::riscv_masked_atomicrmw_umin_i32:
189+
case Intrinsic::riscv_masked_cmpxchg_i32:
189190
PointerType *PtrTy = cast<PointerType>(I.getArgOperand(0)->getType());
190191
Info.opc = ISD::INTRINSIC_W_CHAIN;
191192
Info.memVT = MVT::getVT(PtrTy->getElementType());
@@ -1708,3 +1709,23 @@ Value *RISCVTargetLowering::emitMaskedAtomicRMWIntrinsic(
17081709

17091710
return Builder.CreateCall(LrwOpScwLoop, {AlignedAddr, Incr, Mask, Ordering});
17101711
}
1712+
1713+
TargetLowering::AtomicExpansionKind
1714+
RISCVTargetLowering::shouldExpandAtomicCmpXchgInIR(
1715+
AtomicCmpXchgInst *CI) const {
1716+
unsigned Size = CI->getCompareOperand()->getType()->getPrimitiveSizeInBits();
1717+
if (Size == 8 || Size == 16)
1718+
return AtomicExpansionKind::MaskedIntrinsic;
1719+
return AtomicExpansionKind::None;
1720+
}
1721+
1722+
Value *RISCVTargetLowering::emitMaskedAtomicCmpXchgIntrinsic(
1723+
IRBuilder<> &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr,
1724+
Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const {
1725+
Value *Ordering = Builder.getInt32(static_cast<uint32_t>(Ord));
1726+
Type *Tys[] = {AlignedAddr->getType()};
1727+
Function *MaskedCmpXchg = Intrinsic::getDeclaration(
1728+
CI->getModule(), Intrinsic::riscv_masked_cmpxchg_i32, Tys);
1729+
return Builder.CreateCall(MaskedCmpXchg,
1730+
{AlignedAddr, CmpVal, NewVal, Mask, Ordering});
1731+
}

llvm/lib/Target/RISCV/RISCVISelLowering.h

+7
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,13 @@ class RISCVTargetLowering : public TargetLowering {
126126
virtual Value *emitMaskedAtomicRMWIntrinsic(
127127
IRBuilder<> &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr,
128128
Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const override;
129+
TargetLowering::AtomicExpansionKind
130+
shouldExpandAtomicCmpXchgInIR(AtomicCmpXchgInst *CI) const override;
131+
virtual Value *
132+
emitMaskedAtomicCmpXchgIntrinsic(IRBuilder<> &Builder, AtomicCmpXchgInst *CI,
133+
Value *AlignedAddr, Value *CmpVal,
134+
Value *NewVal, Value *Mask,
135+
AtomicOrdering Ord) const override;
129136
};
130137
}
131138

llvm/lib/Target/RISCV/RISCVInstrInfoA.td

+46-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ class PseudoAMO : Pseudo<(outs GPR:$res, GPR:$scratch),
153153
}
154154

155155
def PseudoAtomicLoadNand32 : PseudoAMO;
156-
// Ordering constants must be kept in sync with the AtomicOrdering enum in
156+
// Ordering constants must be kept in sync with the AtomicOrdering enum in
157157
// AtomicOrdering.h.
158158
def : Pat<(atomic_load_nand_32_monotonic GPR:$addr, GPR:$incr),
159159
(PseudoAtomicLoadNand32 GPR:$addr, GPR:$incr, 2)>;
@@ -230,4 +230,49 @@ def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_umax_i32,
230230
def PseudoMaskedAtomicLoadUMin32 : PseudoMaskedAMOUMinUMax;
231231
def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_umin_i32,
232232
PseudoMaskedAtomicLoadUMin32>;
233+
234+
/// Compare and exchange
235+
236+
class PseudoCmpXchg
237+
: Pseudo<(outs GPR:$res, GPR:$scratch),
238+
(ins GPR:$addr, GPR:$cmpval, GPR:$newval, i32imm:$ordering), []> {
239+
let Constraints = "@earlyclobber $res,@earlyclobber $scratch";
240+
let mayLoad = 1;
241+
let mayStore = 1;
242+
let hasSideEffects = 0;
243+
}
244+
245+
// Ordering constants must be kept in sync with the AtomicOrdering enum in
246+
// AtomicOrdering.h.
247+
multiclass PseudoCmpXchgPat<string Op, Pseudo CmpXchgInst> {
248+
def : Pat<(!cast<PatFrag>(Op#"_monotonic") GPR:$addr, GPR:$cmp, GPR:$new),
249+
(CmpXchgInst GPR:$addr, GPR:$cmp, GPR:$new, 2)>;
250+
def : Pat<(!cast<PatFrag>(Op#"_acquire") GPR:$addr, GPR:$cmp, GPR:$new),
251+
(CmpXchgInst GPR:$addr, GPR:$cmp, GPR:$new, 4)>;
252+
def : Pat<(!cast<PatFrag>(Op#"_release") GPR:$addr, GPR:$cmp, GPR:$new),
253+
(CmpXchgInst GPR:$addr, GPR:$cmp, GPR:$new, 5)>;
254+
def : Pat<(!cast<PatFrag>(Op#"_acq_rel") GPR:$addr, GPR:$cmp, GPR:$new),
255+
(CmpXchgInst GPR:$addr, GPR:$cmp, GPR:$new, 6)>;
256+
def : Pat<(!cast<PatFrag>(Op#"_seq_cst") GPR:$addr, GPR:$cmp, GPR:$new),
257+
(CmpXchgInst GPR:$addr, GPR:$cmp, GPR:$new, 7)>;
258+
}
259+
260+
def PseudoCmpXchg32 : PseudoCmpXchg;
261+
defm : PseudoCmpXchgPat<"atomic_cmp_swap_32", PseudoCmpXchg32>;
262+
263+
def PseudoMaskedCmpXchg32
264+
: Pseudo<(outs GPR:$res, GPR:$scratch),
265+
(ins GPR:$addr, GPR:$cmpval, GPR:$newval, GPR:$mask,
266+
i32imm:$ordering), []> {
267+
let Constraints = "@earlyclobber $res,@earlyclobber $scratch";
268+
let mayLoad = 1;
269+
let mayStore = 1;
270+
let hasSideEffects = 0;
271+
}
272+
273+
def : Pat<(int_riscv_masked_cmpxchg_i32
274+
GPR:$addr, GPR:$cmpval, GPR:$newval, GPR:$mask, imm:$ordering),
275+
(PseudoMaskedCmpXchg32
276+
GPR:$addr, GPR:$cmpval, GPR:$newval, GPR:$mask, imm:$ordering)>;
277+
233278
} // Predicates = [HasStdExtA]

0 commit comments

Comments
 (0)