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

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

Issue 17777004: Concurrency support for PNaCl ABI (Closed) Base URL: http://git.chromium.org/native_client/pnacl-llvm.git@master
Patch Set: Update PNaClLangRef to reflect the implementation work I will now go forward with. Created 7 years, 5 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
OLDNEW
(Empty)
1 //===- RewriteAtomics.cpp - Stabilize instructions used for concurrency ---===//
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 encodes atomics, volatiles and fences using NaCl intrinsics
11 // instead of LLVM's regular IR instructions.
12 //
13 // All of the above are transformed into one of the
14 // @llvm.nacl.atomic.<size> intrinsics.
15 //
16 //===----------------------------------------------------------------------===//
17
18 #include "llvm/ADT/Twine.h"
19 #include "llvm/IR/Function.h"
20 #include "llvm/IR/Instructions.h"
21 #include "llvm/IR/Intrinsics.h"
22 #include "llvm/IR/Module.h"
23 #include "llvm/IR/NaClIntrinsics.h"
24 #include "llvm/InstVisitor.h"
25 #include "llvm/Pass.h"
26 #include "llvm/Support/raw_ostream.h"
27 #include "llvm/Support/raw_ostream.h"
28 #include "llvm/Transforms/NaCl.h"
29
30 using namespace llvm;
31
32 namespace {
33 class RewriteAtomics : public ModulePass {
34 public:
35 static char ID; // Pass identification, replacement for typeid
36 RewriteAtomics() : ModulePass(ID) {
37 // This is a module pass because it may have to introduce
38 // intrinsic declarations into the module and modify a global function.
39 initializeRewriteAtomicsPass(*PassRegistry::getPassRegistry());
40 }
41
42 virtual bool runOnModule(Module &M);
43 };
44
45 template <class T> Twine ToTwine(const T &V) {
46 std::string S;
47 raw_string_ostream OS(S);
48 OS << const_cast<T &>(V);
49 return OS.str();
50 }
51
52 class AtomicVisitor : public InstVisitor<AtomicVisitor> {
53 Module &M;
54 LLVMContext &C;
55 bool ModifiedModule;
56 struct {
57 Function *F;
58 unsigned BitSize;
59 } AtomicFunctions[NaCl::NumAtomicIntrinsics];
60
61 AtomicVisitor();
62 AtomicVisitor(const AtomicVisitor &);
63 AtomicVisitor &operator=(const AtomicVisitor &);
64
65 NaCl::MemoryOrder freezeMemoryOrdering(llvm::AtomicOrdering AO) const;
66 void checkSizeMatchesType(const Instruction &I, unsigned S,
67 const Type *T) const;
68 void checkAlignment(const Instruction &I, unsigned Alignment,
69 unsigned Size) const;
70 Function *atomicIntrinsic(const Instruction &I, unsigned AtomicBitSize);
71
72 // Replace atomic instruction I with a @llvm.nacl.atomic.<size> intrinsic.
73 //
74 // Type and Size are the base atomic integer type and its size in
75 // bits. The subsequent parameters are the ones passed to the
76 // intrinsic, and are detailed in docs/PNaClLangRef.rst.
77 void replaceWithAtomicIntrinsic(Instruction &I, const Type *T, unsigned Size,
78 NaCl::AtomicOperation O, Value *Loc,
79 Value *Val, Value *Old, AtomicOrdering AO);
80
81 // Most atomics instructions deal with at least one pointer, this
82 // struct automates some of this and has generic sanity checks.
83 template <class Instruction> struct PointerHelper {
84 Value *P;
85 Type *PET;
86 unsigned Size;
87 Value *Zero;
88 PointerHelper(const AtomicVisitor &AV, Instruction &I)
89 : P(I.getPointerOperand()) {
90 if (I.getPointerAddressSpace() != 0)
91 report_fatal_error("unhandled pointer address space " +
92 Twine(I.getPointerAddressSpace()) + " for atomic: " +
93 ToTwine(I));
94 assert(P->getType()->isPointerTy() && "expected a pointer");
95 PET = P->getType()->getPointerElementType();
96 Size = PET->getIntegerBitWidth();
97 AV.checkSizeMatchesType(I, Size, PET);
98 Zero = ConstantInt::get(PET, 0);
99 }
100 };
101
102 public:
103 AtomicVisitor(Module &M) : M(M), C(M.getContext()), ModifiedModule(false) {
104 for (size_t i = 0; i != NaCl::NumAtomicIntrinsics; ++i) {
105 AtomicFunctions[i].F =
106 Intrinsic::getDeclaration(&M, NaCl::AtomicIntrinsics[i].ID);
107 AtomicFunctions[i].BitSize = NaCl::AtomicIntrinsics[i].BitSize;
108 }
109 }
110 ~AtomicVisitor() {}
111 bool modifiedModule() const { return ModifiedModule; }
112
113 void visitLoadInst(LoadInst &I);
114 void visitStoreInst(StoreInst &I);
115 void visitAtomicCmpXchgInst(AtomicCmpXchgInst &I);
116 void visitAtomicRMWInst(AtomicRMWInst &I);
117 void visitFenceInst(FenceInst &I);
118 };
119 }
120
121 char RewriteAtomics::ID = 0;
122 INITIALIZE_PASS(RewriteAtomics, "nacl-rewrite-atomics",
123 "rewrite atomics, volatiles and fences into stable "
124 "@llvm.nacl.atomics.<size> intrinsics",
125 false, false)
126
127 bool RewriteAtomics::runOnModule(Module &M) {
128 AtomicVisitor AV(M);
129 AV.visit(M);
130 return AV.modifiedModule();
131 }
132
133 NaCl::MemoryOrder
134 AtomicVisitor::freezeMemoryOrdering(llvm::AtomicOrdering AO) const {
135 // TODO For now only sequential consistency is allowed.
136 return NaCl::MemoryOrderSequentiallyConsistent;
137 }
138
139 void AtomicVisitor::checkSizeMatchesType(const Instruction &I, unsigned S,
140 const Type *T) const {
141 Type *IntType = Type::getIntNTy(C, S);
142 if (IntType && T == IntType)
143 return;
144 report_fatal_error("unsupported atomic type " + ToTwine(*T) + " of size " +
145 Twine(S) + " in: " + ToTwine(I));
146 }
147
148 void AtomicVisitor::checkAlignment(const Instruction &I, unsigned Alignment,
149 unsigned Size) const {
150 if (Alignment < Size)
151 report_fatal_error("atomic load/store must be at least naturally aligned, "
152 "got " + Twine(Alignment) + ", expected at least " +
153 Twine(Size) + ", in: " + ToTwine(I));
154 }
155
156 Function *AtomicVisitor::atomicIntrinsic(const Instruction &I,
157 unsigned AtomicBitSize) {
158 for (size_t Intr = 0; Intr != NaCl::NumAtomicIntrinsics; ++Intr)
159 if (AtomicFunctions[Intr].BitSize == AtomicBitSize)
160 return AtomicFunctions[Intr].F;
161 report_fatal_error("unsupported atomic bit size " + Twine(AtomicBitSize) +
162 " in : " + ToTwine(I));
163 }
164
165 void AtomicVisitor::replaceWithAtomicIntrinsic(Instruction &I, const Type *T,
166 unsigned Size,
167 NaCl::AtomicOperation O,
168 Value *Loc, Value *Val,
169 Value *Old, AtomicOrdering AO) {
170 Value *Args[] = { ConstantInt::get(Type::getInt32Ty(C), O), Loc, Val, Old,
171 ConstantInt::get(Type::getInt32Ty(C),
172 freezeMemoryOrdering(AO)) };
173 CallInst *Call = CallInst::Create(atomicIntrinsic(I, Size), Args, "", &I);
174 Call->setDebugLoc(I.getDebugLoc());
175 if (!I.getType()->isVoidTy())
176 I.replaceAllUsesWith(Call);
177 I.eraseFromParent();
178
179 ModifiedModule = true;
180 }
181
182 // %res = load {atomic|volatile} T* %ptr ordering, align sizeof(T)
183 // becomes:
184 // %res = call T @llvm.nacl.atomic.<sizeof(T)>(Load, %ptr, 0, 0, ordering)
185 void AtomicVisitor::visitLoadInst(LoadInst &I) {
186 if (I.isSimple())
187 return;
188 PointerHelper<LoadInst> PH(*this, I);
189 checkAlignment(I, I.getAlignment() * 8, PH.Size);
190 replaceWithAtomicIntrinsic(I, PH.PET, PH.Size, NaCl::AtomicLoad, PH.P,
191 PH.Zero, PH.Zero, I.getOrdering());
192 }
193
194 // store {atomic|volatile} T %val, T* %ptr ordering, align sizeof(T)
195 // becomes:
196 // call T @llvm.nacl.atomic.<sizeof(T)>(Store, %ptr, %val, 0, ordering)
197 void AtomicVisitor::visitStoreInst(StoreInst &I) {
198 if (I.isSimple())
199 return;
200 PointerHelper<StoreInst> PH(*this, I);
201 checkAlignment(I, I.getAlignment() * 8, PH.Size);
202 checkSizeMatchesType(I, PH.Size, I.getValueOperand()->getType());
203 replaceWithAtomicIntrinsic(I, PH.PET, PH.Size, NaCl::AtomicStore, PH.P,
204 I.getValueOperand(), PH.Zero, I.getOrdering());
205 }
206
207 // %res = cmpxchg T* %ptr, T %old, T %new ordering
208 // becomes:
209 // %res = call T @llvm.nacl.atomic.<sizeof(T)>(CmpXchg, %ptr, %new, %old,
210 // ordering)
211 void AtomicVisitor::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) {
212 PointerHelper<AtomicCmpXchgInst> PH(*this, I);
213 checkSizeMatchesType(I, PH.Size, I.getCompareOperand()->getType());
214 checkSizeMatchesType(I, PH.Size, I.getNewValOperand()->getType());
215 replaceWithAtomicIntrinsic(I, PH.PET, PH.Size, NaCl::AtomicCmpXchg, PH.P,
216 I.getNewValOperand(), I.getCompareOperand(),
217 I.getOrdering());
218 }
219
220 // %res = atomicrmw OP T* %ptr, T %val ordering
221 // becomes:
222 // %res = call T @llvm.nacl.atomic.<sizeof(T)>(OP, %ptr, %val, 0, ordering)
223 void AtomicVisitor::visitAtomicRMWInst(AtomicRMWInst &I) {
224 NaCl::AtomicOperation Op;
225 switch (I.getOperation()) {
226 default:
227 report_fatal_error("unsupported atomicrmw operation: " + ToTwine(I));
228 case AtomicRMWInst::Xchg: Op = NaCl::AtomicXchg; break;
229 case AtomicRMWInst::Add: Op = NaCl::AtomicAdd; break;
230 case AtomicRMWInst::Sub: Op = NaCl::AtomicSub; break;
231 case AtomicRMWInst::And: Op = NaCl::AtomicAnd; break;
232 case AtomicRMWInst::Or: Op = NaCl::AtomicOr; break;
233 case AtomicRMWInst::Xor: Op = NaCl::AtomicXor; break;
234 }
235 PointerHelper<AtomicRMWInst> PH(*this, I);
236 checkSizeMatchesType(I, PH.Size, I.getValOperand()->getType());
237 replaceWithAtomicIntrinsic(I, PH.PET, PH.Size, Op, PH.P, I.getValOperand(),
238 PH.Zero, I.getOrdering());
239 }
240
241 // fence ordering
242 // becomes:
243 // call i32 @llvm.nacl.atomic.<sizeof(T)>(Fence, NULL, 0, 0, ordering)
244 void AtomicVisitor::visitFenceInst(FenceInst &I) {
245 Type *Int32 = Type::getInt32Ty(C);
246 Value *Zero = ConstantInt::get(Int32, 0);
247 Value *Null = ConstantPointerNull::get(PointerType::getUnqual(Int32));
248 replaceWithAtomicIntrinsic(I, Int32, 32, NaCl::AtomicFence, Null, Zero, Zero,
249 I.getOrdering());
250 }
251
252 ModulePass *llvm::createRewriteAtomicsPass() { return new RewriteAtomics(); }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698