1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "sandboxed_api/tools/clang_generator/generator.h"
16
17 #include <cstddef>
18 #include <memory>
19 #include <string>
20 #include <utility>
21 #include <vector>
22
23 #include "absl/container/flat_hash_set.h"
24 #include "absl/status/status.h"
25 #include "absl/strings/match.h"
26 #include "absl/strings/str_cat.h"
27 #include "absl/strings/string_view.h"
28 #include "absl/strings/strip.h"
29 #include "clang/AST/ASTContext.h"
30 #include "clang/AST/Decl.h"
31 #include "clang/AST/Type.h"
32 #include "clang/Basic/Diagnostic.h"
33 #include "clang/Basic/SourceLocation.h"
34 #include "clang/Basic/SourceManager.h"
35 #include "clang/Frontend/CompilerInvocation.h"
36 #include "clang/Lex/PreprocessorOptions.h"
37 #include "clang/Serialization/PCHContainerOperations.h"
38 #include "clang/Tooling/Tooling.h"
39 #include "sandboxed_api/tools/clang_generator/diagnostics.h"
40 #include "sandboxed_api/tools/clang_generator/emitter_base.h"
41
42 namespace sapi {
43 namespace {
44
45 // Replaces the file extension of a path name.
ReplaceFileExtension(absl::string_view path,absl::string_view new_extension)46 std::string ReplaceFileExtension(absl::string_view path,
47 absl::string_view new_extension) {
48 size_t last_slash = path.rfind('/');
49 size_t pos = path.rfind('.', last_slash);
50 if (pos != absl::string_view::npos && last_slash != absl::string_view::npos) {
51 pos += last_slash;
52 }
53 return absl::StrCat(path.substr(0, pos), new_extension);
54 }
55
56 } // namespace
57
GetOutputFilename(absl::string_view source_file)58 std::string GetOutputFilename(absl::string_view source_file) {
59 return ReplaceFileExtension(source_file, ".sapi.h");
60 }
61
VisitTypeDecl(clang::TypeDecl * decl)62 bool GeneratorASTVisitor::VisitTypeDecl(clang::TypeDecl* decl) {
63 collector_.RecordOrderedDecl(decl);
64 return true;
65 }
66
VisitFunctionDecl(clang::FunctionDecl * decl)67 bool GeneratorASTVisitor::VisitFunctionDecl(clang::FunctionDecl* decl) {
68 if (decl->isCXXClassMember() || // Skip classes
69 !decl->isExternC() || // Skip non external functions
70 decl->isTemplated() // Skip function templates
71 ) {
72 return true;
73 }
74
75 // Process either all function or just the requested ones
76 bool all_functions = options_.function_names.empty();
77 if (!all_functions &&
78 !options_.function_names.contains(ToStringView(decl->getName()))) {
79 return true;
80 }
81
82 // Skip Abseil internal functions when all functions are requested. This still
83 // allows them to be specified explicitly.
84 if (all_functions &&
85 absl::StartsWith(decl->getQualifiedNameAsString(), "AbslInternal")) {
86 return true;
87 }
88
89 clang::SourceManager& source_manager =
90 decl->getASTContext().getSourceManager();
91 clang::SourceLocation decl_start = decl->getBeginLoc();
92
93 // Skip functions from system headers when all functions are requested. Like
94 // above, they can still explicitly be specified.
95 if (all_functions && source_manager.isInSystemHeader(decl_start)) {
96 return true;
97 }
98
99 if (all_functions) {
100 const std::string filename(absl::StripPrefix(
101 ToStringView(source_manager.getFilename(decl_start)), "./"));
102 if (options_.limit_scan_depth && !options_.in_files.contains(filename)) {
103 return true;
104 }
105 }
106
107 functions_.push_back(decl);
108
109 collector_.CollectRelatedTypes(decl->getDeclaredReturnType());
110 for (const clang::ParmVarDecl* param : decl->parameters()) {
111 collector_.CollectRelatedTypes(param->getType());
112 }
113
114 return true;
115 }
116
HandleTranslationUnit(clang::ASTContext & context)117 void GeneratorASTConsumer::HandleTranslationUnit(clang::ASTContext& context) {
118 if (!visitor_.TraverseDecl(context.getTranslationUnitDecl())) {
119 ReportFatalError(context.getDiagnostics(),
120 context.getTranslationUnitDecl()->getBeginLoc(),
121 "AST traversal exited early.");
122 return;
123 }
124
125 emitter_.AddTypeDeclarations(visitor_.collector().GetTypeDeclarations());
126 for (clang::FunctionDecl* func : visitor_.functions()) {
127 absl::Status status = emitter_.AddFunction(func);
128 if (!status.ok()) {
129 clang::SourceLocation loc =
130 GetDiagnosticLocationFromStatus(status).value_or(func->getBeginLoc());
131 if (absl::IsCancelled(status)) {
132 ReportWarning(context.getDiagnostics(), loc, status.message());
133 continue;
134 }
135 ReportFatalError(context.getDiagnostics(), loc, status.message());
136 break;
137 }
138 }
139 }
140
runInvocation(std::shared_ptr<clang::CompilerInvocation> invocation,clang::FileManager * files,std::shared_ptr<clang::PCHContainerOperations> pch_container_ops,clang::DiagnosticConsumer * diag_consumer)141 bool GeneratorFactory::runInvocation(
142 std::shared_ptr<clang::CompilerInvocation> invocation,
143 clang::FileManager* files,
144 std::shared_ptr<clang::PCHContainerOperations> pch_container_ops,
145 clang::DiagnosticConsumer* diag_consumer) {
146 auto& options = invocation->getPreprocessorOpts();
147 // Explicitly ask to define __clang_analyzer__ macro.
148 options.SetUpStaticAnalyzer = true;
149 for (const auto& def : {
150 // Enable code to detect whether it is being SAPI-ized
151 "__SAPI__",
152 // TODO: b/222241644 - Figure out how to deal with intrinsics
153 // properly.
154 // Note: The definitions below just need to parse, they don't need to
155 // compile into useful code.
156 // 3DNow!
157 "__builtin_ia32_femms=[](){}",
158 "__builtin_ia32_pavgusb=",
159 "__builtin_ia32_pf2id=",
160 "__builtin_ia32_pfacc=",
161 "__builtin_ia32_pfadd=",
162 "__builtin_ia32_pfcmpeq=",
163 "__builtin_ia32_pfcmpge=",
164 "__builtin_ia32_pfcmpgt=",
165 "__builtin_ia32_pfmax=",
166 "__builtin_ia32_pfmin=",
167 "__builtin_ia32_pfmul=",
168 "__builtin_ia32_pfrcp=",
169 "__builtin_ia32_pfrcpit1=",
170 "__builtin_ia32_pfrcpit2=",
171 "__builtin_ia32_pfrsqrt=",
172 "__builtin_ia32_pfrsqit1=",
173 "__builtin_ia32_pfsub=",
174 "__builtin_ia32_pfsubr=",
175 "__builtin_ia32_pi2fd=",
176 "__builtin_ia32_pmulhrw=",
177 "__builtin_ia32_pf2iw=",
178 "__builtin_ia32_pfnacc=",
179 "__builtin_ia32_pfpnacc=",
180 "__builtin_ia32_pi2fw=",
181 "__builtin_ia32_pswapdsf=",
182 "__builtin_ia32_pswapdsi=",
183 // Intel
184 "__builtin_ia32_cvtsbf162ss_32=[](auto)->long long{return 0;}",
185 "__builtin_ia32_paddsb128=",
186 "__builtin_ia32_paddsb256=",
187 "__builtin_ia32_paddsb512=",
188 "__builtin_ia32_paddsw128=",
189 "__builtin_ia32_paddsw256=",
190 "__builtin_ia32_paddsw512=",
191 "__builtin_ia32_paddusb128=",
192 "__builtin_ia32_paddusb256=",
193 "__builtin_ia32_paddusb512=",
194 "__builtin_ia32_paddusw128=",
195 "__builtin_ia32_paddusw256=",
196 "__builtin_ia32_paddusw512=",
197 "__builtin_ia32_psubsb128=",
198 "__builtin_ia32_psubsb256=",
199 "__builtin_ia32_psubsb512=",
200 "__builtin_ia32_psubsw128=",
201 "__builtin_ia32_psubsw256=",
202 "__builtin_ia32_psubsw512=",
203 "__builtin_ia32_psubusb128=",
204 "__builtin_ia32_psubusb256=",
205 "__builtin_ia32_psubusb512=",
206 "__builtin_ia32_psubusw128=",
207 "__builtin_ia32_psubusw256=",
208 "__builtin_ia32_psubusw512=",
209 "__builtin_ia32_reduce_add_d512=[](auto)->long long{return 0;}",
210 "__builtin_ia32_reduce_add_q512=[](auto)->long long{return 0;}",
211 "__builtin_ia32_reduce_mul_d512=[](auto)->long long{return 0;}",
212 "__builtin_ia32_reduce_mul_q512=[](auto)->long long{return 0;}",
213
214 // SSE2
215 "__builtin_ia32_cvtpd2pi=[](auto)->long long{return 0;}",
216 "__builtin_ia32_cvtpi2pd=[](auto) -> __m128{return {0, 0, 0, 0};}",
217 "__builtin_ia32_cvtpi2ps=[](auto, auto)->__m128{return {0, 0, 0, "
218 "0};}",
219 "__builtin_ia32_cvtps2pi=[](auto)->long long{return 0;}",
220 "__builtin_ia32_cvttpd2pi=[](auto)->long long{return 0;}",
221 "__builtin_ia32_cvttps2pi=[](auto)->long long{return 0;}",
222 "__builtin_ia32_maskmovq=",
223 "__builtin_ia32_movntq=",
224 "__builtin_ia32_pabsb=",
225 "__builtin_ia32_pabsd=",
226 "__builtin_ia32_pabsw=",
227 "__builtin_ia32_packssdw=",
228 "__builtin_ia32_packsswb=",
229 "__builtin_ia32_packuswb=",
230 "__builtin_ia32_paddb=",
231 "__builtin_ia32_paddd=",
232 "__builtin_ia32_paddq=",
233 "__builtin_ia32_paddsb=",
234 "__builtin_ia32_paddsw=",
235 "__builtin_ia32_paddusb=",
236 "__builtin_ia32_paddusw=",
237 "__builtin_ia32_paddw=",
238 "__builtin_ia32_pand=",
239 "__builtin_ia32_pandn=",
240 "__builtin_ia32_pavgb=",
241 "__builtin_ia32_pavgw=",
242 "__builtin_ia32_pcmpeqb=",
243 "__builtin_ia32_pcmpeqd=",
244 "__builtin_ia32_pcmpeqw=",
245 "__builtin_ia32_pcmpgtb=",
246 "__builtin_ia32_pcmpgtd=",
247 "__builtin_ia32_pcmpgtw=",
248 "__builtin_ia32_phaddd=",
249 "__builtin_ia32_phaddsw=",
250 "__builtin_ia32_phaddw=",
251 "__builtin_ia32_phsubd=",
252 "__builtin_ia32_phsubsw=",
253 "__builtin_ia32_phsubw=",
254 "__builtin_ia32_pmaddubsw=",
255 "__builtin_ia32_pmaddwd=",
256 "__builtin_ia32_pmaxsw=",
257 "__builtin_ia32_pmaxub=",
258 "__builtin_ia32_pminsw=",
259 "__builtin_ia32_pminub=",
260 "__builtin_ia32_pmovmskb=[](auto)->long long{return 0;}",
261 "__builtin_ia32_pmulhrsw=",
262 "__builtin_ia32_pmulhuw=",
263 "__builtin_ia32_pmulhw=",
264 "__builtin_ia32_pmullw=",
265 "__builtin_ia32_pmuludq=",
266 "__builtin_ia32_por=",
267 "__builtin_ia32_psadbw=",
268 "__builtin_ia32_pshufb=",
269 "__builtin_ia32_psignb=",
270 "__builtin_ia32_psignd=",
271 "__builtin_ia32_psignw=",
272 "__builtin_ia32_pslld=",
273 "__builtin_ia32_pslldi=[](auto, auto)->long long{return 0;}",
274 "__builtin_ia32_psllq=",
275 "__builtin_ia32_psllqi=[](auto, auto)->long long{return 0;}",
276 "__builtin_ia32_psllw=",
277 "__builtin_ia32_psllwi=[](auto, auto)->long long{return 0;}",
278 "__builtin_ia32_psrad=",
279 "__builtin_ia32_psradi=[](auto, auto)->long long{return 0;}",
280 "__builtin_ia32_psraw=",
281 "__builtin_ia32_psrawi=[](auto, auto)->long long{return 0;}",
282 "__builtin_ia32_psrld=",
283 "__builtin_ia32_psrldi=[](auto, auto)->long long{return 0;}",
284 "__builtin_ia32_psrlq=",
285 "__builtin_ia32_psrlqi=[](auto, auto)->long long{return 0;}",
286 "__builtin_ia32_psrlw=",
287 "__builtin_ia32_psrlwi=[](auto, auto)->long long{return 0;}",
288 "__builtin_ia32_psubb=",
289 "__builtin_ia32_psubd=",
290 "__builtin_ia32_psubq=",
291 "__builtin_ia32_psubsb=",
292 "__builtin_ia32_psubsw=",
293 "__builtin_ia32_psubusb=",
294 "__builtin_ia32_psubusw=",
295 "__builtin_ia32_psubw=",
296 "__builtin_ia32_punpckhbw=",
297 "__builtin_ia32_punpckhdq=",
298 "__builtin_ia32_punpckhwd=",
299 "__builtin_ia32_punpcklbw=",
300 "__builtin_ia32_punpckldq=",
301 "__builtin_ia32_punpcklwd=",
302 "__builtin_ia32_pxor=",
303 "__builtin_ia32_vec_ext_v2si=",
304 "__builtin_ia32_vec_init_v2si=[](auto, auto)->long long{return 0;}",
305 "__builtin_ia32_vec_init_v4hi=[](auto, auto, auto, auto)->long "
306 "long{return 0;}",
307 "__builtin_ia32_vec_init_v8qi=[](auto, auto, auto, auto, auto, "
308 "auto, auto, auto)->long long{return 0;}",
309 // AVX
310 "__builtin_ia32_vpopcntb_128=",
311 "__builtin_ia32_vpopcntb_256=",
312 "__builtin_ia32_vpopcntb_512=",
313 "__builtin_ia32_vpopcntd_128=",
314 "__builtin_ia32_vpopcntd_256=",
315 "__builtin_ia32_vpopcntd_512=",
316 "__builtin_ia32_vpopcntq_128=",
317 "__builtin_ia32_vpopcntq_256=",
318 "__builtin_ia32_vpopcntq_512=",
319 "__builtin_ia32_vpopcntw_128=",
320 "__builtin_ia32_vpopcntw_256=",
321 "__builtin_ia32_vpopcntw_512=",
322 }) {
323 options.addMacroDef(def);
324 // To avoid code to include header with compiler intrinsics, undefine a few
325 // key pre-defines.
326 for (
327 const auto& undef : {
328 // ARM ISA (see
329 // https://developer.arm.com/documentation/101028/0010/Feature-test-macros)
330 "__ARM_NEON",
331 "__ARM_NEON__",
332 // Intel
333 "__AVX__",
334 "__AVX2__",
335 "__AVX512BW__",
336 "__AVX512CD__",
337 "__AVX512DQ__",
338 "__AVX512F__",
339 "__AVX512VL__",
340 "__SSE__",
341 "__SSE2__",
342 "__SSE2_MATH__",
343 "__SSE3__",
344 "__SSE4_1__",
345 "__SSE4_2__",
346 "__SSE_MATH__",
347 "__SSSE3__",
348 }) {
349 options.addMacroUndef(undef);
350 }
351 }
352 return FrontendActionFactory::runInvocation(std::move(invocation), files,
353 std::move(pch_container_ops),
354 diag_consumer);
355 }
356
357 } // namespace sapi
358