blob: 5f5ed03bd821c51bad3d5fb9e28aba7c0bbe654b [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"
Peter Collingbourne3bababf2010-08-03 16:19:16 +000017#include "llvm/Function.h"
Chris Lattnerbdabacd2010-09-05 20:10:47 +000018#include "llvm/IntrinsicInst.h"
Peter Collingbourne3bababf2010-08-03 16:19:16 +000019#include "llvm/Pass.h"
20#include "llvm/Support/IRBuilder.h"
Peter Collingbourne3bababf2010-08-03 16:19:16 +000021using namespace llvm;
22
Chris Lattnerbdabacd2010-09-05 20:10:47 +000023static bool LowerAtomicIntrinsic(IntrinsicInst *II) {
24 IRBuilder<> Builder(II->getParent(), II);
25 unsigned IID = II->getIntrinsicID();
Peter Collingbourne3bababf2010-08-03 16:19:16 +000026 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: {
Chris Lattner3ae09242010-09-05 20:13:07 +000040 Value *Ptr = II->getArgOperand(0), *Delta = II->getArgOperand(1);
Peter Collingbourne3bababf2010-08-03 16:19:16 +000041
42 LoadInst *Orig = Builder.CreateLoad(Ptr);
Nick Lewyckye52e9d62010-08-06 07:43:46 +000043 Value *Res = NULL;
Peter Collingbourne3bababf2010-08-03 16:19:16 +000044 switch (IID) {
Chris Lattner3ae09242010-09-05 20:13:07 +000045 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;
Peter Collingbourne3bababf2010-08-03 16:19:16 +000080 }
81 Builder.CreateStore(Res, Ptr);
82
Chris Lattnerbdabacd2010-09-05 20:10:47 +000083 II->replaceAllUsesWith(Orig);
Peter Collingbourne3bababf2010-08-03 16:19:16 +000084 break;
85 }
86
87 case Intrinsic::atomic_swap: {
Chris Lattner3ae09242010-09-05 20:13:07 +000088 Value *Ptr = II->getArgOperand(0), *Val = II->getArgOperand(1);
Peter Collingbourne3bababf2010-08-03 16:19:16 +000089 LoadInst *Orig = Builder.CreateLoad(Ptr);
90 Builder.CreateStore(Val, Ptr);
Chris Lattnerbdabacd2010-09-05 20:10:47 +000091 II->replaceAllUsesWith(Orig);
Peter Collingbourne3bababf2010-08-03 16:19:16 +000092 break;
93 }
94
95 case Intrinsic::atomic_cmp_swap: {
Chris Lattner3ae09242010-09-05 20:13:07 +000096 Value *Ptr = II->getArgOperand(0), *Cmp = II->getArgOperand(1);
Chris Lattnerbdabacd2010-09-05 20:10:47 +000097 Value *Val = II->getArgOperand(2);
Peter Collingbourne3bababf2010-08-03 16:19:16 +000098
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);
Chris Lattnerbdabacd2010-09-05 20:10:47 +0000103 II->replaceAllUsesWith(Orig);
Peter Collingbourne3bababf2010-08-03 16:19:16 +0000104 break;
105 }
106
107 default:
108 return false;
109 }
110
Chris Lattnerbdabacd2010-09-05 20:10:47 +0000111 assert(II->use_empty() &&
Peter Collingbourne3bababf2010-08-03 16:19:16 +0000112 "Lowering should have eliminated any uses of the intrinsic call!");
Chris Lattnerbdabacd2010-09-05 20:10:47 +0000113 II->eraseFromParent();
Peter Collingbourne3bababf2010-08-03 16:19:16 +0000114
115 return true;
116}
117
Eli Friedman55ba8162011-07-29 03:05:32 +0000118bool 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
Eli Friedman8a552bb2011-07-27 01:08:30 +0000188static bool LowerFenceInst(FenceInst *FI) {
189 FI->eraseFromParent();
190 return true;
191}
192
Chris Lattnerbdabacd2010-09-05 20:10:47 +0000193namespace {
194 struct LowerAtomic : public BasicBlockPass {
195 static char ID;
Owen Anderson081c34b2010-10-19 17:21:58 +0000196 LowerAtomic() : BasicBlockPass(ID) {
197 initializeLowerAtomicPass(*PassRegistry::getPassRegistry());
198 }
Chris Lattnerbdabacd2010-09-05 20:10:47 +0000199 bool runOnBasicBlock(BasicBlock &BB) {
200 bool Changed = false;
Eli Friedman8a552bb2011-07-27 01:08:30 +0000201 for (BasicBlock::iterator DI = BB.begin(), DE = BB.end(); DI != DE; ) {
202 Instruction *Inst = DI++;
203 if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(Inst))
Chris Lattnerbdabacd2010-09-05 20:10:47 +0000204 Changed |= LowerAtomicIntrinsic(II);
Benjamin Kramerb2e7c822011-07-28 01:20:19 +0000205 else if (FenceInst *FI = dyn_cast<FenceInst>(Inst))
Eli Friedman8a552bb2011-07-27 01:08:30 +0000206 Changed |= LowerFenceInst(FI);
Eli Friedman55ba8162011-07-29 03:05:32 +0000207 else if (AtomicCmpXchgInst *CXI = dyn_cast<AtomicCmpXchgInst>(Inst))
208 Changed |= LowerAtomicCmpXchgInst(CXI);
209 else if (AtomicRMWInst *RMWI = dyn_cast<AtomicRMWInst>(Inst))
210 Changed |= LowerAtomicRMWInst(RMWI);
Eli Friedman8a552bb2011-07-27 01:08:30 +0000211 }
Chris Lattnerbdabacd2010-09-05 20:10:47 +0000212 return Changed;
Peter Collingbourne3bababf2010-08-03 16:19:16 +0000213 }
Chris Lattnerbdabacd2010-09-05 20:10:47 +0000214 };
Peter Collingbourne3bababf2010-08-03 16:19:16 +0000215}
216
217char LowerAtomic::ID = 0;
Owen Anderson02dd53e2010-08-23 17:52:01 +0000218INITIALIZE_PASS(LowerAtomic, "loweratomic",
219 "Lower atomic intrinsics to non-atomic form",
Owen Andersonce665bd2010-10-07 22:25:06 +0000220 false, false)
Peter Collingbourne3bababf2010-08-03 16:19:16 +0000221
222Pass *llvm::createLowerAtomicPass() { return new LowerAtomic(); }