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

Side by Side Diff: lib/Analysis/NaCl/PNaClABIVerifyModule.cpp

Issue 14914011: Promote bswap i16, i32, and i64 to be allowed llvm intrinsics. (Closed) Base URL: http://git.chromium.org/native_client/pnacl-llvm.git@master
Patch Set: review Created 7 years, 7 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
« no previous file with comments | « no previous file | test/NaCl/PNaClABI/intrinsics.ll » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
55 ReporterIsOwned(false) { 55 ReporterIsOwned(false) {
56 initializePNaClABIVerifyModulePass(*PassRegistry::getPassRegistry()); 56 initializePNaClABIVerifyModulePass(*PassRegistry::getPassRegistry());
57 } 57 }
58 ~PNaClABIVerifyModule() { 58 ~PNaClABIVerifyModule() {
59 if (ReporterIsOwned) 59 if (ReporterIsOwned)
60 delete Reporter; 60 delete Reporter;
61 } 61 }
62 bool runOnModule(Module &M); 62 bool runOnModule(Module &M);
63 virtual void print(raw_ostream &O, const Module *M) const; 63 virtual void print(raw_ostream &O, const Module *M) const;
64 private: 64 private:
65 void CheckGlobalValueCommon(const GlobalValue *GV); 65 void checkGlobalValueCommon(const GlobalValue *GV);
66 bool IsWhitelistedIntrinsic(const Function* F, unsigned ID); 66 bool isWhitelistedIntrinsic(const Function *F, unsigned ID);
67 bool IsWhitelistedMetadata(const NamedMDNode *MD); 67 bool isWhitelistedMetadata(const NamedMDNode *MD);
68 PNaClABITypeChecker TC; 68 PNaClABITypeChecker TC;
69 PNaClABIErrorReporter *Reporter; 69 PNaClABIErrorReporter *Reporter;
70 bool ReporterIsOwned; 70 bool ReporterIsOwned;
71 }; 71 };
72 72
73 static const char *linkageName(GlobalValue::LinkageTypes LT) { 73 static const char *linkageName(GlobalValue::LinkageTypes LT) {
74 // This logic is taken from PrintLinkage in lib/VMCore/AsmWriter.cpp 74 // This logic is taken from PrintLinkage in lib/VMCore/AsmWriter.cpp
75 switch (LT) { 75 switch (LT) {
76 case GlobalValue::ExternalLinkage: return "external"; 76 case GlobalValue::ExternalLinkage: return "external";
77 case GlobalValue::PrivateLinkage: return "private "; 77 case GlobalValue::PrivateLinkage: return "private ";
(...skipping 15 matching lines...) Expand all
93 return "available_externally "; 93 return "available_externally ";
94 default: 94 default:
95 return "unknown"; 95 return "unknown";
96 } 96 }
97 } 97 }
98 98
99 } // end anonymous namespace 99 } // end anonymous namespace
100 100
101 // Check linkage type and section attributes, which are the same for 101 // Check linkage type and section attributes, which are the same for
102 // GlobalVariables and Functions. 102 // GlobalVariables and Functions.
103 void PNaClABIVerifyModule::CheckGlobalValueCommon(const GlobalValue *GV) { 103 void PNaClABIVerifyModule::checkGlobalValueCommon(const GlobalValue *GV) {
104 assert(!isa<GlobalAlias>(GV)); 104 assert(!isa<GlobalAlias>(GV));
105 const char *GVTypeName = isa<GlobalVariable>(GV) ? 105 const char *GVTypeName = isa<GlobalVariable>(GV) ?
106 "Variable " : "Function "; 106 "Variable " : "Function ";
107 switch (GV->getLinkage()) { 107 switch (GV->getLinkage()) {
108 // TODO(dschuff): Disallow external linkage 108 // TODO(dschuff): Disallow external linkage
109 case GlobalValue::ExternalLinkage: 109 case GlobalValue::ExternalLinkage:
110 case GlobalValue::AvailableExternallyLinkage: 110 case GlobalValue::AvailableExternallyLinkage:
111 case GlobalValue::InternalLinkage: 111 case GlobalValue::InternalLinkage:
112 case GlobalValue::PrivateLinkage: 112 case GlobalValue::PrivateLinkage:
113 break; 113 break;
114 default: 114 default:
115 Reporter->addError() << GVTypeName << GV->getName() 115 Reporter->addError() << GVTypeName << GV->getName()
116 << " has disallowed linkage type: " 116 << " has disallowed linkage type: "
117 << linkageName(GV->getLinkage()) << "\n"; 117 << linkageName(GV->getLinkage()) << "\n";
118 } 118 }
119 if (GV->hasSection()) { 119 if (GV->hasSection()) {
120 Reporter->addError() << GVTypeName << GV->getName() << 120 Reporter->addError() << GVTypeName << GV->getName() <<
121 " has disallowed \"section\" attribute\n"; 121 " has disallowed \"section\" attribute\n";
122 } 122 }
123 } 123 }
124 124
125 bool PNaClABIVerifyModule::IsWhitelistedIntrinsic(const Function* F, 125 static bool TypeAcceptable(const Type *T,
126 const ArrayRef<Type*> &AcceptableTypes) {
127 for (ArrayRef<Type*>::iterator I = AcceptableTypes.begin(),
128 E = AcceptableTypes.end(); I != E; ++I)
129 if (*I == T)
130 return true;
131 return false;
132 }
133
134 // We accept bswap for a limited set of types (i16, i32, i64).
135 // The various backends are able to generate instructions to
136 // implement the intrinsic. Also, i16 and i64 are easy to
137 // implement as along as there is a way to do i32.
138 static bool isWhitelistedBswap(const Function *F) {
139 FunctionType *FT = F->getFunctionType();
140 if (FT->getNumParams() != 1)
141 return false;
142 Type *ParamType = FT->getParamType(0);
143 LLVMContext &C = F->getContext();
144 Type *AcceptableTypes[] = { Type::getInt16Ty(C),
145 Type::getInt32Ty(C),
146 Type::getInt64Ty(C) };
147 return TypeAcceptable(ParamType, AcceptableTypes);
148 }
149
150 bool PNaClABIVerifyModule::isWhitelistedIntrinsic(const Function *F,
126 unsigned ID) { 151 unsigned ID) {
127 // Keep 3 categories of intrinsics for now. 152 // Keep 3 categories of intrinsics for now.
128 // (1) Allowed always 153 // (1) Allowed always
129 // (2) Never allowed 154 // (2) Never allowed
130 // (3) "Dev" intrinsics, which may or may not be allowed. 155 // (3) "Dev" intrinsics, which may or may not be allowed.
131 // "Dev" intrinsics are controlled by the PNaClABIAllowDevIntrinsics flag. 156 // "Dev" intrinsics are controlled by the PNaClABIAllowDevIntrinsics flag.
132 // Please keep these sorted or grouped in a sensible way, within 157 // Please keep these sorted or grouped in a sensible way, within
133 // each category. 158 // each category.
134 switch(ID) { 159 switch(ID) {
135 // Disallow by default. 160 // Disallow by default.
136 default: return false; 161 default: return false;
137 // (1) Always allowed. 162 // (1) Always allowed.
163 case Intrinsic::bswap: return isWhitelistedBswap(F);
138 case Intrinsic::invariant_end: 164 case Intrinsic::invariant_end:
139 case Intrinsic::invariant_start: 165 case Intrinsic::invariant_start:
140 case Intrinsic::lifetime_end: 166 case Intrinsic::lifetime_end:
141 case Intrinsic::lifetime_start: 167 case Intrinsic::lifetime_start:
142 case Intrinsic::memcpy: 168 case Intrinsic::memcpy:
143 case Intrinsic::memmove: 169 case Intrinsic::memmove:
144 case Intrinsic::memset: 170 case Intrinsic::memset:
145 case Intrinsic::nacl_read_tp: 171 case Intrinsic::nacl_read_tp:
146 case Intrinsic::nacl_setjmp: 172 case Intrinsic::nacl_setjmp:
147 case Intrinsic::nacl_longjmp: 173 case Intrinsic::nacl_longjmp:
(...skipping 24 matching lines...) Expand all
172 // Var-args handling is done w/out intrinsics. 198 // Var-args handling is done w/out intrinsics.
173 case Intrinsic::vacopy: 199 case Intrinsic::vacopy:
174 case Intrinsic::vaend: 200 case Intrinsic::vaend:
175 case Intrinsic::vastart: 201 case Intrinsic::vastart:
176 return false; 202 return false;
177 203
178 // (3) Dev intrinsics. 204 // (3) Dev intrinsics.
179 case Intrinsic::dbg_declare: 205 case Intrinsic::dbg_declare:
180 case Intrinsic::dbg_value: 206 case Intrinsic::dbg_value:
181 return PNaClABIAllowDevIntrinsics || PNaClABIAllowDebugMetadata; 207 return PNaClABIAllowDevIntrinsics || PNaClABIAllowDebugMetadata;
182 case Intrinsic::bswap: // Support via compiler_rt if arch doesn't have it?
183 case Intrinsic::cos: // Rounding not defined: support with fast-math? 208 case Intrinsic::cos: // Rounding not defined: support with fast-math?
184 case Intrinsic::ctlz: // Support via compiler_rt if arch doesn't have it? 209 case Intrinsic::ctlz: // Support via compiler_rt if arch doesn't have it?
185 case Intrinsic::ctpop: // Support via compiler_rt if arch doesn't have it? 210 case Intrinsic::ctpop: // Support via compiler_rt if arch doesn't have it?
186 case Intrinsic::cttz: // Support via compiler_rt if arch doesn't have it? 211 case Intrinsic::cttz: // Support via compiler_rt if arch doesn't have it?
187 case Intrinsic::exp: // Rounding not defined: support with fast-math? 212 case Intrinsic::exp: // Rounding not defined: support with fast-math?
188 case Intrinsic::exp2: // Rounding not defined: support with fast-math? 213 case Intrinsic::exp2: // Rounding not defined: support with fast-math?
189 case Intrinsic::expect: // From __builtin_expect. 214 case Intrinsic::expect: // From __builtin_expect.
190 case Intrinsic::flt_rounds: 215 case Intrinsic::flt_rounds: // For FLT_ROUNDS macro from float.h.
216 // We do not have fesetround() in newlib, can we return a
217 // consistent rounding mode though?
191 case Intrinsic::log: // Rounding not defined: support with fast-math? 218 case Intrinsic::log: // Rounding not defined: support with fast-math?
192 case Intrinsic::log2: // Rounding not defined: support with fast-math? 219 case Intrinsic::log2: // Rounding not defined: support with fast-math?
193 case Intrinsic::log10: // Rounding not defined: support with fast-math? 220 case Intrinsic::log10: // Rounding not defined: support with fast-math?
194 case Intrinsic::nacl_target_arch: // Used by translator self-build. 221 case Intrinsic::nacl_target_arch: // Used by translator self-build.
195 case Intrinsic::pow: // Rounding is supposed to be the same as libm. 222 case Intrinsic::pow: // Rounding is supposed to be the same as libm.
196 case Intrinsic::powi: // Rounding not defined: support with fast-math? 223 case Intrinsic::powi: // Rounding not defined: support with fast-math?
197 case Intrinsic::prefetch: // Could ignore if target doesn't support? 224 case Intrinsic::prefetch: // Could ignore if target doesn't support?
198 case Intrinsic::sin: // Rounding not defined: support with fast-math? 225 case Intrinsic::sin: // Rounding not defined: support with fast-math?
199 case Intrinsic::sqrt: 226 case Intrinsic::sqrt: // Rounding is defined, but setting errno up to libm.
200 case Intrinsic::stackrestore: // Used to support C99 VLAs. 227 case Intrinsic::stackrestore: // Used to support C99 VLAs.
201 case Intrinsic::stacksave: 228 case Intrinsic::stacksave: // Used to support C99 VLAs.
202 // the *_with_overflow return struct types, so we'll need to fix these. 229 // the *_with_overflow return struct types, so we'll need to fix these.
203 case Intrinsic::sadd_with_overflow: // Introduced by -ftrapv 230 case Intrinsic::sadd_with_overflow: // Introduced by -ftrapv
204 case Intrinsic::ssub_with_overflow: 231 case Intrinsic::ssub_with_overflow:
205 case Intrinsic::uadd_with_overflow: 232 case Intrinsic::uadd_with_overflow:
206 case Intrinsic::usub_with_overflow: 233 case Intrinsic::usub_with_overflow:
207 case Intrinsic::smul_with_overflow: 234 case Intrinsic::smul_with_overflow:
208 case Intrinsic::umul_with_overflow: // Introduced by c++ new[x * y]. 235 case Intrinsic::umul_with_overflow: // Introduced by c++ new[x * y].
209 return PNaClABIAllowDevIntrinsics; 236 return PNaClABIAllowDevIntrinsics;
210 } 237 }
211 } 238 }
212 239
213 bool PNaClABIVerifyModule::IsWhitelistedMetadata(const NamedMDNode* MD) { 240 bool PNaClABIVerifyModule::isWhitelistedMetadata(const NamedMDNode *MD) {
214 return MD->getName().startswith("llvm.dbg.") && PNaClABIAllowDebugMetadata; 241 return MD->getName().startswith("llvm.dbg.") && PNaClABIAllowDebugMetadata;
215 } 242 }
216 243
217 bool PNaClABIVerifyModule::runOnModule(Module &M) { 244 bool PNaClABIVerifyModule::runOnModule(Module &M) {
218 for (Module::const_global_iterator MI = M.global_begin(), ME = M.global_end(); 245 for (Module::const_global_iterator MI = M.global_begin(), ME = M.global_end();
219 MI != ME; ++MI) { 246 MI != ME; ++MI) {
220 // Check types of global variables and their initializers 247 // Check types of global variables and their initializers
221 if (!TC.isValidType(MI->getType())) { 248 if (!TC.isValidType(MI->getType())) {
222 // GVs are pointers, so print the pointed-to type for clarity 249 // GVs are pointers, so print the pointed-to type for clarity
223 Reporter->addError() << "Variable " << MI->getName() << 250 Reporter->addError() << "Variable " << MI->getName() <<
224 " has disallowed type: " << 251 " has disallowed type: " <<
225 PNaClABITypeChecker::getTypeName(MI->getType()->getContainedType(0)) 252 PNaClABITypeChecker::getTypeName(MI->getType()->getContainedType(0))
226 + "\n"; 253 + "\n";
227 } else if (MI->hasInitializer()) { 254 } else if (MI->hasInitializer()) {
228 // If the type of the global is bad, no point in checking its initializer 255 // If the type of the global is bad, no point in checking its initializer
229 Type *T = TC.checkTypesInConstant(MI->getInitializer()); 256 Type *T = TC.checkTypesInConstant(MI->getInitializer());
230 if (T) { 257 if (T) {
231 Reporter->addError() << "Initializer for " << MI->getName() << 258 Reporter->addError() << "Initializer for " << MI->getName() <<
232 " has disallowed type: " << 259 " has disallowed type: " <<
233 PNaClABITypeChecker::getTypeName(T) << "\n"; 260 PNaClABITypeChecker::getTypeName(T) << "\n";
234 } 261 }
235 } 262 }
236 263
237 CheckGlobalValueCommon(MI); 264 checkGlobalValueCommon(MI);
238 265
239 if (MI->isThreadLocal()) { 266 if (MI->isThreadLocal()) {
240 Reporter->addError() << "Variable " << MI->getName() << 267 Reporter->addError() << "Variable " << MI->getName() <<
241 " has disallowed \"thread_local\" attribute\n"; 268 " has disallowed \"thread_local\" attribute\n";
242 } 269 }
243 } 270 }
244 271
245 // No aliases allowed for now. 272 // No aliases allowed for now.
246 for (Module::alias_iterator MI = M.alias_begin(), 273 for (Module::alias_iterator MI = M.alias_begin(),
247 E = M.alias_end(); MI != E; ++MI) { 274 E = M.alias_end(); MI != E; ++MI) {
248 Reporter->addError() << "Variable " << MI->getName() << 275 Reporter->addError() << "Variable " << MI->getName() <<
249 " is an alias (disallowed)\n"; 276 " is an alias (disallowed)\n";
250 } 277 }
251 278
252 for (Module::const_iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) { 279 for (Module::const_iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) {
253 // Check intrinsics. 280 // Check intrinsics.
254 if (MI->isIntrinsic() 281 if (MI->isIntrinsic()
255 && !IsWhitelistedIntrinsic(MI, MI->getIntrinsicID())) { 282 && !isWhitelistedIntrinsic(MI, MI->getIntrinsicID())) {
256 Reporter->addError() << "Function " << MI->getName() 283 Reporter->addError() << "Function " << MI->getName()
257 << " is a disallowed LLVM intrinsic\n"; 284 << " is a disallowed LLVM intrinsic\n";
258 } 285 }
259 286
260 // Check types of functions and their arguments 287 // Check types of functions and their arguments
261 FunctionType *FT = MI->getFunctionType(); 288 FunctionType *FT = MI->getFunctionType();
262 if (!TC.isValidType(FT->getReturnType())) { 289 if (!TC.isValidType(FT->getReturnType())) {
263 Reporter->addError() << "Function " << MI->getName() << 290 Reporter->addError() << "Function " << MI->getName() <<
264 " has disallowed return type: " << 291 " has disallowed return type: " <<
265 PNaClABITypeChecker::getTypeName(FT->getReturnType()) << "\n"; 292 PNaClABITypeChecker::getTypeName(FT->getReturnType()) << "\n";
266 } 293 }
267 for (unsigned I = 0, E = FT->getNumParams(); I < E; ++I) { 294 for (unsigned I = 0, E = FT->getNumParams(); I < E; ++I) {
268 Type *PT = FT->getParamType(I); 295 Type *PT = FT->getParamType(I);
269 if (!TC.isValidType(PT)) { 296 if (!TC.isValidType(PT)) {
270 Reporter->addError() << "Function " << MI->getName() << " argument " << 297 Reporter->addError() << "Function " << MI->getName() << " argument " <<
271 I + 1 << " has disallowed type: " << 298 I + 1 << " has disallowed type: " <<
272 PNaClABITypeChecker::getTypeName(PT) << "\n"; 299 PNaClABITypeChecker::getTypeName(PT) << "\n";
273 } 300 }
274 } 301 }
275 // Pointers to varargs function types are not yet disallowed, but 302 // Pointers to varargs function types are not yet disallowed, but
276 // we do disallow defining or calling functions of varargs types. 303 // we do disallow defining or calling functions of varargs types.
277 if (MI->isVarArg()) { 304 if (MI->isVarArg()) {
278 Reporter->addError() << "Function " << MI->getName() << 305 Reporter->addError() << "Function " << MI->getName() <<
279 " is a variable-argument function (disallowed)\n"; 306 " is a variable-argument function (disallowed)\n";
280 } 307 }
281 308
282 CheckGlobalValueCommon(MI); 309 checkGlobalValueCommon(MI);
283 310
284 if (MI->hasGC()) { 311 if (MI->hasGC()) {
285 Reporter->addError() << "Function " << MI->getName() << 312 Reporter->addError() << "Function " << MI->getName() <<
286 " has disallowed \"gc\" attribute\n"; 313 " has disallowed \"gc\" attribute\n";
287 } 314 }
288 } 315 }
289 316
290 // Check named metadata nodes 317 // Check named metadata nodes
291 for (Module::const_named_metadata_iterator I = M.named_metadata_begin(), 318 for (Module::const_named_metadata_iterator I = M.named_metadata_begin(),
292 E = M.named_metadata_end(); I != E; ++I) { 319 E = M.named_metadata_end(); I != E; ++I) {
293 if (!IsWhitelistedMetadata(I)) { 320 if (!isWhitelistedMetadata(I)) {
294 Reporter->addError() << "Named metadata node " << I->getName() 321 Reporter->addError() << "Named metadata node " << I->getName()
295 << " is disallowed\n"; 322 << " is disallowed\n";
296 } else { 323 } else {
297 // Check the types in the metadata. 324 // Check the types in the metadata.
298 for (unsigned i = 0, e = I->getNumOperands(); i != e; i++) { 325 for (unsigned i = 0, e = I->getNumOperands(); i != e; i++) {
299 if (Type *T = TC.checkTypesInMDNode(I->getOperand(i))) { 326 if (Type *T = TC.checkTypesInMDNode(I->getOperand(i))) {
300 Reporter->addError() << "Named metadata node " << I->getName() 327 Reporter->addError() << "Named metadata node " << I->getName()
301 << " refers to disallowed type: " 328 << " refers to disallowed type: "
302 << PNaClABITypeChecker::getTypeName(T) << "\n"; 329 << PNaClABITypeChecker::getTypeName(T) << "\n";
303 } 330 }
(...skipping 15 matching lines...) Expand all
319 } 346 }
320 347
321 char PNaClABIVerifyModule::ID = 0; 348 char PNaClABIVerifyModule::ID = 0;
322 INITIALIZE_PASS(PNaClABIVerifyModule, "verify-pnaclabi-module", 349 INITIALIZE_PASS(PNaClABIVerifyModule, "verify-pnaclabi-module",
323 "Verify module for PNaCl", false, true) 350 "Verify module for PNaCl", false, true)
324 351
325 ModulePass *llvm::createPNaClABIVerifyModulePass( 352 ModulePass *llvm::createPNaClABIVerifyModulePass(
326 PNaClABIErrorReporter *Reporter) { 353 PNaClABIErrorReporter *Reporter) {
327 return new PNaClABIVerifyModule(Reporter); 354 return new PNaClABIVerifyModule(Reporter);
328 } 355 }
OLDNEW
« no previous file with comments | « no previous file | test/NaCl/PNaClABI/intrinsics.ll » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698