First pass at abstracting out a class for the target C++ ABI.

llvm-svn: 173514
This commit is contained in:
John McCall 2013-01-25 22:30:49 +00:00
parent c018aadc12
commit 359b885e12
12 changed files with 230 additions and 58 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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");

View File

@ -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() &&

View File

@ -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";
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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.

View File

@ -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;

View File

@ -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());

View File

@ -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");

View File

@ -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();