]> granicus.if.org Git - clang/commitdiff
C++: Add support for -fno-use-cxa-atexit.
authorDaniel Dunbar <daniel@zuster.org>
Sat, 20 Mar 2010 04:15:41 +0000 (04:15 +0000)
committerDaniel Dunbar <daniel@zuster.org>
Sat, 20 Mar 2010 04:15:41 +0000 (04:15 +0000)
 - So much typing, so little gain...

Also, rename the __cxx_global_initialization function just to match llvm-gcc.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@99039 91177308-0d34-0410-b5e6-96231b3b80d8

12 files changed:
include/clang/CodeGen/CodeGenOptions.h
include/clang/Driver/CC1Options.td
include/clang/Driver/Options.td
lib/CodeGen/CGDeclCXX.cpp
lib/CodeGen/CodeGenFunction.h
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/CodeGenModule.h
lib/Driver/Tools.cpp
lib/Frontend/CompilerInvocation.cpp
test/CodeGenCXX/deferred-global-init.cpp
test/CodeGenCXX/global-dtor-no-atexit.cpp [new file with mode: 0644]
test/CodeGenCXX/global-init.cpp

index e0e0f779bf5ac7696cb292c46a0abfa4d7b2334b..85c6c3e3abcf11dfeadca28cdd536c2fd0b25b51 100644 (file)
@@ -30,6 +30,9 @@ public:
   };
 
   unsigned AsmVerbose        : 1; /// -dA, -fverbose-asm.
+  unsigned CXAAtExit         : 1; /// Use __cxa_atexit for calling destructors.
+  unsigned CXXCtorDtorAliases: 1; /// Emit complete ctors/dtors as linker
+                                  /// aliases to base ctors when possible.
   unsigned DebugInfo         : 1; /// Should generate deubg info (-g).
   unsigned DisableFPElim     : 1; /// Set when -fomit-frame-pointer is enabled.
   unsigned DisableLLVMOpts   : 1; /// Don't run any optimizations, for use in
@@ -53,8 +56,6 @@ public:
   unsigned UnwindTables      : 1; /// Emit unwind tables.
   unsigned VerifyModule      : 1; /// Control whether the module should be run
                                   /// through the LLVM Verifier.
-  unsigned CXXCtorDtorAliases: 1; /// Emit complete ctors/dtors as linker
-                                  /// aliases to base ctors when possible.
 
   /// The code model to use (-mcmodel).
   std::string CodeModel;
