| 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 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/NaClIntrinsics.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 { |
| 34 public: |
| 35 ResolvePNaClIntrinsics() : FunctionPass(ID) { |
| 36 initializeResolvePNaClIntrinsicsPass(*PassRegistry::getPassRegistry()); |
| 37 } |
| 38 |
| 39 static char ID; |
| 40 virtual bool runOnFunction(Function &F); |
| 41 |
| 42 // Interface specifying how calls should be resolved. |
| 43 class CallResolver { |
| 30 public: | 44 public: |
| 31 ResolvePNaClIntrinsics() : FunctionPass(ID) { | 45 // Called once the intrinsic's declaration is found in the module. |
| 32 initializeResolvePNaClIntrinsicsPass(*PassRegistry::getPassRegistry()); | 46 void Init() { DoInit(); } |
| 33 } | 47 // Called once per call to the intrinsic in the module. |
| 34 | 48 bool Resolve(CallInst *Call) { |
| 35 static char ID; | 49 // To be a well-behaving FunctionPass, don't touch uses in other |
| 36 virtual bool runOnFunction(Function &F); | 50 // functions. These will be handled when the pass manager gets |
| 51 // to those functions. |
| 52 if (Call->getParent()->getParent() == &F) |
| 53 return DoResolve(Call); |
| 54 return false; |
| 55 } |
| 56 Function *getDeclaration() const { |
| 57 return Intrinsic::getDeclaration(M, IntrinsicID); |
| 58 } |
| 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 virtual void DoInit() = 0; |
| 70 virtual bool DoResolve(CallInst *Call) = 0; |
| 71 |
| 37 private: | 72 private: |
| 38 // Some intrinsic calls are resolved simply by replacing the call with a | 73 CallResolver(const CallResolver &); |
| 39 // call to an alternative function with exactly the same type. | 74 CallResolver &operator=(const CallResolver &); |
| 40 bool resolveSimpleCall(Function &F, Intrinsic::ID IntrinsicID, | |
| 41 const char *TargetFunctionName); | |
| 42 }; | 75 }; |
| 76 |
| 77 private: |
| 78 // Walk calls matching the resolver's declaration, and invoke the |
| 79 // CallResolver methods on each of them. |
| 80 bool walkCalls(CallResolver &Resolver); |
| 81 }; |
| 82 |
| 83 // Rewrite intrinsic calls to another function. |
| 84 class SimpleCallResolver : public ResolvePNaClIntrinsics::CallResolver { |
| 85 public: |
| 86 SimpleCallResolver(Function &F, Intrinsic::ID IntrinsicID, |
| 87 const char *TargetFunctionName) |
| 88 : CallResolver(F, IntrinsicID), TargetFunctionName(TargetFunctionName), |
| 89 TargetFunction(NULL) {} |
| 90 virtual ~SimpleCallResolver() {} |
| 91 |
| 92 private: |
| 93 const char *TargetFunctionName; |
| 94 Function *TargetFunction; |
| 95 |
| 96 virtual void DoInit() { |
| 97 // Expect to find the target function for this intrinsic already declared. |
| 98 TargetFunction = M->getFunction(TargetFunctionName); |
| 99 if (!TargetFunction) |
| 100 report_fatal_error(std::string( |
| 101 "Expected to find external declaration of ") + TargetFunctionName); |
| 102 } |
| 103 virtual bool DoResolve(CallInst *Call) { |
| 104 Call->setCalledFunction(TargetFunction); |
| 105 return true; |
| 106 } |
| 107 |
| 108 SimpleCallResolver(const SimpleCallResolver &); |
| 109 SimpleCallResolver &operator=(const SimpleCallResolver &); |
| 110 }; |
| 111 |
| 112 // Rewrite atomic intrinsics to LLVM IR instructions. |
| 113 class AtomicCallResolver : public ResolvePNaClIntrinsics::CallResolver { |
| 114 public: |
| 115 AtomicCallResolver(Function &F, Intrinsic::ID IntrinsicID) |
| 116 : CallResolver(F, IntrinsicID) {} |
| 117 virtual ~AtomicCallResolver() {} |
| 118 |
| 119 private: |
| 120 virtual void DoInit() {} |
| 121 virtual bool DoResolve(CallInst *Call) { |
| 122 // Assume the @llvm.nacl.atomic.<size> intrinsics follow the PNaCl |
| 123 // ABI: this should have been checked by the verifier. |
| 124 uint64_t Op(cast<Constant>(Call->getArgOperand(0)) |
| 125 ->getUniqueInteger().getLimitedValue()); |
| 126 Value *Ptr = Call->getArgOperand(1); |
| 127 Value *Val = Call->getArgOperand(2); |
| 128 Value *Old = Call->getArgOperand(3); |
| 129 uint64_t MemoryOrder(cast<Constant>(Call->getArgOperand(4)) |
| 130 ->getUniqueInteger().getLimitedValue()); |
| 131 |
| 132 AtomicRMWInst::BinOp RMWOp; |
| 133 switch (Op) { |
| 134 default: RMWOp = AtomicRMWInst::BAD_BINOP; break; |
| 135 case NaCl::AtomicAdd: RMWOp = AtomicRMWInst::Add; break; |
| 136 case NaCl::AtomicSub: RMWOp = AtomicRMWInst::Sub; break; |
| 137 case NaCl::AtomicOr: RMWOp = AtomicRMWInst::Or; break; |
| 138 case NaCl::AtomicAnd: RMWOp = AtomicRMWInst::And; break; |
| 139 case NaCl::AtomicXor: RMWOp = AtomicRMWInst::Xor; break; |
| 140 case NaCl::AtomicXchg: RMWOp = AtomicRMWInst::Xchg; break; |
| 141 } |
| 142 AtomicOrdering Order; |
| 143 switch (MemoryOrder) { |
| 144 // Conservatively use the strongest ordering. |
| 145 default: Order = SequentiallyConsistent; break; |
| 146 case NaCl::MemoryOrderRelaxed: Order = Unordered; break; |
| 147 // TODO Consume is unspecified by LLVM's internal IR. |
| 148 case NaCl::MemoryOrderConsume: Order = SequentiallyConsistent; break; |
| 149 case NaCl::MemoryOrderAcquire: Order = Acquire; break; |
| 150 case NaCl::MemoryOrderRelease: Order = Release; break; |
| 151 case NaCl::MemoryOrderAcquireRelease: Order = AcquireRelease; break; |
| 152 case NaCl::MemoryOrderSequentiallyConsistent: |
| 153 Order = SequentiallyConsistent; break; |
| 154 } |
| 155 const Twine Name(""); |
| 156 bool isVolatile = false; |
| 157 SynchronizationScope SS = CrossThread; |
| 158 bool hasUses; |
| 159 Instruction *I; |
| 160 |
| 161 for (size_t II = 0; II != NaCl::NumAtomicIntrinsics; ++II) { |
| 162 if (IntrinsicID != NaCl::AtomicIntrinsics[II].ID) |
| 163 continue; |
| 164 |
| 165 unsigned BitSize = NaCl::AtomicIntrinsics[II].BitSize; |
| 166 unsigned Align = 1 << (CountTrailingZeros_32(BitSize) - 3); |
| 167 switch (Op) { |
| 168 default: |
| 169 llvm_unreachable("invalid atomic operation"); |
| 170 case NaCl::AtomicLoad: |
| 171 hasUses = true; |
| 172 I = new LoadInst(Ptr, Name, isVolatile, Align, Order, SS, Call); |
| 173 break; |
| 174 case NaCl::AtomicStore: |
| 175 hasUses = false; |
| 176 I = new StoreInst(Val, Ptr, isVolatile, Align, Order, SS, Call); |
| 177 break; |
| 178 case NaCl::AtomicAdd: |
| 179 case NaCl::AtomicSub: |
| 180 case NaCl::AtomicOr: |
| 181 case NaCl::AtomicAnd: |
| 182 case NaCl::AtomicXor: |
| 183 case NaCl::AtomicXchg: |
| 184 hasUses = true; |
| 185 I = new AtomicRMWInst(RMWOp, Ptr, Val, Order, SS, Call); |
| 186 break; |
| 187 case NaCl::AtomicCmpXchg: |
| 188 hasUses = true; |
| 189 I = new AtomicCmpXchgInst(Ptr, Old, Val, Order, SS, Call); |
| 190 break; |
| 191 case NaCl::AtomicFence: |
| 192 hasUses = false; |
| 193 I = new FenceInst(M->getContext(), Order, SS, Call); |
| 194 break; |
| 195 } |
| 196 I->setDebugLoc(Call->getDebugLoc()); |
| 197 if (hasUses) |
| 198 Call->replaceAllUsesWith(I); |
| 199 Call->eraseFromParent(); |
| 200 } |
| 201 return true; |
| 202 } |
| 203 |
| 204 AtomicCallResolver(const AtomicCallResolver &); |
| 205 AtomicCallResolver &operator=(const AtomicCallResolver &); |
| 206 }; |
| 43 } | 207 } |
| 44 | 208 |
| 45 bool ResolvePNaClIntrinsics::resolveSimpleCall(Function &F, | 209 bool ResolvePNaClIntrinsics::walkCalls( |
| 46 Intrinsic::ID IntrinsicID, | 210 ResolvePNaClIntrinsics::CallResolver &Resolver) { |
| 47 const char *TargetFunctionName) { | |
| 48 Module *M = F.getParent(); | |
| 49 bool Changed = false; | 211 bool Changed = false; |
| 50 Function *IntrinsicFunction = Intrinsic::getDeclaration(M, IntrinsicID); | 212 Function *IntrinsicFunction = Resolver.getDeclaration(); |
| 51 | 213 if (!IntrinsicFunction) |
| 52 if (!IntrinsicFunction) { | |
| 53 return false; | 214 return false; |
| 54 } | 215 |
| 55 | 216 Resolver.Init(); |
| 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 | 217 |
| 64 for (Value::use_iterator UI = IntrinsicFunction->use_begin(), | 218 for (Value::use_iterator UI = IntrinsicFunction->use_begin(), |
| 65 UE = IntrinsicFunction->use_end(); UI != UE;) { | 219 UE = IntrinsicFunction->use_end(); |
| 220 UI != UE;) { |
| 66 // At this point, the only uses of the intrinsic can be calls, since | 221 // 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. | 222 // we assume this pass runs on bitcode that passed ABI verification. |
| 68 CallInst *Call = dyn_cast<CallInst>(*UI++); | 223 CallInst *Call = dyn_cast<CallInst>(*UI++); |
| 69 | 224 if (!Call) |
| 70 if (!Call) { | 225 report_fatal_error("Expected use of intrinsic to be a call: " + |
| 71 report_fatal_error( | 226 Resolver.getName()); |
| 72 std::string("Expected use of intrinsic to be a call: ") + | 227 |
| 73 Intrinsic::getName(IntrinsicID)); | 228 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 } | 229 } |
| 84 | 230 |
| 85 return Changed; | 231 return Changed; |
| 86 } | 232 } |
| 87 | 233 |
| 88 bool ResolvePNaClIntrinsics::runOnFunction(Function &F) { | 234 bool ResolvePNaClIntrinsics::runOnFunction(Function &F) { |
| 89 bool Changed = resolveSimpleCall(F, Intrinsic::nacl_setjmp, "setjmp"); | 235 bool Changed = false; |
| 90 Changed |= resolveSimpleCall(F, Intrinsic::nacl_longjmp, "longjmp"); | 236 |
| 237 SimpleCallResolver SetJmpResolver(F, Intrinsic::nacl_setjmp, "setjmp"); |
| 238 SimpleCallResolver LongJmpResolver(F, Intrinsic::nacl_longjmp, "longjmp"); |
| 239 Changed |= walkCalls(SetJmpResolver); |
| 240 Changed |= walkCalls(LongJmpResolver); |
| 241 |
| 242 for (size_t II = 0; II != NaCl::NumAtomicIntrinsics; ++II) { |
| 243 AtomicCallResolver AtomicResolver(F, NaCl::AtomicIntrinsics[II].ID); |
| 244 Changed |= walkCalls(AtomicResolver); |
| 245 } |
| 246 |
| 91 return Changed; | 247 return Changed; |
| 92 } | 248 } |
| 93 | 249 |
| 94 char ResolvePNaClIntrinsics::ID = 0; | 250 char ResolvePNaClIntrinsics::ID = 0; |
| 95 INITIALIZE_PASS(ResolvePNaClIntrinsics, "resolve-pnacl-intrinsics", | 251 INITIALIZE_PASS(ResolvePNaClIntrinsics, "resolve-pnacl-intrinsics", |
| 96 "Resolve PNaCl intrinsic calls", false, false) | 252 "Resolve PNaCl intrinsic calls", false, false) |
| 97 | 253 |
| 98 FunctionPass *llvm::createResolvePNaClIntrinsicsPass() { | 254 FunctionPass *llvm::createResolvePNaClIntrinsicsPass() { |
| 99 return new ResolvePNaClIntrinsics(); | 255 return new ResolvePNaClIntrinsics(); |
| 100 } | 256 } |
| OLD | NEW |