brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.4 KiB · e477da3 Raw
430 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9//  This file implements various things for builtin functions.10//11//===----------------------------------------------------------------------===//12 13#include "clang/Basic/Builtins.h"14#include "BuiltinTargetFeatures.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"19using namespace clang;20 21const char *HeaderDesc::getName() const {22  switch (ID) {23#define HEADER(ID, NAME)                                                       \24  case ID:                                                                     \25    return NAME;26#include "clang/Basic/BuiltinHeaders.def"27#undef HEADER28  };29  llvm_unreachable("Unknown HeaderDesc::HeaderID enum");30}31 32static constexpr unsigned NumBuiltins = Builtin::FirstTSBuiltin;33 34#define GET_BUILTIN_STR_TABLE35#include "clang/Basic/Builtins.inc"36#undef GET_BUILTIN_STR_TABLE37 38static constexpr Builtin::Info BuiltinInfos[] = {39    Builtin::Info{}, // No-builtin info entry.40#define GET_BUILTIN_INFOS41#include "clang/Basic/Builtins.inc"42#undef GET_BUILTIN_INFOS43};44static_assert(std::size(BuiltinInfos) == NumBuiltins);45 46std::pair<const Builtin::InfosShard &, const Builtin::Info &>47Builtin::Context::getShardAndInfo(unsigned ID) const {48  assert((ID < (Builtin::FirstTSBuiltin + NumTargetBuiltins +49                NumAuxTargetBuiltins)) &&50         "Invalid builtin ID!");51 52  ArrayRef<InfosShard> Shards = BuiltinShards;53  if (isAuxBuiltinID(ID)) {54    Shards = AuxTargetShards;55    ID = getAuxBuiltinID(ID) - Builtin::FirstTSBuiltin;56  } else if (ID >= Builtin::FirstTSBuiltin) {57    Shards = TargetShards;58    ID -= Builtin::FirstTSBuiltin;59  }60 61  // Loop over the shards to find the one matching this ID. We don't expect to62  // have many shards and so its better to search linearly than with a binary63  // search.64  for (const auto &Shard : Shards) {65    if (ID < Shard.Infos.size()) {66      return {Shard, Shard.Infos[ID]};67    }68 69    ID -= Shard.Infos.size();70  }71  llvm_unreachable("Invalid target builtin shard structure!");72}73 74std::string Builtin::Info::getName(const Builtin::InfosShard &Shard) const {75  return (Twine(Shard.NamePrefix) + (*Shard.Strings)[Offsets.Name]).str();76}77 78/// Return the identifier name for the specified builtin,79/// e.g. "__builtin_abs".80std::string Builtin::Context::getName(unsigned ID) const {81  const auto &[Shard, I] = getShardAndInfo(ID);82  return I.getName(Shard);83}84 85std::string Builtin::Context::getQuotedName(unsigned ID) const {86  const auto &[Shard, I] = getShardAndInfo(ID);87  return (Twine("'") + Shard.NamePrefix + (*Shard.Strings)[I.Offsets.Name] +88          "'")89      .str();90}91 92const char *Builtin::Context::getTypeString(unsigned ID) const {93  const auto &[Shard, I] = getShardAndInfo(ID);94  return (*Shard.Strings)[I.Offsets.Type].data();95}96 97const char *Builtin::Context::getAttributesString(unsigned ID) const {98  const auto &[Shard, I] = getShardAndInfo(ID);99  return (*Shard.Strings)[I.Offsets.Attributes].data();100}101 102const char *Builtin::Context::getRequiredFeatures(unsigned ID) const {103  const auto &[Shard, I] = getShardAndInfo(ID);104  return (*Shard.Strings)[I.Offsets.Features].data();105}106 107Builtin::Context::Context() : BuiltinShards{{&BuiltinStrings, BuiltinInfos}} {}108 109void Builtin::Context::InitializeTarget(const TargetInfo &Target,110                                        const TargetInfo *AuxTarget) {111  assert(TargetShards.empty() && "Already initialized target?");112  assert(NumTargetBuiltins == 0 && "Already initialized target?");113  TargetShards = Target.getTargetBuiltins();114  for (const auto &Shard : TargetShards)115    NumTargetBuiltins += Shard.Infos.size();116  if (AuxTarget) {117    AuxTargetShards = AuxTarget->getTargetBuiltins();118    for (const auto &Shard : AuxTargetShards)119      NumAuxTargetBuiltins += Shard.Infos.size();120  }121}122 123bool Builtin::Context::isBuiltinFunc(llvm::StringRef FuncName) {124  bool InStdNamespace = FuncName.consume_front("std-");125  for (const auto &Shard : {InfosShard{&BuiltinStrings, BuiltinInfos}})126    if (llvm::StringRef FuncNameSuffix = FuncName;127        FuncNameSuffix.consume_front(Shard.NamePrefix))128      for (const auto &I : Shard.Infos)129        if (FuncNameSuffix == (*Shard.Strings)[I.Offsets.Name] &&130            (bool)strchr((*Shard.Strings)[I.Offsets.Attributes].data(), 'z') ==131                InStdNamespace)132          return strchr((*Shard.Strings)[I.Offsets.Attributes].data(), 'f') !=133                 nullptr;134 135  return false;136}137 138/// Is this builtin supported according to the given language options?139static bool builtinIsSupported(const llvm::StringTable &Strings,140                               const Builtin::Info &BuiltinInfo,141                               const LangOptions &LangOpts) {142  auto AttributesStr = Strings[BuiltinInfo.Offsets.Attributes];143 144  /* Builtins Unsupported */145  if (LangOpts.NoBuiltin && strchr(AttributesStr.data(), 'f') != nullptr)146    return false;147  /* CorBuiltins Unsupported */148  if (!LangOpts.Coroutines && (BuiltinInfo.Langs & COR_LANG))149    return false;150  /* MathBuiltins Unsupported */151  if (LangOpts.NoMathBuiltin && BuiltinInfo.Header.ID == HeaderDesc::MATH_H)152    return false;153  /* GnuMode Unsupported */154  if (!LangOpts.GNUMode && (BuiltinInfo.Langs & GNU_LANG))155    return false;156  /* MSMode Unsupported */157  if (!LangOpts.MicrosoftExt && (BuiltinInfo.Langs & MS_LANG))158    return false;159  /* HLSLMode Unsupported */160  if (!LangOpts.HLSL && (BuiltinInfo.Langs & HLSL_LANG))161    return false;162  /* ObjC Unsupported */163  if (!LangOpts.ObjC && BuiltinInfo.Langs == OBJC_LANG)164    return false;165  /* OpenCLC Unsupported */166  if (!LangOpts.OpenCL && (BuiltinInfo.Langs & ALL_OCL_LANGUAGES))167    return false;168  /* OpenCL GAS Unsupported */169  if (!LangOpts.OpenCLGenericAddressSpace && (BuiltinInfo.Langs & OCL_GAS))170    return false;171  /* OpenCL Pipe Unsupported */172  if (!LangOpts.OpenCLPipes && (BuiltinInfo.Langs & OCL_PIPE))173    return false;174 175  // Device side enqueue is not supported until OpenCL 2.0. In 2.0 and higher176  // support is indicated with language option for blocks.177 178  /* OpenCL DSE Unsupported */179  if ((LangOpts.getOpenCLCompatibleVersion() < 200 || !LangOpts.Blocks) &&180      (BuiltinInfo.Langs & OCL_DSE))181    return false;182  /* OpenMP Unsupported */183  if (!LangOpts.OpenMP && BuiltinInfo.Langs == OMP_LANG)184    return false;185  /* CUDA Unsupported */186  if (!LangOpts.CUDA && BuiltinInfo.Langs == CUDA_LANG)187    return false;188  /* CPlusPlus Unsupported */189  if (!LangOpts.CPlusPlus && BuiltinInfo.Langs == CXX_LANG)190    return false;191  /* consteval Unsupported */192  if (!LangOpts.CPlusPlus20 && strchr(AttributesStr.data(), 'G') != nullptr)193    return false;194  /* C23 unsupported */195  if (!LangOpts.C23 && BuiltinInfo.Langs == C23_LANG)196    return false;197  return true;198}199 200static bool isBuiltinConstForTriple(unsigned BuiltinID, llvm::Triple Trip) {201  // There's a special case with the fma builtins where they are always const202  // if the target environment is GNU or the target is OS is Windows and we're203  // targeting the MSVCRT.dll environment.204  // FIXME: This list can be become outdated. Need to find a way to get it some205  // other way.206  switch (BuiltinID) {207  case Builtin::BI__builtin_fma:208  case Builtin::BI__builtin_fmaf:209  case Builtin::BI__builtin_fmal:210  case Builtin::BI__builtin_fmaf16:211  case Builtin::BIfma:212  case Builtin::BIfmaf:213  case Builtin::BIfmal: {214    if (Trip.isGNUEnvironment() || Trip.isOSMSVCRT())215      return true;216    break;217  }218  default:219    break;220  }221 222  return false;223}224 225bool Builtin::Context::shouldGenerateFPMathIntrinsic(226    unsigned BuiltinID, llvm::Triple Trip, std::optional<bool> ErrnoOverwritten,227    bool MathErrnoEnabled, bool HasOptNoneAttr,228    bool IsOptimizationEnabled) const {229 230  // True if we are compiling at -O2 and errno has been disabled231  // using the '#pragma float_control(precise, off)', and232  // attribute opt-none hasn't been seen.233  bool ErrnoOverridenToFalseWithOpt = ErrnoOverwritten.has_value() &&234                                      !ErrnoOverwritten.value() &&235                                      !HasOptNoneAttr && IsOptimizationEnabled;236 237  // There are LLVM math intrinsics/instructions corresponding to math library238  // functions except the LLVM op will never set errno while the math library239  // might. Also, math builtins have the same semantics as their math library240  // twins. Thus, we can transform math library and builtin calls to their241  // LLVM counterparts if the call is marked 'const' (known to never set errno).242  // In case FP exceptions are enabled, the experimental versions of the243  // intrinsics model those.244  bool ConstAlways =245      isConst(BuiltinID) || isBuiltinConstForTriple(BuiltinID, Trip);246 247  bool ConstWithoutErrnoAndExceptions =248      isConstWithoutErrnoAndExceptions(BuiltinID);249  bool ConstWithoutExceptions = isConstWithoutExceptions(BuiltinID);250 251  // ConstAttr is enabled in fast-math mode. In fast-math mode, math-errno is252  // disabled.253  // Math intrinsics are generated only when math-errno is disabled. Any pragmas254  // or attributes that affect math-errno should prevent or allow math255  // intrinsics to be generated. Intrinsics are generated:256  //   1- In fast math mode, unless math-errno is overriden257  //      via '#pragma float_control(precise, on)', or via an258  //      'attribute__((optnone))'.259  //   2- If math-errno was enabled on command line but overriden260  //      to false via '#pragma float_control(precise, off))' and261  //      'attribute__((optnone))' hasn't been used.262  //   3- If we are compiling with optimization and errno has been disabled263  //      via '#pragma float_control(precise, off)', and264  //      'attribute__((optnone))' hasn't been used.265 266  bool ConstWithoutErrnoOrExceptions =267      ConstWithoutErrnoAndExceptions || ConstWithoutExceptions;268  bool GenerateIntrinsics =269      (ConstAlways && !HasOptNoneAttr) ||270      (!MathErrnoEnabled &&271       !(ErrnoOverwritten.has_value() && ErrnoOverwritten.value()) &&272       !HasOptNoneAttr);273  if (!GenerateIntrinsics) {274    GenerateIntrinsics =275        ConstWithoutErrnoOrExceptions && !ConstWithoutErrnoAndExceptions;276    if (!GenerateIntrinsics)277      GenerateIntrinsics =278          ConstWithoutErrnoOrExceptions &&279          (!MathErrnoEnabled &&280           !(ErrnoOverwritten.has_value() && ErrnoOverwritten.value()) &&281           !HasOptNoneAttr);282    if (!GenerateIntrinsics)283      GenerateIntrinsics =284          ConstWithoutErrnoOrExceptions && ErrnoOverridenToFalseWithOpt;285  }286 287  return GenerateIntrinsics;288}289 290/// initializeBuiltins - Mark the identifiers for all the builtins with their291/// appropriate builtin ID # and mark any non-portable builtin identifiers as292/// such.293void Builtin::Context::initializeBuiltins(IdentifierTable &Table,294                                          const LangOptions &LangOpts) {295  {296    unsigned ID = 0;297    // Step #1: mark all target-independent builtins with their ID's.298    for (const auto &Shard : BuiltinShards)299      for (const auto &I : Shard.Infos) {300        // If this is a real builtin (ID != 0) and is supported, add it.301        if (ID != 0 && builtinIsSupported(*Shard.Strings, I, LangOpts))302          Table.get(I.getName(Shard)).setBuiltinID(ID);303        ++ID;304      }305    assert(ID == FirstTSBuiltin && "Should have added all non-target IDs!");306 307    // Step #2: Register target-specific builtins.308    for (const auto &Shard : TargetShards)309      for (const auto &I : Shard.Infos) {310        if (builtinIsSupported(*Shard.Strings, I, LangOpts))311          Table.get(I.getName(Shard)).setBuiltinID(ID);312        ++ID;313      }314 315    // Step #3: Register target-specific builtins for AuxTarget.316    for (const auto &Shard : AuxTargetShards)317      for (const auto &I : Shard.Infos) {318        Table.get(I.getName(Shard)).setBuiltinID(ID);319        ++ID;320      }321  }322 323  // Step #4: Unregister any builtins specified by -fno-builtin-foo.324  for (llvm::StringRef Name : LangOpts.NoBuiltinFuncs) {325    bool InStdNamespace = Name.consume_front("std-");326    auto NameIt = Table.find(Name);327    if (NameIt != Table.end()) {328      unsigned ID = NameIt->second->getBuiltinID();329      if (ID != Builtin::NotBuiltin && isPredefinedLibFunction(ID) &&330          isInStdNamespace(ID) == InStdNamespace) {331        NameIt->second->clearBuiltinID();332      }333    }334  }335}336 337unsigned Builtin::Context::getRequiredVectorWidth(unsigned ID) const {338  const char *WidthPos = ::strchr(getAttributesString(ID), 'V');339  if (!WidthPos)340    return 0;341 342  ++WidthPos;343  assert(*WidthPos == ':' &&344         "Vector width specifier must be followed by a ':'");345  ++WidthPos;346 347  char *EndPos;348  unsigned Width = ::strtol(WidthPos, &EndPos, 10);349  assert(*EndPos == ':' && "Vector width specific must end with a ':'");350  return Width;351}352 353bool Builtin::Context::isLike(unsigned ID, unsigned &FormatIdx,354                              bool &HasVAListArg, const char *Fmt) const {355  assert(Fmt && "Not passed a format string");356  assert(::strlen(Fmt) == 2 &&357         "Format string needs to be two characters long");358  assert(::toupper(Fmt[0]) == Fmt[1] &&359         "Format string is not in the form \"xX\"");360 361  const char *Like = ::strpbrk(getAttributesString(ID), Fmt);362  if (!Like)363    return false;364 365  HasVAListArg = (*Like == Fmt[1]);366 367  ++Like;368  assert(*Like == ':' && "Format specifier must be followed by a ':'");369  ++Like;370 371  assert(::strchr(Like, ':') && "Format specifier must end with a ':'");372  FormatIdx = ::strtol(Like, nullptr, 10);373  return true;374}375 376bool Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx,377                                    bool &HasVAListArg) {378  return isLike(ID, FormatIdx, HasVAListArg, "pP");379}380 381bool Builtin::Context::isScanfLike(unsigned ID, unsigned &FormatIdx,382                                   bool &HasVAListArg) {383  return isLike(ID, FormatIdx, HasVAListArg, "sS");384}385 386bool Builtin::Context::performsCallback(unsigned ID,387                                        SmallVectorImpl<int> &Encoding) const {388  const char *CalleePos = ::strchr(getAttributesString(ID), 'C');389  if (!CalleePos)390    return false;391 392  ++CalleePos;393  assert(*CalleePos == '<' &&394         "Callback callee specifier must be followed by a '<'");395  ++CalleePos;396 397  char *EndPos;398  int CalleeIdx = ::strtol(CalleePos, &EndPos, 10);399  assert(CalleeIdx >= 0 && "Callee index is supposed to be positive!");400  Encoding.push_back(CalleeIdx);401 402  while (*EndPos == ',') {403    const char *PayloadPos = EndPos + 1;404 405    int PayloadIdx = ::strtol(PayloadPos, &EndPos, 10);406    Encoding.push_back(PayloadIdx);407  }408 409  assert(*EndPos == '>' && "Callback callee specifier must end with a '>'");410  return true;411}412 413bool Builtin::Context::canBeRedeclared(unsigned ID) const {414  return ID == Builtin::NotBuiltin || ID == Builtin::BI__va_start ||415         ID == Builtin::BI__builtin_assume_aligned ||416         (!hasReferenceArgsOrResult(ID) && !hasCustomTypechecking(ID)) ||417         isInStdNamespace(ID);418}419 420bool Builtin::evaluateRequiredTargetFeatures(421    StringRef RequiredFeatures, const llvm::StringMap<bool> &TargetFetureMap) {422  // Return true if the builtin doesn't have any required features.423  if (RequiredFeatures.empty())424    return true;425  assert(!RequiredFeatures.contains(' ') && "Space in feature list");426 427  TargetFeatures TF(TargetFetureMap);428  return TF.hasRequiredFeatures(RequiredFeatures);429}430