1 //===- LowerAtomic.cpp - Lower atomic intrinsics --------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This pass lowers atomic intrinsics to non-atomic form for use in a known
10 // non-preemptible environment.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/Transforms/Scalar/LowerAtomic.h"
15 #include "llvm/IR/Function.h"
16 #include "llvm/IR/IRBuilder.h"
17 #include "llvm/Pass.h"
18 #include "llvm/Transforms/Scalar.h"
21 #define DEBUG_TYPE "loweratomic"
23 static bool LowerAtomicCmpXchgInst(AtomicCmpXchgInst
*CXI
) {
24 IRBuilder
<> Builder(CXI
);
25 Value
*Ptr
= CXI
->getPointerOperand();
26 Value
*Cmp
= CXI
->getCompareOperand();
27 Value
*Val
= CXI
->getNewValOperand();
29 LoadInst
*Orig
= Builder
.CreateLoad(Val
->getType(), Ptr
);
30 Value
*Equal
= Builder
.CreateICmpEQ(Orig
, Cmp
);
31 Value
*Res
= Builder
.CreateSelect(Equal
, Val
, Orig
);
32 Builder
.CreateStore(Res
, Ptr
);
34 Res
= Builder
.CreateInsertValue(UndefValue::get(CXI
->getType()), Orig
, 0);
35 Res
= Builder
.CreateInsertValue(Res
, Equal
, 1);
37 CXI
->replaceAllUsesWith(Res
);
38 CXI
->eraseFromParent();
42 static bool LowerAtomicRMWInst(AtomicRMWInst
*RMWI
) {
43 IRBuilder
<> Builder(RMWI
);
44 Value
*Ptr
= RMWI
->getPointerOperand();
45 Value
*Val
= RMWI
->getValOperand();
47 LoadInst
*Orig
= Builder
.CreateLoad(Val
->getType(), Ptr
);
50 switch (RMWI
->getOperation()) {
51 default: llvm_unreachable("Unexpected RMW operation");
52 case AtomicRMWInst::Xchg
:
55 case AtomicRMWInst::Add
:
56 Res
= Builder
.CreateAdd(Orig
, Val
);
58 case AtomicRMWInst::Sub
:
59 Res
= Builder
.CreateSub(Orig
, Val
);
61 case AtomicRMWInst::And
:
62 Res
= Builder
.CreateAnd(Orig
, Val
);
64 case AtomicRMWInst::Nand
:
65 Res
= Builder
.CreateNot(Builder
.CreateAnd(Orig
, Val
));
67 case AtomicRMWInst::Or
:
68 Res
= Builder
.CreateOr(Orig
, Val
);
70 case AtomicRMWInst::Xor
:
71 Res
= Builder
.CreateXor(Orig
, Val
);
73 case AtomicRMWInst::Max
:
74 Res
= Builder
.CreateSelect(Builder
.CreateICmpSLT(Orig
, Val
),
77 case AtomicRMWInst::Min
:
78 Res
= Builder
.CreateSelect(Builder
.CreateICmpSLT(Orig
, Val
),
81 case AtomicRMWInst::UMax
:
82 Res
= Builder
.CreateSelect(Builder
.CreateICmpULT(Orig
, Val
),
85 case AtomicRMWInst::UMin
:
86 Res
= Builder
.CreateSelect(Builder
.CreateICmpULT(Orig
, Val
),
89 case AtomicRMWInst::FAdd
:
90 Res
= Builder
.CreateFAdd(Orig
, Val
);
92 case AtomicRMWInst::FSub
:
93 Res
= Builder
.CreateFSub(Orig
, Val
);
96 Builder
.CreateStore(Res
, Ptr
);
97 RMWI
->replaceAllUsesWith(Orig
);
98 RMWI
->eraseFromParent();
102 static bool LowerFenceInst(FenceInst
*FI
) {
103 FI
->eraseFromParent();
107 static bool LowerLoadInst(LoadInst
*LI
) {
108 LI
->setAtomic(AtomicOrdering::NotAtomic
);
112 static bool LowerStoreInst(StoreInst
*SI
) {
113 SI
->setAtomic(AtomicOrdering::NotAtomic
);
117 static bool runOnBasicBlock(BasicBlock
&BB
) {
118 bool Changed
= false;
119 for (BasicBlock::iterator DI
= BB
.begin(), DE
= BB
.end(); DI
!= DE
;) {
120 Instruction
*Inst
= &*DI
++;
121 if (FenceInst
*FI
= dyn_cast
<FenceInst
>(Inst
))
122 Changed
|= LowerFenceInst(FI
);
123 else if (AtomicCmpXchgInst
*CXI
= dyn_cast
<AtomicCmpXchgInst
>(Inst
))
124 Changed
|= LowerAtomicCmpXchgInst(CXI
);
125 else if (AtomicRMWInst
*RMWI
= dyn_cast
<AtomicRMWInst
>(Inst
))
126 Changed
|= LowerAtomicRMWInst(RMWI
);
127 else if (LoadInst
*LI
= dyn_cast
<LoadInst
>(Inst
)) {
130 } else if (StoreInst
*SI
= dyn_cast
<StoreInst
>(Inst
)) {
138 static bool lowerAtomics(Function
&F
) {
139 bool Changed
= false;
140 for (BasicBlock
&BB
: F
) {
141 Changed
|= runOnBasicBlock(BB
);
146 PreservedAnalyses
LowerAtomicPass::run(Function
&F
, FunctionAnalysisManager
&) {
148 return PreservedAnalyses::none();
149 return PreservedAnalyses::all();
153 class LowerAtomicLegacyPass
: public FunctionPass
{
157 LowerAtomicLegacyPass() : FunctionPass(ID
) {
158 initializeLowerAtomicLegacyPassPass(*PassRegistry::getPassRegistry());
161 bool runOnFunction(Function
&F
) override
{
162 // Don't skip optnone functions; atomics still need to be lowered.
163 FunctionAnalysisManager DummyFAM
;
164 auto PA
= Impl
.run(F
, DummyFAM
);
165 return !PA
.areAllPreserved();
169 LowerAtomicPass Impl
;
173 char LowerAtomicLegacyPass::ID
= 0;
174 INITIALIZE_PASS(LowerAtomicLegacyPass
, "loweratomic",
175 "Lower atomic intrinsics to non-atomic form", false, false)
177 Pass
*llvm::createLowerAtomicPass() { return new LowerAtomicLegacyPass(); }