blob: 11f52570e18da97d98e8bd73c9966c3030bd7be8 [file] [log] [blame]
Peter Collingbourne3bababf2010-08-03 16:19:16 +00001//===- 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
25using namespace llvm;
26
27namespace {
28
29bool 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
139struct 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
156char LowerAtomic::ID = 0;
157static RegisterPass<LowerAtomic>
158X("loweratomic", "Lower atomic intrinsics to non-atomic form");
159
160Pass *llvm::createLowerAtomicPass() { return new LowerAtomic(); }