[cfe-commits] r96842 - in /cfe/trunk: include/clang/AST/DeclCXX.h lib/AST/DeclCXX.cpp lib/CodeGen/CGCXX.cpp lib/CodeGen/CGCall.cpp lib/CodeGen/CGClass.cpp lib/CodeGen/CodeGenFunction.h lib/CodeGen/CodeGenModule.cpp lib/CodeGen/CodeGenModule.h lib/CodeGen/CodeGenTypes.h test/CodeGenCXX/constructors.cpp test/CodeGenCXX/default-arguments.cpp test/CodeGenCXX/destructors.cpp test/CodeGenCXX/virtual-destructor-calls.cpp test/CodeGenCXX/vtable-pointer-initialization.cpp

John McCall rjmccall at apple.com
Mon Feb 22 16:48:20 PST 2010


Author: rjmccall
Date: Mon Feb 22 18:48:20 2010
New Revision: 96842

URL: http://llvm.org/viewvc/llvm-project?rev=96842&view=rev
Log:
Perform two more constructor/destructor code-size optimizations:

1) emit base destructors as aliases to their unique base class destructors
under some careful conditions.  This is enabled for the same targets that can
support complete-to-base aliases, i.e. not darwin.

2) Emit non-variadic complete constructors for classes with no virtual bases
as calls to the base constructor.  This is enabled on all targets and in
theory can trigger in situations that the alias optimization can't (mostly
involving virtual bases, mostly not yet supported).

These are bundled together because I didn't think it worthwhile to split them,
not because they really need to be.


Added:
    cfe/trunk/test/CodeGenCXX/constructors.cpp
Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/CodeGen/CGCXX.cpp
    cfe/trunk/lib/CodeGen/CGCall.cpp
    cfe/trunk/lib/CodeGen/CGClass.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/lib/CodeGen/CodeGenModule.cpp
    cfe/trunk/lib/CodeGen/CodeGenModule.h
    cfe/trunk/lib/CodeGen/CodeGenTypes.h
    cfe/trunk/test/CodeGenCXX/default-arguments.cpp
    cfe/trunk/test/CodeGenCXX/destructors.cpp
    cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp
    cfe/trunk/test/CodeGenCXX/vtable-pointer-initialization.cpp

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=96842&r1=96841&r2=96842&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Mon Feb 22 18:48:20 2010
@@ -710,7 +710,7 @@
   CXXConstructorDecl *getDefaultConstructor(ASTContext &Context);
 
   /// getDestructor - Returns the destructor decl for this class.
-  CXXDestructorDecl *getDestructor(ASTContext &Context);
+  CXXDestructorDecl *getDestructor(ASTContext &Context) const;
 
   /// isLocalClass - If the class is a local class [class.local], returns
   /// the enclosing function declaration.

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=96842&r1=96841&r2=96842&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Mon Feb 22 18:48:20 2010
@@ -543,14 +543,14 @@
   return 0;
 }
 
