346 lines
12 KiB
C++
346 lines
12 KiB
C++
//===--- 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 "llvm/Support/ErrorHandling.h"
|
|
|
|
namespace clang {
|
|
|
|
/// The basic abstraction for the target C++ ABI.
|
|
class TargetCXXABI {
|
|
public:
|
|
/// The basic C++ ABI kind.
|
|
enum Kind {
|
|
/// The generic Itanium ABI is the standard ABI of most open-source
|
|
/// and Unix-like platforms. It is the primary ABI targeted by
|
|
/// many compilers, including Clang and GCC.
|
|
///
|
|
/// It is documented here:
|
|
/// http://www.codesourcery.com/public/cxx-abi/
|
|
GenericItanium,
|
|
|
|
/// The generic ARM ABI is a modified version of the Itanium ABI
|
|
/// proposed by ARM for use on ARM-based platforms.
|
|
///
|
|
/// These changes include:
|
|
/// - the representation of member function pointers is adjusted
|
|
/// to not conflict with the 'thumb' bit of ARM function pointers;
|
|
/// - constructors and destructors return 'this';
|
|
/// - guard variables are smaller;
|
|
/// - inline functions are never key functions;
|
|
/// - array cookies have a slightly different layout;
|
|
/// - additional convenience functions are specified;
|
|
/// - and more!
|
|
///
|
|
/// It is documented here:
|
|
/// http://infocenter.arm.com
|
|
/// /help/topic/com.arm.doc.ihi0041c/IHI0041C_cppabi.pdf
|
|
GenericARM,
|
|
|
|
/// The iOS ABI is a partial implementation of the ARM ABI.
|
|
/// Several of the features of the ARM ABI were not fully implemented
|
|
/// in the compilers that iOS was launched with.
|
|
///
|
|
/// Essentially, the iOS ABI includes the ARM changes to:
|
|
/// - member function pointers,
|
|
/// - guard variables,
|
|
/// - array cookies, and
|
|
/// - constructor/destructor signatures.
|
|
iOS,
|
|
|
|
/// The iOS 64-bit ABI is follows ARM's published 64-bit ABI more
|
|
/// closely, but we don't guarantee to follow it perfectly.
|
|
///
|
|
/// It is documented here:
|
|
/// http://infocenter.arm.com
|
|
/// /help/topic/com.arm.doc.ihi0059a/IHI0059A_cppabi64.pdf
|
|
iOS64,
|
|
|
|
/// WatchOS is a modernisation of the iOS ABI, which roughly means it's
|
|
/// the iOS64 ABI ported to 32-bits. The primary difference from iOS64 is
|
|
/// that RTTI objects must still be unique at the moment.
|
|
WatchOS,
|
|
|
|
/// The generic AArch64 ABI is also a modified version of the Itanium ABI,
|
|
/// but it has fewer divergences than the 32-bit ARM ABI.
|
|
///
|
|
/// The relevant changes from the generic ABI in this case are:
|
|
/// - representation of member function pointers adjusted as in ARM.
|
|
/// - guard variables are smaller.
|
|
GenericAArch64,
|
|
|
|
/// The generic Mips ABI is a modified version of the Itanium ABI.
|
|
///
|
|
/// At the moment, only change from the generic ABI in this case is:
|
|
/// - representation of member function pointers adjusted as in ARM.
|
|
GenericMIPS,
|
|
|
|
/// The WebAssembly ABI is a modified version of the Itanium ABI.
|
|
///
|
|
/// The changes from the Itanium ABI are:
|
|
/// - representation of member function pointers is adjusted, as in ARM;
|
|
/// - member functions are not specially aligned;
|
|
/// - constructors and destructors return 'this', as in ARM;
|
|
/// - guard variables are 32-bit on wasm32, as in ARM;
|
|
/// - unused bits of guard variables are reserved, as in ARM;
|
|
/// - inline functions are never key functions, as in ARM;
|
|
/// - C++11 POD rules are used for tail padding, as in iOS64.
|
|
///
|
|
/// TODO: At present the WebAssembly ABI is not considered stable, so none
|
|
/// of these details is necessarily final yet.
|
|
WebAssembly,
|
|
|
|
/// The Microsoft ABI is the ABI used by Microsoft Visual Studio (and
|
|
/// compatible compilers).
|
|
///
|
|
/// FIXME: should this be split into Win32 and Win64 variants?
|
|
///
|
|
/// Only scattered and incomplete official documentation exists.
|
|
Microsoft
|
|
};
|
|
|
|
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;
|
|
|
|
public:
|
|
/// 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; }
|
|
|
|
/// Does this ABI generally fall into the Itanium family of ABIs?
|
|
bool isItaniumFamily() const {
|
|
switch (getKind()) {
|
|
case GenericAArch64:
|
|
case GenericItanium:
|
|
case GenericARM:
|
|
case iOS:
|
|
case iOS64:
|
|
case WatchOS:
|
|
case GenericMIPS:
|
|
case WebAssembly:
|
|
return true;
|
|
|
|
case Microsoft:
|
|
return false;
|
|
}
|
|
llvm_unreachable("bad ABI kind");
|
|
}
|
|
|
|
/// Is this ABI an MSVC-compatible ABI?
|
|
bool isMicrosoft() const {
|
|
switch (getKind()) {
|
|
case GenericAArch64:
|
|
case GenericItanium:
|
|
case GenericARM:
|
|
case iOS:
|
|
case iOS64:
|
|
case WatchOS:
|
|
case GenericMIPS:
|
|
case WebAssembly:
|
|
return false;
|
|
|
|
case Microsoft:
|
|
return true;
|
|
}
|
|
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 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 iOS64:
|
|
case WatchOS:
|
|
case Microsoft:
|
|
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 GenericARM:
|
|
case iOS64:
|
|
case WebAssembly:
|
|
case WatchOS:
|
|
return false;
|
|
|
|
case GenericAArch64:
|
|
case GenericItanium:
|
|
case iOS: // old iOS compilers did not follow this rule
|
|
case Microsoft:
|
|
case GenericMIPS:
|
|
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, and yet it is tied to language guarantees which
|
|
/// the committee has so far seen fit to strengthen no less than
|
|
/// three separate times:
|
|
/// - originally, there were no restrictions at all;
|
|
/// - C++98 declared that objects could not be allocated in the
|
|
/// tail padding of a POD type;
|
|
/// - C++03 extended the definition of POD to include classes
|
|
/// containing member pointers; and
|
|
/// - C++11 greatly broadened the definition of POD to include
|
|
/// all trivial standard-layout classes.
|
|
/// Each of these changes technically took several existing
|
|
/// platforms and made them permanently non-conformant.
|
|
enum TailPaddingUseRules {
|
|
/// The tail-padding of a base class is always theoretically
|
|
/// available, even if it's POD. This is not strictly conforming
|
|
/// in any language mode.
|
|
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.
|
|
/// This is non-strictly conforming in C++11 mode.
|
|
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:
|
|
return UseTailPaddingUnlessPOD03;
|
|
|
|
// iOS on ARM64 and WebAssembly use the C++11 POD rules. They do not honor
|
|
// the Itanium exception about classes with over-large bitfields.
|
|
case iOS64:
|
|
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
|