xref: /aosp_15_r20/external/llvm/lib/Transforms/Scalar/LowerAtomic.cpp (revision 9880d6810fe72a1726cb53787c6711e909410d58)
1*9880d681SAndroid Build Coastguard Worker //===- LowerAtomic.cpp - Lower atomic intrinsics --------------------------===//
2*9880d681SAndroid Build Coastguard Worker //
3*9880d681SAndroid Build Coastguard Worker //                     The LLVM Compiler Infrastructure
4*9880d681SAndroid Build Coastguard Worker //
5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*9880d681SAndroid Build Coastguard Worker //
8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*9880d681SAndroid Build Coastguard Worker //
10*9880d681SAndroid Build Coastguard Worker // This pass lowers atomic intrinsics to non-atomic form for use in a known
11*9880d681SAndroid Build Coastguard Worker // non-preemptible environment.
12*9880d681SAndroid Build Coastguard Worker //
13*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
14*9880d681SAndroid Build Coastguard Worker 
15*9880d681SAndroid Build Coastguard Worker #include "llvm/Transforms/Scalar/LowerAtomic.h"
16*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/Function.h"
17*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/IRBuilder.h"
18*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/IntrinsicInst.h"
19*9880d681SAndroid Build Coastguard Worker #include "llvm/Pass.h"
20*9880d681SAndroid Build Coastguard Worker #include "llvm/Transforms/Scalar.h"
21*9880d681SAndroid Build Coastguard Worker using namespace llvm;
22*9880d681SAndroid Build Coastguard Worker 
23*9880d681SAndroid Build Coastguard Worker #define DEBUG_TYPE "loweratomic"
24*9880d681SAndroid Build Coastguard Worker 
LowerAtomicCmpXchgInst(AtomicCmpXchgInst * CXI)25*9880d681SAndroid Build Coastguard Worker static bool LowerAtomicCmpXchgInst(AtomicCmpXchgInst *CXI) {
26*9880d681SAndroid Build Coastguard Worker   IRBuilder<> Builder(CXI);
27*9880d681SAndroid Build Coastguard Worker   Value *Ptr = CXI->getPointerOperand();
28*9880d681SAndroid Build Coastguard Worker   Value *Cmp = CXI->getCompareOperand();
29*9880d681SAndroid Build Coastguard Worker   Value *Val = CXI->getNewValOperand();
30*9880d681SAndroid Build Coastguard Worker 
31*9880d681SAndroid Build Coastguard Worker   LoadInst *Orig = Builder.CreateLoad(Ptr);
32*9880d681SAndroid Build Coastguard Worker   Value *Equal = Builder.CreateICmpEQ(Orig, Cmp);
33*9880d681SAndroid Build Coastguard Worker   Value *Res = Builder.CreateSelect(Equal, Val, Orig);
34*9880d681SAndroid Build Coastguard Worker   Builder.CreateStore(Res, Ptr);
35*9880d681SAndroid Build Coastguard Worker 
36*9880d681SAndroid Build Coastguard Worker   Res = Builder.CreateInsertValue(UndefValue::get(CXI->getType()), Orig, 0);
37*9880d681SAndroid Build Coastguard Worker   Res = Builder.CreateInsertValue(Res, Equal, 1);
38*9880d681SAndroid Build Coastguard Worker 
39*9880d681SAndroid Build Coastguard Worker   CXI->replaceAllUsesWith(Res);
40*9880d681SAndroid Build Coastguard Worker   CXI->eraseFromParent();
41*9880d681SAndroid Build Coastguard Worker   return true;
42*9880d681SAndroid Build Coastguard Worker }
43*9880d681SAndroid Build Coastguard Worker 
LowerAtomicRMWInst(AtomicRMWInst * RMWI)44*9880d681SAndroid Build Coastguard Worker static bool LowerAtomicRMWInst(AtomicRMWInst *RMWI) {
45*9880d681SAndroid Build Coastguard Worker   IRBuilder<> Builder(RMWI);
46*9880d681SAndroid Build Coastguard Worker   Value *Ptr = RMWI->getPointerOperand();
47*9880d681SAndroid Build Coastguard Worker   Value *Val = RMWI->getValOperand();
48*9880d681SAndroid Build Coastguard Worker 
49*9880d681SAndroid Build Coastguard Worker   LoadInst *Orig = Builder.CreateLoad(Ptr);
50*9880d681SAndroid Build Coastguard Worker   Value *Res = nullptr;
51*9880d681SAndroid Build Coastguard Worker 
52*9880d681SAndroid Build Coastguard Worker   switch (RMWI->getOperation()) {
53*9880d681SAndroid Build Coastguard Worker   default: llvm_unreachable("Unexpected RMW operation");
54*9880d681SAndroid Build Coastguard Worker   case AtomicRMWInst::Xchg:
55*9880d681SAndroid Build Coastguard Worker     Res = Val;
56*9880d681SAndroid Build Coastguard Worker     break;
57*9880d681SAndroid Build Coastguard Worker   case AtomicRMWInst::Add:
58*9880d681SAndroid Build Coastguard Worker     Res = Builder.CreateAdd(Orig, Val);
59*9880d681SAndroid Build Coastguard Worker     break;
60*9880d681SAndroid Build Coastguard Worker   case AtomicRMWInst::Sub:
61*9880d681SAndroid Build Coastguard Worker     Res = Builder.CreateSub(Orig, Val);
62*9880d681SAndroid Build Coastguard Worker     break;
63*9880d681SAndroid Build Coastguard Worker   case AtomicRMWInst::And:
64*9880d681SAndroid Build Coastguard Worker     Res = Builder.CreateAnd(Orig, Val);
65*9880d681SAndroid Build Coastguard Worker     break;
66*9880d681SAndroid Build Coastguard Worker   case AtomicRMWInst::Nand:
67*9880d681SAndroid Build Coastguard Worker     Res = Builder.CreateNot(Builder.CreateAnd(Orig, Val));
68*9880d681SAndroid Build Coastguard Worker     break;
69*9880d681SAndroid Build Coastguard Worker   case AtomicRMWInst::Or:
70*9880d681SAndroid Build Coastguard Worker     Res = Builder.CreateOr(Orig, Val);
71*9880d681SAndroid Build Coastguard Worker     break;
72*9880d681SAndroid Build Coastguard Worker   case AtomicRMWInst::Xor:
73*9880d681SAndroid Build Coastguard Worker     Res = Builder.CreateXor(Orig, Val);
74*9880d681SAndroid Build Coastguard Worker     break;
75*9880d681SAndroid Build Coastguard Worker   case AtomicRMWInst::Max:
76*9880d681SAndroid Build Coastguard Worker     Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Val),
77*9880d681SAndroid Build Coastguard Worker                                Val, Orig);
78*9880d681SAndroid Build Coastguard Worker     break;
79*9880d681SAndroid Build Coastguard Worker   case AtomicRMWInst::Min:
80*9880d681SAndroid Build Coastguard Worker     Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Val),
81*9880d681SAndroid Build Coastguard Worker                                Orig, Val);
82*9880d681SAndroid Build Coastguard Worker     break;
83*9880d681SAndroid Build Coastguard Worker   case AtomicRMWInst::UMax:
84*9880d681SAndroid Build Coastguard Worker     Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Val),
85*9880d681SAndroid Build Coastguard Worker                                Val, Orig);
86*9880d681SAndroid Build Coastguard Worker     break;
87*9880d681SAndroid Build Coastguard Worker   case AtomicRMWInst::UMin:
88*9880d681SAndroid Build Coastguard Worker     Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Val),
89*9880d681SAndroid Build Coastguard Worker                                Orig, Val);
90*9880d681SAndroid Build Coastguard Worker     break;
91*9880d681SAndroid Build Coastguard Worker   }
92*9880d681SAndroid Build Coastguard Worker   Builder.CreateStore(Res, Ptr);
93*9880d681SAndroid Build Coastguard Worker   RMWI->replaceAllUsesWith(Orig);
94*9880d681SAndroid Build Coastguard Worker   RMWI->eraseFromParent();
95*9880d681SAndroid Build Coastguard Worker   return true;
96*9880d681SAndroid Build Coastguard Worker }
97*9880d681SAndroid Build Coastguard Worker 
LowerFenceInst(FenceInst * FI)98*9880d681SAndroid Build Coastguard Worker static bool LowerFenceInst(FenceInst *FI) {
99*9880d681SAndroid Build Coastguard Worker   FI->eraseFromParent();
100*9880d681SAndroid Build Coastguard Worker   return true;
101*9880d681SAndroid Build Coastguard Worker }
102*9880d681SAndroid Build Coastguard Worker 
LowerLoadInst(LoadInst * LI)103*9880d681SAndroid Build Coastguard Worker static bool LowerLoadInst(LoadInst *LI) {
104*9880d681SAndroid Build Coastguard Worker   LI->setAtomic(AtomicOrdering::NotAtomic);
105*9880d681SAndroid Build Coastguard Worker   return true;
106*9880d681SAndroid Build Coastguard Worker }
107*9880d681SAndroid Build Coastguard Worker 
LowerStoreInst(StoreInst * SI)108*9880d681SAndroid Build Coastguard Worker static bool LowerStoreInst(StoreInst *SI) {
109*9880d681SAndroid Build Coastguard Worker   SI->setAtomic(AtomicOrdering::NotAtomic);
110*9880d681SAndroid Build Coastguard Worker   return true;
111*9880d681SAndroid Build Coastguard Worker }
112*9880d681SAndroid Build Coastguard Worker 
runOnBasicBlock(BasicBlock & BB)113*9880d681SAndroid Build Coastguard Worker static bool runOnBasicBlock(BasicBlock &BB) {
114*9880d681SAndroid Build Coastguard Worker   bool Changed = false;
115*9880d681SAndroid Build Coastguard Worker   for (BasicBlock::iterator DI = BB.begin(), DE = BB.end(); DI != DE;) {
116*9880d681SAndroid Build Coastguard Worker     Instruction *Inst = &*DI++;
117*9880d681SAndroid Build Coastguard Worker     if (FenceInst *FI = dyn_cast<FenceInst>(Inst))
118*9880d681SAndroid Build Coastguard Worker       Changed |= LowerFenceInst(FI);
119*9880d681SAndroid Build Coastguard Worker     else if (AtomicCmpXchgInst *CXI = dyn_cast<AtomicCmpXchgInst>(Inst))
120*9880d681SAndroid Build Coastguard Worker       Changed |= LowerAtomicCmpXchgInst(CXI);
121*9880d681SAndroid Build Coastguard Worker     else if (AtomicRMWInst *RMWI = dyn_cast<AtomicRMWInst>(Inst))
122*9880d681SAndroid Build Coastguard Worker       Changed |= LowerAtomicRMWInst(RMWI);
123*9880d681SAndroid Build Coastguard Worker     else if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) {
124*9880d681SAndroid Build Coastguard Worker       if (LI->isAtomic())
125*9880d681SAndroid Build Coastguard Worker         LowerLoadInst(LI);
126*9880d681SAndroid Build Coastguard Worker     } else if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) {
127*9880d681SAndroid Build Coastguard Worker       if (SI->isAtomic())
128*9880d681SAndroid Build Coastguard Worker         LowerStoreInst(SI);
129*9880d681SAndroid Build Coastguard Worker     }
130*9880d681SAndroid Build Coastguard Worker   }
131*9880d681SAndroid Build Coastguard Worker   return Changed;
132*9880d681SAndroid Build Coastguard Worker }
133*9880d681SAndroid Build Coastguard Worker 
lowerAtomics(Function & F)134*9880d681SAndroid Build Coastguard Worker static bool lowerAtomics(Function &F) {
135*9880d681SAndroid Build Coastguard Worker   bool Changed = false;
136*9880d681SAndroid Build Coastguard Worker   for (BasicBlock &BB : F) {
137*9880d681SAndroid Build Coastguard Worker     Changed |= runOnBasicBlock(BB);
138*9880d681SAndroid Build Coastguard Worker   }
139*9880d681SAndroid Build Coastguard Worker   return Changed;
140*9880d681SAndroid Build Coastguard Worker }
141*9880d681SAndroid Build Coastguard Worker 
run(Function & F,FunctionAnalysisManager &)142*9880d681SAndroid Build Coastguard Worker PreservedAnalyses LowerAtomicPass::run(Function &F, FunctionAnalysisManager &) {
143*9880d681SAndroid Build Coastguard Worker   if (lowerAtomics(F))
144*9880d681SAndroid Build Coastguard Worker     return PreservedAnalyses::none();
145*9880d681SAndroid Build Coastguard Worker   return PreservedAnalyses::all();
146*9880d681SAndroid Build Coastguard Worker }
147*9880d681SAndroid Build Coastguard Worker 
148*9880d681SAndroid Build Coastguard Worker namespace {
149*9880d681SAndroid Build Coastguard Worker class LowerAtomicLegacyPass : public FunctionPass {
150*9880d681SAndroid Build Coastguard Worker public:
151*9880d681SAndroid Build Coastguard Worker   static char ID;
152*9880d681SAndroid Build Coastguard Worker 
LowerAtomicLegacyPass()153*9880d681SAndroid Build Coastguard Worker   LowerAtomicLegacyPass() : FunctionPass(ID) {
154*9880d681SAndroid Build Coastguard Worker     initializeLowerAtomicLegacyPassPass(*PassRegistry::getPassRegistry());
155*9880d681SAndroid Build Coastguard Worker   }
156*9880d681SAndroid Build Coastguard Worker 
runOnFunction(Function & F)157*9880d681SAndroid Build Coastguard Worker   bool runOnFunction(Function &F) override {
158*9880d681SAndroid Build Coastguard Worker     if (skipFunction(F))
159*9880d681SAndroid Build Coastguard Worker       return false;
160*9880d681SAndroid Build Coastguard Worker     FunctionAnalysisManager DummyFAM;
161*9880d681SAndroid Build Coastguard Worker     auto PA = Impl.run(F, DummyFAM);
162*9880d681SAndroid Build Coastguard Worker     return !PA.areAllPreserved();
163*9880d681SAndroid Build Coastguard Worker   }
164*9880d681SAndroid Build Coastguard Worker 
165*9880d681SAndroid Build Coastguard Worker private:
166*9880d681SAndroid Build Coastguard Worker   LowerAtomicPass Impl;
167*9880d681SAndroid Build Coastguard Worker   };
168*9880d681SAndroid Build Coastguard Worker }
169*9880d681SAndroid Build Coastguard Worker 
170*9880d681SAndroid Build Coastguard Worker char LowerAtomicLegacyPass::ID = 0;
171*9880d681SAndroid Build Coastguard Worker INITIALIZE_PASS(LowerAtomicLegacyPass, "loweratomic",
172*9880d681SAndroid Build Coastguard Worker                 "Lower atomic intrinsics to non-atomic form", false, false)
173*9880d681SAndroid Build Coastguard Worker 
createLowerAtomicPass()174*9880d681SAndroid Build Coastguard Worker Pass *llvm::createLowerAtomicPass() { return new LowerAtomicLegacyPass(); }
175