Skip to content

Commit 5e69134

Browse files
author
Brendan Sweeney
committed
[RISCV][ISEL] Lowering to load-acquire/store-release for RISCV. (The Zalasr extension)
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 a8c3b3e commit 5e69134

File tree

5 files changed

+350
-18
lines changed

5 files changed

+350
-18
lines changed

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20832,6 +20832,32 @@ unsigned RISCVTargetLowering::getCustomCtpopCost(EVT VT,
2083220832
return isCtpopFast(VT) ? 0 : 1;
2083320833
}
2083420834

20835+
bool RISCVTargetLowering::shouldInsertFencesForAtomic(
20836+
const Instruction *I) const {
20837+
if (Subtarget.hasStdExtZalasr()) {
20838+
if (Subtarget.hasStdExtZtso()) {
20839+
// Zalasr + TSO means that atomic_load_acquire and atomic_store_release
20840+
// should be lowered to plain load/store. The easiest way to do this is
20841+
// to say we should insert fences for them, and the fence insertion code
20842+
// will just not insert any fences
20843+
auto LI = dyn_cast<LoadInst>(I);
20844+
auto SI = dyn_cast<StoreInst>(I);
20845+
if ((LI &&
20846+
(LI->getOrdering() == AtomicOrdering::SequentiallyConsistent)) ||
20847+
(SI &&
20848+
(SI->getOrdering() == AtomicOrdering::SequentiallyConsistent))) {
20849+
// Here, this is a load or store which is seq_cst, and needs a .aq or
20850+
// .rl therefore we shouldn't try to insert fences
20851+
return false;
20852+
}
20853+
// Here, we are a TSO inst that isn't a seq_cst load/store
20854+
return isa<LoadInst>(I) || isa<StoreInst>(I);
20855+
}
20856+
return false;
20857+
}
20858+
return isa<LoadInst>(I) || isa<StoreInst>(I);
20859+
}
20860+
2083520861
bool RISCVTargetLowering::fallBackToDAGISel(const Instruction &Inst) const {
2083620862

2083720863
// 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
@@ -650,9 +650,8 @@ class RISCVTargetLowering : public TargetLowering {
650650

651651
bool preferZeroCompareBranch() const override { return true; }
652652

653-
bool shouldInsertFencesForAtomic(const Instruction *I) const override {
654-
return isa<LoadInst>(I) || isa<StoreInst>(I);
655-
}
653+
bool shouldInsertFencesForAtomic(const Instruction *I) const override;
654+
656655
Instruction *emitLeadingFence(IRBuilderBase &Builder, Instruction *Inst,
657656
AtomicOrdering Ord) const override;
658657
Instruction *emitTrailingFence(IRBuilderBase &Builder, Instruction *Inst,

llvm/lib/Target/RISCV/RISCVInstrInfoA.td

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -105,22 +105,65 @@ defm AMOMAXU_D : AMO_rr_aq_rl<0b11100, 0b011, "amomaxu.d">,
105105
// Pseudo-instructions and codegen patterns
106106
//===----------------------------------------------------------------------===//
107107

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

116-
def : StPat<atomic_store_8, SB, GPR, XLenVT>;
117-
def : StPat<atomic_store_16, SH, GPR, XLenVT>;
118-
def : StPat<atomic_store_32, SW, GPR, XLenVT>;
159+
def : StPat<relaxed_store<atomic_store_8>, SB, GPR, XLenVT>;
160+
def : StPat<relaxed_store<atomic_store_16>, SH, GPR, XLenVT>;
161+
def : StPat<relaxed_store<atomic_store_32>, SW, GPR, XLenVT>;
119162
}
120163

121164
let Predicates = [HasAtomicLdSt, IsRV64] in {
122-
def : LdPat<atomic_load_64, LD, i64>;
123-
def : StPat<atomic_store_64, SD, GPR, i64>;
165+
def : LdPat<relaxed_load<atomic_load_64>, LD, i64>;
166+
def : StPat<relaxed_store<atomic_store_64>, SD, GPR, i64>;
124167
}
125168

126169
/// AMOs
@@ -423,12 +466,12 @@ let Predicates = [HasStdExtA, IsRV64] in
423466
defm : PseudoCmpXchgPat<"atomic_cmp_swap_32", PseudoCmpXchg32, i32>;
424467

425468
let Predicates = [HasAtomicLdSt] in {
426-
def : LdPat<atomic_load_8, LB, i32>;
427-
def : LdPat<atomic_load_16, LH, i32>;
428-
def : LdPat<atomic_load_32, LW, i32>;
469+
def : LdPat<relaxed_load<atomic_load_8>, LB, i32>;
470+
def : LdPat<relaxed_load<atomic_load_16>, LH, i32>;
471+
def : LdPat<relaxed_load<atomic_load_32>, LW, i32>;
429472

430-
def : StPat<atomic_store_8, SB, GPR, i32>;
431-
def : StPat<atomic_store_16, SH, GPR, i32>;
432-
def : StPat<atomic_store_32, SW, GPR, i32>;
473+
def : StPat<relaxed_store<atomic_store_8>, SB, GPR, i32>;
474+
def : StPat<relaxed_store<atomic_store_16>, SH, GPR, i32>;
475+
def : StPat<relaxed_store<atomic_store_32>, SW, GPR, i32>;
433476
}
434477

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)