17
17
#include " llvm/ADT/Twine.h"
18
18
#include " llvm/Analysis/NaCl.h"
19
19
#include " llvm/IR/DerivedTypes.h"
20
+ #include " llvm/IR/Intrinsics.h"
20
21
#include " llvm/IR/Module.h"
22
+ #include " llvm/Support/Debug.h"
21
23
#include " llvm/Support/raw_ostream.h"
22
24
23
25
#include " PNaClABITypeChecker.h"
@@ -28,8 +30,14 @@ cl::opt<bool>
28
30
PNaClABIAllowDebugMetadata (" pnaclabi-allow-debug-metadata" ,
29
31
cl::desc (" Allow debug metadata during PNaCl ABI verification." ),
30
32
cl::init(false ));
33
+
31
34
}
32
35
36
+ static cl::opt<bool >
37
+ PNaClABIAllowDevIntrinsics (" pnaclabi-allow-dev-intrinsics" ,
38
+ cl::desc (" Allow all LLVM intrinsics during PNaCl ABI verification." ),
39
+ cl::init(true )); // TODO(jvoung): Make this false by default.
40
+
33
41
namespace {
34
42
// This pass should not touch function bodies, to stay streaming-friendly
35
43
class PNaClABIVerifyModule : public ModulePass {
@@ -55,6 +63,7 @@ class PNaClABIVerifyModule : public ModulePass {
55
63
virtual void print (raw_ostream &O, const Module *M) const ;
56
64
private:
57
65
void CheckGlobalValueCommon (const GlobalValue *GV);
66
+ bool IsWhitelistedIntrinsic (const Function* F, unsigned ID);
58
67
bool IsWhitelistedMetadata (const NamedMDNode *MD);
59
68
PNaClABITypeChecker TC;
60
69
PNaClABIErrorReporter *Reporter;
@@ -113,6 +122,76 @@ void PNaClABIVerifyModule::CheckGlobalValueCommon(const GlobalValue *GV) {
113
122
}
114
123
}
115
124
125
+ bool PNaClABIVerifyModule::IsWhitelistedIntrinsic (const Function* F,
126
+ unsigned ID) {
127
+ // Keep 3 categories of intrinsics for now.
128
+ // (1) Allowed always
129
+ // (2) Never allowed
130
+ // (3) "Dev" intrinsics, which may or may not be allowed.
131
+ // "Dev" intrinsics are controlled by the PNaClABIAllowDevIntrinsics flag.
132
+ // Please keep these sorted within each category.
133
+ switch (ID) {
134
+ // Disallow by default.
135
+ default : return false ;
136
+ // (1) Always allowed.
137
+ case Intrinsic::invariant_end:
138
+ case Intrinsic::invariant_start:
139
+ case Intrinsic::lifetime_end:
140
+ case Intrinsic::lifetime_start:
141
+ case Intrinsic::memcpy :
142
+ case Intrinsic::memmove :
143
+ case Intrinsic::memset :
144
+ case Intrinsic::nacl_read_tp:
145
+ case Intrinsic::trap:
146
+ return true ;
147
+
148
+ // (2) Known to be never allowed.
149
+ case Intrinsic::not_intrinsic:
150
+ case Intrinsic::adjust_trampoline:
151
+ case Intrinsic::init_trampoline:
152
+ case Intrinsic::stackprotector:
153
+ case Intrinsic::vacopy:
154
+ case Intrinsic::vaend:
155
+ case Intrinsic::vastart:
156
+ return false ;
157
+
158
+ // (3) Dev intrinsics.
159
+ case Intrinsic::dbg_declare:
160
+ case Intrinsic::dbg_value:
161
+ return PNaClABIAllowDevIntrinsics || PNaClABIAllowDebugMetadata;
162
+ case Intrinsic::bswap: // Support via compiler_rt if arch doesn't have it?
163
+ case Intrinsic::cos : // Rounding not defined: support with fast-math?
164
+ case Intrinsic::ctlz: // Support via compiler_rt if arch doesn't have it?
165
+ case Intrinsic::ctpop: // Support via compiler_rt if arch doesn't have it?
166
+ case Intrinsic::cttz: // Support via compiler_rt if arch doesn't have it?
167
+ case Intrinsic::eh_dwarf_cfa: // For EH tests.
168
+ case Intrinsic::exp : // Rounding not defined: support with fast-math?
169
+ case Intrinsic::exp2 : // Rounding not defined: support with fast-math?
170
+ case Intrinsic::expect: // From __builtin_expect.
171
+ case Intrinsic::flt_rounds:
172
+ case Intrinsic::frameaddress: // Support for 0-level or not?
173
+ case Intrinsic::log : // Rounding not defined: support with fast-math?
174
+ case Intrinsic::log2 : // Rounding not defined: support with fast-math?
175
+ case Intrinsic::log10 : // Rounding not defined: support with fast-math?
176
+ case Intrinsic::nacl_target_arch: // Used by translator self-build.
177
+ case Intrinsic::pow : // Rounding not defined: support with fast-math?
178
+ case Intrinsic::prefetch: // Could ignore if target doesn't support?
179
+ case Intrinsic::returnaddress: // Support for 0-level or not?
180
+ case Intrinsic::sin : // Rounding not defined: support with fast-math?
181
+ case Intrinsic::sqrt :
182
+ case Intrinsic::stackrestore: // Used to support C99 VLAs.
183
+ case Intrinsic::stacksave:
184
+ // the *_with_overflow return struct types, so we'll need to fix these.
185
+ case Intrinsic::sadd_with_overflow: // Introduced by -ftrapv
186
+ case Intrinsic::ssub_with_overflow:
187
+ case Intrinsic::uadd_with_overflow:
188
+ case Intrinsic::usub_with_overflow:
189
+ case Intrinsic::smul_with_overflow:
190
+ case Intrinsic::umul_with_overflow: // Introduced by c++ new[x * y].
191
+ return PNaClABIAllowDevIntrinsics;
192
+ }
193
+ }
194
+
116
195
bool PNaClABIVerifyModule::IsWhitelistedMetadata (const NamedMDNode* MD) {
117
196
return MD->getName ().startswith (" llvm.dbg." ) && PNaClABIAllowDebugMetadata;
118
197
}
@@ -153,6 +232,13 @@ bool PNaClABIVerifyModule::runOnModule(Module &M) {
153
232
}
154
233
155
234
for (Module::const_iterator MI = M.begin (), ME = M.end (); MI != ME; ++MI) {
235
+ // Check intrinsics.
236
+ if (MI->isIntrinsic ()
237
+ && !IsWhitelistedIntrinsic (MI, MI->getIntrinsicID ())) {
238
+ Reporter->addError () << " Function " << MI->getName ()
239
+ << " is a disallowed LLVM intrinsic\n " ;
240
+ }
241
+
156
242
// Check types of functions and their arguments
157
243
FunctionType *FT = MI->getFunctionType ();
158
244
if (!TC.isValidType (FT->getReturnType ())) {
0 commit comments