-CXXDestructorDecl *CXXRecordDecl::getDestructor(ASTContext &Context) {
+CXXDestructorDecl *CXXRecordDecl::getDestructor(ASTContext &Context) const {
   QualType ClassType = Context.getTypeDeclType(this);
 
   DeclarationName Name
     = Context.DeclarationNames.getCXXDestructorName(
                                           Context.getCanonicalType(ClassType));
 
-  DeclContext::lookup_iterator I, E;
+  DeclContext::lookup_const_iterator I, E;
   llvm::tie(I, E) = lookup(Name);
   assert(I != E && "Did not find a destructor!");
 

Modified: cfe/trunk/lib/CodeGen/CGCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXX.cpp?rev=96842&r1=96841&r2=96842&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCXX.cpp Mon Feb 22 18:48:20 2010
@@ -27,24 +27,88 @@
 using namespace clang;
 using namespace CodeGen;
 
-/// Try to emit a definition as a global alias for another definition.
-bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
-                                             GlobalDecl TargetDecl) {
+/// Determines whether the given function has a trivial body that does
+/// not require any specific codegen.
+static bool HasTrivialBody(const FunctionDecl *FD) {
+  Stmt *S = FD->getBody();
+  if (!S)
+    return true;
+  if (isa<CompoundStmt>(S) && cast<CompoundStmt>(S)->body_empty())
+    return true;
+  return false;
+}
+
+/// Try to emit a base destructor as an alias to its primary
+/// base-class destructor.
+bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
   if (!getCodeGenOpts().CXXCtorDtorAliases)
     return true;
 
-  // Find the referrent.
-  llvm::GlobalValue *Ref = cast<llvm::GlobalValue>(GetAddrOfGlobal(TargetDecl));
+  // If the destructor doesn't have a trivial body, we have to emit it
+  // separately.
+  if (!HasTrivialBody(D))
+    return true;
 
-  // Look for an existing entry.
-  const char *MangledName = getMangledName(AliasDecl);
-  llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName];
-  if (Entry) {
-    assert(Entry->isDeclaration() && "definition already exists for alias");
-    assert(Entry->getType() == Ref->getType() &&
-           "declaration exists with different type");
+  const CXXRecordDecl *Class = D->getParent();
+
+  // If we need to manipulate a VTT parameter, give up.
+  if (Class->getNumVBases()) {
+    // Extra Credit:  passing extra parameters is perfectly safe
+    // in many calling conventions, so only bail out if the ctor's
+    // calling convention is nonstandard.
+    return true;
   }
 
+  // If any fields have a non-trivial destructor, we have to emit it
+  // separately.
+  for (CXXRecordDecl::field_iterator I = Class->field_begin(),
+         E = Class->field_end(); I != E; ++I)
+    if (const RecordType *RT = (*I)->getType()->getAs<RecordType>())
+      if (!cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor())
+        return true;
+
+  // Try to find a unique base class with a non-trivial destructor.
+  const CXXRecordDecl *UniqueBase = 0;
+  for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(),
+         E = Class->bases_end(); I != E; ++I) {
+
+    // We're in the base destructor, so skip virtual bases.
+    if (I->isVirtual()) continue;
+
+    // Skip base classes with trivial destructors.
+    const CXXRecordDecl *Base
+      = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+    if (Base->hasTrivialDestructor()) continue;
+
+    // If we've already found a base class with a non-trivial
+    // destructor, give up.
+    if (UniqueBase) return true;
+    UniqueBase = Base;
+  }
+
+  // If we didn't find any bases with a non-trivial destructor, then
+  // the base destructor is actually effectively trivial, which can
+  // happen if it was needlessly user-defined or if there are virtual
+  // bases with non-trivial destructors.
+  if (!UniqueBase)
+    return true;
+
+  // If the base is at a non-zero offset, give up.
+  const ASTRecordLayout &ClassLayout = Context.getASTRecordLayout(Class);
+  if (ClassLayout.getBaseClassOffset(UniqueBase) != 0)
+    return true;
+
+  const CXXDestructorDecl *BaseD = UniqueBase->getDestructor(getContext());
+  return TryEmitDefinitionAsAlias(GlobalDecl(D, Dtor_Base),
+                                  GlobalDecl(BaseD, Dtor_Base));
+}
+
+/// Try to emit a definition as a global alias for another definition.
+bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
+                                             GlobalDecl TargetDecl) {
+  if (!getCodeGenOpts().CXXCtorDtorAliases)
+    return true;
+
   // The alias will use the linkage of the referrent.  If we can't
   // support aliases with that linkage, fail.
   llvm::GlobalValue::LinkageTypes Linkage
@@ -72,11 +136,32 @@
     return true;
   }
 
+  // Derive the type for the alias.
+  const llvm::PointerType *AliasType
+    = getTypes().GetFunctionType(AliasDecl)->getPointerTo();
+
+  // Look for an existing entry.
+  const char *MangledName = getMangledName(AliasDecl);
+  llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName];
+  if (Entry) {
+    assert(Entry->isDeclaration() && "definition already exists for alias");
+    assert(Entry->getType() == AliasType &&
+           "declaration exists with different type");
+  }
+
+  // Find the referrent.  Some aliases might require a bitcast, in
+  // which case the caller is responsible for ensuring the soundness
+  // of these semantics.
+  llvm::GlobalValue *Ref = cast<llvm::GlobalValue>(GetAddrOfGlobal(TargetDecl));
+  llvm::Constant *Aliasee = Ref;
+  if (Ref->getType() != AliasType)
+    Aliasee = llvm::ConstantExpr::getBitCast(Ref, AliasType);
+
   // Create the alias with no name.
   llvm::GlobalAlias *Alias = 
-    new llvm::GlobalAlias(Ref->getType(), Linkage, "", Ref, &getModule());
+    new llvm::GlobalAlias(AliasType, Linkage, "", Aliasee, &getModule());
 
