//===--- TargetCXXABI.h - C++ ABI Target Configuration ----------*- C++ -*-===//
 
//
 
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 
// See https://llvm.org/LICENSE.txt for license information.
 
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
//
 
//===----------------------------------------------------------------------===//
 
///
 
/// \file
 
/// Defines the TargetCXXABI class, which abstracts details of the
 
/// C++ ABI that we're targeting.
 
///
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_CLANG_BASIC_TARGETCXXABI_H
 
#define LLVM_CLANG_BASIC_TARGETCXXABI_H
 
 
 
#include <map>
 
 
 
#include "clang/Basic/LLVM.h"
 
#include "llvm/ADT/StringMap.h"
 
#include "llvm/ADT/Triple.h"
 
#include "llvm/Support/ErrorHandling.h"
 
 
 
namespace clang {
 
 
 
/// The basic abstraction for the target C++ ABI.
 
class TargetCXXABI {
 
public:
 
  /// The basic C++ ABI kind.
 
  enum Kind {
 
#define CXXABI(Name, Str) Name,
 
#include "TargetCXXABI.def"
 
  };
 
 
 
private:
 
  // Right now, this class is passed around as a cheap value type.
 
  // If you add more members, especially non-POD members, please
 
  // audit the users to pass it by reference instead.
 
  Kind TheKind;
 
 
 
  static const auto &getABIMap() {
 
    static llvm::StringMap<Kind> ABIMap = {
 
#define CXXABI(Name, Str) {Str, Name},
 
#include "TargetCXXABI.def"
 
    };
 
    return ABIMap;
 
  }
 
 
 
  static const auto &getSpellingMap() {
 
    static std::map<Kind, std::string> SpellingMap = {
 
#define CXXABI(Name, Str) {Name, Str},
 
#include "TargetCXXABI.def"
 
    };
 
    return SpellingMap;
 
  }
 
 
 
public:
 
  static Kind getKind(StringRef Name) { return getABIMap().lookup(Name); }
 
  static const auto &getSpelling(Kind ABIKind) {
 
    return getSpellingMap().find(ABIKind)->second;
 
  }
 
  static bool isABI(StringRef Name) {
 
    return getABIMap().find(Name) != getABIMap().end();
 
  }
 
 
 
  // Return true if this target should use the relative vtables C++ ABI by
 
  // default.
 
  static bool usesRelativeVTables(const llvm::Triple &T) {
 
    return T.isOSFuchsia();
 
  }
 
 
 
  /// A bogus initialization of the platform ABI.
 
  TargetCXXABI() : TheKind(GenericItanium) {}
 
 
 
  TargetCXXABI(Kind kind) : TheKind(kind) {}
 
 
 
  void set(Kind kind) {
 
    TheKind = kind;
 
  }
 
 
 
  Kind getKind() const { return TheKind; }
 
 
 
  // Check that the kind provided by the fc++-abi flag is supported on this
 
  // target. Users who want to experiment using different ABIs on specific
 
  // platforms can change this freely, but this function should be conservative
 
  // enough such that not all ABIs are allowed on all platforms. For example, we
 
  // probably don't want to allow usage of an ARM ABI on an x86 architecture.
 
  static bool isSupportedCXXABI(const llvm::Triple &T, Kind Kind) {
 
    switch (Kind) {
 
    case GenericARM:
 
      return T.isARM() || T.isAArch64();
 
 
 
    case iOS:
 
    case WatchOS:
 
    case AppleARM64:
 
      return T.isOSDarwin();
 
 
 
    case Fuchsia:
 
      return T.isOSFuchsia();
 
 
 
    case GenericAArch64:
 
      return T.isAArch64();
 
 
 
    case GenericMIPS:
 
      return T.isMIPS();
 
 
 
    case WebAssembly:
 
      return T.isWasm();
 
 
 
    case XL:
 
      return T.isOSAIX();
 
 
 
    case GenericItanium:
 
      return true;
 
 
 
    case Microsoft:
 
      return T.isKnownWindowsMSVCEnvironment();
 
    }
 
    llvm_unreachable("invalid CXXABI kind");
 
  };
 
 
 
