1 //===- LowerAtomic.cpp - Lower atomic intrinsics --------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This pass lowers atomic intrinsics to non-atomic form for use in a known
11 // non-preemptible environment.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #define DEBUG_TYPE "loweratomic"
16 #include "llvm/Transforms/Scalar.h"
17 #include "llvm/Function.h"
18 #include "llvm/IntrinsicInst.h"
19 #include "llvm/Pass.h"
20 #include "llvm/Support/IRBuilder.h"
21 using namespace llvm;
22
LowerAtomicCmpXchgInst(AtomicCmpXchgInst * CXI)23 static bool LowerAtomicCmpXchgInst(AtomicCmpXchgInst *CXI) {
24 IRBuilder<> Builder(CXI->getParent(), CXI);
25 Value *Ptr = CXI->getPointerOperand();
26 Value *Cmp = CXI->getCompareOperand();
27 Value *Val = CXI->getNewValOperand();
28
29 LoadInst *Orig = Builder.CreateLoad(Ptr);
30 Value *Equal = Builder.CreateICmpEQ(Orig, Cmp);
31 Value *Res = Builder.CreateSelect(Equal, Val, Orig);
32 Builder.CreateStore(Res, Ptr);
33
34 CXI->replaceAllUsesWith(Orig);
35 CXI->eraseFromParent();
36 return true;
37 }
38
LowerAtomicRMWInst(AtomicRMWInst * RMWI)39 static bool LowerAtomicRMWInst(AtomicRMWInst *RMWI) {
40 IRBuilder<> Builder(RMWI->getParent(), RMWI);
41 Value *Ptr = RMWI->getPointerOperand();
42 Value *Val = RMWI->getValOperand();
43
44 LoadInst *Orig = Builder.CreateLoad(Ptr);
45 Value *Res = NULL;
46
47 switch (RMWI->getOperation()) {
48 default: llvm_unreachable("Unexpected RMW operation");
49 case AtomicRMWInst::Xchg:
50 Res = Val;
51 break;
52 case AtomicRMWInst::Add:
53 Res = Builder.CreateAdd(Orig, Val);
54 break;
55 case AtomicRMWInst::Sub:
56 Res = Builder.CreateSub(Orig, Val);
57 break;
58 case AtomicRMWInst::And:
59 Res = Builder.CreateAnd(Orig, Val);
60 break;
61 case AtomicRMWInst::Nand:
62 Res = Builder.CreateNot(Builder.CreateAnd(Orig, Val));
63 break;
64 case AtomicRMWInst::Or:
65 Res = Builder.CreateOr(Orig, Val);
66 break;
67 case AtomicRMWInst::Xor:
68 Res = Builder.CreateXor(Orig, Val);
69 break;
70 case AtomicRMWInst::Max:
71 Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Val),
72 Val, Orig);
73 break;
74 case AtomicRMWInst::Min:
75 Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Val),
76 Orig, Val);
77 break;
78 case AtomicRMWInst::UMax:
79 Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Val),
80 Val, Orig);
81 break;
82 case AtomicRMWInst::UMin:
83 Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Val),
84 Orig, Val);
85 break;
86 }
87 Builder.CreateStore(Res, Ptr);
88 RMWI->replaceAllUsesWith(Orig);
89 RMWI->eraseFromParent();
90 return true;
91 }
92
LowerFenceInst(FenceInst * FI)93 static bool LowerFenceInst(FenceInst *FI) {
94 FI->eraseFromParent();
95 return true;
96 }
97
LowerLoadInst(LoadInst * LI)98 static bool LowerLoadInst(LoadInst *LI) {
99 LI->setAtomic(NotAtomic);
100 return true;
101 }
102
LowerStoreInst(StoreInst * SI)103 static bool LowerStoreInst(StoreInst *SI) {
104 SI->setAtomic(NotAtomic);
105 return true;
106 }
107
108 namespace {
109 struct LowerAtomic : public BasicBlockPass {
110 static char ID;
LowerAtomic__anon47cd0ca70111::LowerAtomic111 LowerAtomic() : BasicBlockPass(ID) {
112 initializeLowerAtomicPass(*PassRegistry::getPassRegistry());
113 }
runOnBasicBlock__anon47cd0ca70111::LowerAtomic114 bool runOnBasicBlock(BasicBlock &BB) {
115 bool Changed = false;
116 for (BasicBlock::iterator DI = BB.begin(), DE = BB.end(); DI != DE; ) {
117 Instruction *Inst = DI++;
118 if (FenceInst *FI = dyn_cast<FenceInst>(Inst))
119 Changed |= LowerFenceInst(FI);
120 else if (AtomicCmpXchgInst *CXI = dyn_cast<AtomicCmpXchgInst>(Inst))
121 Changed |= LowerAtomicCmpXchgInst(CXI);
122 else if (AtomicRMWInst *RMWI = dyn_cast<AtomicRMWInst>(Inst))
123 Changed |= LowerAtomicRMWInst(RMWI);
124 else if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) {
125 if (LI->isAtomic())
126 LowerLoadInst(LI);
127 } else if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) {
128 if (SI->isAtomic())
129 LowerStoreInst(SI);
130 }
131 }
132 return Changed;
133 }
134 };
135 }
136
137 char LowerAtomic::ID = 0;
138 INITIALIZE_PASS(LowerAtomic, "loweratomic",
139 "Lower atomic intrinsics to non-atomic form",
140 false, false)
141
createLowerAtomicPass()142 Pass *llvm::createLowerAtomicPass() { return new LowerAtomic(); }
143