First pass at abstracting out a class for the target C++ ABI.
llvm-svn: 173514
This commit is contained in:
parent
c018aadc12
commit
359b885e12
|
@ -0,0 +1,159 @@
|
|||
//===--- TargetCXXABI.h - C++ ABI Target Configuration ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Defines the TargetCXXABI class, which abstracts details of the
|
||||
/// C++ ABI that we're targeting.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_TARGETCXXABI_H
|
||||
#define LLVM_CLANG_TARGETCXXABI_H
|
||||
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// \brief The basic abstraction for the target C++ ABI.
|
||||
class TargetCXXABI {
|
||||
public:
|
||||
/// \brief 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 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; }
|
||||
|
||||
/// \brief Does this ABI generally fall into the Itanium family of ABIs?
|
||||
bool isItaniumFamily() const {
|
||||
switch (getKind()) {
|
||||
case GenericItanium:
|
||||
case GenericARM:
|
||||
case iOS:
|
||||
return true;
|
||||
|
||||
case Microsoft:
|
||||
return false;
|
||||
}
|
||||
llvm_unreachable("bad ABI kind");
|
||||
}
|
||||
|
||||
/// \brief Is this ABI an MSVC-compatible ABI?
|
||||
bool isMicrosoft() const {
|
||||
switch (getKind()) {
|
||||
case GenericItanium:
|
||||
case GenericARM:
|
||||
case iOS:
|
||||
return false;
|
||||
|
||||
case Microsoft:
|
||||
return true;
|
||||
}
|
||||
llvm_unreachable("bad ABI kind");
|
||||
}
|
||||
|
||||
/// \brief Is the default C++ member function calling convention
|
||||
/// the same as the default calling convention?
|
||||
bool isMemberFunctionCCDefault() const {
|
||||
// Right now, this is always true for Microsoft.
|
||||
return !isMicrosoft();
|
||||
}
|
||||
|
||||
/// \brief Does this ABI have different entrypoints for complete-object
|
||||
/// and base-subobject constructors?
|
||||
bool hasConstructorVariants() const {
|
||||
return isItaniumFamily();
|
||||
}
|
||||
|
||||
/// \brief Does this ABI have different entrypoints for complete-object
|
||||
/// and base-subobject destructors?
|
||||
bool hasDestructorVariants() const {
|
||||
return isItaniumFamily();
|
||||
}
|
||||
|
||||
/// \brief Does this ABI allow virtual bases to be primary base classes?
|
||||
bool hasPrimaryVBases() const {
|
||||
return isItaniumFamily();
|
||||
}
|
||||
|
||||
/// Try to parse an ABI name, returning false on error.
|
||||
bool tryParse(llvm::StringRef name);
|
||||
|
||||
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
|
|
@ -16,6 +16,7 @@
|
|||
#define LLVM_CLANG_BASIC_TARGETINFO_H
|
||||
|
||||
#include "clang/Basic/AddressSpaces.h"
|
||||
#include "clang/Basic/TargetCXXABI.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
#include "clang/Basic/TargetOptions.h"
|
||||
|
@ -43,22 +44,6 @@ class SourceManager;
|
|||
|
||||
namespace Builtin { struct Info; }
|
||||
|
||||
/// \brief The types of C++ ABIs for which we can generate code.
|
||||
enum TargetCXXABI {
|
||||
/// The generic ("Itanium") C++ ABI, documented at:
|
||||
/// http://www.codesourcery.com/public/cxx-abi/
|
||||
CXXABI_Itanium,
|
||||
|
||||
/// The ARM C++ ABI, based largely on the Itanium ABI but with
|
||||
/// significant differences.
|
||||
/// http://infocenter.arm.com
|
||||
/// /help/topic/com.arm.doc.ihi0041c/IHI0041C_cppabi.pdf
|
||||
CXXABI_ARM,
|
||||
|
||||
/// The Visual Studio ABI. Only scattered official documentation exists.
|
||||
CXXABI_Microsoft
|
||||
};
|
||||
|
||||
/// \brief Exposes information about the current target.
|
||||
///
|
||||
class TargetInfo : public RefCountedBase<TargetInfo> {
|
||||
|
@ -89,7 +74,7 @@ protected:
|
|||
const llvm::fltSemantics *HalfFormat, *FloatFormat, *DoubleFormat,
|
||||
*LongDoubleFormat;
|
||||
unsigned char RegParmMax, SSERegParmMax;
|
||||
TargetCXXABI CXXABI;
|
||||
TargetCXXABI TheCXXABI;
|
||||
const LangAS::Map *AddrSpaceMap;
|
||||
|
||||
mutable StringRef PlatformName;
|
||||
|
@ -634,8 +619,8 @@ public:
|
|||
}
|
||||
|
||||
/// \brief Get the C++ ABI currently in use.
|
||||
virtual TargetCXXABI getCXXABI() const {
|
||||
return CXXABI;
|
||||
TargetCXXABI getCXXABI() const {
|
||||
return TheCXXABI;
|
||||
}
|
||||
|
||||
/// \brief Target the specified CPU.
|
||||
|
@ -655,14 +640,9 @@ public:
|
|||
/// \brief Use this specified C++ ABI.
|
||||
///
|
||||
/// \return False on error (invalid C++ ABI name).
|
||||
bool setCXXABI(const std::string &Name) {
|
||||
static const TargetCXXABI Unknown = static_cast<TargetCXXABI>(-1);
|
||||
TargetCXXABI ABI = llvm::StringSwitch<TargetCXXABI>(Name)
|
||||
.Case("arm", CXXABI_ARM)
|
||||
.Case("itanium", CXXABI_Itanium)
|
||||
.Case("microsoft", CXXABI_Microsoft)
|
||||
.Default(Unknown);
|
||||
if (ABI == Unknown) return false;
|
||||
bool setCXXABI(llvm::StringRef name) {
|
||||
TargetCXXABI ABI;
|
||||
if (!ABI.tryParse(name)) return false;
|
||||
return setCXXABI(ABI);
|
||||
}
|
||||
|
||||
|
@ -670,7 +650,7 @@ public:
|
|||
///
|
||||
/// \return False on error (ABI not valid on this target)
|
||||
virtual bool setCXXABI(TargetCXXABI ABI) {
|
||||
CXXABI = ABI;
|
||||
TheCXXABI = ABI;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -583,12 +583,13 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
|
|||
CXXABI *ASTContext::createCXXABI(const TargetInfo &T) {
|
||||
if (!LangOpts.CPlusPlus) return 0;
|
||||
|
||||
switch (T.getCXXABI()) {
|
||||
case CXXABI_ARM:
|
||||
switch (T.getCXXABI().getKind()) {
|
||||
case TargetCXXABI::GenericARM:
|
||||
case TargetCXXABI::iOS:
|
||||
return CreateARMCXXABI(*this);
|
||||
case CXXABI_Itanium:
|
||||
case TargetCXXABI::GenericItanium:
|
||||
return CreateItaniumCXXABI(*this);
|
||||
case CXXABI_Microsoft:
|
||||
case TargetCXXABI::Microsoft:
|
||||
return CreateMicrosoftCXXABI(*this);
|
||||
}
|
||||
llvm_unreachable("Invalid CXXABI type!");
|
||||
|
@ -7607,7 +7608,8 @@ CallingConv ASTContext::getDefaultCXXMethodCallConv(bool isVariadic) {
|
|||
}
|
||||
|
||||
CallingConv ASTContext::getCanonicalCallConv(CallingConv CC) const {
|
||||
if (CC == CC_C && !LangOpts.MRTD && getTargetInfo().getCXXABI() != CXXABI_Microsoft)
|
||||
if (CC == CC_C && !LangOpts.MRTD &&
|
||||
getTargetInfo().getCXXABI().isMemberFunctionCCDefault())
|
||||
return CC_Default;
|
||||
return CC;
|
||||
}
|
||||
|
@ -7618,11 +7620,12 @@ bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const {
|
|||
}
|
||||
|
||||
MangleContext *ASTContext::createMangleContext() {
|
||||
switch (Target->getCXXABI()) {
|
||||
case CXXABI_ARM:
|
||||
case CXXABI_Itanium:
|
||||
switch (Target->getCXXABI().getKind()) {
|
||||
case TargetCXXABI::GenericItanium:
|
||||
case TargetCXXABI::GenericARM:
|
||||
case TargetCXXABI::iOS:
|
||||
return createItaniumMangleContext(*this, getDiagnostics());
|
||||
case CXXABI_Microsoft:
|
||||
case TargetCXXABI::Microsoft:
|
||||
return createMicrosoftMangleContext(*this, getDiagnostics());
|
||||
}
|
||||
llvm_unreachable("Unsupported ABI");
|
||||
|
|
|
@ -75,10 +75,9 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
|
|||
#ifndef NDEBUG
|
||||
if (const CXXRecordDecl *PrimaryBase = getPrimaryBase()) {
|
||||
if (isPrimaryBaseVirtual()) {
|
||||
// Microsoft ABI doesn't have primary virtual base
|
||||
if (Ctx.getTargetInfo().getCXXABI() != CXXABI_Microsoft) {
|
||||
assert(getVBaseClassOffset(PrimaryBase).isZero() &&
|
||||
"Primary virtual base must be at offset 0!");
|
||||
if (Ctx.getTargetInfo().getCXXABI().hasPrimaryVBases()) {
|
||||
assert(getVBaseClassOffset(PrimaryBase).isZero() &&
|
||||
"Primary virtual base must be at offset 0!");
|
||||
}
|
||||
} else {
|
||||
assert(getBaseClassOffset(PrimaryBase).isZero() &&
|
||||
|
|
|
@ -676,8 +676,12 @@ protected:
|
|||
bool FieldPacked, const FieldDecl *D);
|
||||
void LayoutBitField(const FieldDecl *D);
|
||||
|
||||
TargetCXXABI getCXXABI() const {
|
||||
return Context.getTargetInfo().getCXXABI();
|
||||
}
|
||||
|
||||
bool isMicrosoftCXXABI() const {
|
||||
return Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft;
|
||||
return getCXXABI().isMicrosoft();
|
||||
}
|
||||
|
||||
void MSLayoutVirtualBases(const CXXRecordDecl *RD);
|
||||
|
@ -2606,7 +2610,7 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
|
|||
|
||||
// Vtable pointer.
|
||||
if (RD->isDynamicClass() && !PrimaryBase &&
|
||||
C.getTargetInfo().getCXXABI() != CXXABI_Microsoft) {
|
||||
!C.getTargetInfo().getCXXABI().isMicrosoft()) {
|
||||
PrintOffset(OS, Offset, IndentLevel);
|
||||
OS << '(' << *RD << " vtable pointer)\n";
|
||||
}
|
||||
|
|
|
@ -2197,7 +2197,8 @@ VTableLayout::~VTableLayout() { }
|
|||
|
||||
VTableContext::VTableContext(ASTContext &Context)
|
||||
: Context(Context),
|
||||
IsMicrosoftABI(Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft) { }
|
||||
IsMicrosoftABI(Context.getTargetInfo().getCXXABI().isMicrosoft()) {
|
||||
}
|
||||
|
||||
VTableContext::~VTableContext() {
|
||||
llvm::DeleteContainerSeconds(VTableLayouts);
|
||||
|
|
|
@ -84,7 +84,7 @@ TargetInfo::TargetInfo(const std::string &T) : TargetOpts(), Triple(T)
|
|||
ComplexLongDoubleUsesFP2Ret = false;
|
||||
|
||||
// Default to using the Itanium ABI.
|
||||
CXXABI = CXXABI_Itanium;
|
||||
TheCXXABI.set(TargetCXXABI::GenericItanium);
|
||||
|
||||
// Default to an empty address space map.
|
||||
AddrSpaceMap = &DefaultAddrSpaceMap;
|
||||
|
@ -496,3 +496,17 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TargetCXXABI::tryParse(llvm::StringRef name) {
|
||||
const Kind unknown = static_cast<Kind>(-1);
|
||||
Kind kind = llvm::StringSwitch<Kind>(name)
|
||||
.Case("arm", GenericARM)
|
||||
.Case("ios", iOS)
|
||||
.Case("itanium", GenericItanium)
|
||||
.Case("microsoft", Microsoft)
|
||||
.Default(unknown);
|
||||
if (kind == unknown) return false;
|
||||
|
||||
set(kind);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -3081,7 +3081,7 @@ public:
|
|||
}
|
||||
|
||||
// ARM targets default to using the ARM C++ ABI.
|
||||
CXXABI = CXXABI_ARM;
|
||||
TheCXXABI.set(TargetCXXABI::GenericARM);
|
||||
|
||||
// ARM has atomics up to 8 bytes
|
||||
// FIXME: Set MaxAtomicInlineWidth if we have the feature v6e
|
||||
|
@ -3491,6 +3491,9 @@ public:
|
|||
// iOS always has 64-bit atomic instructions.
|
||||
// FIXME: This should be based off of the target features in ARMTargetInfo.
|
||||
MaxAtomicInlineWidth = 64;
|
||||
|
||||
// Darwin on iOS uses a variant of the ARM C++ ABI.
|
||||
TheCXXABI.set(TargetCXXABI::iOS);
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace.
|
||||
|
|
|
@ -721,7 +721,7 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
|
|||
// Before we go any further, try the complete->base constructor
|
||||
// delegation optimization.
|
||||
if (CtorType == Ctor_Complete && IsConstructorDelegationValid(Ctor) &&
|
||||
CGM.getContext().getTargetInfo().getCXXABI() != CXXABI_Microsoft) {
|
||||
CGM.getContext().getTargetInfo().getCXXABI().hasConstructorVariants()) {
|
||||
if (CGDebugInfo *DI = getDebugInfo())
|
||||
DI->EmitLocation(Builder, Ctor->getLocEnd());
|
||||
EmitDelegateCXXConstructorCall(Ctor, Ctor_Base, Args);
|
||||
|
@ -920,7 +920,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
|
|||
// Enter the cleanup scopes for virtual bases.
|
||||
EnterDtorCleanups(Dtor, Dtor_Complete);
|
||||
|
||||
if (!isTryBody && CGM.getContext().getTargetInfo().getCXXABI() != CXXABI_Microsoft) {
|
||||
if (!isTryBody &&
|
||||
CGM.getContext().getTargetInfo().getCXXABI().hasDestructorVariants()) {
|
||||
EmitCXXDestructorCall(Dtor, Dtor_Base, /*ForVirtualBase=*/false,
|
||||
LoadCXXThis());
|
||||
break;
|
||||
|
|
|
@ -814,7 +814,7 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
|
|||
|
||||
// Lay out the virtual bases. The MS ABI uses a different
|
||||
// algorithm here due to the lack of primary virtual bases.
|
||||
if (Types.getContext().getTargetInfo().getCXXABI() != CXXABI_Microsoft) {
|
||||
if (Types.getContext().getTargetInfo().getCXXABI().hasPrimaryVBases()) {
|
||||
RD->getIndirectPrimaryBases(IndirectPrimaryBases);
|
||||
if (Layout.isPrimaryBaseVirtual())
|
||||
IndirectPrimaryBases.insert(Layout.getPrimaryBase());
|
||||
|
|
|
@ -52,10 +52,13 @@ using namespace CodeGen;
|
|||
static const char AnnotationSection[] = "llvm.metadata";
|
||||
|
||||
static CGCXXABI &createCXXABI(CodeGenModule &CGM) {
|
||||
switch (CGM.getContext().getTargetInfo().getCXXABI()) {
|
||||
case CXXABI_ARM: return *CreateARMCXXABI(CGM);
|
||||
case CXXABI_Itanium: return *CreateItaniumCXXABI(CGM);
|
||||
case CXXABI_Microsoft: return *CreateMicrosoftCXXABI(CGM);
|
||||
switch (CGM.getContext().getTargetInfo().getCXXABI().getKind()) {
|
||||
// For IR-generation purposes, there's no significant difference
|
||||
// between the ARM and iOS ABIs.
|
||||
case TargetCXXABI::GenericARM: return *CreateARMCXXABI(CGM);
|
||||
case TargetCXXABI::iOS: return *CreateARMCXXABI(CGM);
|
||||
case TargetCXXABI::GenericItanium: return *CreateItaniumCXXABI(CGM);
|
||||
case TargetCXXABI::Microsoft: return *CreateMicrosoftCXXABI(CGM);
|
||||
}
|
||||
|
||||
llvm_unreachable("invalid C++ ABI kind");
|
||||
|
|
|
@ -1667,11 +1667,16 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
|
|||
return QualType();
|
||||
}
|
||||
|
||||
// In the Microsoft ABI, the class is allowed to be an incomplete
|
||||
// type. In such cases, the compiler makes a worst-case assumption.
|
||||
// We make no such assumption right now, so emit an error if the
|
||||
// class isn't a complete type.
|
||||
if (Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft &&
|
||||
// C++ allows the class type in a member pointer to be an incomplete type.
|
||||
// In the Microsoft ABI, the size of the member pointer can vary
|
||||
// according to the class type, which means that we really need a
|
||||
// complete type if possible, which means we need to instantiate templates.
|
||||
//
|
||||
// For now, just require a complete type, which will instantiate
|
||||
// templates. This will also error if the type is just forward-declared,
|
||||
// which is a bug, but it's a bug that saves us from dealing with some
|
||||
// complexities at the moment.
|
||||
if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
|
||||
RequireCompleteType(Loc, Class, diag::err_incomplete_type))
|
||||
return QualType();
|
||||
|
||||
|
|
Loading…
Reference in New Issue