  /// Does this ABI generally fall into the Itanium family of ABIs?
 
  bool isItaniumFamily() const {
 
    switch (getKind()) {
 
#define CXXABI(Name, Str)
 
#define ITANIUM_CXXABI(Name, Str) case Name:
 
#include "TargetCXXABI.def"
 
      return true;
 
 
 
    default:
 
      return false;
 
    }
 
    llvm_unreachable("bad ABI kind");
 
  }
 
 
 
  /// Is this ABI an MSVC-compatible ABI?
 
  bool isMicrosoft() const {
 
    switch (getKind()) {
 
#define CXXABI(Name, Str)
 
#define MICROSOFT_CXXABI(Name, Str) case Name:
 
#include "TargetCXXABI.def"
 
      return true;
 
 
 
    default:
 
      return false;
 
    }
 
    llvm_unreachable("bad ABI kind");
 
  }
 
 
 
  /// Are member functions differently aligned?
 
  ///
 
  /// Many Itanium-style C++ ABIs require member functions to be aligned, so
 
  /// that a pointer to such a function is guaranteed to have a zero in the
 
  /// least significant bit, so that pointers to member functions can use that
 
  /// bit to distinguish between virtual and non-virtual functions. However,
 
  /// some Itanium-style C++ ABIs differentiate between virtual and non-virtual
 
  /// functions via other means, and consequently don't require that member
 
  /// functions be aligned.
 
  bool areMemberFunctionsAligned() const {
 
    switch (getKind()) {
 
    case WebAssembly:
 
      // WebAssembly doesn't require any special alignment for member functions.
 
      return false;
 
    case AppleARM64:
 
    case Fuchsia:
 
    case GenericARM:
 
    case GenericAArch64:
 
    case GenericMIPS:
 
      // TODO: ARM-style pointers to member functions put the discriminator in
 
      //       the this adjustment, so they don't require functions to have any
 
      //       special alignment and could therefore also return false.
 
    case GenericItanium:
 
    case iOS:
 
    case WatchOS:
 
    case Microsoft:
 
    case XL:
 
      return true;
 
    }
 
    llvm_unreachable("bad ABI kind");
 
  }
 
 
 
  /// Are arguments to a call destroyed left to right in the callee?
 
  /// This is a fundamental language change, since it implies that objects
 
  /// passed by value do *not* live to the end of the full expression.
 
  /// Temporaries passed to a function taking a const reference live to the end
 
  /// of the full expression as usual.  Both the caller and the callee must
 
  /// have access to the destructor, while only the caller needs the
 
  /// destructor if this is false.
 
  bool areArgsDestroyedLeftToRightInCallee() const {
 
    return isMicrosoft();
 
  }
 
 
 
  /// Does this ABI have different entrypoints for complete-object
 
  /// and base-subobject constructors?
 
  bool hasConstructorVariants() const {
 
    return isItaniumFamily();
 
  }
 
 
 
  /// Does this ABI allow virtual bases to be primary base classes?
 
  bool hasPrimaryVBases() const {
 
    return isItaniumFamily();
 
  }
 
 
 
  /// Does this ABI use key functions?  If so, class data such as the
 
  /// vtable is emitted with strong linkage by the TU containing the key
 
  /// function.
 
  bool hasKeyFunctions() const {
 
    return isItaniumFamily();
 
  }
 
 
 
  /// Can an out-of-line inline function serve as a key function?
 
  ///
 
  /// This flag is only useful in ABIs where type data (for example,
 
  /// vtables and type_info objects) are emitted only after processing
 
  /// the definition of a special "key" virtual function.  (This is safe
 
  /// because the ODR requires that every virtual function be defined
 
  /// somewhere in a program.)  This usually permits such data to be
 
  /// emitted in only a single object file, as opposed to redundantly
 
  /// in every object file that requires it.
 
  ///
 
  /// One simple and common definition of "key function" is the first
 
