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

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

Issue 17777004: Concurrency support for PNaCl ABI (Closed) Base URL: http://git.chromium.org/native_client/pnacl-llvm.git@master
Patch Set: 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
1 //===- ResolvePNaClIntrinsics.cpp - Resolve calls to PNaCl intrinsics ----====// 1 //===- ResolvePNaClIntrinsics.cpp - Resolve calls to PNaCl intrinsics ----====//
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 resolves calls to PNaCl stable bitcode intrinsics. It is 10 // This pass resolves calls to PNaCl stable bitcode intrinsics. It is
11 // normally run in the PNaCl translator. 11 // normally run in the PNaCl translator.
12 // 12 //
13 // Running AddPNaClExternalDeclsPass is a precondition for running this pass. 13 // Running AddPNaClExternalDeclsPass is a precondition for running this pass.
14 // They are separate because one is a ModulePass and the other is a 14 // They are separate because one is a ModulePass and the other is a
15 // FunctionPass. 15 // FunctionPass.
16 // 16 //
17 //===----------------------------------------------------------------------===// 17 //===----------------------------------------------------------------------===//
18 18
19 #include "llvm/ADT/SmallVector.h" 19 #include "llvm/ADT/SmallVector.h"
20 #include "llvm/IR/Constant.h"
20 #include "llvm/IR/Instructions.h" 21 #include "llvm/IR/Instructions.h"
21 #include "llvm/IR/Intrinsics.h" 22 #include "llvm/IR/Intrinsics.h"
22 #include "llvm/IR/Module.h" 23 #include "llvm/IR/Module.h"
24 #include "llvm/IR/NaCl.h"
25 #include "llvm/IR/Value.h"
23 #include "llvm/Pass.h" 26 #include "llvm/Pass.h"
27 #include "llvm/Support/MathExtras.h"
24 #include "llvm/Transforms/NaCl.h" 28 #include "llvm/Transforms/NaCl.h"
25 29
26 using namespace llvm; 30 using namespace llvm;
27 31
28 namespace { 32 namespace {
29 class ResolvePNaClIntrinsics : public FunctionPass { 33 class ResolvePNaClIntrinsics : public FunctionPass {
30 public: 34 public:
31 ResolvePNaClIntrinsics() : FunctionPass(ID) { 35 ResolvePNaClIntrinsics() : FunctionPass(ID) {
32 initializeResolvePNaClIntrinsicsPass(*PassRegistry::getPassRegistry()); 36 initializeResolvePNaClIntrinsicsPass(*PassRegistry::getPassRegistry());
33 } 37 }
34 38
35 static char ID; 39 static char ID;
36 virtual bool runOnFunction(Function &F); 40 virtual bool runOnFunction(Function &F);
37 private: 41 private:
38 // Some intrinsic calls are resolved simply by replacing the call with a 42 // Some intrinsic calls are resolved simply by replacing the call with a
39 // call to an alternative function with exactly the same type. 43 // call to an alternative function with exactly the same type.
40 bool resolveSimpleCall(Function &F, Intrinsic::ID IntrinsicID, 44 bool resolveSimpleCall(Function &F, Intrinsic::ID IntrinsicID);
41 const char *TargetFunctionName); 45 // All atomic calls are rewritten to a single instruction, and the
46 // call is removed.
47 void rewriteAtomicCall(Module *M, Function &F, Intrinsic::ID IntrinsicID,
48 CallInst *Call);
42 }; 49 };
43 } 50 }
44 51
45 bool ResolvePNaClIntrinsics::resolveSimpleCall(Function &F, 52 bool ResolvePNaClIntrinsics::resolveSimpleCall(Function &F,
46 Intrinsic::ID IntrinsicID, 53 Intrinsic::ID IntrinsicID) {
47 const char *TargetFunctionName) {
48 Module *M = F.getParent(); 54 Module *M = F.getParent();
49 bool Changed = false; 55 bool Changed = false;
50 Function *IntrinsicFunction = Intrinsic::getDeclaration(M, IntrinsicID); 56 Function *IntrinsicFunction = Intrinsic::getDeclaration(M, IntrinsicID);
51 57
52 if (!IntrinsicFunction) { 58 if (!IntrinsicFunction) {
53 return false; 59 return false;
54 } 60 }
55 61
56 // Expect to find the target function for this intrinsic already declared 62 Function *TargetFunction = NULL;
57 Function *TargetFunction = M->getFunction(TargetFunctionName); 63 if (IntrinsicID == Intrinsic::nacl_setjmp ||
eliben 2013/06/26 16:20:57 No no no no no :-) resolveSimpleCall's comment is
JF 2013/06/26 22:23:12 Done: rewrote to use one class per type of rewrite
58 if (!TargetFunction) { 64 IntrinsicID == Intrinsic::nacl_longjmp) {
59 report_fatal_error( 65 // Expect to find the target function for this intrinsic already declared.
60 std::string("Expected to find external declaration of ") + 66 const char *TargetFunctionName = IntrinsicID == Intrinsic::nacl_setjmp
61 TargetFunctionName); 67 ? "setjmp" : "longjmp";
68 TargetFunction = M->getFunction(TargetFunctionName);
69 if (!TargetFunction) {
70 report_fatal_error(
71 std::string("Expected to find external declaration of ") +
72 TargetFunctionName);
73 }
62 } 74 }
63 75
64 for (Value::use_iterator UI = IntrinsicFunction->use_begin(), 76 for (Value::use_iterator UI = IntrinsicFunction->use_begin(),
65 UE = IntrinsicFunction->use_end(); UI != UE;) { 77 UE = IntrinsicFunction->use_end(); UI != UE;) {
66 // At this point, the only uses of the intrinsic can be calls, since 78 // At this point, the only uses of the intrinsic can be calls, since
67 // we assume this pass runs on bitcode that passed ABI verification. 79 // we assume this pass runs on bitcode that passed ABI verification.
68 CallInst *Call = dyn_cast<CallInst>(*UI++); 80 CallInst *Call = dyn_cast<CallInst>(*UI++);
69 81
70 if (!Call) { 82 if (!Call) {
71 report_fatal_error( 83 report_fatal_error(
72 std::string("Expected use of intrinsic to be a call: ") + 84 std::string("Expected use of intrinsic to be a call: ") +
73 Intrinsic::getName(IntrinsicID)); 85 Intrinsic::getName(IntrinsicID));
74 } 86 }
75 87
76 // To be a well-behaving FunctionPass, don't touch uses in other 88 // To be a well-behaving FunctionPass, don't touch uses in other
77 // functions. These will be handled when the pass manager gets to those 89 // functions. These will be handled when the pass manager gets to those
78 // functions. 90 // functions.
79 if (Call->getParent()->getParent() == &F) { 91 if (Call->getParent()->getParent() == &F) {
80 Call->setCalledFunction(TargetFunction); 92 if (IntrinsicID == Intrinsic::nacl_setjmp ||
93 IntrinsicID == Intrinsic::nacl_longjmp)
94 Call->setCalledFunction(TargetFunction);
95 else
96 rewriteAtomicCall(M, F, IntrinsicID, Call);
81 Changed = true; 97 Changed = true;
82 } 98 }
83 } 99 }
84 100
85 return Changed; 101 return Changed;
86 } 102 }
87 103
104 void ResolvePNaClIntrinsics::rewriteAtomicCall(Module *M, Function &F,
105 Intrinsic::ID IntrinsicID,
106 CallInst *Call) {
107 // Assume the @nacl.atomic.<size> intrinsics follow the PNaCl
108 // ABI: this should have been checked by the verifier.
109 uint64_t Op(cast<Constant>(
110 Call->getArgOperand(0))->getUniqueInteger().getLimitedValue());
111 Value *Ptr(Call->getArgOperand(1));
Mark Seaborn 2013/06/26 14:33:41 Just write "Ptr = Call->getArgOperand(1)"? Using
JF 2013/06/26 15:52:29 Done.
112 Value *Val(Call->getArgOperand(2));
113 Value *Old(Call->getArgOperand(3));
114 uint64_t MemoryOrder(cast<Constant>(
115 Call->getArgOperand(4))->getUniqueInteger().getLimitedValue());
116
117 AtomicRMWInst::BinOp RMWOp;
118 switch (Op) {
119 default: RMWOp = AtomicRMWInst::BAD_BINOP; break;
120 case NaCl::AtomicAdd: RMWOp = AtomicRMWInst::Add; break;
121 case NaCl::AtomicSub: RMWOp = AtomicRMWInst::Sub; break;
122 case NaCl::AtomicOr: RMWOp = AtomicRMWInst::Or; break;
123 case NaCl::AtomicAnd: RMWOp = AtomicRMWInst::And; break;
124 case NaCl::AtomicXor: RMWOp = AtomicRMWInst::Xor; break;
125 case NaCl::AtomicXchg: RMWOp = AtomicRMWInst::Xchg; break;
126 }
127 AtomicOrdering Order;
128 switch (MemoryOrder) {
129 default:
130 // Conservatively use the strongest ordering.
131 Order = SequentiallyConsistent; break;
132 case NaCl::MemoryOrderRelaxed: Order = Unordered; break;
133 case NaCl::MemoryOrderConsume:
134 // TODO Unspecified by LLVM's internal IR.
135 Order = SequentiallyConsistent; break;
136 case NaCl::MemoryOrderAcquire: Order = Acquire; break;
137 case NaCl::MemoryOrderRelease: Order = Release; break;
138 case NaCl::MemoryOrderAcquireRelease: Order = AcquireRelease; break;
139 case NaCl::MemoryOrderSequentiallyConsistent:
140 Order = SequentiallyConsistent; break;
141 }
142 const Twine Name("");
143 bool isVolatile = false;
144 SynchronizationScope SS = CrossThread;
145 bool hasUses;
146 Instruction *I;
147
148 for (size_t II = 0; II != NaCl::NumAtomicIntrinsics; ++II) {
149 if (IntrinsicID != NaCl::AtomicIntrinsics[II].ID)
150 continue;
151
152 unsigned BitSize = NaCl::AtomicIntrinsics[II].BitSize;
153 unsigned Align = 1 << (CountTrailingZeros_32(BitSize) - 3);
154 switch (Op) {
155 default: llvm_unreachable("invalid atomic operation");
156 case NaCl::AtomicLoad:
157 hasUses = true;
158 I = new LoadInst(Ptr, Name, isVolatile, Align, Order, SS, Call);
159 break;
160 case NaCl::AtomicStore:
161 hasUses = false;
162 I = new StoreInst(Val, Ptr, isVolatile, Align, Order, SS, Call);
163 break;
164 case NaCl::AtomicAdd:
165 case NaCl::AtomicSub:
166 case NaCl::AtomicOr:
167 case NaCl::AtomicAnd:
168 case NaCl::AtomicXor:
169 case NaCl::AtomicXchg:
170 hasUses = true;
171 I = new AtomicRMWInst(RMWOp, Ptr, Val, Order, SS, Call);
172 break;
173 case NaCl::AtomicCmpXchg:
174 hasUses = true;
175 I = new AtomicCmpXchgInst(Ptr, Old, Val, Order, SS, Call);
176 break;
177 case NaCl::AtomicFence:
178 hasUses = false;
179 I = new FenceInst(M->getContext(), Order, SS, Call);
180 break;
181 }
182 I->setDebugLoc(Call->getDebugLoc());
183 if (hasUses)
Mark Seaborn 2013/06/26 14:33:41 I think you can do the RAUW unconditionally
JF 2013/06/26 15:52:29 No: assert(New->getType() == getType() &&
184 Call->replaceAllUsesWith(I);
185 Call->eraseFromParent();
186 }
187 }
188
88 bool ResolvePNaClIntrinsics::runOnFunction(Function &F) { 189 bool ResolvePNaClIntrinsics::runOnFunction(Function &F) {
89 bool Changed = resolveSimpleCall(F, Intrinsic::nacl_setjmp, "setjmp"); 190 bool Changed = resolveSimpleCall(F, Intrinsic::nacl_setjmp);
90 Changed |= resolveSimpleCall(F, Intrinsic::nacl_longjmp, "longjmp"); 191 Changed |= resolveSimpleCall(F, Intrinsic::nacl_longjmp);
192 for (size_t II = 0; II != NaCl::NumAtomicIntrinsics; ++II) {
193 Changed |= resolveSimpleCall(F, NaCl::AtomicIntrinsics[II].ID);
194 }
91 return Changed; 195 return Changed;
92 } 196 }
93 197
94 char ResolvePNaClIntrinsics::ID = 0; 198 char ResolvePNaClIntrinsics::ID = 0;
95 INITIALIZE_PASS(ResolvePNaClIntrinsics, "resolve-pnacl-intrinsics", 199 INITIALIZE_PASS(ResolvePNaClIntrinsics, "resolve-pnacl-intrinsics",
96 "Resolve PNaCl intrinsic calls", false, false) 200 "Resolve PNaCl intrinsic calls", false, false)
97 201
98 FunctionPass *llvm::createResolvePNaClIntrinsicsPass() { 202 FunctionPass *llvm::createResolvePNaClIntrinsicsPass() {
99 return new ResolvePNaClIntrinsics(); 203 return new ResolvePNaClIntrinsics();
100 } 204 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698