@@ -86,6 +87,8 @@ public:
 public:
   CodeGenOptions() {
     AsmVerbose = 0;
+    CXAAtExit = 1;
+    CXXCtorDtorAliases = 0;
     DebugInfo = 0;
     DisableFPElim = 0;
     DisableLLVMOpts = 0;
@@ -103,7 +106,6 @@ public:
     UnrollLoops = 0;
     UnwindTables = 0;
     VerifyModule = 1;
-    CXXCtorDtorAliases = 0;
 
     Inlining = NoInlining;
     RelocationModel = "pic";
index 3696a4b1fbce30d493d34e15e6fc64ffc8b9c546..feebbc78864f78b99a64dda81c7739bf56275bd3 100644 (file)
@@ -355,10 +355,12 @@ def fno_elide_constructors : Flag<"-fno-elide-constructors">,
   HelpText<"Disable C++ copy constructor elision">;
 def fno_lax_vector_conversions : Flag<"-fno-lax-vector-conversions">,
   HelpText<"Disallow implicit conversions between vectors with a different number of elements or different element types">;
-def fno_signed_char : Flag<"-fno-signed-char">,
-  HelpText<"Char is unsigned">;
 def fno_operator_names : Flag<"-fno-operator-names">,
   HelpText<"Do not treat C++ operator name keywords as synonyms for operators">;
+def fno_signed_char : Flag<"-fno-signed-char">,
+  HelpText<"Char is unsigned">;
+def fno_use_cxa_atexit : Flag<"-fno-use-cxa-atexit">,
+  HelpText<"Don't use __cxa_atexit for calling destructors">;
 def fconstant_string_class : Separate<"-fconstant-string-class">,
   MetaVarName<"<class name>">,
   HelpText<"Specify the class to use for constant Objective-C string objects.">;
index 00fb7d09752943b83b5d9547b2a95ad69c201609..71258f9814be7b31e4e57a35d072a9760445e82e 100644 (file)
@@ -263,6 +263,7 @@ def femit_all_decls : Flag<"-femit-all-decls">, Group<f_Group>;
 def fencoding_EQ : Joined<"-fencoding=">, Group<f_Group>;
 def fexceptions : Flag<"-fexceptions">, Group<f_Group>;
 def fextdirs_EQ : Joined<"-fextdirs=">, Group<f_Group>;
+def fhosted : Flag<"-fhosted">, Group<f_Group>;
 def ffreestanding : Flag<"-ffreestanding">, Group<f_Group>;
 def fgnu_runtime : Flag<"-fgnu-runtime">, Group<f_Group>;
 def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">;
@@ -315,6 +316,7 @@ def fno_show_source_location : Flag<"-fno-show-source-location">, Group<f_Group>
 def fno_stack_protector : Flag<"-fno-stack-protector">, Group<f_Group>;
 def fno_strict_aliasing : Flag<"-fno-strict-aliasing">, Group<clang_ignored_f_Group>;
 def fno_threadsafe_statics : Flag<"-fno-threadsafe-statics">, Group<f_Group>;
+def fno_use_cxa_atexit : Flag<"-fno-use-cxa-atexit">, Group<f_Group>;
 def fno_unit_at_a_time : Flag<"-fno-unit-at-a-time">, Group<f_Group>;
 def fno_unwind_tables : Flag<"-fno-unwind-tables">, Group<f_Group>;
 def fno_working_directory : Flag<"-fno-working-directory">, Group<f_Group>;
@@ -363,6 +365,7 @@ def funit_at_a_time : Flag<"-funit-at-a-time">, Group<f_Group>;
 def funsigned_bitfields : Flag<"-funsigned-bitfields">, Group<f_Group>;
 def funsigned_char : Flag<"-funsigned-char">, Group<f_Group>;
 def funwind_tables : Flag<"-funwind-tables">, Group<f_Group>;
+def fuse_cxa_atexit : Flag<"-fuse-cxa-atexit">, Group<f_Group>;
 def fverbose_asm : Flag<"-fverbose-asm">, Group<f_Group>;
 def fvisibility_EQ : Joined<"-fvisibility=">, Group<f_Group>;
 def fwritable_strings : Flag<"-fwritable-strings">, Group<f_Group>;
index 22a103ce35fd730e8def9f8cba5f8dbd8aa9b82a..40c18ca3c2a3334fb9fbad5b05a6bc40ebdb274f 100644 (file)
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "CodeGenFunction.h"
+#include "clang/CodeGen/CodeGenOptions.h"
 using namespace clang;
 using namespace CodeGen;
 
@@ -89,8 +90,15 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
                    "global variable that binds reference to a non-lvalue");
 }
 
-void CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
-                                                    llvm::Constant *DeclPtr) {
+void
+CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
+                                               llvm::Constant *DeclPtr) {
+  // Generate a global destructor entry if not using __cxa_atexit.
+  if (!CGM.getCodeGenOpts().CXAAtExit) {
+    CGM.AddCXXDtorEntry(DtorFn, DeclPtr);
+    return;
+  }
+
   const llvm::Type *Int8PtrTy = 
     llvm::Type::getInt8Ty(VMContext)->getPointerTo();
 
@@ -123,7 +131,8 @@ void CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
   Builder.CreateCall(AtExitFn, &Args[0], llvm::array_endof(Args));
 }
 
-void CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D) {
+void
+CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D) {
   const llvm::FunctionType *FTy
     = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
                               false);
@@ -133,18 +142,13 @@ void CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D) {
     llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
                            "__cxx_global_var_init", &TheModule);
 
-  StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
-                SourceLocation());
-
-  llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D);
-  EmitCXXGlobalVarDeclInit(*D, DeclPtr);
-
-  FinishFunction();
+  CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D);
 
   CXXGlobalInits.push_back(Fn);
 }
 
-void CodeGenModule::EmitCXXGlobalInitFunc() {
+void
+CodeGenModule::EmitCXXGlobalInitFunc() {
   if (CXXGlobalInits.empty())
     return;
 
@@ -153,20 +157,73 @@ void CodeGenModule::EmitCXXGlobalInitFunc() {
                               false);
 
   // Create our global initialization function.
-  // FIXME: Should this be tweakable by targets?
   llvm::Function *Fn =
     llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
-                           "__cxx_global_initialization", &TheModule);
+                           "_GLOBAL__I_a", &TheModule);
+
+  CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn,
+                                                   &CXXGlobalInits[0],
+                                                   CXXGlobalInits.size());
+  AddGlobalCtor(Fn);
+}
+
+void CodeGenModule::AddCXXDtorEntry(llvm::Constant *DtorFn,
+                                    llvm::Constant *Object) {
+  CXXGlobalDtors.push_back(std::make_pair(DtorFn, Object));
+}
+
+void CodeGenModule::EmitCXXGlobalDtorFunc() {
+  if (CXXGlobalDtors.empty())
+    return;
+
+  const llvm::FunctionType *FTy
+    = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
+                              false);
+
+  // Create our global destructor function.
+  llvm::Function *Fn =
+    llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
+                           "_GLOBAL__D_a", &TheModule);
+
+  CodeGenFunction(*this).GenerateCXXGlobalDtorFunc(Fn, CXXGlobalDtors);
+  AddGlobalDtor(Fn);
+}
 
