Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(255)

Side by Side Diff: lib/Transforms/NaCl/RewriteAtomics.cpp

Issue 927493002: PNaCl: Impl the other atomicrmw operations: nand, max, min, umax, and umin. Base URL: https://chromium.googlesource.com/native_client/pnacl-llvm.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/Transforms/NaCl/LLVMBuild.txt ('k') | test/Transforms/NaCl/atomic/extra-rmw-operations.ll » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 //===- RewriteAtomics.cpp - Stabilize instructions used for concurrency ---===// 1 //===- RewriteAtomics.cpp - Stabilize instructions used for concurrency ---===//
2 // 2 //
3 // The LLVM Compiler Infrastructure 3 // The LLVM Compiler Infrastructure
4 // 4 //
5 // This file is distributed under the University of Illinois Open Source 5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details. 6 // License. See LICENSE.TXT for details.
7 // 7 //
8 //===----------------------------------------------------------------------===// 8 //===----------------------------------------------------------------------===//
9 // 9 //
10 // This pass encodes atomics, volatiles and fences using NaCl intrinsics 10 // This pass encodes atomics, volatiles and fences using NaCl intrinsics
11 // instead of LLVM's regular IR instructions. 11 // instead of LLVM's regular IR instructions.
12 // 12 //
13 // All of the above are transformed into one of the 13 // All of the above are transformed into one of the
14 // @llvm.nacl.atomic.* intrinsics. 14 // @llvm.nacl.atomic.* intrinsics.
15 // 15 //
16 //===----------------------------------------------------------------------===// 16 //===----------------------------------------------------------------------===//
17 17
18 #include "llvm/ADT/Triple.h"
18 #include "llvm/ADT/Twine.h" 19 #include "llvm/ADT/Twine.h"
20 #include "llvm/Analysis/NaCl/PNaClSimplificationAnalyses.h"
21 #include "llvm/CodeGen/AtomicExpandUtils.h"
22 #include "llvm/IR/IRBuilder.h"
19 #include "llvm/IR/DataLayout.h" 23 #include "llvm/IR/DataLayout.h"
20 #include "llvm/IR/Function.h" 24 #include "llvm/IR/Function.h"
21 #include "llvm/IR/InlineAsm.h" 25 #include "llvm/IR/InlineAsm.h"
22 #include "llvm/IR/InstVisitor.h" 26 #include "llvm/IR/InstVisitor.h"
23 #include "llvm/IR/Instructions.h" 27 #include "llvm/IR/Instructions.h"
24 #include "llvm/IR/Intrinsics.h" 28 #include "llvm/IR/Intrinsics.h"
25 #include "llvm/IR/Module.h" 29 #include "llvm/IR/Module.h"
26 #include "llvm/IR/NaClAtomicIntrinsics.h" 30 #include "llvm/IR/NaClAtomicIntrinsics.h"
27 #include "llvm/Pass.h" 31 #include "llvm/Pass.h"
28 #include "llvm/Support/CommandLine.h" 32 #include "llvm/Support/CommandLine.h"
29 #include "llvm/Support/Compiler.h" 33 #include "llvm/Support/Compiler.h"
30 #include "llvm/Support/raw_ostream.h" 34 #include "llvm/Support/raw_ostream.h"
35 #include "llvm/Support/TargetRegistry.h"
31 #include "llvm/Transforms/NaCl.h" 36 #include "llvm/Transforms/NaCl.h"
32 #include <climits> 37 #include <climits>
33 #include <string> 38 #include <string>
34 39
35 using namespace llvm; 40 using namespace llvm;
36 41
37 static cl::opt<bool> PNaClMemoryOrderSeqCstOnly( 42 static cl::opt<bool> PNaClMemoryOrderSeqCstOnly(
38 "pnacl-memory-order-seq-cst-only", 43 "pnacl-memory-order-seq-cst-only",
39 cl::desc("PNaCl should upgrade all atomic memory orders to seq_cst"), 44 cl::desc("PNaCl should upgrade all atomic memory orders to seq_cst"),
40 cl::init(false)); 45 cl::init(false));
41 46
42 namespace { 47 namespace {
43 48
44 class RewriteAtomics : public ModulePass { 49 class RewriteAtomicsPass {
45 public: 50 public:
46 static char ID; // Pass identification, replacement for typeid 51 static StringRef name() { return "RewriteAtomicsPass"; }
47 RewriteAtomics() : ModulePass(ID) {
48 // This is a module pass because it may have to introduce
49 // intrinsic declarations into the module and modify a global function.
50 initializeRewriteAtomicsPass(*PassRegistry::getPassRegistry());
51 }
52 52
53 virtual bool runOnModule(Module &M); 53 RewriteAtomicsPass() { }
54 RewriteAtomicsPass(RewriteAtomicsPass &&Rhs) { }
55 RewriteAtomicsPass &operator=(RewriteAtomicsPass &&Rhs) { return *this; }
56
57 PreservedAnalyses run(Function &F, AnalysisManager<Function> *AM);
54 }; 58 };
55 59
56 template <class T> std::string ToStr(const T &V) { 60 template <class T> std::string ToStr(const T &V) {
57 std::string S; 61 std::string S;
58 raw_string_ostream OS(S); 62 raw_string_ostream OS(S);
59 OS << const_cast<T &>(V); 63 OS << const_cast<T &>(V);
60 return OS.str(); 64 return OS.str();
61 } 65 }
62 66
63 class AtomicVisitor : public InstVisitor<AtomicVisitor> { 67 class AtomicVisitor : public InstVisitor<AtomicVisitor> {
64 public: 68 public:
65 AtomicVisitor(Module &M, Pass &P) 69 AtomicVisitor(Module &M)
66 : M(M), C(M.getContext()), 70 : M(M), C(M.getContext()), TD(M.getDataLayout()), AI(C) {}
67 TD(M.getDataLayout()), AI(C),
68 ModifiedModule(false) {}
69 ~AtomicVisitor() {} 71 ~AtomicVisitor() {}
70 bool modifiedModule() const { return ModifiedModule; } 72 bool modifiedFunction() const { return Modified; }
71 73
72 void visitLoadInst(LoadInst &I); 74 void visitLoadInst(LoadInst &I);
73 void visitStoreInst(StoreInst &I); 75 void visitStoreInst(StoreInst &I);
74 void visitAtomicCmpXchgInst(AtomicCmpXchgInst &I); 76 void visitAtomicCmpXchgInst(AtomicCmpXchgInst &I);
75 void visitAtomicRMWInst(AtomicRMWInst &I); 77 void visitAtomicRMWInst(AtomicRMWInst &I);
76 void visitFenceInst(FenceInst &I); 78 void visitFenceInst(FenceInst &I);
77 79
78 private: 80 private:
79 Module &M; 81 Module &M;
80 LLVMContext &C; 82 LLVMContext &C;
81 const DataLayout TD; 83 const DataLayout TD;
82 NaCl::AtomicIntrinsics AI; 84 NaCl::AtomicIntrinsics AI;
83 bool ModifiedModule; 85 bool Modified = false;
84 86
85 AtomicVisitor() = delete; 87 AtomicVisitor() = delete;
86 AtomicVisitor(const AtomicVisitor &) = delete; 88 AtomicVisitor(const AtomicVisitor &) = delete;
87 AtomicVisitor &operator=(const AtomicVisitor &) = delete; 89 AtomicVisitor &operator=(const AtomicVisitor &) = delete;
88 90
89 /// Create an integer constant holding a NaCl::MemoryOrder that can be 91 /// Create an integer constant holding a NaCl::MemoryOrder that can be
90 /// passed as an argument to one of the @llvm.nacl.atomic.* 92 /// passed as an argument to one of the @llvm.nacl.atomic.*
91 /// intrinsics. This function may strengthen the ordering initially 93 /// intrinsics. This function may strengthen the ordering initially
92 /// specified by the instruction \p I for stability purpose. 94 /// specified by the instruction \p I for stability purpose.
93 template <class Instruction> 95 template <class Instruction>
94 ConstantInt *freezeMemoryOrder(const Instruction &I, AtomicOrdering O) const; 96 ConstantInt *freezeMemoryOrder(const Instruction &I, AtomicOrdering O) const;
95 std::pair<ConstantInt *, ConstantInt *> 97 std::pair<ConstantInt *, ConstantInt *>
96 freezeMemoryOrder(const AtomicCmpXchgInst &I, AtomicOrdering S, 98 freezeMemoryOrder(const Instruction &I, AtomicOrdering S,
97 AtomicOrdering F) const; 99 AtomicOrdering F) const;
98 100
99 /// Sanity-check that instruction \p I which has pointer and value 101 /// Sanity-check that instruction \p I which has pointer and value
100 /// parameters have matching sizes \p BitSize for the type-pointed-to 102 /// parameters have matching sizes \p BitSize for the type-pointed-to
101 /// and the value's type \p T. 103 /// and the value's type \p T.
102 void checkSizeMatchesType(const Instruction &I, unsigned BitSize, 104 void checkSizeMatchesType(const Value &I, unsigned BitSize,
103 const Type *T) const; 105 const Type *T) const;
104 106
105 /// Verify that loads and stores are at least naturally aligned. Use 107 /// Verify that loads and stores are at least naturally aligned. Use
106 /// byte alignment because converting to bits could truncate the 108 /// byte alignment because converting to bits could truncate the
107 /// value. 109 /// value.
108 void checkAlignment(const Instruction &I, unsigned ByteAlignment, 110 void checkAlignment(const Instruction &I, unsigned ByteAlignment,
109 unsigned ByteSize) const; 111 unsigned ByteSize) const;
110 112
111 /// Create a cast before Instruction \p I from \p Src to \p Dst with \p Name. 113 /// Create a cast before Instruction \p I from \p Src to \p Dst with \p Name.
112 CastInst *createCast(Instruction &I, Value *Src, Type *Dst, Twine Name) const; 114 CastInst *createCast(Instruction &I, Value *Src, Type *Dst, Twine Name) const;
(...skipping 12 matching lines...) Expand all
125 Instruction &I, const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic, 127 Instruction &I, const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic,
126 Type *DstType, Type *OverloadedType, ArrayRef<Value *> Args); 128 Type *DstType, Type *OverloadedType, ArrayRef<Value *> Args);
127 129
128 /// Most atomics instructions deal with at least one pointer, this 130 /// Most atomics instructions deal with at least one pointer, this
129 /// struct automates some of this and has generic sanity checks. 131 /// struct automates some of this and has generic sanity checks.
130 template <class Instruction> struct PointerHelper { 132 template <class Instruction> struct PointerHelper {
131 Value *P; 133 Value *P;
132 Type *OriginalPET; 134 Type *OriginalPET;
133 Type *PET; 135 Type *PET;
134 unsigned BitSize; 136 unsigned BitSize;
135 PointerHelper(const AtomicVisitor &AV, Instruction &I) 137 PointerHelper(const AtomicVisitor &AV, Instruction &I,
138 IRBuilder<> *Builder = nullptr)
136 : P(I.getPointerOperand()) { 139 : P(I.getPointerOperand()) {
137 if (I.getPointerAddressSpace() != 0) 140 if (I.getPointerAddressSpace() != 0)
138 report_fatal_error("unhandled pointer address space " + 141 report_fatal_error("unhandled pointer address space " +
139 Twine(I.getPointerAddressSpace()) + " for atomic: " + 142 Twine(I.getPointerAddressSpace()) + " for atomic: " +
140 ToStr(I)); 143 ToStr(I));
141 assert(P->getType()->isPointerTy() && "expected a pointer"); 144 assert(P->getType()->isPointerTy() && "expected a pointer");
142 PET = OriginalPET = P->getType()->getPointerElementType(); 145 PET = OriginalPET = P->getType()->getPointerElementType();
143 BitSize = AV.TD.getTypeSizeInBits(OriginalPET); 146 BitSize = AV.TD.getTypeSizeInBits(OriginalPET);
144 if (!OriginalPET->isIntegerTy()) { 147 if (!OriginalPET->isIntegerTy()) {
145 // The pointer wasn't to an integer type. We define atomics in 148 // The pointer wasn't to an integer type. We define atomics in
146 // terms of integers, so bitcast the pointer to an integer of 149 // terms of integers, so bitcast the pointer to an integer of
147 // the proper width. 150 // the proper width.
148 Type *IntNPtr = Type::getIntNPtrTy(AV.C, BitSize); 151 Type *IntNPtr = Type::getIntNPtrTy(AV.C, BitSize);
149 P = AV.createCast(I, P, IntNPtr, P->getName() + ".cast"); 152 if(!Builder) {
153 P = AV.createCast(I, P, IntNPtr, P->getName() + ".cast");
154 } else {
155 P = Builder->CreateBitOrPointerCast(P, IntNPtr, P->getName() + ".cast" );
156 }
150 PET = P->getType()->getPointerElementType(); 157 PET = P->getType()->getPointerElementType();
151 } 158 }
152 AV.checkSizeMatchesType(I, BitSize, PET); 159 AV.checkSizeMatchesType(I, BitSize, PET);
153 } 160 }
154 }; 161 };
155 }; 162 };
156 } 163 }
157 164
158 char RewriteAtomics::ID = 0; 165 static bool
159 INITIALIZE_PASS(RewriteAtomics, "nacl-rewrite-atomics", 166 ExpandAtomicInstructions(Function &F, AtomicInfo &Info) {
160 "rewrite atomics, volatiles and fences into stable " 167 bool Changed = false;
161 "@llvm.nacl.atomics.* intrinsics", 168 AtomicVisitor AV(*F.getParent());
162 false, false)
163 169
164 bool RewriteAtomics::runOnModule(Module &M) { 170 auto &CmpXchgs = Info.getCmpXchgs();
165 AtomicVisitor AV(M, *this); 171 for (auto *CmpXchg : CmpXchgs) {
166 AV.visit(M); 172 AV.visitAtomicCmpXchgInst(*CmpXchg);
167 return AV.modifiedModule(); 173 Changed = true;
174 }
175
176 auto &Loads = Info.getLoads();
177 for (auto *Load : Loads) {
178 AV.visitLoadInst(*Load);
179 Changed = true;
180 }
181
182 auto &Stores = Info.getStores();
183 for (auto *Store : Stores) {
184 AV.visitStoreInst(*Store);
185 Changed = true;
186 }
187
188 auto &RMWs = Info.getRMWs();
189 for (auto *RMW : RMWs) {
190 AV.visitAtomicRMWInst(*RMW);
191 Changed = true;
192 }
193
194 auto &Fences = Info.getFences();
195 for (auto *Fence : Fences) {
196 AV.visitFenceInst(*Fence);
197 Changed = true;
198 }
199
200 return Changed;
201 }
202
203 PreservedAnalyses RewriteAtomicsPass::run(Function &F,
204 AnalysisManager<Function> *AM) {
205 auto &Info = AM->getResult<AtomicAnalysis>(F);
206
207 if (ExpandAtomicInstructions(F, Info)) {
208 return PreservedAnalyses::none();
209 } else {
210 return PreservedAnalyses::all();
211 }
168 } 212 }
169 213
170 template <class Instruction> 214 template <class Instruction>
171 ConstantInt *AtomicVisitor::freezeMemoryOrder(const Instruction &I, 215 ConstantInt *AtomicVisitor::freezeMemoryOrder(const Instruction &I,
172 AtomicOrdering O) const { 216 AtomicOrdering O) const {
173 NaCl::MemoryOrder AO = NaCl::MemoryOrderInvalid; 217 NaCl::MemoryOrder AO = NaCl::MemoryOrderInvalid;
174 218
175 // TODO Volatile load/store are promoted to sequentially consistent 219 // TODO Volatile load/store are promoted to sequentially consistent
176 // for now. We could do something weaker. 220 // for now. We could do something weaker.
177 if (const LoadInst *L = dyn_cast<LoadInst>(&I)) { 221 if (const LoadInst *L = dyn_cast<LoadInst>(&I)) {
178 if (L->isVolatile()) 222 if (L->isVolatile())
179 AO = NaCl::MemoryOrderSequentiallyConsistent; 223 AO = NaCl::MemoryOrderSequentiallyConsistent;
180 } else if (const StoreInst *S = dyn_cast<StoreInst>(&I)) { 224 } else if (const StoreInst *S = dyn_cast<StoreInst>(&I)) {
181 if (S->isVolatile()) 225 if (S->isVolatile())
182 AO = NaCl::MemoryOrderSequentiallyConsistent; 226 AO = NaCl::MemoryOrderSequentiallyConsistent;
183 } 227 }
184 228
185 if (AO == NaCl::MemoryOrderInvalid) { 229 if (AO == NaCl::MemoryOrderInvalid) {
186 switch (O) { 230 switch (O) {
187 case NotAtomic: llvm_unreachable("unexpected memory order"); 231 case NotAtomic:
232 llvm_unreachable("unexpected memory order");
188 // Monotonic is a strict superset of Unordered. Both can therefore 233 // Monotonic is a strict superset of Unordered. Both can therefore
189 // map to Relaxed ordering, which is in the C11/C++11 standard. 234 // map to Relaxed ordering, which is in the C11/C++11 standard.
190 case Unordered: AO = NaCl::MemoryOrderRelaxed; break; 235 case Unordered:
191 case Monotonic: AO = NaCl::MemoryOrderRelaxed; break; 236 AO = NaCl::MemoryOrderRelaxed;
237 break;
238 case Monotonic:
239 AO = NaCl::MemoryOrderRelaxed;
240 break;
192 // TODO Consume is currently unspecified by LLVM's internal IR. 241 // TODO Consume is currently unspecified by LLVM's internal IR.
193 case Acquire: AO = NaCl::MemoryOrderAcquire; break; 242 case Acquire:
194 case Release: AO = NaCl::MemoryOrderRelease; break; 243 AO = NaCl::MemoryOrderAcquire;
195 case AcquireRelease: AO = NaCl::MemoryOrderAcquireRelease; break; 244 break;
245 case Release:
246 AO = NaCl::MemoryOrderRelease;
247 break;
248 case AcquireRelease:
249 AO = NaCl::MemoryOrderAcquireRelease;
250 break;
196 case SequentiallyConsistent: 251 case SequentiallyConsistent:
197 AO = NaCl::MemoryOrderSequentiallyConsistent; break; 252 AO = NaCl::MemoryOrderSequentiallyConsistent;
253 break;
198 } 254 }
199 } 255 }
200 256
201 // TODO For now only acquire/release/acq_rel/seq_cst are allowed. 257 // TODO For now only acquire/release/acq_rel/seq_cst are allowed.
202 if (PNaClMemoryOrderSeqCstOnly || AO == NaCl::MemoryOrderRelaxed) 258 if (PNaClMemoryOrderSeqCstOnly || AO == NaCl::MemoryOrderRelaxed)
203 AO = NaCl::MemoryOrderSequentiallyConsistent; 259 AO = NaCl::MemoryOrderSequentiallyConsistent;
204 260
205 return ConstantInt::get(Type::getInt32Ty(C), AO); 261 return ConstantInt::get(Type::getInt32Ty(C), AO);
206 } 262 }
207 263
208 std::pair<ConstantInt *, ConstantInt *> 264 std::pair<ConstantInt *, ConstantInt *>
209 AtomicVisitor::freezeMemoryOrder(const AtomicCmpXchgInst &I, AtomicOrdering S, 265 AtomicVisitor::freezeMemoryOrder(const Instruction &I, AtomicOrdering S,
210 AtomicOrdering F) const { 266 AtomicOrdering F) const {
211 if (S == Release || (S == AcquireRelease && F != Acquire)) 267 if (S == Release || (S == AcquireRelease && F != Acquire))
212 // According to C++11's [atomics.types.operations.req], cmpxchg with release 268 // According to C++11's [atomics.types.operations.req], cmpxchg with release
213 // success memory ordering must have relaxed failure memory ordering, which 269 // success memory ordering must have relaxed failure memory ordering, which
214 // PNaCl currently disallows. The next-strongest ordering is acq_rel which 270 // PNaCl currently disallows. The next-strongest ordering is acq_rel which
215 // is also an invalid failure ordering, we therefore have to change the 271 // is also an invalid failure ordering, we therefore have to change the
216 // success ordering to seq_cst, which can then fail as seq_cst. 272 // success ordering to seq_cst, which can then fail as seq_cst.
217 S = F = SequentiallyConsistent; 273 S = F = SequentiallyConsistent;
218 if (F == Unordered || F == Monotonic) // Both are treated as relaxed. 274 if (F == Unordered || F == Monotonic) // Both are treated as relaxed.
219 F = AtomicCmpXchgInst::getStrongestFailureOrdering(S); 275 F = AtomicCmpXchgInst::getStrongestFailureOrdering(S);
220 return std::make_pair(freezeMemoryOrder(I, S), freezeMemoryOrder(I, F)); 276 return std::make_pair(freezeMemoryOrder(I, S), freezeMemoryOrder(I, F));
221 } 277 }
222 278
223 void AtomicVisitor::checkSizeMatchesType(const Instruction &I, unsigned BitSize, 279 void AtomicVisitor::checkSizeMatchesType(const Value &I, unsigned BitSize,
224 const Type *T) const { 280 const Type *T) const {
225 Type *IntType = Type::getIntNTy(C, BitSize); 281 Type *IntType = Type::getIntNTy(C, BitSize);
226 if (IntType && T == IntType) 282 if (IntType && T == IntType)
227 return; 283 return;
228 report_fatal_error("unsupported atomic type " + ToStr(*T) + " of size " + 284 report_fatal_error("unsupported atomic type " + ToStr(*T) + " of size " +
229 Twine(BitSize) + " bits in: " + ToStr(I)); 285 Twine(BitSize) + " bits in: " + ToStr(I));
230 } 286 }
231 287
232 void AtomicVisitor::checkAlignment(const Instruction &I, unsigned ByteAlignment, 288 void AtomicVisitor::checkAlignment(const Instruction &I, unsigned ByteAlignment,
233 unsigned ByteSize) const { 289 unsigned ByteSize) const {
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
290 Success, 1, Name + ".insert.success", &I); 346 Success, 1, Name + ".insert.success", &I);
291 } else if (!Call->getType()->isVoidTy() && DstType != OverloadedType) { 347 } else if (!Call->getType()->isVoidTy() && DstType != OverloadedType) {
292 // The call returns a value which needs to be cast to a non-integer. 348 // The call returns a value which needs to be cast to a non-integer.
293 Res = createCast(I, Call, DstType, Name + ".cast"); 349 Res = createCast(I, Call, DstType, Name + ".cast");
294 Res->setDebugLoc(I.getDebugLoc()); 350 Res->setDebugLoc(I.getDebugLoc());
295 } 351 }
296 352
297 I.replaceAllUsesWith(Res); 353 I.replaceAllUsesWith(Res);
298 I.eraseFromParent(); 354 I.eraseFromParent();
299 Call->setName(Name); 355 Call->setName(Name);
300 ModifiedModule = true; 356 Modified = true;
301 } 357 }
302 358
303 /// %res = load {atomic|volatile} T* %ptr memory_order, align sizeof(T) 359 /// %res = load {atomic|volatile} T* %ptr memory_order, align sizeof(T)
304 /// becomes: 360 /// becomes:
305 /// %res = call T @llvm.nacl.atomic.load.i<size>(%ptr, memory_order) 361 /// %res = call T @llvm.nacl.atomic.load.i<size>(%ptr, memory_order)
306 void AtomicVisitor::visitLoadInst(LoadInst &I) { 362 void AtomicVisitor::visitLoadInst(LoadInst &I) {
307 if (I.isSimple()) 363 if (I.isSimple())
308 return; 364 return;
309 PointerHelper<LoadInst> PH(*this, I); 365 PointerHelper<LoadInst> PH(*this, I);
310 const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic = 366 const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic =
(...skipping 29 matching lines...) Expand all
340 replaceInstructionWithIntrinsicCall(I, Intrinsic, PH.OriginalPET, PH.PET, 396 replaceInstructionWithIntrinsicCall(I, Intrinsic, PH.OriginalPET, PH.PET,
341 Args); 397 Args);
342 } 398 }
343 399
344 /// %res = atomicrmw OP T* %ptr, T %val memory_order 400 /// %res = atomicrmw OP T* %ptr, T %val memory_order
345 /// becomes: 401 /// becomes:
346 /// %res = call T @llvm.nacl.atomic.rmw.i<size>(OP, %ptr, %val, memory_order) 402 /// %res = call T @llvm.nacl.atomic.rmw.i<size>(OP, %ptr, %val, memory_order)
347 void AtomicVisitor::visitAtomicRMWInst(AtomicRMWInst &I) { 403 void AtomicVisitor::visitAtomicRMWInst(AtomicRMWInst &I) {
348 NaCl::AtomicRMWOperation Op; 404 NaCl::AtomicRMWOperation Op;
349 switch (I.getOperation()) { 405 switch (I.getOperation()) {
350 default: report_fatal_error("unsupported atomicrmw operation: " + ToStr(I)); 406 default: {
351 case AtomicRMWInst::Add: Op = NaCl::AtomicAdd; break; 407 auto Factory = [this, &I] (IRBuilder<> &Builder, Value *Addr,
352 case AtomicRMWInst::Sub: Op = NaCl::AtomicSub; break; 408 Value *Loaded, Value *NewVal,
353 case AtomicRMWInst::And: Op = NaCl::AtomicAnd; break; 409 AtomicOrdering MemOpOrder,
354 case AtomicRMWInst::Or: Op = NaCl::AtomicOr; break; 410 Value *&Success, Value *&NewLoaded) {
355 case AtomicRMWInst::Xor: Op = NaCl::AtomicXor; break; 411 PointerHelper<AtomicRMWInst> PH(*this, I, &Builder);
356 case AtomicRMWInst::Xchg: Op = NaCl::AtomicExchange; break; 412
413 const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic =
414 findAtomicIntrinsic(I, Intrinsic::nacl_atomic_cmpxchg, PH.PET);
415
416 auto Order = freezeMemoryOrder(I, MemOpOrder, MemOpOrder);
417 Value *Args[] = {PH.P, Loaded, NewVal,
418 Order.first, Order.second};
419
420 Function *F = Intrinsic->getDeclaration(&this->M);
421
422 Value* UnCastedValue = Builder.CreateCall(F, Args, "");
423 if(PH.P->getType() != Addr->getType()) {
424 NewLoaded = Builder.CreateBitOrPointerCast(UnCastedValue, Addr->getType( ),
425 "cast." + Addr->getName());
426 } else {
427 NewLoaded = UnCastedValue;
428 }
429 Success = Builder.CreateICmp(CmpInst::ICMP_EQ, NewLoaded, Loaded, "success ");
430 };
431 Modified = expandAtomicRMWToCmpXchg(&I, Factory) || Modified;
432 return;
433 }
434 case AtomicRMWInst::Add:
435 Op = NaCl::AtomicAdd;
436 break;
437 case AtomicRMWInst::Sub:
438 Op = NaCl::AtomicSub;
439 break;
440 case AtomicRMWInst::And:
441 Op = NaCl::AtomicAnd;
442 break;
443 case AtomicRMWInst::Or:
444 Op = NaCl::AtomicOr;
445 break;
446 case AtomicRMWInst::Xor:
447 Op = NaCl::AtomicXor;
448 break;
449 case AtomicRMWInst::Xchg:
450 Op = NaCl::AtomicExchange;
451 break;
357 } 452 }
358 PointerHelper<AtomicRMWInst> PH(*this, I); 453 PointerHelper<AtomicRMWInst> PH(*this, I);
359 const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic = 454 const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic =
360 findAtomicIntrinsic(I, Intrinsic::nacl_atomic_rmw, PH.PET); 455 findAtomicIntrinsic(I, Intrinsic::nacl_atomic_rmw, PH.PET);
361 checkSizeMatchesType(I, PH.BitSize, I.getValOperand()->getType()); 456 checkSizeMatchesType(I, PH.BitSize, I.getValOperand()->getType());
362 Value *Args[] = {ConstantInt::get(Type::getInt32Ty(C), Op), PH.P, 457 Value *Args[] = {ConstantInt::get(Type::getInt32Ty(C), Op), PH.P,
363 I.getValOperand(), freezeMemoryOrder(I, I.getOrdering())}; 458 I.getValOperand(), freezeMemoryOrder(I, I.getOrdering())};
364 replaceInstructionWithIntrinsicCall(I, Intrinsic, PH.OriginalPET, PH.PET, 459 replaceInstructionWithIntrinsicCall(I, Intrinsic, PH.OriginalPET, PH.PET,
365 Args); 460 Args);
366 } 461 }
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
419 replaceInstructionWithIntrinsicCall(I, Intrinsic, T, T, 514 replaceInstructionWithIntrinsicCall(I, Intrinsic, T, T,
420 ArrayRef<Value *>()); 515 ArrayRef<Value *>());
421 } else { 516 } else {
422 const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic = 517 const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic =
423 findAtomicIntrinsic(I, Intrinsic::nacl_atomic_fence, T); 518 findAtomicIntrinsic(I, Intrinsic::nacl_atomic_fence, T);
424 Value *Args[] = {freezeMemoryOrder(I, I.getOrdering())}; 519 Value *Args[] = {freezeMemoryOrder(I, I.getOrdering())};
425 replaceInstructionWithIntrinsicCall(I, Intrinsic, T, T, Args); 520 replaceInstructionWithIntrinsicCall(I, Intrinsic, T, T, Args);
426 } 521 }
427 } 522 }
428 523
429 ModulePass *llvm::createRewriteAtomicsPass() { return new RewriteAtomics(); } 524 /// Wrapper for the legacy pass manager.
525 class RewriteAtomics : public FunctionPass {
526 public:
527 static char ID; // Pass identification, replacement for typeid
528 RewriteAtomics() : FunctionPass(ID) {
529 initializeRewriteAtomicsPass(*PassRegistry::getPassRegistry());
530 }
531
532 bool runOnFunction(Function &F) override {
533 auto &Info = getAnalysis<AtomicAnalysisWrapperPass>().getInfo();
534 return ExpandAtomicInstructions(F, Info);
535 }
536
537 void getAnalysisUsage(AnalysisUsage &AU) const override {
538 AU.addRequired<AtomicAnalysisWrapperPass>();
539 }
540 };
541 char RewriteAtomics::ID = 0;
542 INITIALIZE_PASS_BEGIN(RewriteAtomics, "nacl-rewrite-atomics",
543 "rewrite atomics, volatiles and fences into stable "
544 "@llvm.nacl.atomics.* intrinsics",
545 false, false)
546 INITIALIZE_PASS_DEPENDENCY(AtomicAnalysisWrapperPass);
547 INITIALIZE_PASS_END(RewriteAtomics, "nacl-rewrite-atomics",
548 "rewrite atomics, volatiles and fences into stable "
549 "@llvm.nacl.atomics.* intrinsics",
550 false, false)
551
552 FunctionPass *llvm::createRewriteAtomicsPass() { return new RewriteAtomics(); }
OLDNEW
« no previous file with comments | « lib/Transforms/NaCl/LLVMBuild.txt ('k') | test/Transforms/NaCl/atomic/extra-rmw-operations.ll » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698