Chromium Code Reviews| 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 |