-  // Switch any previous uses to the alias and continue.
+  // Switch any previous uses to the alias and kill the previous decl.
   if (Entry) {
     Entry->replaceAllUsesWith(Alias);
     Entry->eraseFromParent();
@@ -90,7 +175,6 @@
   return false;
 }
 
-
 void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) {
   // The constructor used for constructing this as a complete class;
   // constucts the virtual bases, then calls the base constructor.
@@ -169,6 +253,13 @@
                                 GlobalDecl(D, Dtor_Base)))
     return;
 
+  // The base destructor is equivalent to the base destructor of its
+  // base class if there is exactly one non-virtual base class with a
+  // non-trivial destructor, there are no fields with a non-trivial
+  // destructor, and the body of the destructor is trivial.
+  if (Type == Dtor_Base && !TryEmitBaseDestructorAsAlias(D))
+    return;
+
   llvm::Function *Fn = cast<llvm::Function>(GetAddrOfCXXDestructor(D, Type));
 
   CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn);

Modified: cfe/trunk/lib/CodeGen/CGCall.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=96842&r1=96841&r2=96842&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCall.cpp Mon Feb 22 18:48:20 2010
@@ -416,6 +416,18 @@
   return FI.getReturnInfo().isIndirect();
 }
 
+const llvm::FunctionType *CodeGenTypes::GetFunctionType(GlobalDecl GD) {
+  const CGFunctionInfo &FI = getFunctionInfo(GD);
+  
+  // For definition purposes, don't consider a K&R function variadic.
+  bool Variadic = false;
+  if (const FunctionProtoType *FPT =
+        cast<FunctionDecl>(GD.getDecl())->getType()->getAs<FunctionProtoType>())
+    Variadic = FPT->isVariadic();
+
+  return GetFunctionType(FI, Variadic);
+}
+
 const llvm::FunctionType *
 CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic) {
   std::vector<const llvm::Type*> ArgTys;

Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=96842&r1=96841&r2=96842&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Mon Feb 22 18:48:20 2010
@@ -891,31 +891,80 @@
   }
 }
 
+/// Checks whether the given constructor is a valid subject for the
+/// complete-to-base constructor delegation optimization, i.e.
+/// emitting the complete constructor as a simple call to the base
+/// constructor.
+static bool IsConstructorDelegationValid(const CXXConstructorDecl *Ctor) {
+
+  // Currently we disable the optimization for classes with virtual
+  // bases because (1) the addresses of parameter variables need to be
+  // consistent across all initializers but (2) the delegate function
+  // call necessarily creates a second copy of the parameter variable.
+  //
+  // The limiting example (purely theoretical AFAIK):
+  //   struct A { A(int &c) { c++; } };
+  //   struct B : virtual A {
+  //     B(int count) : A(count) { printf("%d\n", count); }
+  //   };
+  // ...although even this example could in principle be emitted as a
+  // delegation since the address of the parameter doesn't escape.
+  if (Ctor->getParent()->getNumVBases()) {
+    // TODO: white-list trivial vbase initializers.  This case wouldn't
+    // be subject to the restrictions below.
+
+    // TODO: white-list cases where:
+    //  - there are no non-reference parameters to the constructor
+    //  - the initializers don't access any non-reference parameters
+    //  - the initializers don't take the address of non-reference
+    //    parameters
+    //  - etc.
+    // If we ever add any of the above cases, remember that:
+    //  - function-try-blocks will always blacklist this optimization
+    //  - we need to perform the constructor prologue and cleanup in
+    //    EmitConstructorBody.
+
+    return false;
+  }
+
+  // We also disable the optimization for variadic functions because
+  // it's impossible to "re-pass" varargs.
+  if (Ctor->getType()->getAs<FunctionProtoType>()->isVariadic())
+    return false;
+
+  return true;
+}
+
 /// EmitConstructorBody - Emits the body of the current constructor.
 void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
   const CXXConstructorDecl *Ctor = cast<CXXConstructorDecl>(CurGD.getDecl());
   CXXCtorType CtorType = CurGD.getCtorType();
 
+  // Before we go any further, try the complete->base constructor
+  // delegation optimization.
+  if (CtorType == Ctor_Complete && IsConstructorDelegationValid(Ctor)) {
+    EmitDelegateCXXConstructorCall(Ctor, Ctor_Base, Args);
+    return;
+  }
+
   Stmt *Body = Ctor->getBody();
 
