Reapply r110396, with fixes to appease the Linux buildbot gods.
[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 = NULL;
56     switch (IID) {
57       default: assert(0 && "Unrecognized atomic modify operation");
58       case Intrinsic::atomic_load_add:
59         Res = Builder.CreateAdd(Orig, Delta);
60         break;
61       case Intrinsic::atomic_load_sub:
62         Res = Builder.CreateSub(Orig, Delta);
63         break;
64       case Intrinsic::atomic_load_and:
65         Res = Builder.CreateAnd(Orig, Delta);
66         break;
67       case Intrinsic::atomic_load_nand:
68         Res = Builder.CreateNot(Builder.CreateAnd(Orig, Delta));
69         break;
70       case Intrinsic::atomic_load_or:
71         Res = Builder.CreateOr(Orig, Delta);
72         break;
73       case Intrinsic::atomic_load_xor:
74         Res = Builder.CreateXor(Orig, Delta);
75         break;
76       case Intrinsic::atomic_load_max:
77         Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta),
78                                    Delta,
79                                    Orig);
80         break;
81       case Intrinsic::atomic_load_min:
82         Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta),
83                                    Orig,
84                                    Delta);
85         break;
86       case Intrinsic::atomic_load_umax:
87         Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta),
88                                    Delta,
89                                    Orig);
90         break;
91       case Intrinsic::atomic_load_umin:
92         Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta),
93                                    Orig,
94                                    Delta);
95         break;
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(); }