Home | History | Annotate | Line # | Download | only in Basic
      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"
     18 using namespace clang;
     19 
     20 static 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 
     31 const 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 
     42 void 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 
     50 bool 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 
     58 bool 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 CUDAUnsupported = !LangOpts.CUDA && BuiltinInfo.Langs == CUDA_LANG;
     79   bool CPlusPlusUnsupported =
     80       !LangOpts.CPlusPlus && BuiltinInfo.Langs == CXX_LANG;
     81   return !BuiltinsUnsupported && !MathBuiltinsUnsupported && !OclCUnsupported &&
     82          !OclC1Unsupported && !OclC2Unsupported && !OpenMPUnsupported &&
     83          !GnuModeUnsupported && !MSModeUnsupported && !ObjCUnsupported &&
     84          !CPlusPlusUnsupported && !CUDAUnsupported;
     85 }
     86 
     87 /// initializeBuiltins - Mark the identifiers for all the builtins with their
     88 /// appropriate builtin ID # and mark any non-portable builtin identifiers as
     89 /// such.
     90 void Builtin::Context::initializeBuiltins(IdentifierTable &Table,
     91                                           const LangOptions& LangOpts) {
     92   // Step #1: mark all target-independent builtins with their ID's.
     93   for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i)
     94     if (builtinIsSupported(BuiltinInfo[i], LangOpts)) {
     95       Table.get(BuiltinInfo[i].Name).setBuiltinID(i);
     96     }
     97 
     98   // Step #2: Register target-specific builtins.
     99   for (unsigned i = 0, e = TSRecords.size(); i != e; ++i)
    100     if (builtinIsSupported(TSRecords[i], LangOpts))
    101       Table.get(TSRecords[i].Name).setBuiltinID(i + Builtin::FirstTSBuiltin);
    102 
    103   // Step #3: Register target-specific builtins for AuxTarget.
    104   for (unsigned i = 0, e = AuxTSRecords.size(); i != e; ++i)
    105     Table.get(AuxTSRecords[i].Name)
    106         .setBuiltinID(i + Builtin::FirstTSBuiltin + TSRecords.size());
    107 }
    108 
    109 unsigned Builtin::Context::getRequiredVectorWidth(unsigned ID) const {
    110   const char *WidthPos = ::strchr(getRecord(ID).Attributes, 'V');
    111   if (!WidthPos)
    112     return 0;
    113 
    114   ++WidthPos;
    115   assert(*WidthPos == ':' &&
    116          "Vector width specifier must be followed by a ':'");
    117   ++WidthPos;
    118 
    119   char *EndPos;
    120   unsigned Width = ::strtol(WidthPos, &EndPos, 10);
    121   assert(*EndPos == ':' && "Vector width specific must end with a ':'");
    122   return Width;
    123 }
    124 
    125 bool Builtin::Context::isLike(unsigned ID, unsigned &FormatIdx,
    126                               bool &HasVAListArg, const char *Fmt) const {
    127   assert(Fmt && "Not passed a format string");
    128   assert(::strlen(Fmt) == 2 &&
    129          "Format string needs to be two characters long");
    130   assert(::toupper(Fmt[0]) == Fmt[1] &&
    131          "Format string is not in the form \"xX\"");
    132 
    133   const char *Like = ::strpbrk(getRecord(ID).Attributes, Fmt);
    134   if (!Like)
    135     return false;
    136 
    137   HasVAListArg = (*Like == Fmt[1]);
    138 
    139   ++Like;
    140   assert(*Like == ':' && "Format specifier must be followed by a ':'");
    141   ++Like;
    142 
    143   assert(::strchr(Like, ':') && "Format specifier must end with a ':'");
    144   FormatIdx = ::strtol(Like, nullptr, 10);
    145   return true;
    146 }
    147 
    148 bool Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx,
    149                                     bool &HasVAListArg) {
    150   return isLike(ID, FormatIdx, HasVAListArg, "pP");
    151 }
    152 
    153 bool Builtin::Context::isScanfLike(unsigned ID, unsigned &FormatIdx,
    154                                    bool &HasVAListArg) {
    155   return isLike(ID, FormatIdx, HasVAListArg, "sS");
    156 }
    157 
    158 bool Builtin::Context::performsCallback(unsigned ID,
    159                                         SmallVectorImpl<int> &Encoding) const {
    160   const char *CalleePos = ::strchr(getRecord(ID).Attributes, 'C');
    161   if (!CalleePos)
    162     return false;
    163 
    164   ++CalleePos;
    165   assert(*CalleePos == '<' &&
    166          "Callback callee specifier must be followed by a '<'");
    167   ++CalleePos;
    168 
    169   char *EndPos;
    170   int CalleeIdx = ::strtol(CalleePos, &EndPos, 10);
    171   assert(CalleeIdx >= 0 && "Callee index is supposed to be positive!");
    172   Encoding.push_back(CalleeIdx);
    173 
    174   while (*EndPos == ',') {
    175     const char *PayloadPos = EndPos + 1;
    176 
    177     int PayloadIdx = ::strtol(PayloadPos, &EndPos, 10);
    178     Encoding.push_back(PayloadIdx);
    179   }
    180 
    181   assert(*EndPos == '>' && "Callback callee specifier must end with a '>'");
    182   return true;
    183 }
    184 
    185 bool Builtin::Context::canBeRedeclared(unsigned ID) const {
    186   return ID == Builtin::NotBuiltin ||
    187          ID == Builtin::BI__va_start ||
    188          (!hasReferenceArgsOrResult(ID) &&
    189           !hasCustomTypechecking(ID));
    190 }
    191