-  // Some of the optimizations we want to do can't be done with
-  // function try blocks.
+  // Enter the function-try-block before the constructor prologue if
+  // applicable.
   CXXTryStmtInfo TryInfo;
-  bool isTryBody = (Body && isa<CXXTryStmt>(Body));
-  if (isTryBody)
+  bool IsTryBody = (Body && isa<CXXTryStmt>(Body));
+
+  if (IsTryBody)
     TryInfo = EnterCXXTryStmt(*cast<CXXTryStmt>(Body));
 
   unsigned CleanupStackSize = CleanupEntries.size();
 
-  // Emit the constructor prologue, i.e. the base and member initializers.
-
-  // TODO: for non-variadic complete-object constructors without a
-  // function try block for a body, we can get away with just emitting
-  // the vbase initializers, then calling the base constructor.
+  // Emit the constructor prologue, i.e. the base and member
+  // initializers.
   EmitCtorPrologue(Ctor, CtorType);
 
   // Emit the body of the statement.
-  if (isTryBody)
+  if (IsTryBody)
     EmitStmt(cast<CXXTryStmt>(Body)->getTryBlock());
   else if (Body)
     EmitStmt(Body);
@@ -933,7 +982,7 @@
   // constructed.
   EmitCleanupBlocks(CleanupStackSize);
 
-  if (isTryBody)
+  if (IsTryBody)
     ExitCXXTryStmt(*cast<CXXTryStmt>(Body), TryInfo);
 }
 
@@ -1406,6 +1455,71 @@
   EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, VTT, ArgBeg, ArgEnd);
 }
 
+void
+CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
+                                                CXXCtorType CtorType,
+                                                const FunctionArgList &Args) {
+  CallArgList DelegateArgs;
+
+  FunctionArgList::const_iterator I = Args.begin(), E = Args.end();
+  assert(I != E && "no parameters to constructor");
+
+  // this
+  DelegateArgs.push_back(std::make_pair(RValue::get(LoadCXXThis()),
+                                        I->second));
+  ++I;
+
+  // vtt
+  if (llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(Ctor, CtorType))) {
+    QualType VoidPP = getContext().getPointerType(getContext().VoidPtrTy);
+    DelegateArgs.push_back(std::make_pair(RValue::get(VTT), VoidPP));
+
+    if (CGVtableInfo::needsVTTParameter(CurGD)) {
+      assert(I != E && "cannot skip vtt parameter, already done with args");
+      assert(I->second == VoidPP && "skipping parameter not of vtt type");
+      ++I;
+    }
+  }
+
+  // Explicit arguments.
+  for (; I != E; ++I) {
+    
+    const VarDecl *Param = I->first;
+    QualType ArgType = Param->getType(); // because we're passing it to itself
+
+    // StartFunction converted the ABI-lowered parameter(s) into a
+    // local alloca.  We need to turn that into an r-value suitable
+    // for EmitCall.
+    llvm::Value *Local = GetAddrOfLocalVar(Param);
+    RValue Arg;
+ 
+    // For the most part, we just need to load the alloca, except:
+    // 1) aggregate r-values are actually pointers to temporaries, and
+    // 2) references to aggregates are pointers directly to the aggregate.
+    // I don't know why references to non-aggregates are different here.
+    if (ArgType->isReferenceType()) {
+      const ReferenceType *RefType = ArgType->getAs<ReferenceType>();
+      if (hasAggregateLLVMType(RefType->getPointeeType()))
+        Arg = RValue::getAggregate(Local);
+      else
+        // Locals which are references to scalars are represented
+        // with allocas holding the pointer.
+        Arg = RValue::get(Builder.CreateLoad(Local));
+    } else {
+      if (hasAggregateLLVMType(ArgType))
+        Arg = RValue::getAggregate(Local);
+      else
+        Arg = RValue::get(EmitLoadOfScalar(Local, false, ArgType));
+    }
+
+    DelegateArgs.push_back(std::make_pair(Arg, ArgType));
+  }
+
+  EmitCall(CGM.getTypes().getFunctionInfo(Ctor, CtorType),
+           CGM.GetAddrOfCXXConstructor(Ctor, CtorType), 
+           ReturnValueSlot(), DelegateArgs, Ctor);
+}
+
 void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
                                             CXXDtorType Type,
                                             llvm::Value *This) {

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=96842&r1=96841&r2=96842&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Mon Feb 22 18:48:20 2010
@@ -789,6 +789,9 @@
                                const CXXRecordDecl *BaseClassDecl,
                                QualType Ty);
 