+void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
+                                                       const VarDecl *D) {
   StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
                 SourceLocation());
 
-  for (unsigned i = 0, e = CXXGlobalInits.size(); i != e; ++i)
-    Builder.CreateCall(CXXGlobalInits[i]);
+  llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D);
+  EmitCXXGlobalVarDeclInit(*D, DeclPtr);
 
   FinishFunction();
+}
 
-  AddGlobalCtor(Fn);
+void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
+                                                llvm::Constant **Decls,
+                                                unsigned NumDecls) {
+  StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
+                SourceLocation());
+
+  for (unsigned i = 0; i != NumDecls; ++i)
+    Builder.CreateCall(Decls[i]);
+
+  FinishFunction();
+}
+
+void CodeGenFunction::GenerateCXXGlobalDtorFunc(llvm::Function *Fn,
+                const std::vector<std::pair<llvm::Constant*, llvm::Constant*> >
+                                                &DtorsAndObjects) {
+  StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
+                SourceLocation());
+
+  // Emit the dtors, in reverse order from construction.
+  for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i)
+    Builder.CreateCall(DtorsAndObjects[e - i - 1].first,
+                       DtorsAndObjects[e - i - 1].second);
+
+  FinishFunction();
 }
 
 static llvm::Constant *getGuardAcquireFn(CodeGenFunction &CGF) {
index d9b1457811466ac429bddf8af7d0e2b97e717f70..bd12c4a87c299b82c7fd21af0faf1f28d5277949 100644 (file)
@@ -1225,6 +1225,20 @@ public:
   void EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
                                      llvm::Constant *DeclPtr);
 
+  /// GenerateCXXGlobalInitFunc - Generates code for initializing global
+  /// variables.
+  void GenerateCXXGlobalInitFunc(llvm::Function *Fn,
+                                 llvm::Constant **Decls,
+                                 unsigned NumDecls);
+
+  /// GenerateCXXGlobalDtorFunc - Generates code for destroying global
+  /// variables.
+  void GenerateCXXGlobalDtorFunc(llvm::Function *Fn,
+                                 const std::vector<std::pair<llvm::Constant*,
+                                   llvm::Constant*> > &DtorsAndObjects);
+
+  void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D);
+
   void EmitCXXConstructExpr(llvm::Value *Dest, const CXXConstructExpr *E);
 
   RValue EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E,
index 3b04cc125eb2ec332d463b84b3721e4c55925f99..b4b5bbdb99aa267a59f410552163eb744da6a70a 100644 (file)
@@ -81,6 +81,7 @@ void CodeGenModule::createObjCRuntime() {
 void CodeGenModule::Release() {
   EmitDeferred();
   EmitCXXGlobalInitFunc();
+  EmitCXXGlobalDtorFunc();
   if (Runtime)
     if (llvm::Function *ObjCInitFunction = Runtime->ModuleInitFunction())
       AddGlobalCtor(ObjCInitFunction);
index b93f3c634d3c2882da9c4ee821e87b349f16d955..febb8560367bb2619376c7b8def3b3281fedc6a7 100644 (file)
@@ -138,10 +138,14 @@ class CodeGenModule : public BlockModule {
   llvm::StringMap<llvm::Constant*> CFConstantStringMap;
   llvm::StringMap<llvm::Constant*> ConstantStringMap;
 
-  /// CXXGlobalInits - Variables with global initializers that need to run
+  /// CXXGlobalInits - Global variables with initializers that need to run
   /// before main.
   std::vector<llvm::Constant*> CXXGlobalInits;
 
+  /// CXXGlobalDtors - Global destructor functions and arguments that need to
+  /// run on termination.
+  std::vector<std::pair<llvm::Constant*,llvm::Constant*> > CXXGlobalDtors;
+
   /// CFConstantStringClassRef - Cached reference to the class for constant
   /// strings. This value has type int * but is actually an Obj-C class pointer.
   llvm::Constant *CFConstantStringClassRef;
@@ -321,6 +325,10 @@ public:
 
   void AddAnnotation(llvm::Constant *C) { Annotations.push_back(C); }
 
+  /// AddCXXDtorEntry - Add a destructor and object to add to the C++ global
+  /// destructor function.
+  void AddCXXDtorEntry(llvm::Constant *DtorFn, llvm::Constant *Object);
+
   /// CreateRuntimeFunction - Create a new runtime function with the specified
   /// type and name.
   llvm::Constant *CreateRuntimeFunction(const llvm::FunctionType *Ty,
@@ -496,9 +504,12 @@ private:
   /// a C++ destructor Decl.
   void EmitCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type);
 
-  /// EmitCXXGlobalInitFunc - Emit a function that initializes C++ globals.
+  /// EmitCXXGlobalInitFunc - Emit the function that initializes C++ globals.
   void EmitCXXGlobalInitFunc();
 
+  /// EmitCXXGlobalDtorFunc - Emit the function that destroys C++ globals.
+  void EmitCXXGlobalDtorFunc();
+
   void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D);
 
   // FIXME: Hardcoding priority here is gross.
index 58a4cdb89b3cc9522b66503dd6e1b4494238e0e1..87449760a73412b64cfad35aa41b9277898d73b9 100644 (file)
@@ -1118,6 +1118,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
                     options::OPT_fno_threadsafe_statics))
     CmdArgs.push_back("-fno-threadsafe-statics");
 
