LowerAtomic.cpp revision 21006d40ac9ec7715bca2095451075a83773dc52
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"
21using namespace llvm;
22
23static bool LowerAtomicIntrinsic(IntrinsicInst *II) {
24  IRBuilder<> Builder(II->getParent(), II);
25  unsigned IID = II->getIntrinsicID();
26  switch (IID) {
27  case Intrinsic::memory_barrier:
28    break;
29
30  case Intrinsic::atomic_load_add:
31  case Intrinsic::atomic_load_sub:
32  case Intrinsic::atomic_load_and:
33  case Intrinsic::atomic_load_nand:
34  case Intrinsic::atomic_load_or:
35  case Intrinsic::atomic_load_xor:
36  case Intrinsic::atomic_load_max:
37  case Intrinsic::atomic_load_min:
38  case Intrinsic::atomic_load_umax:
39  case Intrinsic::atomic_load_umin: {
40    Value *Ptr = II->getArgOperand(0), *Delta = II->getArgOperand(1);
41
42    LoadInst *Orig = Builder.CreateLoad(Ptr);
43    Value *Res = NULL;
44    switch (IID) {
45    default: assert(0 && "Unrecognized atomic modify operation");
46    case Intrinsic::atomic_load_add:
47      Res = Builder.CreateAdd(Orig, Delta);
48      break;
49    case Intrinsic::atomic_load_sub:
50      Res = Builder.CreateSub(Orig, Delta);
51      break;
52    case Intrinsic::atomic_load_and:
53      Res = Builder.CreateAnd(Orig, Delta);
54      break;
55    case Intrinsic::atomic_load_nand:
56      Res = Builder.CreateNot(Builder.CreateAnd(Orig, Delta));
57      break;
58    case Intrinsic::atomic_load_or:
59      Res = Builder.CreateOr(Orig, Delta);
60      break;
61    case Intrinsic::atomic_load_xor:
62      Res = Builder.CreateXor(Orig, Delta);
63      break;
64    case Intrinsic::atomic_load_max:
65      Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta),
66                                 Delta, Orig);
67      break;
68    case Intrinsic::atomic_load_min:
69      Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta),
70                                 Orig, Delta);
71      break;
72    case Intrinsic::atomic_load_umax:
73      Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta),
74                                 Delta, Orig);
75      break;
76    case Intrinsic::atomic_load_umin:
77      Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta),
78                                 Orig, Delta);
79      break;
80    }
81    Builder.CreateStore(Res, Ptr);
82
83    II->replaceAllUsesWith(Orig);
84    break;
85  }
86
87  case Intrinsic::atomic_swap: {
88    Value *Ptr = II->getArgOperand(0), *Val = II->getArgOperand(1);
89    LoadInst *Orig = Builder.CreateLoad(Ptr);
90    Builder.CreateStore(Val, Ptr);
91    II->replaceAllUsesWith(Orig);
92    break;
93  }
94
95  case Intrinsic::atomic_cmp_swap: {
96    Value *Ptr = II->getArgOperand(0), *Cmp = II->getArgOperand(1);
97    Value *Val = II->getArgOperand(2);
98
99    LoadInst *Orig = Builder.CreateLoad(Ptr);
100    Value *Equal = Builder.CreateICmpEQ(Orig, Cmp);
101    Value *Res = Builder.CreateSelect(Equal, Val, Orig);
102    Builder.CreateStore(Res, Ptr);
103    II->replaceAllUsesWith(Orig);
104    break;
105  }
106
107  default:
108    return false;
109  }
110
111  assert(II->use_empty() &&
112         "Lowering should have eliminated any uses of the intrinsic call!");
113  II->eraseFromParent();
114
115  return true;
116}
117
118bool LowerAtomicCmpXchgInst(AtomicCmpXchgInst *CXI) {
119  IRBuilder<> Builder(CXI->getParent(), CXI);
120  Value *Ptr = CXI->getPointerOperand();
121  Value *Cmp = CXI->getCompareOperand();
122  Value *Val = CXI->getNewValOperand();
123
124  LoadInst *Orig = Builder.CreateLoad(Ptr);
125  Value *Equal = Builder.CreateICmpEQ(Orig, Cmp);
126  Value *Res = Builder.CreateSelect(Equal, Val, Orig);
127  Builder.CreateStore(Res, Ptr);
128
129  CXI->replaceAllUsesWith(Orig);
130  CXI->eraseFromParent();
131  return true;
132}
133
134bool LowerAtomicRMWInst(AtomicRMWInst *RMWI) {
135  IRBuilder<> Builder(RMWI->getParent(), RMWI);
136  Value *Ptr = RMWI->getPointerOperand();
137  Value *Val = RMWI->getValOperand();
138
139  LoadInst *Orig = Builder.CreateLoad(Ptr);
140  Value *Res = NULL;
141
142  switch (RMWI->getOperation()) {
143  default: llvm_unreachable("Unexpected RMW operation");
144  case AtomicRMWInst::Xchg:
145    Res = Val;
146    break;
147  case AtomicRMWInst::Add:
148    Res = Builder.CreateAdd(Orig, Val);
149    break;
150  case AtomicRMWInst::Sub:
151    Res = Builder.CreateSub(Orig, Val);
152    break;
153  case AtomicRMWInst::And:
154    Res = Builder.CreateAnd(Orig, Val);
155    break;
156  case AtomicRMWInst::Nand:
157    Res = Builder.CreateNot(Builder.CreateAnd(Orig, Val));
158    break;
159  case AtomicRMWInst::Or:
160    Res = Builder.CreateOr(Orig, Val);
161    break;
162  case AtomicRMWInst::Xor:
163    Res = Builder.CreateXor(Orig, Val);
164    break;
165  case AtomicRMWInst::Max:
166    Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Val),
167                               Val, Orig);
168    break;
169  case AtomicRMWInst::Min:
170    Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Val),
171                               Orig, Val);
172    break;
173  case AtomicRMWInst::UMax:
174    Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Val),
175                               Val, Orig);
176    break;
177  case AtomicRMWInst::UMin:
178    Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Val),
179                               Orig, Val);
180    break;
181  }
182  Builder.CreateStore(Res, Ptr);
183  RMWI->replaceAllUsesWith(Orig);
184  RMWI->eraseFromParent();
185  return true;
186}
187
188static bool LowerFenceInst(FenceInst *FI) {
189  FI->eraseFromParent();
190  return true;
191}
192
193static bool LowerLoadInst(LoadInst *LI) {
194  LI->setAtomic(NotAtomic);
195  return true;
196}
197
198static bool LowerStoreInst(StoreInst *SI) {
199  SI->setAtomic(NotAtomic);
200  return true;
201}
202
203namespace {
204  struct LowerAtomic : public BasicBlockPass {
205    static char ID;
206    LowerAtomic() : BasicBlockPass(ID) {
207      initializeLowerAtomicPass(*PassRegistry::getPassRegistry());
208    }
209    bool runOnBasicBlock(BasicBlock &BB) {
210      bool Changed = false;
211      for (BasicBlock::iterator DI = BB.begin(), DE = BB.end(); DI != DE; ) {
212        Instruction *Inst = DI++;
213        if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(Inst))
214          Changed |= LowerAtomicIntrinsic(II);
215        else if (FenceInst *FI = dyn_cast<FenceInst>(Inst))
216          Changed |= LowerFenceInst(FI);
217        else if (AtomicCmpXchgInst *CXI = dyn_cast<AtomicCmpXchgInst>(Inst))
218          Changed |= LowerAtomicCmpXchgInst(CXI);
219        else if (AtomicRMWInst *RMWI = dyn_cast<AtomicRMWInst>(Inst))
220          Changed |= LowerAtomicRMWInst(RMWI);
221        else if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) {
222          if (LI->isAtomic())
223            LowerLoadInst(LI);
224        } else if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) {
225          if (SI->isAtomic())
226            LowerStoreInst(SI);
227        }
228      }
229      return Changed;
230    }
231  };
232}
233
234char LowerAtomic::ID = 0;
235INITIALIZE_PASS(LowerAtomic, "loweratomic",
236                "Lower atomic intrinsics to non-atomic form",
237                false, false)
238
239Pass *llvm::createLowerAtomicPass() { return new LowerAtomic(); }
240