+  void EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
+                                      CXXCtorType CtorType,
+                                      const FunctionArgList &Args);
   void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type,
                               llvm::Value *This,
                               CallExpr::const_arg_iterator ArgBeg,

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=96842&r1=96841&r2=96842&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Mon Feb 22 18:48:20 2010
@@ -1195,28 +1195,8 @@
 
 
 void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
-  const llvm::FunctionType *Ty;
   const FunctionDecl *D = cast<FunctionDecl>(GD.getDecl());
-
-  if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
-    bool isVariadic = D->getType()->getAs<FunctionProtoType>()->isVariadic();
-
-    Ty = getTypes().GetFunctionType(getTypes().getFunctionInfo(MD), isVariadic);
-  } else {
-    Ty = cast<llvm::FunctionType>(getTypes().ConvertType(D->getType()));
-
-    // As a special case, make sure that definitions of K&R function
-    // "type foo()" aren't declared as varargs (which forces the backend
-    // to do unnecessary work).
-    if (D->getType()->isFunctionNoProtoType()) {
-      assert(Ty->isVarArg() && "Didn't lower type as expected");
-      // Due to stret, the lowered function could have arguments.
-      // Just create the same type as was lowered by ConvertType
-      // but strip off the varargs bit.
-      std::vector<const llvm::Type*> Args(Ty->param_begin(), Ty->param_end());
-      Ty = llvm::FunctionType::get(Ty->getReturnType(), Args, false);
-    }
-  }
+  const llvm::FunctionType *Ty = getTypes().GetFunctionType(GD);
 
   // Get or create the prototype for the function.
   llvm::Constant *Entry = GetAddrOfFunction(GD, Ty);

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=96842&r1=96841&r2=96842&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.h Mon Feb 22 18:48:20 2010
@@ -485,6 +485,7 @@
   // C++ related functions.
 
   bool TryEmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target);
+  bool TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D);
 
   void EmitNamespace(const NamespaceDecl *D);
   void EmitLinkageSpec(const LinkageSpecDecl *D);

Modified: cfe/trunk/lib/CodeGen/CodeGenTypes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenTypes.h?rev=96842&r1=96841&r2=96842&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenTypes.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenTypes.h Mon Feb 22 18:48:20 2010
@@ -168,6 +168,8 @@
   const llvm::FunctionType *GetFunctionType(const CGFunctionInfo &Info,
                                             bool IsVariadic);
 
+  const llvm::FunctionType *GetFunctionType(GlobalDecl GD);
+
 
   /// GetFunctionTypeForVtable - Get the LLVM function type for use in a vtable,
   /// given a CXXMethodDecl. If the method to has an incomplete return type, 

