OLD | NEW |
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 |
14 // They are separate because one is a ModulePass and the other is a | 14 // pass. They are separate because one is a ModulePass and the other is |
15 // FunctionPass. | 15 // a 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" |
| 22 #include "llvm/IR/IntrinsicInst.h" |
21 #include "llvm/IR/Intrinsics.h" | 23 #include "llvm/IR/Intrinsics.h" |
22 #include "llvm/IR/Module.h" | 24 #include "llvm/IR/Module.h" |
| 25 #include "llvm/IR/NaClAtomicIntrinsics.h" |
| 26 #include "llvm/IR/Value.h" |
23 #include "llvm/Pass.h" | 27 #include "llvm/Pass.h" |
| 28 #include "llvm/Support/Compiler.h" |
24 #include "llvm/Transforms/NaCl.h" | 29 #include "llvm/Transforms/NaCl.h" |
25 | 30 |
26 using namespace llvm; | 31 using namespace llvm; |
27 | 32 |
28 namespace { | 33 namespace { |
29 class ResolvePNaClIntrinsics : public FunctionPass { | 34 class ResolvePNaClIntrinsics : public FunctionPass { |
| 35 public: |
| 36 ResolvePNaClIntrinsics() : FunctionPass(ID) { |
| 37 initializeResolvePNaClIntrinsicsPass(*PassRegistry::getPassRegistry()); |
| 38 } |
| 39 |
| 40 static char ID; |
| 41 virtual bool runOnFunction(Function &F); |
| 42 |
| 43 /// Interface specifying how intrinsic calls should be resolved. Each |
| 44 /// intrinsic call handled by the implementor will be visited by the |
| 45 /// doResolve method. |
| 46 class CallResolver { |
30 public: | 47 public: |
31 ResolvePNaClIntrinsics() : FunctionPass(ID) { | 48 /// Called once per \p Call to the intrinsic in the module. |
32 initializeResolvePNaClIntrinsicsPass(*PassRegistry::getPassRegistry()); | 49 /// Returns true if the Function was changed. |
33 } | 50 bool resolve(IntrinsicInst *Call) { |
34 | 51 // To be a well-behaving FunctionPass, don't touch uses in other |
35 static char ID; | 52 // functions. These will be handled when the pass manager gets to |
36 virtual bool runOnFunction(Function &F); | 53 // those functions. |
| 54 if (Call->getParent()->getParent() == &F) |
| 55 return doResolve(Call); |
| 56 return false; |
| 57 } |
| 58 Function *getDeclaration() const { return doGetDeclaration(); } |
| 59 std::string getName() { return Intrinsic::getName(IntrinsicID); } |
| 60 |
| 61 protected: |
| 62 Function &F; |
| 63 Module *M; |
| 64 Intrinsic::ID IntrinsicID; |
| 65 |
| 66 CallResolver(Function &F, Intrinsic::ID IntrinsicID) |
| 67 : F(F), M(F.getParent()), IntrinsicID(IntrinsicID) {} |
| 68 virtual ~CallResolver() {} |
| 69 |
| 70 /// The following pure virtual methods must be defined by |
| 71 /// implementors, and will be called once per intrinsic call. |
| 72 virtual Function *doGetDeclaration() const = 0; |
| 73 /// Returns true if the Function was changed. |
| 74 virtual bool doResolve(IntrinsicInst *Call) = 0; |
| 75 |
37 private: | 76 private: |
38 // Some intrinsic calls are resolved simply by replacing the call with a | 77 CallResolver(const CallResolver &) LLVM_DELETED_FUNCTION; |
39 // call to an alternative function with exactly the same type. | 78 CallResolver &operator=(const CallResolver &) LLVM_DELETED_FUNCTION; |
40 bool resolveSimpleCall(Function &F, Intrinsic::ID IntrinsicID, | |
41 const char *TargetFunctionName); | |
42 }; | 79 }; |
| 80 |
| 81 private: |
| 82 /// Visit all calls matching the \p Resolver's declaration, and invoke |
| 83 /// the CallResolver methods on each of them. |
| 84 bool visitCalls(CallResolver &Resolver); |
| 85 }; |
| 86 |
| 87 /// Rewrite intrinsic calls to another function. |
| 88 class SimpleCallResolver : public ResolvePNaClIntrinsics::CallResolver { |
| 89 public: |
| 90 SimpleCallResolver(Function &F, Intrinsic::ID IntrinsicID, |
| 91 const char *TargetFunctionName) |
| 92 : CallResolver(F, IntrinsicID), |
| 93 TargetFunction(M->getFunction(TargetFunctionName)) { |
| 94 // Expect to find the target function for this intrinsic already |
| 95 // declared, even if it is never used. |
| 96 if (!TargetFunction) |
| 97 report_fatal_error( |
| 98 std::string("Expected to find external declaration of ") + |
| 99 TargetFunctionName); |
| 100 } |
| 101 virtual ~SimpleCallResolver() {} |
| 102 |
| 103 private: |
| 104 Function *TargetFunction; |
| 105 |
| 106 virtual Function *doGetDeclaration() const { |
| 107 return Intrinsic::getDeclaration(M, IntrinsicID); |
| 108 } |
| 109 |
| 110 virtual bool doResolve(IntrinsicInst *Call) { |
| 111 Call->setCalledFunction(TargetFunction); |
| 112 return true; |
| 113 } |
| 114 |
| 115 SimpleCallResolver(const SimpleCallResolver &) LLVM_DELETED_FUNCTION; |
| 116 SimpleCallResolver &operator=( |
| 117 const SimpleCallResolver &) LLVM_DELETED_FUNCTION; |
| 118 }; |
| 119 |
| 120 /// Rewrite atomic intrinsics to LLVM IR instructions. |
| 121 class AtomicCallResolver : public ResolvePNaClIntrinsics::CallResolver { |
| 122 public: |
| 123 AtomicCallResolver(Function &F, |
| 124 const NaCl::AtomicIntrinsics::AtomicIntrinsic *I) |
| 125 : CallResolver(F, I->ID), I(I) {} |
| 126 virtual ~AtomicCallResolver() {} |
| 127 |
| 128 private: |
| 129 const NaCl::AtomicIntrinsics::AtomicIntrinsic *I; |
| 130 |
| 131 virtual Function *doGetDeclaration() const { return I->getDeclaration(M); } |
| 132 |
| 133 virtual bool doResolve(IntrinsicInst *Call) { |
| 134 // Assume the @llvm.nacl.atomic.* intrinsics follow the PNaCl ABI: |
| 135 // this should have been checked by the verifier. |
| 136 bool isVolatile = false; |
| 137 SynchronizationScope SS = CrossThread; |
| 138 Instruction *I; |
| 139 |
| 140 switch (Call->getIntrinsicID()) { |
| 141 default: |
| 142 llvm_unreachable("unknown atomic intrinsic"); |
| 143 case Intrinsic::nacl_atomic_load: |
| 144 I = new LoadInst(Call->getArgOperand(0), "", isVolatile, |
| 145 alignmentFromPointer(Call->getArgOperand(0)), |
| 146 thawMemoryOrder(Call->getArgOperand(1)), SS, Call); |
| 147 break; |
| 148 case Intrinsic::nacl_atomic_store: |
| 149 I = new StoreInst(Call->getArgOperand(0), Call->getArgOperand(1), |
| 150 isVolatile, |
| 151 alignmentFromPointer(Call->getArgOperand(1)), |
| 152 thawMemoryOrder(Call->getArgOperand(2)), SS, Call); |
| 153 break; |
| 154 case Intrinsic::nacl_atomic_rmw: |
| 155 I = new AtomicRMWInst(thawRMWOperation(Call->getArgOperand(0)), |
| 156 Call->getArgOperand(1), Call->getArgOperand(2), |
| 157 thawMemoryOrder(Call->getArgOperand(3)), SS, Call); |
| 158 break; |
| 159 case Intrinsic::nacl_atomic_cmpxchg: |
| 160 // TODO LLVM currently doesn't support specifying separate memory |
| 161 // orders for compare exchange's success and failure cases: |
| 162 // LLVM IR implicitly drops the Release part of the specified |
| 163 // memory order on failure. It is therefore correct to map |
| 164 // the success memory order onto the LLVM IR and ignore the |
| 165 // failure one. |
| 166 I = new AtomicCmpXchgInst(Call->getArgOperand(0), Call->getArgOperand(1), |
| 167 Call->getArgOperand(2), |
| 168 thawMemoryOrder(Call->getArgOperand(3)), SS, |
| 169 Call); |
| 170 break; |
| 171 case Intrinsic::nacl_atomic_fence: |
| 172 I = new FenceInst(M->getContext(), |
| 173 thawMemoryOrder(Call->getArgOperand(0)), SS, Call); |
| 174 break; |
| 175 } |
| 176 I->setName(Call->getName()); |
| 177 I->setDebugLoc(Call->getDebugLoc()); |
| 178 Call->replaceAllUsesWith(I); |
| 179 Call->eraseFromParent(); |
| 180 |
| 181 return true; |
| 182 } |
| 183 |
| 184 unsigned alignmentFromPointer(const Value *Ptr) const { |
| 185 const PointerType *PtrType = cast<PointerType>(Ptr->getType()); |
| 186 unsigned BitWidth = PtrType->getElementType()->getIntegerBitWidth(); |
| 187 return BitWidth / 8; |
| 188 } |
| 189 |
| 190 AtomicOrdering thawMemoryOrder(const Value *MemoryOrder) const { |
| 191 NaCl::MemoryOrder MO = (NaCl::MemoryOrder)cast<Constant>(MemoryOrder) |
| 192 ->getUniqueInteger().getLimitedValue(); |
| 193 switch (MO) { |
| 194 // Only valid values should pass validation. |
| 195 default: llvm_unreachable("unknown memory order"); |
| 196 case NaCl::MemoryOrderRelaxed: return Monotonic; |
| 197 // TODO Consume is unspecified by LLVM's internal IR. |
| 198 case NaCl::MemoryOrderConsume: return SequentiallyConsistent; |
| 199 case NaCl::MemoryOrderAcquire: return Acquire; |
| 200 case NaCl::MemoryOrderRelease: return Release; |
| 201 case NaCl::MemoryOrderAcquireRelease: return AcquireRelease; |
| 202 case NaCl::MemoryOrderSequentiallyConsistent: return SequentiallyConsistent; |
| 203 } |
| 204 } |
| 205 |
| 206 AtomicRMWInst::BinOp thawRMWOperation(const Value *Operation) const { |
| 207 NaCl::AtomicRMWOperation Op = |
| 208 (NaCl::AtomicRMWOperation)cast<Constant>(Operation)->getUniqueInteger() |
| 209 .getLimitedValue(); |
| 210 switch (Op) { |
| 211 // Only valid values should pass validation. |
| 212 default: llvm_unreachable("unknown atomic RMW operation"); |
| 213 case NaCl::AtomicAdd: return AtomicRMWInst::Add; |
| 214 case NaCl::AtomicSub: return AtomicRMWInst::Sub; |
| 215 case NaCl::AtomicOr: return AtomicRMWInst::Or; |
| 216 case NaCl::AtomicAnd: return AtomicRMWInst::And; |
| 217 case NaCl::AtomicXor: return AtomicRMWInst::Xor; |
| 218 case NaCl::AtomicExchange: return AtomicRMWInst::Xchg; |
| 219 } |
| 220 } |
| 221 |
| 222 AtomicCallResolver(const AtomicCallResolver &); |
| 223 AtomicCallResolver &operator=(const AtomicCallResolver &); |
| 224 }; |
43 } | 225 } |
44 | 226 |
45 bool ResolvePNaClIntrinsics::resolveSimpleCall(Function &F, | 227 bool ResolvePNaClIntrinsics::visitCalls( |
46 Intrinsic::ID IntrinsicID, | 228 ResolvePNaClIntrinsics::CallResolver &Resolver) { |
47 const char *TargetFunctionName) { | |
48 Module *M = F.getParent(); | |
49 bool Changed = false; | 229 bool Changed = false; |
50 Function *IntrinsicFunction = Intrinsic::getDeclaration(M, IntrinsicID); | 230 Function *IntrinsicFunction = Resolver.getDeclaration(); |
51 | 231 if (!IntrinsicFunction) |
52 if (!IntrinsicFunction) { | |
53 return false; | 232 return false; |
54 } | |
55 | |
56 // Expect to find the target function for this intrinsic already declared | |
57 Function *TargetFunction = M->getFunction(TargetFunctionName); | |
58 if (!TargetFunction) { | |
59 report_fatal_error( | |
60 std::string("Expected to find external declaration of ") + | |
61 TargetFunctionName); | |
62 } | |
63 | 233 |
64 for (Value::use_iterator UI = IntrinsicFunction->use_begin(), | 234 for (Value::use_iterator UI = IntrinsicFunction->use_begin(), |
65 UE = IntrinsicFunction->use_end(); UI != UE;) { | 235 UE = IntrinsicFunction->use_end(); |
| 236 UI != UE;) { |
66 // At this point, the only uses of the intrinsic can be calls, since | 237 // 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. | 238 // we assume this pass runs on bitcode that passed ABI verification. |
68 CallInst *Call = dyn_cast<CallInst>(*UI++); | 239 IntrinsicInst *Call = dyn_cast<IntrinsicInst>(*UI++); |
69 | 240 if (!Call) |
70 if (!Call) { | 241 report_fatal_error("Expected use of intrinsic to be a call: " + |
71 report_fatal_error( | 242 Resolver.getName()); |
72 std::string("Expected use of intrinsic to be a call: ") + | 243 |
73 Intrinsic::getName(IntrinsicID)); | 244 Changed |= Resolver.resolve(Call); |
74 } | |
75 | |
76 // 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 | |
78 // functions. | |
79 if (Call->getParent()->getParent() == &F) { | |
80 Call->setCalledFunction(TargetFunction); | |
81 Changed = true; | |
82 } | |
83 } | 245 } |
84 | 246 |
85 return Changed; | 247 return Changed; |
86 } | 248 } |
87 | 249 |
88 bool ResolvePNaClIntrinsics::runOnFunction(Function &F) { | 250 bool ResolvePNaClIntrinsics::runOnFunction(Function &F) { |
89 bool Changed = resolveSimpleCall(F, Intrinsic::nacl_setjmp, "setjmp"); | 251 bool Changed = false; |
90 Changed |= resolveSimpleCall(F, Intrinsic::nacl_longjmp, "longjmp"); | 252 |
| 253 SimpleCallResolver SetJmpResolver(F, Intrinsic::nacl_setjmp, "setjmp"); |
| 254 SimpleCallResolver LongJmpResolver(F, Intrinsic::nacl_longjmp, "longjmp"); |
| 255 Changed |= visitCalls(SetJmpResolver); |
| 256 Changed |= visitCalls(LongJmpResolver); |
| 257 |
| 258 NaCl::AtomicIntrinsics AI(F.getParent()->getContext()); |
| 259 NaCl::AtomicIntrinsics::View V = AI.allIntrinsicsAndOverloads(); |
| 260 for (NaCl::AtomicIntrinsics::View::iterator I = V.begin(), E = V.end(); |
| 261 I != E; ++I) { |
| 262 AtomicCallResolver AtomicResolver(F, I); |
| 263 Changed |= visitCalls(AtomicResolver); |
| 264 } |
| 265 |
91 return Changed; | 266 return Changed; |
92 } | 267 } |
93 | 268 |
94 char ResolvePNaClIntrinsics::ID = 0; | 269 char ResolvePNaClIntrinsics::ID = 0; |
95 INITIALIZE_PASS(ResolvePNaClIntrinsics, "resolve-pnacl-intrinsics", | 270 INITIALIZE_PASS(ResolvePNaClIntrinsics, "resolve-pnacl-intrinsics", |
96 "Resolve PNaCl intrinsic calls", false, false) | 271 "Resolve PNaCl intrinsic calls", false, false) |
97 | 272 |
98 FunctionPass *llvm::createResolvePNaClIntrinsicsPass() { | 273 FunctionPass *llvm::createResolvePNaClIntrinsicsPass() { |
99 return new ResolvePNaClIntrinsics(); | 274 return new ResolvePNaClIntrinsics(); |
100 } | 275 } |
OLD | NEW |