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/StringRef.h" 19 using namespace clang; 20 21 static const Builtin::Info BuiltinInfo[] = { 22 { "not a builtin function", nullptr, nullptr, nullptr, ALL_LANGUAGES,nullptr}, 23 #define BUILTIN(ID, TYPE, ATTRS) \ 24 { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, 25 #define LANGBUILTIN(ID, TYPE, ATTRS, LANGS) \ 26 { #ID, TYPE, ATTRS, nullptr, LANGS, nullptr }, 27 #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, LANGS) \ 28 { #ID, TYPE, ATTRS, HEADER, LANGS, nullptr }, 29 #include "clang/Basic/Builtins.def" 30 }; 31 32 const Builtin::Info &Builtin::Context::getRecord(unsigned ID) const { 33 if (ID < Builtin::FirstTSBuiltin) 34 return BuiltinInfo[ID]; 35 assert(ID - Builtin::FirstTSBuiltin < (NumTSRecords + NumAuxTSRecords) && 36 "Invalid builtin ID!"); 37 if (isAuxBuiltinID(ID)) 38 return AuxTSRecords[getAuxBuiltinID(ID) - Builtin::FirstTSBuiltin]; 39 return TSRecords[ID - Builtin::FirstTSBuiltin]; 40 } 41 42 Builtin::Context::Context() { 43 // Get the target specific builtins from the target. 44 TSRecords = nullptr; 45 AuxTSRecords = nullptr; 46 NumTSRecords = 0; 47 NumAuxTSRecords = 0; 48 } 49 50 void Builtin::Context::InitializeTarget(const TargetInfo &Target, 51 const TargetInfo *AuxTarget) { 52 assert(NumTSRecords == 0 && "Already initialized target?"); 53 Target.getTargetBuiltins(TSRecords, NumTSRecords); 54 if (AuxTarget) 55 AuxTarget->getTargetBuiltins(AuxTSRecords, NumAuxTSRecords); 56 } 57 58 bool Builtin::Context::builtinIsSupported(const Builtin::Info &BuiltinInfo, 59 const LangOptions &LangOpts) { 60 bool BuiltinsUnsupported = LangOpts.NoBuiltin && 61 strchr(BuiltinInfo.Attributes, 'f'); 62 bool MathBuiltinsUnsupported = 63 LangOpts.NoMathBuiltin && BuiltinInfo.HeaderName && 64 llvm::StringRef(BuiltinInfo.HeaderName).equals("math.h"); 65 bool GnuModeUnsupported = !LangOpts.GNUMode && (BuiltinInfo.Langs & GNU_LANG); 66 bool MSModeUnsupported = 67 !LangOpts.MicrosoftExt && (BuiltinInfo.Langs & MS_LANG); 68 bool ObjCUnsupported = !LangOpts.ObjC1 && BuiltinInfo.Langs == OBJC_LANG; 69 return !BuiltinsUnsupported && !MathBuiltinsUnsupported && 70 !GnuModeUnsupported && !MSModeUnsupported && !ObjCUnsupported; 71 } 72 73 /// initializeBuiltins - Mark the identifiers for all the builtins with their 74 /// appropriate builtin ID # and mark any non-portable builtin identifiers as 75 /// such. 76 void Builtin::Context::initializeBuiltins(IdentifierTable &Table, 77 const LangOptions& LangOpts) { 78 // Step #1: mark all target-independent builtins with their ID's. 79 for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) 80 if (builtinIsSupported(BuiltinInfo[i], LangOpts)) { 81 Table.get(BuiltinInfo[i].Name).setBuiltinID(i); 82 } 83 84 // Step #2: Register target-specific builtins. 85 for (unsigned i = 0, e = NumTSRecords; i != e; ++i) 86 if (builtinIsSupported(TSRecords[i], LangOpts)) 87 Table.get(TSRecords[i].Name).setBuiltinID(i + Builtin::FirstTSBuiltin); 88 89 // Step #3: Register target-specific builtins for AuxTarget. 90 for (unsigned i = 0, e = NumAuxTSRecords; i != e; ++i) 91 Table.get(AuxTSRecords[i].Name) 92 .setBuiltinID(i + Builtin::FirstTSBuiltin + NumTSRecords); 93 } 94 95 void Builtin::Context::forgetBuiltin(unsigned ID, IdentifierTable &Table) { 96 Table.get(getRecord(ID).Name).setBuiltinID(0); 97 } 98 99 bool Builtin::Context::isLike(unsigned ID, unsigned &FormatIdx, 100 bool &HasVAListArg, const char *Fmt) const { 101 assert(Fmt && "Not passed a format string"); 102 assert(::strlen(Fmt) == 2 && 103 "Format string needs to be two characters long"); 104 assert(::toupper(Fmt[0]) == Fmt[1] && 105 "Format string is not in the form \"xX\""); 106 107 const char *Like = ::strpbrk(getRecord(ID).Attributes, Fmt); 108 if (!Like) 109 return false; 110 111 HasVAListArg = (*Like == Fmt[1]); 112 113 ++Like; 114 assert(*Like == ':' && "Format specifier must be followed by a ':'"); 115 ++Like; 116 117 assert(::strchr(Like, ':') && "Format specifier must end with a ':'"); 118 FormatIdx = ::strtol(Like, nullptr, 10); 119 return true; 120 } 121 122 bool Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx, 123 bool &HasVAListArg) { 124 return isLike(ID, FormatIdx, HasVAListArg, "pP"); 125 } 126 127 bool Builtin::Context::isScanfLike(unsigned ID, unsigned &FormatIdx, 128 bool &HasVAListArg) { 129 return isLike(ID, FormatIdx, HasVAListArg, "sS"); 130 } 131