Revert r110396 to fix buildbots.
[oota-llvm.git] / lib / Transforms / Scalar / LowerAtomic.cpp
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/BasicBlock.h"
18 #include "llvm/Function.h"
19 #include "llvm/Instruction.h"
20 #include "llvm/Instructions.h"
21 #include "llvm/Intrinsics.h"
22 #include "llvm/Pass.h"
23 #include "llvm/Support/IRBuilder.h"
24
25 using namespace llvm;
26
27 namespace {
28
29 bool LowerAtomicIntrinsic(CallInst *CI) {
30   IRBuilder<> Builder(CI->getParent(), CI);
31
32   Function *Callee = CI->getCalledFunction();
33   if (!Callee)
34     return false;
35
36   unsigned IID = Callee->getIntrinsicID();
37   switch (IID) {
38   case Intrinsic::memory_barrier:
39     break;
40
41   case Intrinsic::atomic_load_add:
42   case Intrinsic::atomic_load_sub:
43   case Intrinsic::atomic_load_and:
44   case Intrinsic::atomic_load_nand:
45   case Intrinsic::atomic_load_or:
46   case Intrinsic::atomic_load_xor:
47   case Intrinsic::atomic_load_max:
48   case Intrinsic::atomic_load_min:
49   case Intrinsic::atomic_load_umax:
50   case Intrinsic::atomic_load_umin: {
51     Value *Ptr = CI->getArgOperand(0);
52     Value *Delta = CI->getArgOperand(1);
53
54     LoadInst *Orig = Builder.CreateLoad(Ptr);
55     Value *Res;
56     switch (IID) {
57       case Intrinsic::atomic_load_add:
58         Res = Builder.CreateAdd(Orig, Delta);
59         break;
60       case Intrinsic::atomic_load_sub:
61         Res = Builder.CreateSub(Orig, Delta);
62         break;
63       case Intrinsic::atomic_load_and:
64         Res = Builder.CreateAnd(Orig, Delta);
65         break;
66       case Intrinsic::atomic_load_nand:
67         Res = Builder.CreateNot(Builder.CreateAnd(Orig, Delta));
68         break;
69       case Intrinsic::atomic_load_or:
70         Res = Builder.CreateOr(Orig, Delta);
71         break;
72       case Intrinsic::atomic_load_xor:
73         Res = Builder.CreateXor(Orig, Delta);
74         break;
75       case Intrinsic::atomic_load_max:
76         Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta),
77                                    Delta,
78                                    Orig);
79         break;
80       case Intrinsic::atomic_load_min:
81         Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta),
82                                    Orig,
83                                    Delta);
84         break;
85       case Intrinsic::atomic_load_umax:
86         Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta),
87                                    Delta,
88                                    Orig);
89         break;
90       case Intrinsic::atomic_load_umin:
91         Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta),
92                                    Orig,
93                                    Delta);
94         break;
95       default: assert(0 && "Unrecognized atomic modify operation");
96     }
97     Builder.CreateStore(Res, Ptr);
98
99     CI->replaceAllUsesWith(Orig);
100     break;
101   }
102
103   case Intrinsic::atomic_swap: {
104     Value *Ptr = CI->getArgOperand(0);
105     Value *Val = CI->getArgOperand(1);
106
107     LoadInst *Orig = Builder.CreateLoad(Ptr);
108     Builder.CreateStore(Val, Ptr);
109
110     CI->replaceAllUsesWith(Orig);
111     break;
112   }
113
114   case Intrinsic::atomic_cmp_swap: {
115     Value *Ptr = CI->getArgOperand(0);
116     Value *Cmp = CI->getArgOperand(1);
117     Value *Val = CI->getArgOperand(2);
118
119     LoadInst *Orig = Builder.CreateLoad(Ptr);
120     Value *Equal = Builder.CreateICmpEQ(Orig, Cmp);
121     Value *Res = Builder.CreateSelect(Equal, Val, Orig);
122     Builder.CreateStore(Res, Ptr);
123
124     CI->replaceAllUsesWith(Orig);
125     break;
126   }
127
128   default:
129     return false;
130   }
131
132   assert(CI->use_empty() &&
133          "Lowering should have eliminated any uses of the intrinsic call!");
134   CI->eraseFromParent();
135
136   return true;
137 }
138
139 struct LowerAtomic : public BasicBlockPass {
140   static char ID;
141   LowerAtomic() : BasicBlockPass(&ID) {}
142   bool runOnBasicBlock(BasicBlock &BB) {
143     bool Changed = false;
144     for (BasicBlock::iterator DI = BB.begin(), DE = BB.end(); DI != DE; ) {
145       Instruction *Inst = DI++;
146       if (CallInst *CI = dyn_cast<CallInst>(Inst))
147         Changed |= LowerAtomicIntrinsic(CI);
148     }
149     return Changed;
150   }
151
152 };
153
154 }
155
156 char LowerAtomic::ID = 0;
157 static RegisterPass<LowerAtomic>
158 X("loweratomic", "Lower atomic intrinsics to non-atomic form");
159
160 Pass *llvm::createLowerAtomicPass() { return new LowerAtomic(); }