//===--- 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