1 /*
2  * Copyright 2010, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "slang_rs_pragma_handler.h"
18 
19 #include <map>
20 #include <sstream>
21 #include <string>
22 
23 #include "clang/AST/ASTContext.h"
24 
25 #include "clang/Basic/TokenKinds.h"
26 
27 #include "clang/Lex/LiteralSupport.h"
28 #include "clang/Lex/Preprocessor.h"
29 #include "clang/Lex/Token.h"
30 
31 #include "slang_assert.h"
32 #include "slang_rs_context.h"
33 #include "slang_rs_export_reduce.h"
34 #include "slang_version.h"
35 
36 namespace slang {
37 
38 namespace {  // Anonymous namespace
39 
40 class RSExportTypePragmaHandler : public RSPragmaHandler {
41  private:
handleItem(const std::string & Item)42   void handleItem(const std::string &Item) {
43     mContext->addPragma(this->getName(), Item);
44     mContext->addExportType(Item);
45   }
46 
47  public:
RSExportTypePragmaHandler(llvm::StringRef Name,RSContext * Context)48   RSExportTypePragmaHandler(llvm::StringRef Name, RSContext *Context)
49       : RSPragmaHandler(Name, Context) { }
50 
HandlePragma(clang::Preprocessor & PP,clang::PragmaIntroducerKind Introducer,clang::Token & FirstToken)51   void HandlePragma(clang::Preprocessor &PP,
52                     clang::PragmaIntroducerKind Introducer,
53                     clang::Token &FirstToken) {
54     this->handleItemListPragma(PP, FirstToken);
55   }
56 };
57 
58 class RSJavaPackageNamePragmaHandler : public RSPragmaHandler {
59  public:
RSJavaPackageNamePragmaHandler(llvm::StringRef Name,RSContext * Context)60   RSJavaPackageNamePragmaHandler(llvm::StringRef Name, RSContext *Context)
61       : RSPragmaHandler(Name, Context) { }
62 
HandlePragma(clang::Preprocessor & PP,clang::PragmaIntroducerKind Introducer,clang::Token & FirstToken)63   void HandlePragma(clang::Preprocessor &PP,
64                     clang::PragmaIntroducerKind Introducer,
65                     clang::Token &FirstToken) {
66     // FIXME: Need to validate the extracted package name from pragma.
67     // Currently "all chars" specified in pragma will be treated as package
68     // name.
69     //
70     // 18.1 The Grammar of the Java Programming Language
71     // (http://java.sun.com/docs/books/jls/third_edition/html/syntax.html#18.1)
72     //
73     // CompilationUnit:
74     //     [[Annotations] package QualifiedIdentifier   ;  ] {ImportDeclaration}
75     //     {TypeDeclaration}
76     //
77     // QualifiedIdentifier:
78     //     Identifier { . Identifier }
79     //
80     // Identifier:
81     //     IDENTIFIER
82     //
83     // 3.8 Identifiers
84     // (http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#3.8)
85     //
86     //
87 
88     clang::Token &PragmaToken = FirstToken;
89     std::string PackageName;
90 
91     // Skip first token, "java_package_name"
92     PP.LexUnexpandedToken(PragmaToken);
93 
94     // Now, the current token must be clang::tok::lpara
95     if (PragmaToken.isNot(clang::tok::l_paren))
96       return;
97 
98     while (PragmaToken.isNot(clang::tok::eod)) {
99       // Lex package name
100       PP.LexUnexpandedToken(PragmaToken);
101 
102       bool Invalid;
103       std::string Spelling = PP.getSpelling(PragmaToken, &Invalid);
104       if (!Invalid)
105         PackageName.append(Spelling);
106 
107       // Pre-mature end (syntax error will be triggered by preprocessor later)
108       if (PragmaToken.is(clang::tok::eod) || PragmaToken.is(clang::tok::eof)) {
109         break;
110       } else {
111         // Next token is ')' (end of pragma)
112         const clang::Token &NextTok = PP.LookAhead(0);
113         if (NextTok.is(clang::tok::r_paren)) {
114           mContext->addPragma(this->getName(), PackageName);
115           mContext->setReflectJavaPackageName(PackageName);
116           // Lex until meets clang::tok::eod
117           do {
118             PP.LexUnexpandedToken(PragmaToken);
119           } while (PragmaToken.isNot(clang::tok::eod));
120           break;
121         }
122       }
123     }
124   }
125 };
126 
127 class RSReducePragmaHandler : public RSPragmaHandler {
128  public:
RSReducePragmaHandler(llvm::StringRef Name,RSContext * Context)129   RSReducePragmaHandler(llvm::StringRef Name, RSContext *Context)
130       : RSPragmaHandler(Name, Context) { }
131 
HandlePragma(clang::Preprocessor & PP,clang::PragmaIntroducerKind Introducer,clang::Token & FirstToken)132   void HandlePragma(clang::Preprocessor &PP,
133                     clang::PragmaIntroducerKind Introducer,
134                     clang::Token &FirstToken) override {
135     // #pragma rs reduce(name)
136     //   initializer(initializename)
137     //   accumulator(accumulatename)
138     //   combiner(combinename)
139     //   outconverter(outconvertname)
140     //   halter(haltname)
141 
142     const clang::SourceLocation PragmaLocation = FirstToken.getLocation();
143 
144     clang::Token &PragmaToken = FirstToken;
145 
146     // Grab "reduce(name)" ("reduce" is already known to be the first
147     // token) and all the "keyword(value)" contributions
148     KeywordValueMapType KeywordValueMap({std::make_pair(RSExportReduce::KeyReduce, ""),
149                                          std::make_pair(RSExportReduce::KeyInitializer, ""),
150                                          std::make_pair(RSExportReduce::KeyAccumulator, ""),
151                                          std::make_pair(RSExportReduce::KeyCombiner, ""),
152                                          std::make_pair(RSExportReduce::KeyOutConverter, "")});
153     if (mContext->getTargetAPI() >= SLANG_FEATURE_GENERAL_REDUCTION_HALTER_API) {
154       // Halter functionality has not been released, nor has its
155       // specification been finalized with partners.  We do not have a
156       // specification that extends through the full RenderScript
157       // software stack, either.
158       KeywordValueMap.insert(std::make_pair(RSExportReduce::KeyHalter, ""));
159     }
160     while (PragmaToken.is(clang::tok::identifier)) {
161       if (!ProcessKeywordAndValue(PP, PragmaToken, KeywordValueMap))
162         return;
163     }
164 
165     // Make sure there's no end-of-line garbage
166     if (PragmaToken.isNot(clang::tok::eod)) {
167       PP.Diag(PragmaToken.getLocation(),
168               PP.getDiagnostics().getCustomDiagID(
169                 clang::DiagnosticsEngine::Error,
170                 "did not expect '%0' here for '#pragma rs %1'"))
171           << PP.getSpelling(PragmaToken) << getName();
172       return;
173     }
174 
175     // Make sure we have an accumulator
176     if (KeywordValueMap[RSExportReduce::KeyAccumulator].empty()) {
177       PP.Diag(PragmaLocation, PP.getDiagnostics().getCustomDiagID(
178                                 clang::DiagnosticsEngine::Error,
179                                 "missing '%0' for '#pragma rs %1'"))
180           << RSExportReduce::KeyAccumulator << getName();
181       return;
182     }
183 
184     // Make sure the reduction kernel name is unique.  (If we were
185     // worried there might be a VERY large number of pragmas, then we
186     // could do something more efficient than walking a list to search
187     // for duplicates.)
188     for (auto I = mContext->export_reduce_begin(),
189               E = mContext->export_reduce_end();
190          I != E; ++I) {
191       if ((*I)->getNameReduce() == KeywordValueMap[RSExportReduce::KeyReduce]) {
192         PP.Diag(PragmaLocation, PP.getDiagnostics().getCustomDiagID(
193                                   clang::DiagnosticsEngine::Error,
194                                   "reduction kernel '%0' declared multiple "
195                                   "times (first one is at %1)"))
196             << KeywordValueMap[RSExportReduce::KeyReduce]
197             << (*I)->getLocation().printToString(PP.getSourceManager());
198         return;
199       }
200     }
201 
202     // Check API version.
203     if (mContext->getTargetAPI() < SLANG_FEATURE_GENERAL_REDUCTION_API) {
204       PP.Diag(PragmaLocation,
205               PP.getDiagnostics().getCustomDiagID(
206                 clang::DiagnosticsEngine::Error,
207                 "reduction kernels are not supported in SDK levels %0-%1"))
208           << SLANG_MINIMUM_TARGET_API
209           << (SLANG_FEATURE_GENERAL_REDUCTION_API - 1);
210       return;
211     }
212 
213     // Handle backward reference from pragma (see Backend::HandleTopLevelDecl for forward reference).
214     MarkUsed(PP, KeywordValueMap[RSExportReduce::KeyInitializer]);
215     MarkUsed(PP, KeywordValueMap[RSExportReduce::KeyAccumulator]);
216     MarkUsed(PP, KeywordValueMap[RSExportReduce::KeyCombiner]);
217     MarkUsed(PP, KeywordValueMap[RSExportReduce::KeyOutConverter]);
218     MarkUsed(PP, KeywordValueMap[RSExportReduce::KeyHalter]);
219 
220     mContext->addExportReduce(RSExportReduce::Create(mContext, PragmaLocation,
221                                                      KeywordValueMap[RSExportReduce::KeyReduce],
222                                                      KeywordValueMap[RSExportReduce::KeyInitializer],
223                                                      KeywordValueMap[RSExportReduce::KeyAccumulator],
224                                                      KeywordValueMap[RSExportReduce::KeyCombiner],
225                                                      KeywordValueMap[RSExportReduce::KeyOutConverter],
226                                                      KeywordValueMap[RSExportReduce::KeyHalter]));
227   }
228 
229  private:
230   typedef std::map<std::string, std::string> KeywordValueMapType;
231 
MarkUsed(clang::Preprocessor & PP,const std::string & FunctionName)232   void MarkUsed(clang::Preprocessor &PP, const std::string &FunctionName) {
233     if (FunctionName.empty())
234       return;
235 
236     clang::ASTContext &ASTC = mContext->getASTContext();
237     clang::TranslationUnitDecl *TUDecl = ASTC.getTranslationUnitDecl();
238     slangAssert(TUDecl);
239     if (const clang::IdentifierInfo *II = PP.getIdentifierInfo(FunctionName)) {
240       for (auto Decl : TUDecl->lookup(II)) {
241         clang::FunctionDecl *FDecl = Decl->getAsFunction();
242         if (!FDecl || !FDecl->isThisDeclarationADefinition())
243           continue;
244         // Handle backward reference from pragma (see
245         // Backend::HandleTopLevelDecl for forward reference).
246         mContext->markUsedByReducePragma(FDecl, RSContext::CheckNameNo);
247       }
248     }
249   }
250 
251   // Return comma-separated list of all keys in the map
ListKeywords(const KeywordValueMapType & KeywordValueMap)252   static std::string ListKeywords(const KeywordValueMapType &KeywordValueMap) {
253     std::string Ret;
254     bool First = true;
255     for (auto const &entry : KeywordValueMap) {
256       if (First)
257         First = false;
258       else
259         Ret += ", ";
260       Ret += "'";
261       Ret += entry.first;
262       Ret += "'";
263     }
264     return Ret;
265   }
266 
267   // Parse "keyword(value)" and set KeywordValueMap[keyword] = value.  (Both
268   // "keyword" and "value" are identifiers.)
269   // Does both syntactic validation and the following semantic validation:
270   // - The keyword must be present in the map.
271   // - The map entry for the keyword must not contain a value.
ProcessKeywordAndValue(clang::Preprocessor & PP,clang::Token & PragmaToken,KeywordValueMapType & KeywordValueMap)272   bool ProcessKeywordAndValue(clang::Preprocessor &PP,
273                               clang::Token &PragmaToken,
274                               KeywordValueMapType &KeywordValueMap) {
275     // The current token must be an identifier in KeywordValueMap
276     KeywordValueMapType::iterator Entry;
277     if (PragmaToken.isNot(clang::tok::identifier) ||
278         ((Entry = KeywordValueMap.find(
279             PragmaToken.getIdentifierInfo()->getName())) ==
280          KeywordValueMap.end())) {
281       // Note that we should never get here for the "reduce" token
282       // itself, which should already have been recognized.
283       PP.Diag(PragmaToken.getLocation(),
284               PP.getDiagnostics().getCustomDiagID(
285                 clang::DiagnosticsEngine::Error,
286                 "did not recognize '%0' for '#pragma %1'; expected one of "
287                 "the following keywords: %2"))
288           << PragmaToken.getIdentifierInfo()->getName() << getName()
289           << ListKeywords(KeywordValueMap);
290       return false;
291     }
292     // ... and there must be no value for this keyword yet
293     if (!Entry->second.empty()) {
294       PP.Diag(PragmaToken.getLocation(),
295               PP.getDiagnostics().getCustomDiagID(
296                 clang::DiagnosticsEngine::Error,
297                 "more than one '%0' for '#pragma rs %1'"))
298           << Entry->first << getName();
299       return false;
300     }
301     PP.LexUnexpandedToken(PragmaToken);
302 
303     // The current token must be clang::tok::l_paren
304     if (PragmaToken.isNot(clang::tok::l_paren)) {
305       PP.Diag(PragmaToken.getLocation(),
306               PP.getDiagnostics().getCustomDiagID(
307                 clang::DiagnosticsEngine::Error,
308                 "missing '(' after '%0' for '#pragma rs %1'"))
309           << Entry->first << getName();
310       return false;
311     }
312     PP.LexUnexpandedToken(PragmaToken);
313 
314     // The current token must be an identifier (a name)
315     if (PragmaToken.isNot(clang::tok::identifier)) {
316       PP.Diag(PragmaToken.getLocation(),
317               PP.getDiagnostics().getCustomDiagID(
318                 clang::DiagnosticsEngine::Error,
319                 "missing name after '%0(' for '#pragma rs %1'"))
320           << Entry->first << getName();
321       return false;
322     }
323     const std::string Name = PragmaToken.getIdentifierInfo()->getName();
324     PP.LexUnexpandedToken(PragmaToken);
325 
326     // The current token must be clang::tok::r_paren
327     if (PragmaToken.isNot(clang::tok::r_paren)) {
328       PP.Diag(PragmaToken.getLocation(),
329               PP.getDiagnostics().getCustomDiagID(
330                 clang::DiagnosticsEngine::Error,
331                 "missing ')' after '%0(%1' for '#pragma rs %2'"))
332           << Entry->first << Name << getName();
333       return false;
334     }
335     PP.LexUnexpandedToken(PragmaToken);
336 
337     // Success
338     Entry->second = Name;
339     return true;
340   }
341 };
342 
343 class RSReflectLicensePragmaHandler : public RSPragmaHandler {
344  private:
handleItem(const std::string & Item)345   void handleItem(const std::string &Item) {
346     mContext->addPragma(this->getName(), Item);
347     mContext->setLicenseNote(Item);
348   }
349 
350  public:
RSReflectLicensePragmaHandler(llvm::StringRef Name,RSContext * Context)351   RSReflectLicensePragmaHandler(llvm::StringRef Name, RSContext *Context)
352       : RSPragmaHandler(Name, Context) { }
353 
HandlePragma(clang::Preprocessor & PP,clang::PragmaIntroducerKind Introducer,clang::Token & FirstToken)354   void HandlePragma(clang::Preprocessor &PP,
355                     clang::PragmaIntroducerKind Introducer,
356                     clang::Token &FirstToken) {
357     this->handleOptionalStringLiteralParamPragma(PP, FirstToken);
358   }
359 };
360 
361 class RSVersionPragmaHandler : public RSPragmaHandler {
362  private:
handleInt(clang::Preprocessor & PP,clang::Token & Tok,const int v)363   void handleInt(clang::Preprocessor &PP,
364                  clang::Token &Tok,
365                  const int v) {
366     if (v != 1) {
367       PP.Diag(Tok,
368               PP.getDiagnostics().getCustomDiagID(
369                   clang::DiagnosticsEngine::Error,
370                   "pragma for version in source file must be set to 1"));
371       mContext->setVersion(1);
372       return;
373     }
374     std::stringstream ss;
375     ss << v;
376     mContext->addPragma(this->getName(), ss.str());
377     mContext->setVersion(v);
378   }
379 
380  public:
RSVersionPragmaHandler(llvm::StringRef Name,RSContext * Context)381   RSVersionPragmaHandler(llvm::StringRef Name, RSContext *Context)
382       : RSPragmaHandler(Name, Context) { }
383 
HandlePragma(clang::Preprocessor & PP,clang::PragmaIntroducerKind Introducer,clang::Token & FirstToken)384   void HandlePragma(clang::Preprocessor &PP,
385                     clang::PragmaIntroducerKind Introducer,
386                     clang::Token &FirstToken) {
387     this->handleIntegerParamPragma(PP, FirstToken);
388   }
389 };
390 
391 // Handles the pragmas rs_fp_full, rs_fp_relaxed, and rs_fp_imprecise.
392 // There's one instance of this handler for each of the above values.
393 // Only getName() differs between the instances.
394 class RSPrecisionPragmaHandler : public RSPragmaHandler {
395 public:
RSPrecisionPragmaHandler(llvm::StringRef Name,RSContext * Context)396   RSPrecisionPragmaHandler(llvm::StringRef Name, RSContext *Context)
397       : RSPragmaHandler(Name, Context) {}
398 
HandlePragma(clang::Preprocessor & PP,clang::PragmaIntroducerKind Introducer,clang::Token & Token)399   void HandlePragma(clang::Preprocessor &PP,
400                     clang::PragmaIntroducerKind Introducer,
401                     clang::Token &Token) {
402     std::string Precision = getName();
403     // We are deprecating rs_fp_imprecise.
404     if (Precision == "rs_fp_imprecise") {
405       PP.Diag(Token, PP.getDiagnostics().getCustomDiagID(
406                          clang::DiagnosticsEngine::Warning,
407                          "rs_fp_imprecise is deprecated.  Assuming "
408                          "rs_fp_relaxed instead."));
409       Precision = "rs_fp_relaxed";
410     }
411     // Check if we have already encountered a precision pragma already.
412     std::string PreviousPrecision = mContext->getPrecision();
413     if (!PreviousPrecision.empty()) {
414       // If the previous specified a different value, it's an error.
415       if (PreviousPrecision != Precision) {
416         PP.Diag(Token, PP.getDiagnostics().getCustomDiagID(
417                            clang::DiagnosticsEngine::Error,
418                            "Multiple float precisions specified.  Encountered "
419                            "%0 previously."))
420             << PreviousPrecision;
421       }
422       // Otherwise we ignore redundant entries.
423       return;
424     }
425 
426     mContext->addPragma(Precision, "");
427     mContext->setPrecision(Precision);
428   }
429 };
430 
431 }  // namespace
432 
handleItemListPragma(clang::Preprocessor & PP,clang::Token & FirstToken)433 void RSPragmaHandler::handleItemListPragma(clang::Preprocessor &PP,
434                                            clang::Token &FirstToken) {
435   clang::Token &PragmaToken = FirstToken;
436 
437   // Skip first token, like "export_var"
438   PP.LexUnexpandedToken(PragmaToken);
439 
440   // Now, the current token must be clang::tok::lpara
441   if (PragmaToken.isNot(clang::tok::l_paren))
442     return;
443 
444   while (PragmaToken.isNot(clang::tok::eod)) {
445     // Lex variable name
446     PP.LexUnexpandedToken(PragmaToken);
447     if (PragmaToken.is(clang::tok::identifier))
448       this->handleItem(PP.getSpelling(PragmaToken));
449     else
450       break;
451 
452     slangAssert(PragmaToken.isNot(clang::tok::eod));
453 
454     PP.LexUnexpandedToken(PragmaToken);
455 
456     if (PragmaToken.isNot(clang::tok::comma))
457       break;
458   }
459 }
460 
handleNonParamPragma(clang::Preprocessor & PP,clang::Token & FirstToken)461 void RSPragmaHandler::handleNonParamPragma(clang::Preprocessor &PP,
462                                            clang::Token &FirstToken) {
463   clang::Token &PragmaToken = FirstToken;
464 
465   // Skip first token, like "export_var_all"
466   PP.LexUnexpandedToken(PragmaToken);
467 
468   // Should be end immediately
469   if (PragmaToken.isNot(clang::tok::eod))
470     if (PragmaToken.isNot(clang::tok::r_paren)) {
471       PP.Diag(PragmaToken,
472               PP.getDiagnostics().getCustomDiagID(
473                   clang::DiagnosticsEngine::Error,
474                   "expected a ')'"));
475       return;
476     }
477 }
478 
handleOptionalStringLiteralParamPragma(clang::Preprocessor & PP,clang::Token & FirstToken)479 void RSPragmaHandler::handleOptionalStringLiteralParamPragma(
480     clang::Preprocessor &PP, clang::Token &FirstToken) {
481   clang::Token &PragmaToken = FirstToken;
482 
483   // Skip first token, like "set_reflect_license"
484   PP.LexUnexpandedToken(PragmaToken);
485 
486   // Now, the current token must be clang::tok::lpara
487   if (PragmaToken.isNot(clang::tok::l_paren))
488     return;
489 
490   // If not ')', eat the following string literal as the license
491   PP.LexUnexpandedToken(PragmaToken);
492   if (PragmaToken.isNot(clang::tok::r_paren)) {
493     // Eat the whole string literal
494     clang::StringLiteralParser StringLiteral(PragmaToken, PP);
495     if (StringLiteral.hadError) {
496       // Diagnostics will be generated automatically
497       return;
498     } else {
499       this->handleItem(std::string(StringLiteral.GetString()));
500     }
501 
502     // The current token should be clang::tok::r_para
503     PP.LexUnexpandedToken(PragmaToken);
504     if (PragmaToken.isNot(clang::tok::r_paren)) {
505       PP.Diag(PragmaToken,
506               PP.getDiagnostics().getCustomDiagID(
507                   clang::DiagnosticsEngine::Error,
508                   "expected a ')'"));
509       return;
510     }
511   } else {
512     // If no argument, remove the license
513     this->handleItem("");
514   }
515 }
516 
handleIntegerParamPragma(clang::Preprocessor & PP,clang::Token & FirstToken)517 void RSPragmaHandler::handleIntegerParamPragma(
518     clang::Preprocessor &PP, clang::Token &FirstToken) {
519   clang::Token &PragmaToken = FirstToken;
520 
521   // Skip first token, like "version"
522   PP.LexUnexpandedToken(PragmaToken);
523 
524   // Now, the current token must be clang::tok::lpara
525   if (PragmaToken.isNot(clang::tok::l_paren)) {
526     // If no argument, set the version to 0
527     this->handleInt(PP, PragmaToken, 0);
528     return;
529   }
530   PP.LexUnexpandedToken(PragmaToken);
531 
532   if (PragmaToken.is(clang::tok::numeric_constant)) {
533     llvm::SmallString<128> SpellingBuffer;
534     SpellingBuffer.resize(PragmaToken.getLength() + 1);
535     llvm::StringRef TokSpelling = PP.getSpelling(PragmaToken, SpellingBuffer);
536     clang::NumericLiteralParser NumericLiteral(TokSpelling,
537         PragmaToken.getLocation(), PP);
538     if (NumericLiteral.hadError) {
539       // Diagnostics will be generated automatically
540       return;
541     } else {
542       llvm::APInt Val(32, 0);
543       NumericLiteral.GetIntegerValue(Val);
544       this->handleInt(PP, PragmaToken, static_cast<int>(Val.getSExtValue()));
545     }
546     PP.LexUnexpandedToken(PragmaToken);
547   } else {
548     // If no argument, set the version to 0
549     this->handleInt(PP, PragmaToken, 0);
550   }
551 
552   if (PragmaToken.isNot(clang::tok::r_paren)) {
553     PP.Diag(PragmaToken,
554             PP.getDiagnostics().getCustomDiagID(
555                 clang::DiagnosticsEngine::Error,
556                 "expected a ')'"));
557     return;
558   }
559 
560   do {
561     PP.LexUnexpandedToken(PragmaToken);
562   } while (PragmaToken.isNot(clang::tok::eod));
563 }
564 
AddPragmaHandlers(clang::Preprocessor & PP,RSContext * RsContext)565 void AddPragmaHandlers(clang::Preprocessor &PP, RSContext *RsContext) {
566   // For #pragma rs export_type
567   PP.AddPragmaHandler("rs",
568                       new RSExportTypePragmaHandler("export_type", RsContext));
569 
570   // For #pragma rs java_package_name
571   PP.AddPragmaHandler(
572       "rs", new RSJavaPackageNamePragmaHandler("java_package_name", RsContext));
573 
574   // For #pragma rs reduce
575   PP.AddPragmaHandler(
576       "rs", new RSReducePragmaHandler(RSExportReduce::KeyReduce, RsContext));
577 
578   // For #pragma rs set_reflect_license
579   PP.AddPragmaHandler(
580       "rs", new RSReflectLicensePragmaHandler("set_reflect_license", RsContext));
581 
582   // For #pragma version
583   PP.AddPragmaHandler(new RSVersionPragmaHandler("version", RsContext));
584 
585   // For #pragma rs_fp*
586   PP.AddPragmaHandler(new RSPrecisionPragmaHandler("rs_fp_full", RsContext));
587   PP.AddPragmaHandler(new RSPrecisionPragmaHandler("rs_fp_relaxed", RsContext));
588   PP.AddPragmaHandler(new RSPrecisionPragmaHandler("rs_fp_imprecise", RsContext));
589 }
590 
591 
592 }  // namespace slang
593