• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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