]> granicus.if.org Git - clang/commitdiff
First pass at abstracting out a class for the target C++ ABI.
authorJohn McCall <rjmccall@apple.com>
Fri, 25 Jan 2013 22:30:49 +0000 (22:30 +0000)
committerJohn McCall <rjmccall@apple.com>
Fri, 25 Jan 2013 22:30:49 +0000 (22:30 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@173514 91177308-0d34-0410-b5e6-96231b3b80d8

12 files changed:
include/clang/Basic/TargetCXXABI.h [new file with mode: 0644]
include/clang/Basic/TargetInfo.h
lib/AST/ASTContext.cpp
lib/AST/RecordLayout.cpp
lib/AST/RecordLayoutBuilder.cpp
lib/AST/VTableBuilder.cpp
lib/Basic/TargetInfo.cpp
lib/Basic/Targets.cpp
lib/CodeGen/CGClass.cpp
lib/CodeGen/CGRecordLayoutBuilder.cpp
lib/CodeGen/CodeGenModule.cpp
lib/Sema/SemaType.cpp

diff --git a/include/clang/Basic/TargetCXXABI.h b/include/clang/Basic/TargetCXXABI.h
new file mode 100644 (file)
index 0000000..2a8f5d0
--- /dev/null
@@ -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
index 463c2ea69190ab5d6c4a9c4a9db1f8b765b149cc..716d776df6ed4c9ae14646b3ebe4151055c8af99 100644 (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;
   }
 
index fff2f82e23bf0e9dc98b4159ad74beb0eb55762a..b5d60f589bc92dab462d41f9cddcd3e58aa9baa5 100644 (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");
index 2ae0aab19f699129c87493bc0fa97361be2cea2f..f6cfe63cd34e47f38622bb31f6eb53ff45021191 100644 (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() &&
index 7f84c56d527870fae511f42bffe88f67baeed9f8..08f6d5c54b47bcde632a44c728206dbcec150127 100644 (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";
   }
index 00a186e9ee8b51f8efe613b77152d48ca86e4931..5af3b652618cd9c49ed1fe33f26bb6e6f1bdb64c 100644 (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);
index 9cf04afc5f6812940316327cce586c14b08b04f6..fe68a9df6ad7941d79fcf7aa03c933ce7bf6bd27 100644 (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;
+}
index 084b6b364ebffa623c810eb84d41ae93e6347858..b90d49ec845d1c2e13a995ab8fe3b678a3925118 100644 (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.
index 585d3ba54e7fcf3ddd595807e8cb6988bfe87084..5d1e30fef64667402dced28e506ec0a6375f1216 100644 (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;
index 02920cd9b66bc1e6a64dc75165e34d3a12e4174b..2c6438b0b67cdf389cc3473e2b1349e8d99045eb 100644 (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());
index d5284f803c01214593f63b32028e55d3785efb9b..2da9dba5b71e6201cd2dac7b3065df78f23148e6 100644 (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");
index f6cad26989c3f451a0e95b28d940bf8107a6c919..4819363f277cf0da6d6adb6ed968bc7d52d79861 100644 (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();