Skip to content

Commit bfe8a21

Browse files
authored
[RISCV][ISEL] Lowering to load-acquire/store-release for RISCV Zalasr (llvm#82914)
Lowering to load-acquire/store-release for RISCV Zalasr. Currently uses the psABI lowerings for WMO load-acquire/store-release (which are identical to A.7). These are incompatable with the A.6 lowerings currently used by LLVM. This should be OK for now since Zalasr is behind the enable experimental extensions flag, but needs to be fixed before it is removed from that. 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 300deeb commit bfe8a21

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)