Added: cfe/trunk/test/CodeGenCXX/constructors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/constructors.cpp?rev=96842&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/constructors.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/constructors.cpp Mon Feb 22 18:48:20 2010
@@ -0,0 +1,94 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -emit-llvm -o - | FileCheck %s
+
+struct Member { int x; Member(); Member(int); Member(const Member &); };
+struct VBase { int x; VBase(); VBase(int); VBase(const VBase &); };
+
+struct ValueClass {
+  ValueClass(int x, int y) : x(x), y(y) {}
+  int x;
+  int y;
+}; // subject to ABI trickery
+
+
+
+/* Test basic functionality. */
+class A {
+  A(struct Undeclared &);
+  A(ValueClass);
+  Member mem;
+};
+
+A::A(struct Undeclared &ref) : mem(0) {}
+
+// Check that delegation works.
+// CHECK: define void @_ZN1AC1ER10Undeclared(
+// CHECK: call void @_ZN1AC2ER10Undeclared(
+
+// CHECK: define void @_ZN1AC2ER10Undeclared(
+// CHECK: call void @_ZN6MemberC1Ei(
+
+A::A(ValueClass v) : mem(v.y - v.x) {}
+
+// CHECK: define void @_ZN1AC1E10ValueClass(
+// CHECK: call void @_ZN1AC2E10ValueClass(
+
+// CHECK: define void @_ZN1AC2E10ValueClass(
+// CHECK: call void @_ZN6MemberC1Ei(
+
+
+/* Test that things work for inheritance. */
+struct B : A {
+  B(struct Undeclared &);
+  Member mem;
+};
+
+B::B(struct Undeclared &ref) : A(ref), mem(1) {}
+
+// CHECK: define void @_ZN1BC1ER10Undeclared(
+// CHECK: call void @_ZN1BC2ER10Undeclared(
+
+// CHECK: define void @_ZN1BC2ER10Undeclared(
+// CHECK: call void @_ZN1AC2ER10Undeclared(
+// CHECK: call void @_ZN6MemberC1Ei(
+
+
+
+/* Test that the delegation optimization is disabled for classes with
+   virtual bases (for now).  This is necessary because a vbase
+   initializer could access one of the parameter variables by
+   reference.  That's a solvable problem, but let's not solve it right
+   now. */
+struct C : virtual A {
+  C(int);
+  Member mem;
+};
+C::C(int x) : A(ValueClass(x, x+1)), mem(x * x) {}
+
+// CHECK: define void @_ZN1CC1Ei(
+// CHECK: call void @_ZN10ValueClassC1Eii(
+// CHECK: call void @_ZN1AC2E10ValueClass(
+// CHECK: call void @_ZN6MemberC1Ei(
+
+// CHECK: define void @_ZN1CC2Ei(
+// CHECK: call void @_ZN6MemberC1Ei(
+
+
+
+/* Test that the delegation optimization is disabled for varargs
+   constructors. */
+struct D : A {
+  D(int, ...);
+  Member mem;
+};
+
+D::D(int x, ...) : A(ValueClass(x, x+1)), mem(x*x) {}
+
+// CHECK: define void @_ZN1DC1Eiz(
+// CHECK: call void @_ZN10ValueClassC1Eii(
+// CHECK: call void @_ZN1AC2E10ValueClass(
+// CHECK: call void @_ZN6MemberC1Ei(
+
+// CHECK: define void @_ZN1DC2Eiz(
+// CHECK: call void @_ZN10ValueClassC1Eii(
+// CHECK: call void @_ZN1AC2E10ValueClass(
+// CHECK: call void @_ZN6MemberC1Ei(

Modified: cfe/trunk/test/CodeGenCXX/default-arguments.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/default-arguments.cpp?rev=96842&r1=96841&r2=96842&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/default-arguments.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/default-arguments.cpp Mon Feb 22 18:48:20 2010
@@ -43,11 +43,7 @@
 };
 
 // CHECK: define void @_ZN1CC1Ev(
-// CHECK: call void @_ZN2A1C1Ev(
-// CHECK: call void @_ZN2A2C1Ev(
-// CHECK: call void @_ZN1BC1ERK2A1RK2A2(
-// CHECK: call void @_ZN2A2D1Ev
-// CHECK: call void @_ZN2A1D1Ev
+// CHECK: call void @_ZN1CC2Ev(
 
 // CHECK: define void @_ZN1CC2Ev(
 // CHECK: call void @_ZN2A1C1Ev(

Modified: cfe/trunk/test/CodeGenCXX/destructors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/destructors.cpp?rev=96842&r1=96841&r2=96842&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/destructors.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/destructors.cpp Mon Feb 22 18:48:20 2010
@@ -1,4 +1,11 @@
 // RUN: %clang_cc1 %s -emit-llvm -o - -mconstructor-aliases | FileCheck %s
+
+// CHECK: @_ZN5test01AD1Ev = alias {{.*}} @_ZN5test01AD2Ev
+// CHECK: @_ZN5test11MD2Ev = alias {{.*}} @_ZN5test11AD2Ev
+// CHECK: @_ZN5test11ND2Ev = alias {{.*}} @_ZN5test11AD2Ev
+// CHECK: @_ZN5test11OD2Ev = alias {{.*}} @_ZN5test11AD2Ev
+// CHECK: @_ZN5test11SD2Ev = alias bitcast {{.*}} @_ZN5test11AD2Ev
+
 struct A {
   int a;
   
@@ -60,7 +67,7 @@
   // The function-try-block won't suppress -mconstructor-aliases here.
   A::~A() try { } catch (int i) {}
 
-// CHECK: @_ZN5test01AD1Ev = alias {{.*}} @_ZN5test01AD2Ev
+// complete destructor alias tested above
 
 // CHECK: define void @_ZN5test01AD2Ev
 // CHECK: invoke void @_ZN5test06MemberD1Ev
@@ -89,3 +96,40 @@
 // CHECK: invoke void @_ZN5test04BaseD2Ev
 // CHECK:   unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]]
 }
