Skip to content

Commit 4235064

Browse files
author
Brendan Sweeney
committed
[RISCV][ISEL] Lowering to load-acquire/store-release for RISCV. (The Zalasr extension)
Uses the psABI lowerings for WMO load-acquire/store-release (which are identical to A.7). These are compatible with the A.6/A.7 compatibility mappings introduced in LLVM19. For TSO, it uses the standard Ztso mappings except for lowering seq_cst loads/store to load-acquire/store-release, I had Andrea review that.
1 parent f9c8c01 commit 4235064

File tree

5 files changed

+359
-11
lines changed

5 files changed

+359
-11
lines changed

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22291,6 +22291,35 @@ unsigned RISCVTargetLowering::getCustomCtpopCost(EVT VT,
2229122291
return isCtpopFast(VT) ? 0 : 1;
2229222292
}
2229322293

22294+
bool RISCVTargetLowering::shouldInsertFencesForAtomic(
22295+
const Instruction *I) const {
22296+
if (Subtarget.hasStdExtZalasr()) {
22297+
if (Subtarget.hasStdExtZtso()) {
22298+
// Zalasr + TSO means that atomic_load_acquire and atomic_store_release
22299+
// should be lowered to plain load/store. The easiest way to do this is
22300+
// to say we should insert fences for them, and the fence insertion code
22301+
// will just not insert any fences
22302+
auto *LI = dyn_cast<LoadInst>(I);
22303+
auto *SI = dyn_cast<StoreInst>(I);
22304+
if ((LI &&
22305+
(LI->getOrdering() == AtomicOrdering::SequentiallyConsistent)) ||
22306+
(SI &&
22307+
(SI->getOrdering() == AtomicOrdering::SequentiallyConsistent))) {
22308+
// Here, this is a load or store which is seq_cst, and needs a .aq or
22309+
// .rl therefore we shouldn't try to insert fences
22310+
return false;
22311+
}
22312+
// Here, we are a TSO inst that isn't a seq_cst load/store
22313+
return isa<LoadInst>(I) || isa<StoreInst>(I);
22314+
}
22315+
return false;
22316+
}
22317+
// Note that one specific case requires fence insertion for an
22318+
// AtomicCmpXchgInst but is handled via the RISCVZacasABIFix pass rather
22319+
// than this hook due to limitations in the interface here.
22320+
return isa<LoadInst>(I) || isa<StoreInst>(I);
22321+
}
22322+
2229422323
bool RISCVTargetLowering::fallBackToDAGISel(const Instruction &Inst) const {
2229522324

2229622325
// GISel support is in progress or complete for these opcodes.

llvm/lib/Target/RISCV/RISCVISelLowering.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -703,9 +703,8 @@ class RISCVTargetLowering : public TargetLowering {
703703
// Note that one specific case requires fence insertion for an
704704
// AtomicCmpXchgInst but is handled via the RISCVZacasABIFix pass rather
705705
// than this hook due to limitations in the interface here.
706-
bool shouldInsertFencesForAtomic(const Instruction *I) const override {
707-
return isa<LoadInst>(I) || isa<StoreInst>(I);
708-
}
706+
bool shouldInsertFencesForAtomic(const Instruction *I) const override;
707+
709708
Instruction *emitLeadingFence(IRBuilderBase &Builder, Instruction *Inst,
710709
AtomicOrdering Ord) const override;
711710
Instruction *emitTrailingFence(IRBuilderBase &Builder, Instruction *Inst,

llvm/lib/Target/RISCV/RISCVInstrInfoA.td

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -118,22 +118,65 @@ defm AMOMAXU_D : AMO_rr_aq_rl<0b11100, 0b011, "amomaxu.d">,
118118
// Pseudo-instructions and codegen patterns
119119
//===----------------------------------------------------------------------===//
120120

121+
let IsAtomic = 1 in {
122+
// An atomic load operation that does not need either acquire or release
123+
// semantics.
124+
class relaxed_load<PatFrags base>
125+
: PatFrag<(ops node:$ptr), (base node:$ptr)> {
126+
let IsAtomicOrderingAcquireOrStronger = 0;
127+
}
128+
129+
// A atomic load operation that actually needs acquire semantics.
130+
class acquiring_load<PatFrags base>
131+
: PatFrag<(ops node:$ptr), (base node:$ptr)> {
132+
let IsAtomicOrderingAcquire = 1;
133+
}
134+
135+
// An atomic load operation that needs sequential consistency.
136+
class seq_cst_load<PatFrags base>
137+
: PatFrag<(ops node:$ptr), (base node:$ptr)> {
138+
let IsAtomicOrderingSequentiallyConsistent = 1;
139+
}
140+
141+
// An atomic store operation that does not need either acquire or release
142+
// semantics.
143+
class relaxed_store<PatFrag base>
144+
: PatFrag<(ops node:$val, node:$ptr), (base node:$val, node:$ptr)> {
145+
let IsAtomicOrderingReleaseOrStronger = 0;
146+
}
147+
148+
// A store operation that actually needs release semantics.
149+
class releasing_store<PatFrag base>
150+
: PatFrag<(ops node:$val, node:$ptr), (base node:$val, node:$ptr)> {
151+
let IsAtomicOrderingRelease = 1;
152+
}
153+
154+
// A store operation that actually needs sequential consistency.
155+
class seq_cst_store<PatFrag base>
156+
: PatFrag<(ops node:$val, node:$ptr), (base node:$val, node:$ptr)> {
157+
let IsAtomicOrderingSequentiallyConsistent = 1;
158+
}
159+
} // IsAtomic = 1
160+
121161
// Atomic load/store are available under both +a and +force-atomics.
122162
// Fences will be inserted for atomic load/stores according to the logic in
123163
// RISCVTargetLowering::{emitLeadingFence,emitTrailingFence}.
164+
// The normal loads/stores are relaxed (unordered) loads/stores that don't have
165+
// any ordering. This is necessary because AtomicExpandPass has added fences to
166+
// atomic load/stores and changed them to unordered ones.
124167
let Predicates = [HasAtomicLdSt] in {
125-
def : LdPat<atomic_load_8, LB>;
126-
def : LdPat<atomic_load_16, LH>;
127-
def : LdPat<atomic_load_32, LW>;
168+
def : LdPat<relaxed_load<atomic_load_8>, LB>;
169+
def : LdPat<relaxed_load<atomic_load_16>, LH>;
170+
def : LdPat<relaxed_load<atomic_load_32>, LW>;
128171

129-
def : StPat<atomic_store_8, SB, GPR, XLenVT>;
130-
def : StPat<atomic_store_16, SH, GPR, XLenVT>;
131-
def : StPat<atomic_store_32, SW, GPR, XLenVT>;
172+
def : StPat<relaxed_store<atomic_store_8>, SB, GPR, XLenVT>;
173+
def : StPat<relaxed_store<atomic_store_16>, SH, GPR, XLenVT>;
174+
def : StPat<relaxed_store<atomic_store_32>, SW, GPR, XLenVT>;
132175
}
133176

134177
let Predicates = [HasAtomicLdSt, IsRV64] in {
135-
def : LdPat<atomic_load_64, LD, i64>;
136-
def : StPat<atomic_store_64, SD, GPR, i64>;
178+
def : LdPat<relaxed_load<atomic_load_64>, LD, i64>;
179+
def : StPat<relaxed_store<atomic_store_64>, SD, GPR, i64>;
137180
}
138181

139182
/// AMOs
@@ -386,3 +429,14 @@ def : Pat<(int_riscv_masked_cmpxchg_i64
386429
(PseudoMaskedCmpXchg32
387430
GPR:$addr, GPR:$cmpval, GPR:$newval, GPR:$mask, timm:$ordering)>;
388431
} // Predicates = [HasStdExtA, IsRV64]
432+
433+
let Predicates = [HasAtomicLdSt] in {
434+
def : LdPat<relaxed_load<atomic_load_8>, LB, i32>;
435+
def : LdPat<relaxed_load<atomic_load_16>, LH, i32>;
436+
def : LdPat<relaxed_load<atomic_load_32>, LW, i32>;
437+
438+
def : StPat<relaxed_store<atomic_store_8>, SB, GPR, i32>;
439+
def : StPat<relaxed_store<atomic_store_16>, SH, GPR, i32>;
440+
def : StPat<relaxed_store<atomic_store_32>, SW, GPR, i32>;
441+
}
442+

llvm/lib/Target/RISCV/RISCVInstrInfoZalasr.td

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,50 @@ let Predicates = [HasStdExtZalasr, IsRV64] in {
5757
defm LD : LAQ_r_aq_rl<0b011, "ld">;
5858
defm SD : SRL_r_aq_rl<0b011, "sd">;
5959
} // Predicates = [HasStdExtZalasr, IsRV64]
60+
61+
//===----------------------------------------------------------------------===//
62+
// Pseudo-instructions and codegen patterns
63+
//===----------------------------------------------------------------------===//
64+
65+
class PatLAQ<SDPatternOperator OpNode, RVInst Inst, ValueType vt = XLenVT>
66+
: Pat<(vt (OpNode (vt GPRMemZeroOffset:$rs1))), (Inst GPRMemZeroOffset:$rs1)>;
67+
68+
// n.b. this switches order of arguments
69+
// to deal with the fact that SRL has addr, data
70+
// while atomic_store has data, addr
71+
class PatSRL<SDPatternOperator OpNode, RVInst Inst, ValueType vt = XLenVT>
72+
: Pat<(OpNode (vt GPR:$rs2), (vt GPRMemZeroOffset:$rs1)),
73+
(Inst GPRMemZeroOffset:$rs1, GPR:$rs2)>;
74+
75+
76+
let Predicates = [HasStdExtZalasr] in {
77+
// the sequentially consistent loads use
78+
// .aq instead of .aqrl to match the psABI/A.7
79+
def : PatLAQ<acquiring_load<atomic_load_8>, LB_AQ>;
80+
def : PatLAQ<seq_cst_load<atomic_load_8>, LB_AQ>;
81+
82+
def : PatLAQ<acquiring_load<atomic_load_16>, LH_AQ>;
83+
def : PatLAQ<seq_cst_load<atomic_load_16>, LH_AQ>;
84+
85+
def : PatLAQ<acquiring_load<atomic_load_32>, LW_AQ>;
86+
def : PatLAQ<seq_cst_load<atomic_load_32>, LW_AQ>;
87+
88+
// the sequentially consistent stores use
89+
// .rl instead of .aqrl to match the psABI/A.7
90+
def : PatSRL<releasing_store<atomic_store_8>, SB_RL>;
91+
def : PatSRL<seq_cst_store<atomic_store_8>, SB_RL>;
92+
93+
def : PatSRL<releasing_store<atomic_store_16>, SH_RL>;
94+
def : PatSRL<seq_cst_store<atomic_store_16>, SH_RL>;
95+
96+
def : PatSRL<releasing_store<atomic_store_32>, SW_RL>;
97+
def : PatSRL<seq_cst_store<atomic_store_32>, SW_RL>;
98+
} // Predicates = [HasStdExtZalasr]
99+
100+
let Predicates = [HasStdExtZalasr, IsRV64] in {
101+
def : PatLAQ<acquiring_load<atomic_load_64>, LD_AQ>;
102+
def : PatLAQ<seq_cst_load<atomic_load_64>, LD_AQ>;
103+
104+
def : PatSRL<releasing_store<atomic_store_64>, SD_RL>;
105+
def : PatSRL<seq_cst_store<atomic_store_64>, SD_RL>;
106+
} // Predicates = [HasStdExtZalasr, IsRV64]

0 commit comments

Comments
 (0)