OLD | NEW |
---|---|
1 //===- PNaClABIVerifyModule.cpp - Verify PNaCl ABI rules ------------------===// | 1 //===- PNaClABIVerifyModule.cpp - Verify PNaCl ABI rules ------------------===// |
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 // Verify module-level PNaCl ABI requirements (specifically those that do not | 10 // Verify module-level PNaCl ABI requirements (specifically those that do not |
11 // require looking at the function bodies) | 11 // require looking at the function bodies) |
12 // | 12 // |
13 // | 13 // |
14 //===----------------------------------------------------------------------===// | 14 //===----------------------------------------------------------------------===// |
15 | 15 |
16 #include "llvm/Pass.h" | |
17 #include "llvm/ADT/Twine.h" | 16 #include "llvm/ADT/Twine.h" |
18 #include "llvm/Analysis/NaCl.h" | 17 #include "llvm/Analysis/NaCl.h" |
19 #include "llvm/IR/Constants.h" | 18 #include "llvm/IR/Constants.h" |
20 #include "llvm/IR/DerivedTypes.h" | 19 #include "llvm/IR/DerivedTypes.h" |
20 #include "llvm/IR/Instructions.h" | |
21 #include "llvm/IR/Intrinsics.h" | 21 #include "llvm/IR/Intrinsics.h" |
22 #include "llvm/IR/Module.h" | 22 #include "llvm/IR/Module.h" |
23 #include "llvm/IR/NaCl.h" | |
24 #include "llvm/Pass.h" | |
23 #include "llvm/Support/Debug.h" | 25 #include "llvm/Support/Debug.h" |
24 #include "llvm/Support/raw_ostream.h" | 26 #include "llvm/Support/raw_ostream.h" |
25 | 27 |
26 #include "PNaClABITypeChecker.h" | 28 #include "PNaClABITypeChecker.h" |
27 using namespace llvm; | 29 using namespace llvm; |
28 | 30 |
29 namespace llvm { | 31 namespace llvm { |
30 cl::opt<bool> | 32 cl::opt<bool> |
31 PNaClABIAllowDebugMetadata("pnaclabi-allow-debug-metadata", | 33 PNaClABIAllowDebugMetadata("pnaclabi-allow-debug-metadata", |
32 cl::desc("Allow debug metadata during PNaCl ABI verification."), | 34 cl::desc("Allow debug metadata during PNaCl ABI verification."), |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
174 static bool isWhitelistedCountBits(const Function *F, unsigned num_params) { | 176 static bool isWhitelistedCountBits(const Function *F, unsigned num_params) { |
175 FunctionType *FT = F->getFunctionType(); | 177 FunctionType *FT = F->getFunctionType(); |
176 if (FT->getNumParams() != num_params) | 178 if (FT->getNumParams() != num_params) |
177 return false; | 179 return false; |
178 Type *ParamType = FT->getParamType(0); | 180 Type *ParamType = FT->getParamType(0); |
179 LLVMContext &C = F->getContext(); | 181 LLVMContext &C = F->getContext(); |
180 Type *AcceptableTypes[] = { Type::getInt32Ty(C), Type::getInt64Ty(C) }; | 182 Type *AcceptableTypes[] = { Type::getInt32Ty(C), Type::getInt64Ty(C) }; |
181 return TypeAcceptable(ParamType, AcceptableTypes); | 183 return TypeAcceptable(ParamType, AcceptableTypes); |
182 } | 184 } |
183 | 185 |
186 // The signature for atomics is: | |
187 // T nacl.atomic.<size>(int32_t operation, T *location, T value, | |
Derek Schuff
2013/06/26 17:03:29
should be llvm.nacl.atomic.<size> when represented
JF
2013/06/26 23:41:12
Yes, I fixed all of these in a previous change.
| |
188 // T old_value, int32_t memory_order); | |
189 // With: | |
190 // - T in {i8, i16, i32, i64}. | |
191 // - operation as a valid NaCl::AtomicOperation. | |
192 // - memory_order as a valid NaCl::MemoryOrder. | |
193 static bool isWhitelistedAtomic(const Function *F, unsigned ID) { | |
194 LLVMContext &C = F->getContext(); | |
195 FunctionType *FT = F->getFunctionType(); | |
196 | |
197 Type *ReturnType = FT->getReturnType(); | |
198 switch (ID) { | |
199 default: llvm_unreachable("unhandled atomic intrinsic"); | |
200 case Intrinsic::nacl_atomic_8: | |
201 if (ReturnType != Type::getInt8Ty(C)) return false; | |
202 break; | |
203 case Intrinsic::nacl_atomic_16: | |
204 if (ReturnType != Type::getInt16Ty(C)) return false; | |
205 break; | |
206 case Intrinsic::nacl_atomic_32: | |
207 if (ReturnType != Type::getInt32Ty(C)) return false; | |
208 break; | |
209 case Intrinsic::nacl_atomic_64: | |
210 if (ReturnType != Type::getInt64Ty(C)) return false; | |
211 break; | |
212 } | |
213 | |
214 if ((FT->getNumParams() != 5) || | |
215 (FT->getParamType(0) != Type::getInt32Ty(C)) || | |
216 (!FT->getParamType(1)->isPointerTy()) || | |
217 (FT->getParamType(1)->getPointerElementType() != ReturnType) || | |
218 (FT->getParamType(2) != ReturnType) || | |
219 (FT->getParamType(3) != ReturnType) || | |
220 (FT->getParamType(4) != Type::getInt32Ty(C))) | |
221 return false; | |
222 | |
223 // Validate the operation and memory_order arguments have whitelisted values. | |
224 for (Value::const_use_iterator Call(F->use_begin()), CallEnd(F->use_end()); | |
Derek Schuff
2013/06/26 17:03:29
= instead of constructor syntax here too.
JF
2013/06/26 23:41:12
Done in a previous change.
| |
225 Call != CallEnd; ++Call) { | |
226 if (const CallInst *C = dyn_cast<CallInst>(*Call)) { | |
227 assert(C->getNumArgOperands() == 5 && "call should have as many " | |
228 "arguments as the corresponding intrinsic"); | |
229 const Value *Operation = C->getArgOperand(0); | |
230 const Value *MemoryOrder = C->getArgOperand(4); | |
231 const Constant *OperationC = dyn_cast<Constant>(Operation); | |
232 const Constant *MemoryOrderC = dyn_cast<Constant>(MemoryOrder); | |
233 if (!Operation || !MemoryOrder) | |
234 return false; | |
235 const APInt &OperationI = OperationC->getUniqueInteger(); | |
236 const APInt &MemoryOrderI = MemoryOrderC->getUniqueInteger(); | |
237 if (OperationI.ule(NaCl::AtomicInvalid) || | |
238 OperationI.uge(NaCl::AtomicNum)) | |
239 return false; | |
240 if (MemoryOrderI.ule(NaCl::MemoryOrderInvalid) || | |
241 MemoryOrderI.uge(NaCl::MemoryOrderNum)) | |
242 return false; | |
243 // TODO For now only sequential consistency is allowed. | |
244 if (MemoryOrderI != NaCl::MemoryOrderSequentiallyConsistent) | |
245 return false; | |
246 } else { | |
247 return false; | |
248 } | |
249 } | |
250 | |
251 return true; | |
252 } | |
253 | |
184 bool PNaClABIVerifyModule::isWhitelistedIntrinsic(const Function *F, | 254 bool PNaClABIVerifyModule::isWhitelistedIntrinsic(const Function *F, |
185 unsigned ID) { | 255 unsigned ID) { |
186 // Keep 3 categories of intrinsics for now. | 256 // Keep 3 categories of intrinsics for now. |
Derek Schuff
2013/06/26 17:03:29
new! now with 33% more categories!
JF
2013/06/26 23:41:12
<marquee>
| |
187 // (1) Allowed always | 257 // (1) Allowed always |
188 // (2) Never allowed | 258 // (2) Allowed with certain restrictions. |
189 // (3) "Dev" intrinsics, which may or may not be allowed. | 259 // (3) Never allowed |
260 // (4) "Dev" intrinsics, which may or may not be allowed. | |
190 // "Dev" intrinsics are controlled by the PNaClABIAllowDevIntrinsics flag. | 261 // "Dev" intrinsics are controlled by the PNaClABIAllowDevIntrinsics flag. |
191 // Please keep these sorted or grouped in a sensible way, within | 262 // Please keep these sorted or grouped in a sensible way, within |
192 // each category. | 263 // each category. |
193 switch(ID) { | 264 switch(ID) { |
194 // Disallow by default. | 265 // Disallow by default. |
195 default: return false; | 266 default: return false; |
196 // (1) Always allowed. | 267 // (1) Always allowed. |
197 case Intrinsic::bswap: return isWhitelistedBswap(F); | |
198 case Intrinsic::ctlz: | |
199 case Intrinsic::cttz: return isWhitelistedCountBits(F, 2); | |
200 case Intrinsic::ctpop: return isWhitelistedCountBits(F, 1); | |
201 case Intrinsic::memcpy: | 268 case Intrinsic::memcpy: |
202 case Intrinsic::memmove: | 269 case Intrinsic::memmove: |
203 case Intrinsic::memset: | 270 case Intrinsic::memset: |
204 case Intrinsic::nacl_read_tp: | 271 case Intrinsic::nacl_read_tp: |
205 case Intrinsic::nacl_setjmp: | 272 case Intrinsic::nacl_setjmp: |
206 case Intrinsic::nacl_longjmp: | 273 case Intrinsic::nacl_longjmp: |
207 case Intrinsic::trap: | 274 case Intrinsic::trap: |
208 return true; | 275 return true; |
209 | 276 |
210 // (2) Known to be never allowed. | 277 // (2) Allowed with certain restrictions. |
278 case Intrinsic::bswap: return isWhitelistedBswap(F); | |
279 case Intrinsic::ctlz: | |
280 case Intrinsic::cttz: return isWhitelistedCountBits(F, 2); | |
281 case Intrinsic::ctpop: return isWhitelistedCountBits(F, 1); | |
282 case Intrinsic::nacl_atomic_8: | |
283 case Intrinsic::nacl_atomic_16: | |
284 case Intrinsic::nacl_atomic_32: | |
285 case Intrinsic::nacl_atomic_64: return isWhitelistedAtomic(F, ID); | |
286 | |
287 // (3) Known to be never allowed. | |
211 case Intrinsic::not_intrinsic: | 288 case Intrinsic::not_intrinsic: |
212 // Trampolines depend on a target-specific-sized/aligned buffer. | 289 // Trampolines depend on a target-specific-sized/aligned buffer. |
213 case Intrinsic::adjust_trampoline: | 290 case Intrinsic::adjust_trampoline: |
214 case Intrinsic::init_trampoline: | 291 case Intrinsic::init_trampoline: |
215 // CXX exception handling is not stable. | 292 // CXX exception handling is not stable. |
216 case Intrinsic::eh_dwarf_cfa: | 293 case Intrinsic::eh_dwarf_cfa: |
217 case Intrinsic::eh_return_i32: | 294 case Intrinsic::eh_return_i32: |
218 case Intrinsic::eh_return_i64: | 295 case Intrinsic::eh_return_i64: |
219 case Intrinsic::eh_sjlj_callsite: | 296 case Intrinsic::eh_sjlj_callsite: |
220 case Intrinsic::eh_sjlj_functioncontext: | 297 case Intrinsic::eh_sjlj_functioncontext: |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
262 case Intrinsic::sin: // Rounding not defined: support with fast-math? | 339 case Intrinsic::sin: // Rounding not defined: support with fast-math? |
263 // We run -lower-expect to convert Intrinsic::expect into branch weights | 340 // We run -lower-expect to convert Intrinsic::expect into branch weights |
264 // and consume in the middle-end. The backend just ignores llvm.expect. | 341 // and consume in the middle-end. The backend just ignores llvm.expect. |
265 case Intrinsic::expect: | 342 case Intrinsic::expect: |
266 // For FLT_ROUNDS macro from float.h. It works for ARM and X86 | 343 // For FLT_ROUNDS macro from float.h. It works for ARM and X86 |
267 // (but not MIPS). Also, wait until we add a set_flt_rounds intrinsic | 344 // (but not MIPS). Also, wait until we add a set_flt_rounds intrinsic |
268 // before we bless this. | 345 // before we bless this. |
269 case Intrinsic::flt_rounds: | 346 case Intrinsic::flt_rounds: |
270 return false; | 347 return false; |
271 | 348 |
272 // (3) Dev intrinsics. | 349 // (4) Dev intrinsics. |
273 case Intrinsic::dbg_declare: | 350 case Intrinsic::dbg_declare: |
274 case Intrinsic::dbg_value: | 351 case Intrinsic::dbg_value: |
275 return PNaClABIAllowDevIntrinsics || PNaClABIAllowDebugMetadata; | 352 return PNaClABIAllowDevIntrinsics || PNaClABIAllowDebugMetadata; |
276 case Intrinsic::nacl_target_arch: // Used by translator self-build. | 353 case Intrinsic::nacl_target_arch: // Used by translator self-build. |
277 case Intrinsic::pow: // Rounding is supposed to be the same as libm. | 354 case Intrinsic::pow: // Rounding is supposed to be the same as libm. |
278 case Intrinsic::powi: // Rounding not defined: support with fast-math? | 355 case Intrinsic::powi: // Rounding not defined: support with fast-math? |
279 case Intrinsic::prefetch: // Could ignore if target doesn't support? | 356 case Intrinsic::prefetch: // Could ignore if target doesn't support? |
280 case Intrinsic::sqrt: // Rounding is defined, but setting errno up to libm. | 357 case Intrinsic::sqrt: // Rounding is defined, but setting errno up to libm. |
281 case Intrinsic::stackrestore: // Used to support C99 VLAs. | 358 case Intrinsic::stackrestore: // Used to support C99 VLAs. |
282 case Intrinsic::stacksave: // Used to support C99 VLAs. | 359 case Intrinsic::stacksave: // Used to support C99 VLAs. |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
471 } | 548 } |
472 | 549 |
473 char PNaClABIVerifyModule::ID = 0; | 550 char PNaClABIVerifyModule::ID = 0; |
474 INITIALIZE_PASS(PNaClABIVerifyModule, "verify-pnaclabi-module", | 551 INITIALIZE_PASS(PNaClABIVerifyModule, "verify-pnaclabi-module", |
475 "Verify module for PNaCl", false, true) | 552 "Verify module for PNaCl", false, true) |
476 | 553 |
477 ModulePass *llvm::createPNaClABIVerifyModulePass( | 554 ModulePass *llvm::createPNaClABIVerifyModulePass( |
478 PNaClABIErrorReporter *Reporter, bool StreamingMode) { | 555 PNaClABIErrorReporter *Reporter, bool StreamingMode) { |
479 return new PNaClABIVerifyModule(Reporter, StreamingMode); | 556 return new PNaClABIVerifyModule(Reporter, StreamingMode); |
480 } | 557 } |
OLD | NEW |