+
+// Test base-class aliasing.
+namespace test1 {
+  struct A { ~A(); char ***m; }; // non-trivial destructor
+  struct B { ~B(); }; // non-trivial destructor
+  struct Empty { }; // trivial destructor, empty
+  struct NonEmpty { int x; }; // trivial destructor, non-empty
+
+  struct M : A { ~M(); };
+  M::~M() {} // alias tested above
+
+  struct N : A, Empty { ~N(); };
+  N::~N() {} // alias tested above
+
+  struct O : Empty, A { ~O(); };
+  O::~O() {} // alias tested above
+
+  struct P : NonEmpty, A { ~P(); };
+  P::~P() {} // CHECK: define void @_ZN5test11PD2Ev
+
+  struct Q : A, B { ~Q(); };
+  Q::~Q() {} // CHECK: define void @_ZN5test11QD2Ev
+
+  struct R : A { ~R(); };
+  R::~R() { A a; } // CHECK: define void @_ZN5test11RD2Ev
+
+  struct S : A { ~S(); int x; };
+  S::~S() {} // alias tested above
+
+  struct T : A { ~T(); B x; };
+  T::~T() {} // CHECK: define void @_ZN5test11TD2Ev
+
+  // The VTT parameter prevents this.  We could still make this work
+  // for calling conventions that are safe against extra parameters.
+  struct U : A, virtual B { ~U(); };
+  U::~U() {} // CHECK: define void @_ZN5test11UD2Ev
+}

Modified: cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp?rev=96842&r1=96841&r2=96842&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp Mon Feb 22 18:48:20 2010
@@ -1,16 +1,25 @@
 // RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 -mconstructor-aliases | FileCheck %s
 
+struct Member {
+  ~Member();
+};
+
 struct A {
   virtual ~A();
 };
 
 struct B : A {
+  Member m;
   virtual ~B();
 };
 
 // Complete dtor: just an alias because there are no virtual bases.
 // CHECK: @_ZN1BD1Ev = alias {{.*}} @_ZN1BD2Ev
 
+// (aliases from C)
+// CHECK: @_ZN1CD1Ev = alias {{.*}} @_ZN1CD2Ev
+// CHECK: @_ZN1CD2Ev = alias bitcast {{.*}} @_ZN1BD2Ev
+
 // Deleting dtor: defers to the complete dtor.
 // CHECK: define void @_ZN1BD0Ev
 // CHECK: call void @_ZN1BD1Ev
@@ -18,6 +27,22 @@
 
 // Base dtor: actually calls A's base dtor.
 // CHECK: define void @_ZN1BD2Ev
+// CHECK: call void @_ZN6MemberD1Ev
 // CHECK: call void @_ZN1AD2Ev
 
 B::~B() { }
+
+struct C : B {
+  ~C();
+};
+
+C::~C() { }
+
+// Complete dtor: just an alias (checked above).
+
+// Deleting dtor: defers to the complete dtor.
+// CHECK: define void @_ZN1CD0Ev
+// CHECK: call void @_ZN1CD1Ev
+// CHECK: call void @_ZdlPv
+
+// Base dtor: just an alias to B's base dtor.

Modified: cfe/trunk/test/CodeGenCXX/vtable-pointer-initialization.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/vtable-pointer-initialization.cpp?rev=96842&r1=96841&r2=96842&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/vtable-pointer-initialization.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/vtable-pointer-initialization.cpp Mon Feb 22 18:48:20 2010
@@ -42,13 +42,16 @@
 void f() { B b; }
 
 // CHECK: define linkonce_odr void @_ZN1BC1Ev(
-// CHECK: call void @_ZN4BaseC2Ev(
-// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2)
-// CHECK: call void @_ZN5FieldC1Ev
-// CHECK: ret void
+// CHECK: call void @_ZN1BC2Ev(
 
 // CHECK: define linkonce_odr void @_ZN1BD1Ev(
 // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2)
 // CHECK: call void @_ZN5FieldD1Ev(
 // CHECK: call void @_ZN4BaseD2Ev(
 // CHECK: ret void
+
+// CHECK: define linkonce_odr void @_ZN1BC2Ev(
+// CHECK: call void @_ZN4BaseC2Ev(
+// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2)
+// CHECK: call void @_ZN5FieldC1Ev
+// CHECK: ret void





More information about the cfe-commits mailing list