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-disable-inline-asm-barrier-opt",
46 cl::desc(
"Disable optimization of memory barriers in InlineAsm"),
50 "loongarch-replace-eliminated-dbar-to-nop",
51 cl::desc(
"Replace eliminated DBARs with NOPs to preserve code layout"),
84static std::optional<std::pair<StringRef, StringRef>> parseMB(
StringRef Asm) {
86 if (!
T1.first.equals_insensitive(
"dbar"))
92 if (T3.first.trim().empty() || T3.first.starts_with(
'#'))
93 return std::pair(
T1.first, T2.first);
97static std::optional<std::pair<StringRef, StringRef>>
101 if (!
MI.isInlineAsm())
108#define CASE(Name, Suffix) \
109 .Case(#Name "." #Suffix, MergeAMOWithMB ? #Name "_DB." #Suffix : "") \
110 .Case(#Name "_DB." #Suffix, #Name "_DB." #Suffix)
115static std::optional<std::pair<StringRef, StringRef>> parseAM(
StringRef Asm) {
121 if (T2.first.empty())
124 if (T3.first.empty())
127 if (T4.first.empty())
130 if (T5.first.trim().empty() || T5.first.starts_with(
'#')) {
132 T4.first.data() + T4.first.size() - T2.first.data());
138static std::optional<std::pair<StringRef, StringRef>>
142 if (!
MI.isInlineAsm())
149 return MI.getOpcode() == LoongArch::DBAR;
153 switch (
MI.getOpcode()) {
154 case LoongArch::LL_W:
155 case LoongArch::LL_D:
163 switch (
MI.getOpcode()) {
164 case LoongArch::SC_W:
165 case LoongArch::SC_D:
166 case LoongArch::SC_Q:
174#define CASE(Name, Suffix) \
175 case LoongArch::Name##_##Suffix: \
176 if (!MergeAMOWithMB) \
177 return std::nullopt; \
179 case LoongArch::Name##__DB_##Suffix: \
180 return LoongArch::Name##__DB_##Suffix;
181 switch (
MI.getOpcode()) {
190 if (
MI.mayLoadOrStore())
192 if (
MI.isCall() ||
MI.isReturn())
194 if (
MI.isInlineAsm())
195 return isAsmMB(
MI) != std::nullopt;
196 if (
MI.hasUnmodeledSideEffects())
202 BarrierHint(
unsigned Hint) : Hint(Hint) {}
204 bool subsumes(
const BarrierHint &O)
const {
return (Hint &
O.Hint) == Hint; }
206 BarrierHint
merge(
const BarrierHint &O)
const {
207 return BarrierHint(Hint &
O.Hint);
210 static inline bool isValid(
unsigned Hint) {
return (Hint & ~0x1f) == 0; }
216 InstBarrier(MachineInstr &MI)
220 unsigned Hint = MI.getOperand(0).getImm();
221 if (!BarrierHint::isValid(Hint))
224 Pre = Post = BarrierHint(Hint);
225 }
else if (isLL(MI)) {
227 Pre = BarrierHint(0b10000);
228 Post = BarrierHint(0b11111);
229 }
else if (isSC(MI)) {
231 Pre = BarrierHint(0b11111);
232 Post = BarrierHint(0b10000);
233 }
else if (
auto R = isAM(MI)) {
236 Pre = Post = BarrierHint(0b10000);
237 }
else if (
auto R = isAsmMB(MI)) {
239 Operands = (*R).second;
240 auto B = parseAsmMB(Operands, MI);
241 if (!
B || !BarrierHint::isValid((*B).first))
245 HintOff = (*B).second;
246 Pre = Post = BarrierHint((*B).first);
247 }
else if (
auto R = isAsmAM(MI)) {
249 Operands = (*R).second;
252 Pre = Post = BarrierHint(0b10000);
256 static std::optional<std::pair<unsigned, unsigned>>
257 parseAsmMB(StringRef Operand, MachineInstr &MI) {
258 unsigned Hint, HintOff = 0;
263 return std::pair(Hint, HintOff);
266 unsigned N = 0,
Off, AsmDescOp;
270 while (AsmDescOp != MI.getNumOperands()) {
271 const MachineOperand &MO = MI.getOperand(AsmDescOp);
273 const InlineAsm::Flag
F(MO.
getImm());
277 HintOff = AsmDescOp + 1;
278 Hint = MI.getOperand(HintOff).getImm();
279 return std::pair(Hint, HintOff);
281 AsmDescOp += 1 +
F.getNumOperandRegisters();
306 LoongArchMemoryBarrierOpt() : MachineFunctionPass(ID) {}
308 StringRef getPassName()
const override {
312 void getAnalysisUsage(AnalysisUsage &AU)
const override {
315 AU.
addRequired<MachinePostDominatorTreeWrapperPass>();
324 CandidateA = 1u << 0,
325 CandidateB = 1u << 1,
328 unsigned resolveBarrierRedundancy(
const MachineInstr *
A,
329 const MachineInstr *
B)
const;
330 bool eliminateRedundantBarrier(InstBarrier &IA, InstBarrier &IB)
const;
333 const MachineDominatorTree *MDT;
334 const MachinePostDominatorTree *MPDT;
348 while (!Worklist.
empty()) {
356 if (!isSafeToSkip(
MI))
363 if (Visited.
insert(Succ).second)
368 if (Visited.
insert(Pred).second)
378unsigned LoongArchMemoryBarrierOpt::resolveBarrierRedundancy(
380 const MachineBasicBlock *MBBA =
A->
getParent();
381 const MachineBasicBlock *MBBB =
B->
getParent();
385 for (
auto It = std::next(
A->getIterator()); It != MBBA->
end(); ++It) {
386 if (It ==
B->getIterator())
387 return CandidateA | CandidateB;
388 if (!isSafeToSkip(*It))
396 bool BPostDomA = MPDT->
dominates(MBBB, MBBA);
398 if (!ADomB && !BPostDomA)
402 for (
auto It = std::next(
A->getIterator()); It != MBBA->
end(); ++It)
403 if (!isSafeToSkip(*It))
406 for (
auto It = MBBB->
begin(); It !=
B->getIterator(); ++It)
407 if (!isSafeToSkip(*It))
412 if (checkAllPathSafe(MBBA, MBBB,
true ))
417 if (checkAllPathSafe(MBBA, MBBB,
false ))
424static void updateMB(InstBarrier &
I, BarrierHint Hint,
MachineFunction *MF) {
425 assert(
I.IsMB &&
"Unexpected!");
428 I.MI->getOperand(0).setImm(
Hint.Hint);
432 I.MI->getOperand(
I.HintOff).setImm(
Hint.Hint);
446 I.MI->setDesc(
ST.getInstrInfo()->get(
I.OpcAMDB));
452 auto New =
I.OpName.str() +
" " +
I.Operands.str();
456bool LoongArchMemoryBarrierOpt::eliminateRedundantBarrier(
457 InstBarrier &IA, InstBarrier &IB)
const {
458 MachineInstr *
A =
IA.MI;
459 MachineInstr *
B =
IB.MI;
466 unsigned Mask = resolveBarrierRedundancy(
A,
B);
470 auto eraseOrReplaceWithNop = [&](MachineInstr *
MI) {
473 BuildMI(*
MI->getParent(),
MI->getIterator(),
MI->getDebugLoc(),
474 ST.getInstrInfo()->get(LoongArch::ANDI), LoongArch::R0)
478 MI->eraseFromParent();
486 if ((Mask & CandidateA) &&
IA.IsMB) {
487 if (!
IB.Pre.subsumes(
IA.Post)) {
490 updateMB(IB,
IB.Pre.merge(
IA.Post), MF);
493 eraseOrReplaceWithNop(
A);
503 if ((Mask & CandidateB) &&
IB.IsMB) {
504 if (!
IA.Post.subsumes(
IB.Pre)) {
507 updateMB(IA,
IA.Post.merge(
IB.Pre), MF);
510 eraseOrReplaceWithNop(
B);
518bool LoongArchMemoryBarrierOpt::runOnMachineFunction(
MachineFunction &Fn) {
523 MDT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
524 MPDT = &getAnalysis<MachinePostDominatorTreeWrapperPass>().getPostDomTree();
529 for (MachineBasicBlock &
MBB : Fn)
530 for (MachineInstr &
MI :
MBB) {
532 if (
IB.IsMB ||
IB.IsAM)
536 for (
size_t a = 0; a < Sites.
size(); ++a) {
537 for (
size_t b = a + 1;
b < Sites.
size(); ++
b) {
538 InstBarrier &
IA = Sites[a];
539 InstBarrier &
IB = Sites[
b];
540 Changed |= eliminateRedundantBarrier(IA, IB);
541 Changed |= eliminateRedundantBarrier(IB, IA);
549char LoongArchMemoryBarrierOpt::ID = 0;
558 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)
static cl::opt< bool > DisableInlineAsm("loongarch-disable-inline-asm-barrier-opt", cl::desc("Disable optimization of memory barriers in InlineAsm"), cl::init(false), 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.
const char * createExternalSymbolName(StringRef Name)
Allocate a string and populate it with the given external symbol name.
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.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
LLVM_ABI void ChangeToES(const char *SymName, unsigned TargetFlags=0)
ChangeToES - Replace this operand with a new external symbol operand.
unsigned getTargetFlags() const
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
A switch()-like statement whose cases are string literals.
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.
LLVM_ABI std::pair< StringRef, StringRef > getToken(StringRef Source, StringRef Delimiters=" \t\n\v\f\r")
getToken - This function extracts one token from source, ignoring any leading characters that appear ...
FunctionPass * createLoongArchMemoryBarrierOptPass()
std::string utostr(uint64_t X, bool isNeg=false)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...