+  // -fuse-cxa-atexit is default.
+  if (!Args.hasFlag(options::OPT_fuse_cxa_atexit,
+                    options::OPT_fno_use_cxa_atexit))
+    CmdArgs.push_back("-fno-use-cxa-atexit");
+
   // -fms-extensions=0 is default.
   if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
                    getToolChain().getTriple().getOS() == llvm::Triple::Win32))
index 2dfc592ec89e445d898e9a85ded7197cdc78a306..6e18f346d5612631fa546a4dc76307ec6354a73f 100644 (file)
@@ -154,6 +154,10 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
     Res.push_back("-mcode-model");
     Res.push_back(Opts.CodeModel);
   }
+  if (!Opts.CXAAtExit)
+    Res.push_back("-fno-use-cxa-atexit");
+  if (Opts.CXXCtorDtorAliases)
+    Res.push_back("-mconstructor-aliases");
   if (!Opts.DebugPass.empty()) {
     Res.push_back("-mdebug-pass");
     Res.push_back(Opts.DebugPass);
@@ -180,8 +184,6 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
     Res.push_back("-mrelocation-model");
     Res.push_back(Opts.RelocationModel);
   }
-  if (Opts.CXXCtorDtorAliases)
-    Res.push_back("-mconstructor-aliases");
   if (!Opts.VerifyModule)
     Res.push_back("-disable-llvm-verifier");
 }
@@ -784,6 +786,8 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
   Opts.UnrollLoops = (Opts.OptimizationLevel > 1 && !Opts.OptimizeSize);
 
   Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose);
+  Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit);
+  Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases);
   Opts.CodeModel = getLastArgValue(Args, OPT_mcode_model);
   Opts.DebugPass = getLastArgValue(Args, OPT_mdebug_pass);
   Opts.DisableFPElim = Args.hasArg(OPT_mdisable_fp_elim);
@@ -794,7 +798,6 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
   Opts.SoftFloat = Args.hasArg(OPT_msoft_float);
   Opts.UnwindTables = Args.hasArg(OPT_munwind_tables);
   Opts.RelocationModel = getLastArgValue(Args, OPT_mrelocation_model, "pic");
-  Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases);
 
   Opts.MainFileName = getLastArgValue(Args, OPT_main_file_name);
   Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier);
index 802042dd8b908fe88c501d5a2132191e29fc1a26..24c8c675b006f75612e8edb341d6aeaeb8e34932 100644 (file)
@@ -11,6 +11,6 @@ void* bar() { return a; }
 // CHECK: load i8** @foo
 // CHECK: ret void
 
-// CHECK: define internal void @__cxx_global_initialization
+// CHECK: define internal void @_GLOBAL__I_a
 // CHECK: call void @__cxx_global_var_init()
 // CHECK: ret void
diff --git a/test/CodeGenCXX/global-dtor-no-atexit.cpp b/test/CodeGenCXX/global-dtor-no-atexit.cpp
new file mode 100644 (file)
index 0000000..81e2199
--- /dev/null
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple x86_64 %s -fno-use-cxa-atexit -emit-llvm -o - | FileCheck %s
+
+// CHECK: define internal void @_GLOBAL__D_a()
+// CHECK:   call void @_ZN1AD1Ev(%class.A* @b)
+// CHECK:   call void @_ZN1AD1Ev(%class.A* @a)
+// CHECK: }
+
+class A {
+public:
+  A();
+  ~A();
+};
+
+A a, b;
index b60e056d708f4376be2333fbec3e5e346ecbcc13..7cbd55940b43991d6e8cf1030d2bac78adb55494 100644 (file)
@@ -28,4 +28,4 @@ C c;
 // CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1DD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @d, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*))
 D d;
 
-// CHECK: define internal void @__cxx_global_initialization() {
+// CHECK: define internal void @_GLOBAL__I_a() {