30#define DEBUG_TYPE "loongarch-memory-barrier-opt"
31#define LOONGARCH_MEMORY_BARRIER_OPT_NAME \
32 "LoongArch Memory Barrier Optimisation pass"
35 "loongarch-require-no-path-bypass",
36 cl::desc(
"Optimize only when no paths bypass either memory barrier"),
40 "loongarch-merge-amo-with-dbar",
41 cl::desc(
"Merge AMOs with DBARs into AMO_DB during optimization"),
45 "loongarch-replace-eliminated-dbar-to-nop",
46 cl::desc(
"Replace eliminated DBARs with NOPs to preserve code layout"),
80 return MI.getOpcode() == LoongArch::DBAR;
84 switch (
MI.getOpcode()) {
94 switch (
MI.getOpcode()) {
105#define CASE(Name, Suffix) \
106 case LoongArch::Name##_##Suffix: \
107 if (!MergeAMOWithMB) \
108 return std::nullopt; \
110 case LoongArch::Name##__DB_##Suffix: \
111 return LoongArch::Name##__DB_##Suffix;
112 switch (
MI.getOpcode()) {
121 if (
MI.mayLoadOrStore())
123 if (
MI.isCall() ||
MI.isReturn())
125 if (
MI.isInlineAsm())
127 if (
MI.hasUnmodeledSideEffects())
133 BarrierHint(
unsigned Hint) : Hint(Hint) {}
135 bool subsumes(
const BarrierHint &O)
const {
return (Hint &
O.Hint) == Hint; }
137 BarrierHint
merge(
const BarrierHint &O)
const {
138 return BarrierHint(Hint &
O.Hint);
141 static inline bool isValid(
unsigned Hint) {
return (Hint & ~0x1f) == 0; }
147 InstBarrier(MachineInstr &MI)
148 : MI(&MI), Pre(0), Post(0), OpcAMDB(0), IsMB(
false), IsAM(
false) {
150 unsigned Hint = MI.getOperand(0).getImm();
151 if (!BarrierHint::isValid(Hint))
154 Pre = Post = BarrierHint(Hint);
155 }
else if (isLL(MI)) {
157 Pre = BarrierHint(0b10000);
158 Post = BarrierHint(0b11111);
159 }
else if (isSC(MI)) {
161 Pre = BarrierHint(0b11111);
162 Post = BarrierHint(0b10000);
163 }
else if (
auto R = isAM(MI)) {
166 Pre = Post = BarrierHint(0b10000);
184 LoongArchMemoryBarrierOpt() : MachineFunctionPass(ID) {}
186 StringRef getPassName()
const override {
190 void getAnalysisUsage(AnalysisUsage &AU)
const override {
193 AU.
addRequired<MachinePostDominatorTreeWrapperPass>();
202 CandidateA = 1u << 0,
203 CandidateB = 1u << 1,
206 unsigned resolveBarrierRedundancy(
const MachineInstr *
A,
207 const MachineInstr *
B)
const;
208 bool eliminateRedundantBarrier(InstBarrier &IA, InstBarrier &IB)
const;
211 const MachineDominatorTree *MDT;
212 const MachinePostDominatorTree *MPDT;
226 while (!Worklist.
empty()) {
234 if (!isSafeToSkip(
MI))
241 if (Visited.
insert(Succ).second)
246 if (Visited.
insert(Pred).second)
256unsigned LoongArchMemoryBarrierOpt::resolveBarrierRedundancy(
258 const MachineBasicBlock *MBBA =
A->
getParent();
259 const MachineBasicBlock *MBBB =
B->
getParent();
263 for (
auto It = std::next(
A->getIterator()); It != MBBA->
end(); ++It) {
264 if (It ==
B->getIterator())
265 return CandidateA | CandidateB;
266 if (!isSafeToSkip(*It))
274 bool BPostDomA = MPDT->
dominates(MBBB, MBBA);
276 if (!ADomB && !BPostDomA)
280 for (
auto It = std::next(
A->getIterator()); It != MBBA->
end(); ++It)
281 if (!isSafeToSkip(*It))
284 for (
auto It = MBBB->
begin(); It !=
B->getIterator(); ++It)
285 if (!isSafeToSkip(*It))
290 if (checkAllPathSafe(MBBA, MBBB,
true ))
295 if (checkAllPathSafe(MBBA, MBBB,
false ))
302static void updateMB(InstBarrier &
I, BarrierHint Hint,
MachineFunction *MF) {
303 assert(
I.IsMB &&
"Unexpected!");
305 I.MI->getOperand(0).setImm(
Hint.Hint);
314 I.MI->setDesc(
ST.getInstrInfo()->get(
I.OpcAMDB));
318bool LoongArchMemoryBarrierOpt::eliminateRedundantBarrier(
319 InstBarrier &IA, InstBarrier &IB)
const {
320 MachineInstr *
A =
IA.MI;
321 MachineInstr *
B =
IB.MI;
328 unsigned Mask = resolveBarrierRedundancy(
A,
B);
332 auto eraseOrReplaceWithNop = [&](MachineInstr *
MI) {
335 BuildMI(*
MI->getParent(),
MI->getIterator(),
MI->getDebugLoc(),
336 ST.getInstrInfo()->get(LoongArch::ANDI), LoongArch::R0)
340 MI->eraseFromParent();
348 if ((Mask & CandidateA) &&
IA.IsMB) {
349 if (!
IB.Pre.subsumes(
IA.Post)) {
352 updateMB(IB,
IB.Pre.merge(
IA.Post), MF);
355 eraseOrReplaceWithNop(
A);
365 if ((Mask & CandidateB) &&
IB.IsMB) {
366 if (!
IA.Post.subsumes(
IB.Pre)) {
369 updateMB(IA,
IA.Post.merge(
IB.Pre), MF);
372 eraseOrReplaceWithNop(
B);
380bool LoongArchMemoryBarrierOpt::runOnMachineFunction(
MachineFunction &Fn) {
385 MDT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
386 MPDT = &getAnalysis<MachinePostDominatorTreeWrapperPass>().getPostDomTree();
391 for (MachineBasicBlock &
MBB : Fn)
392 for (MachineInstr &
MI :
MBB) {
394 if (
IB.IsMB ||
IB.IsAM)
398 for (
size_t a = 0; a < Sites.
size(); ++a) {
399 for (
size_t b = a + 1;
b < Sites.
size(); ++
b) {
400 InstBarrier &
IA = Sites[a];
401 InstBarrier &
IB = Sites[
b];
402 Changed |= eliminateRedundantBarrier(IA, IB);
403 Changed |= eliminateRedundantBarrier(IB, IA);
411char LoongArchMemoryBarrierOpt::ID = 0;
420 return new LoongArchMemoryBarrierOpt();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static cl::opt< bool > RequireNoPathBypass("loongarch-require-no-path-bypass", cl::desc("Optimize only when no paths bypass either memory barrier"), cl::init(true), cl::Hidden)
#define LOONGARCH_MEMORY_BARRIER_OPT_NAME
static cl::opt< bool > ReplaceEliminatedMBToNop("loongarch-replace-eliminated-dbar-to-nop", cl::desc("Replace eliminated DBARs with NOPs to preserve code layout"), cl::init(false), cl::Hidden)
static cl::opt< bool > MergeAMOWithMB("loongarch-merge-amo-with-dbar", cl::desc("Merge AMOs with DBARs into AMO_DB during optimization"), cl::init(true), cl::Hidden)
static LoopDeletionResult merge(LoopDeletionResult A, LoopDeletionResult B)
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
Implements a dense probed hash-table based set.
bool dominates(const DomTreeNodeBase< NodeT > *A, const DomTreeNodeBase< NodeT > *B) const
dominates - Returns true iff A dominates B.
FunctionPass class - This class is used to implement most global optimizations.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
iterator_range< succ_iterator > successors()
iterator_range< pred_iterator > predecessors()
Analysis pass which computes a MachineDominatorTree.
bool dominates(const MachineInstr *A, const MachineInstr *B) const
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
Representation of each machine instruction.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
std::pair< iterator, bool > insert(const ValueT &V)
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
FunctionPass * createLoongArchMemoryBarrierOptPass()
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...