  /// virtual function in the class definition which is not defined there.
 
  /// This rule works very well when that function has a non-inline
 
  /// definition in some non-header file.  Unfortunately, when that
 
  /// function is defined inline, this rule requires the type data
 
  /// to be emitted weakly, as if there were no key function.
 
  ///
 
  /// The ARM ABI observes that the ODR provides an additional guarantee:
 
  /// a virtual function is always ODR-used, so if it is defined inline,
 
  /// that definition must appear in every translation unit that defines
 
  /// the class.  Therefore, there is no reason to allow such functions
 
  /// to serve as key functions.
 
  ///
 
  /// Because this changes the rules for emitting type data,
 
  /// it can cause type data to be emitted with both weak and strong
 
  /// linkage, which is not allowed on all platforms.  Therefore,
 
  /// exploiting this observation requires an ABI break and cannot be
 
  /// done on a generic Itanium platform.
 
  bool canKeyFunctionBeInline() const {
 
    switch (getKind()) {
 
    case AppleARM64:
 
    case Fuchsia:
 
    case GenericARM:
 
    case WebAssembly:
 
    case WatchOS:
 
      return false;
 
 
 
    case GenericAArch64:
 
    case GenericItanium:
 
    case iOS:   // old iOS compilers did not follow this rule
 
    case Microsoft:
 
    case GenericMIPS:
 
    case XL:
 
      return true;
 
    }
 
    llvm_unreachable("bad ABI kind");
 
  }
 
 
 
  /// When is record layout allowed to allocate objects in the tail
 
  /// padding of a base class?
 
  ///
 
  /// This decision cannot be changed without breaking platform ABI
 
  /// compatibility. In ISO C++98, tail padding reuse was only permitted for
 
  /// non-POD base classes, but that restriction was removed retroactively by
 
  /// DR 43, and tail padding reuse is always permitted in all de facto C++
 
  /// language modes. However, many platforms use a variant of the old C++98
 
  /// rule for compatibility.
 
  enum TailPaddingUseRules {
 
    /// The tail-padding of a base class is always theoretically
 
    /// available, even if it's POD.
 
    AlwaysUseTailPadding,
 
 
 
    /// Only allocate objects in the tail padding of a base class if
 
    /// the base class is not POD according to the rules of C++ TR1.
 
    UseTailPaddingUnlessPOD03,
 
 
 
    /// Only allocate objects in the tail padding of a base class if
 
    /// the base class is not POD according to the rules of C++11.
 
    UseTailPaddingUnlessPOD11
 
  };
 
  TailPaddingUseRules getTailPaddingUseRules() const {
 
    switch (getKind()) {
 
    // To preserve binary compatibility, the generic Itanium ABI has
 
    // permanently locked the definition of POD to the rules of C++ TR1,
 
    // and that trickles down to derived ABIs.
 
    case GenericItanium:
 
    case GenericAArch64:
 
    case GenericARM:
 
    case iOS:
 
    case GenericMIPS:
 
    case XL:
 
      return UseTailPaddingUnlessPOD03;
 
 
 
    // AppleARM64 and WebAssembly use the C++11 POD rules.  They do not honor
 
    // the Itanium exception about classes with over-large bitfields.
 
    case AppleARM64:
 
    case Fuchsia:
 
    case WebAssembly:
 
    case WatchOS:
 
      return UseTailPaddingUnlessPOD11;
 
 
 
    // MSVC always allocates fields in the tail-padding of a base class
 
    // subobject, even if they're POD.
 
    case Microsoft:
 
      return AlwaysUseTailPadding;
 
    }
 
    llvm_unreachable("bad ABI kind");
 
  }
 
 
 
  friend bool operator==(const TargetCXXABI &left, const TargetCXXABI &right) {
 
    return left.getKind() == right.getKind();
 
  }
 
 
 
  friend bool operator!=(const TargetCXXABI &left, const TargetCXXABI &right) {
 
    return !(left == right);
 
  }
 
};
 
 
 
}  // end namespace clang
 
 
 
#endif