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