xref: /llvm-project/clang/lib/Basic/Builtins.cpp (revision 35869a26cd94e592ab6e740f3030c62c568f0048)
1 //===--- Builtins.cpp - Builtin function implementation -------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  This file implements various things for builtin functions.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "clang/Basic/Builtins.h"
15 #include "clang/Basic/IdentifierTable.h"
16 #include "clang/Basic/LangOptions.h"
17 #include "clang/Basic/TargetInfo.h"
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/ADT/StringRef.h"
20 using namespace clang;
21 
22 static const Builtin::Info BuiltinInfo[] = {
23   { "not a builtin function", nullptr, nullptr, nullptr, ALL_LANGUAGES},
24 #define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
25 #define LANGBUILTIN(ID, TYPE, ATTRS, LANGS)                                    \
26   { #ID, TYPE, ATTRS, 0, LANGS }                                               \
27   ,
28 #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, LANGS)                             \
29   { #ID, TYPE, ATTRS, HEADER, LANGS }                                          \
30   ,
31 #include "clang/Basic/Builtins.def"
32 };
33 
34 const Builtin::Info &Builtin::Context::GetRecord(unsigned ID) const {
35   if (ID < Builtin::FirstTSBuiltin)
36     return BuiltinInfo[ID];
37   assert(ID - Builtin::FirstTSBuiltin < NumTSRecords && "Invalid builtin ID!");
38   return TSRecords[ID - Builtin::FirstTSBuiltin];
39 }
40 
41 Builtin::Context::Context() {
42   // Get the target specific builtins from the target.
43   TSRecords = nullptr;
44   NumTSRecords = 0;
45 }
46 
47 void Builtin::Context::InitializeTarget(const TargetInfo &Target) {
48   assert(NumTSRecords == 0 && "Already initialized target?");
49   Target.getTargetBuiltins(TSRecords, NumTSRecords);
50 }
51 
52 bool Builtin::Context::BuiltinIsSupported(const Builtin::Info &BuiltinInfo,
53                                           const LangOptions &LangOpts) {
54   bool BuiltinsUnsupported = LangOpts.NoBuiltin &&
55                              strchr(BuiltinInfo.Attributes, 'f');
56   bool MathBuiltinsUnsupported =
57     LangOpts.NoMathBuiltin && BuiltinInfo.HeaderName &&
58     llvm::StringRef(BuiltinInfo.HeaderName).equals("math.h");
59   bool GnuModeUnsupported = !LangOpts.GNUMode && (BuiltinInfo.Langs & GNU_LANG);
60   bool MSModeUnsupported =
61       !LangOpts.MicrosoftExt && (BuiltinInfo.Langs & MS_LANG);
62   bool ObjCUnsupported = !LangOpts.ObjC1 && BuiltinInfo.Langs == OBJC_LANG;
63   return !BuiltinsUnsupported && !MathBuiltinsUnsupported &&
64          !GnuModeUnsupported && !MSModeUnsupported && !ObjCUnsupported;
65 }
66 
67 /// InitializeBuiltins - Mark the identifiers for all the builtins with their
68 /// appropriate builtin ID # and mark any non-portable builtin identifiers as
69 /// such.
70 void Builtin::Context::InitializeBuiltins(IdentifierTable &Table,
71                                           const LangOptions& LangOpts) {
72   // Step #1: mark all target-independent builtins with their ID's.
73   for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i)
74     if (BuiltinIsSupported(BuiltinInfo[i], LangOpts)) {
75       Table.get(BuiltinInfo[i].Name).setBuiltinID(i);
76     }
77 
78   // Step #2: Register target-specific builtins.
79   for (unsigned i = 0, e = NumTSRecords; i != e; ++i)
80     if (BuiltinIsSupported(TSRecords[i], LangOpts))
81       Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin);
82 }
83 
84 void Builtin::Context::ForgetBuiltin(unsigned ID, IdentifierTable &Table) {
85   Table.get(GetRecord(ID).Name).setBuiltinID(0);
86 }
87 
88 bool Builtin::Context::isLike(unsigned ID, unsigned &FormatIdx,
89                               bool &HasVAListArg, const char *Fmt) const {
90   assert(Fmt && "Not passed a format string");
91   assert(::strlen(Fmt) == 2 &&
92          "Format string needs to be two characters long");
93   assert(::toupper(Fmt[0]) == Fmt[1] &&
94          "Format string is not in the form \"xX\"");
95 
96   const char *Like = ::strpbrk(GetRecord(ID).Attributes, Fmt);
97   if (!Like)
98     return false;
99 
100   HasVAListArg = (*Like == Fmt[1]);
101 
102   ++Like;
103   assert(*Like == ':' && "Format specifier must be followed by a ':'");
104   ++Like;
105 
106   assert(::strchr(Like, ':') && "Format specifier must end with a ':'");
107   FormatIdx = ::strtol(Like, nullptr, 10);
108   return true;
109 }
110 
111 bool Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx,
112                                     bool &HasVAListArg) {
113   return isLike(ID, FormatIdx, HasVAListArg, "pP");
114 }
115 
116 bool Builtin::Context::isScanfLike(unsigned ID, unsigned &FormatIdx,
117                                    bool &HasVAListArg) {
118   return isLike(ID, FormatIdx, HasVAListArg, "sS");
119 }
120