Builtins.cpp revision 360784
1//===--- Builtins.cpp - Builtin function implementation -------------------===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8// 9// This file implements various things for builtin functions. 10// 11//===----------------------------------------------------------------------===// 12 13#include "clang/Basic/Builtins.h" 14#include "clang/Basic/IdentifierTable.h" 15#include "clang/Basic/LangOptions.h" 16#include "clang/Basic/TargetInfo.h" 17#include "llvm/ADT/StringRef.h" 18using namespace clang; 19 20static const Builtin::Info BuiltinInfo[] = { 21 { "not a builtin function", nullptr, nullptr, nullptr, ALL_LANGUAGES,nullptr}, 22#define BUILTIN(ID, TYPE, ATTRS) \ 23 { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, 24#define LANGBUILTIN(ID, TYPE, ATTRS, LANGS) \ 25 { #ID, TYPE, ATTRS, nullptr, LANGS, nullptr }, 26#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, LANGS) \ 27 { #ID, TYPE, ATTRS, HEADER, LANGS, nullptr }, 28#include "clang/Basic/Builtins.def" 29}; 30 31const Builtin::Info &Builtin::Context::getRecord(unsigned ID) const { 32 if (ID < Builtin::FirstTSBuiltin) 33 return BuiltinInfo[ID]; 34 assert(((ID - Builtin::FirstTSBuiltin) < 35 (TSRecords.size() + AuxTSRecords.size())) && 36 "Invalid builtin ID!"); 37 if (isAuxBuiltinID(ID)) 38 return AuxTSRecords[getAuxBuiltinID(ID) - Builtin::FirstTSBuiltin]; 39 return TSRecords[ID - Builtin::FirstTSBuiltin]; 40} 41 42void Builtin::Context::InitializeTarget(const TargetInfo &Target, 43 const TargetInfo *AuxTarget) { 44 assert(TSRecords.empty() && "Already initialized target?"); 45 TSRecords = Target.getTargetBuiltins(); 46 if (AuxTarget) 47 AuxTSRecords = AuxTarget->getTargetBuiltins(); 48} 49 50bool Builtin::Context::isBuiltinFunc(llvm::StringRef FuncName) { 51 for (unsigned i = Builtin::NotBuiltin + 1; i != Builtin::FirstTSBuiltin; ++i) 52 if (FuncName.equals(BuiltinInfo[i].Name)) 53 return strchr(BuiltinInfo[i].Attributes, 'f') != nullptr; 54 55 return false; 56} 57 58bool Builtin::Context::builtinIsSupported(const Builtin::Info &BuiltinInfo, 59 const LangOptions &LangOpts) { 60 bool BuiltinsUnsupported = 61 (LangOpts.NoBuiltin || LangOpts.isNoBuiltinFunc(BuiltinInfo.Name)) && 62 strchr(BuiltinInfo.Attributes, 'f'); 63 bool MathBuiltinsUnsupported = 64 LangOpts.NoMathBuiltin && BuiltinInfo.HeaderName && 65 llvm::StringRef(BuiltinInfo.HeaderName).equals("math.h"); 66 bool GnuModeUnsupported = !LangOpts.GNUMode && (BuiltinInfo.Langs & GNU_LANG); 67 bool MSModeUnsupported = 68 !LangOpts.MicrosoftExt && (BuiltinInfo.Langs & MS_LANG); 69 bool ObjCUnsupported = !LangOpts.ObjC && BuiltinInfo.Langs == OBJC_LANG; 70 bool OclC1Unsupported = (LangOpts.OpenCLVersion / 100) != 1 && 71 (BuiltinInfo.Langs & ALL_OCLC_LANGUAGES ) == OCLC1X_LANG; 72 bool OclC2Unsupported = 73 (LangOpts.OpenCLVersion != 200 && !LangOpts.OpenCLCPlusPlus) && 74 (BuiltinInfo.Langs & ALL_OCLC_LANGUAGES) == OCLC20_LANG; 75 bool OclCUnsupported = !LangOpts.OpenCL && 76 (BuiltinInfo.Langs & ALL_OCLC_LANGUAGES); 77 bool OpenMPUnsupported = !LangOpts.OpenMP && BuiltinInfo.Langs == OMP_LANG; 78 bool CPlusPlusUnsupported = 79 !LangOpts.CPlusPlus && BuiltinInfo.Langs == CXX_LANG; 80 return !BuiltinsUnsupported && !MathBuiltinsUnsupported && !OclCUnsupported && 81 !OclC1Unsupported && !OclC2Unsupported && !OpenMPUnsupported && 82 !GnuModeUnsupported && !MSModeUnsupported && !ObjCUnsupported && 83 !CPlusPlusUnsupported; 84} 85 86/// initializeBuiltins - Mark the identifiers for all the builtins with their 87/// appropriate builtin ID # and mark any non-portable builtin identifiers as 88/// such. 89void Builtin::Context::initializeBuiltins(IdentifierTable &Table, 90 const LangOptions& LangOpts) { 91 // Step #1: mark all target-independent builtins with their ID's. 92 for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) 93 if (builtinIsSupported(BuiltinInfo[i], LangOpts)) { 94 Table.get(BuiltinInfo[i].Name).setBuiltinID(i); 95 } 96 97 // Step #2: Register target-specific builtins. 98 for (unsigned i = 0, e = TSRecords.size(); i != e; ++i) 99 if (builtinIsSupported(TSRecords[i], LangOpts)) 100 Table.get(TSRecords[i].Name).setBuiltinID(i + Builtin::FirstTSBuiltin); 101 102 // Step #3: Register target-specific builtins for AuxTarget. 103 for (unsigned i = 0, e = AuxTSRecords.size(); i != e; ++i) 104 Table.get(AuxTSRecords[i].Name) 105 .setBuiltinID(i + Builtin::FirstTSBuiltin + TSRecords.size()); 106} 107 108void Builtin::Context::forgetBuiltin(unsigned ID, IdentifierTable &Table) { 109 Table.get(getRecord(ID).Name).setBuiltinID(0); 110} 111 112unsigned Builtin::Context::getRequiredVectorWidth(unsigned ID) const { 113 const char *WidthPos = ::strchr(getRecord(ID).Attributes, 'V'); 114 if (!WidthPos) 115 return 0; 116 117 ++WidthPos; 118 assert(*WidthPos == ':' && 119 "Vector width specifier must be followed by a ':'"); 120 ++WidthPos; 121 122 char *EndPos; 123 unsigned Width = ::strtol(WidthPos, &EndPos, 10); 124 assert(*EndPos == ':' && "Vector width specific must end with a ':'"); 125 return Width; 126} 127 128bool Builtin::Context::isLike(unsigned ID, unsigned &FormatIdx, 129 bool &HasVAListArg, const char *Fmt) const { 130 assert(Fmt && "Not passed a format string"); 131 assert(::strlen(Fmt) == 2 && 132 "Format string needs to be two characters long"); 133 assert(::toupper(Fmt[0]) == Fmt[1] && 134 "Format string is not in the form \"xX\""); 135 136 const char *Like = ::strpbrk(getRecord(ID).Attributes, Fmt); 137 if (!Like) 138 return false; 139 140 HasVAListArg = (*Like == Fmt[1]); 141 142 ++Like; 143 assert(*Like == ':' && "Format specifier must be followed by a ':'"); 144 ++Like; 145 146 assert(::strchr(Like, ':') && "Format specifier must end with a ':'"); 147 FormatIdx = ::strtol(Like, nullptr, 10); 148 return true; 149} 150 151bool Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx, 152 bool &HasVAListArg) { 153 return isLike(ID, FormatIdx, HasVAListArg, "pP"); 154} 155 156bool Builtin::Context::isScanfLike(unsigned ID, unsigned &FormatIdx, 157 bool &HasVAListArg) { 158 return isLike(ID, FormatIdx, HasVAListArg, "sS"); 159} 160 161bool Builtin::Context::performsCallback(unsigned ID, 162 SmallVectorImpl<int> &Encoding) const { 163 const char *CalleePos = ::strchr(getRecord(ID).Attributes, 'C'); 164 if (!CalleePos) 165 return false; 166 167 ++CalleePos; 168 assert(*CalleePos == '<' && 169 "Callback callee specifier must be followed by a '<'"); 170 ++CalleePos; 171 172 char *EndPos; 173 int CalleeIdx = ::strtol(CalleePos, &EndPos, 10); 174 assert(CalleeIdx >= 0 && "Callee index is supposed to be positive!"); 175 Encoding.push_back(CalleeIdx); 176 177 while (*EndPos == ',') { 178 const char *PayloadPos = EndPos + 1; 179 180 int PayloadIdx = ::strtol(PayloadPos, &EndPos, 10); 181 Encoding.push_back(PayloadIdx); 182 } 183 184 assert(*EndPos == '>' && "Callback callee specifier must end with a '>'"); 185 return true; 186} 187 188bool Builtin::Context::canBeRedeclared(unsigned ID) const { 189 return ID == Builtin::NotBuiltin || 190 ID == Builtin::BI__va_start || 191 (!hasReferenceArgsOrResult(ID) && 192 !hasCustomTypechecking(ID)); 193} 194