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/InitializePasses.h"
18 #include "llvm/Pass.h"
19 #include "llvm/Transforms/Scalar.h"
22 #define DEBUG_TYPE "loweratomic"
24 static bool LowerAtomicCmpXchgInst(AtomicCmpXchgInst
*CXI
) {
25 IRBuilder
<> Builder(CXI
);
26 Value
*Ptr
= CXI
->getPointerOperand();
27 Value
*Cmp
= CXI
->getCompareOperand();
28 Value
*Val
= CXI
->getNewValOperand();
30 LoadInst
*Orig
= Builder
.CreateLoad(Val
->getType(), Ptr
);
31 Value
*Equal
= Builder
.CreateICmpEQ(Orig
, Cmp
);
32 Value
*Res
= Builder
.CreateSelect(Equal
, Val
, Orig
);
33 Builder
.CreateStore(Res
, Ptr
);
35 Res
= Builder
.CreateInsertValue(UndefValue::get(CXI
->getType()), Orig
, 0);
36 Res
= Builder
.CreateInsertValue(Res
, Equal
, 1);
38 CXI
->replaceAllUsesWith(Res
);
39 CXI
->eraseFromParent();
43 bool llvm::lowerAtomicRMWInst(AtomicRMWInst
*RMWI
) {
44 IRBuilder
<> Builder(RMWI
);
45 Value
*Ptr
= RMWI
->getPointerOperand();
46 Value
*Val
= RMWI
->getValOperand();
48 LoadInst
*Orig
= Builder
.CreateLoad(Val
->getType(), Ptr
);
51 switch (RMWI
->getOperation()) {
52 default: llvm_unreachable("Unexpected RMW operation");
53 case AtomicRMWInst::Xchg
:
56 case AtomicRMWInst::Add
:
57 Res
= Builder
.CreateAdd(Orig
, Val
);
59 case AtomicRMWInst::Sub
:
60 Res
= Builder
.CreateSub(Orig
, Val
);
62 case AtomicRMWInst::And
:
63 Res
= Builder
.CreateAnd(Orig
, Val
);
65 case AtomicRMWInst::Nand
:
66 Res
= Builder
.CreateNot(Builder
.CreateAnd(Orig
, Val
));
68 case AtomicRMWInst::Or
:
69 Res
= Builder
.CreateOr(Orig
, Val
);
71 case AtomicRMWInst::Xor
:
72 Res
= Builder
.CreateXor(Orig
, Val
);
74 case AtomicRMWInst::Max
:
75 Res
= Builder
.CreateSelect(Builder
.CreateICmpSLT(Orig
, Val
),
78 case AtomicRMWInst::Min
:
79 Res
= Builder
.CreateSelect(Builder
.CreateICmpSLT(Orig
, Val
),
82 case AtomicRMWInst::UMax
:
83 Res
= Builder
.CreateSelect(Builder
.CreateICmpULT(Orig
, Val
),
86 case AtomicRMWInst::UMin
:
87 Res
= Builder
.CreateSelect(Builder
.CreateICmpULT(Orig
, Val
),
90 case AtomicRMWInst::FAdd
:
91 Res
= Builder
.CreateFAdd(Orig
, Val
);
93 case AtomicRMWInst::FSub
:
94 Res
= Builder
.CreateFSub(Orig
, Val
);
97 Builder
.CreateStore(Res
, Ptr
);
98 RMWI
->replaceAllUsesWith(Orig
);
99 RMWI
->eraseFromParent();
103 static bool LowerFenceInst(FenceInst
*FI
) {
104 FI
->eraseFromParent();
108 static bool LowerLoadInst(LoadInst
*LI
) {
109 LI
->setAtomic(AtomicOrdering::NotAtomic
);
113 static bool LowerStoreInst(StoreInst
*SI
) {
114 SI
->setAtomic(AtomicOrdering::NotAtomic
);
118 static bool runOnBasicBlock(BasicBlock
&BB
) {
119 bool Changed
= false;
120 for (Instruction
&Inst
: make_early_inc_range(BB
)) {
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(); }