]> granicus.if.org Git - clang/commitdiff
Add support for threadsafe statics, and make them the default (matching gcc).
authorAnders Carlsson <andersca@mac.com>
Sat, 6 Feb 2010 23:23:06 +0000 (23:23 +0000)
committerAnders Carlsson <andersca@mac.com>
Sat, 6 Feb 2010 23:23:06 +0000 (23:23 +0000)
Daniel, I'd appreciate a review of the driver/cc1 parts.

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

include/clang/Basic/LangOptions.h
include/clang/Driver/CC1Options.td
include/clang/Driver/Options.td
lib/CodeGen/CGDeclCXX.cpp
lib/Driver/Tools.cpp
lib/Frontend/CompilerInvocation.cpp
lib/Sema/SemaInit.cpp
test/CodeGenCXX/threadsafe-statics.cpp [new file with mode: 0644]

index 2b6092dea3095c1d81ab4147b35160ad441f5ddd..2abf9ef7a08dc48ab2acf5ff7d63c0ddd5daed3e 100644 (file)
@@ -136,8 +136,7 @@ public:
 
     SymbolVisibility = (unsigned) Default;
 
-    // FIXME: The default should be 1.
-    ThreadsafeStatics = 0;
+    ThreadsafeStatics = 1;
     POSIXThreads = 0;
     Blocks = 0;
     BlockIntrospection = 0;
index aefb6fca193ebd472a91f925d78d1a23ecf6f8ba..23275b63ffc93025f64566819c3fef4221cad679 100644 (file)
@@ -115,6 +115,8 @@ def no_implicit_float : Flag<"-no-implicit-float">,
   HelpText<"Don't generate implicit floating point instructions (x86-only)">;
 def fno_merge_all_constants : Flag<"-fno-merge-all-constants">,
   HelpText<"Disallow merging of constants.">;
+def fno_threadsafe_statics : Flag<"-fno-threadsafe-statics">,
+  HelpText<"Do not emit code to make initialization of local statics thread safe">;
 def masm_verbose : Flag<"-masm-verbose">,
   HelpText<"Generate verbose assembly output">;
 def mcode_model : Separate<"-mcode-model">,
index dbdddf4eb3298add1b0884d466932609a1064042..767123b14b7ab040e80ad232344376237d9ebc87 100644 (file)
@@ -311,6 +311,7 @@ def fno_show_column : Flag<"-fno-show-column">, Group<f_Group>;
 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_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>;
@@ -351,6 +352,7 @@ def fsyntax_only : Flag<"-fsyntax-only">, Flags<[DriverOption]>;
 def ftabstop_EQ : Joined<"-ftabstop=">, Group<f_Group>;
 def ftemplate_depth_ : Joined<"-ftemplate-depth-">, Group<f_Group>;
 def fterminated_vtables : Flag<"-fterminated-vtables">, Group<f_Group>;
+def fthreadsafe_statics : Flag<"-fthreadsafe-statics">, Group<f_Group>;
 def ftime_report : Flag<"-ftime-report">, Group<f_Group>;
 def ftrapv : Flag<"-ftrapv">, Group<f_Group>;
 def funit_at_a_time : Flag<"-funit-at-a-time">, Group<f_Group>;
index 3d5a4e8051bd4cc83be31145314a6cbeee4fb429..0de3b0be4b1a192f6cf57f8d560cb0d6c04ade37 100644 (file)
@@ -184,42 +184,100 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
   FinishFunction();
 }
 
+static llvm::Constant *getGuardAcquireFn(CodeGenFunction &CGF) {
+  // int __cxa_guard_acquire(__int64_t *guard_object);
+  
+  const llvm::Type *Int64PtrTy = 
+    llvm::Type::getInt64PtrTy(CGF.getLLVMContext());
+  
+  std::vector<const llvm::Type*> Args(1, Int64PtrTy);
+  
+  const llvm::FunctionType *FTy =
+    llvm::FunctionType::get(CGF.ConvertType(CGF.getContext().IntTy),
+                            Args, /*isVarArg=*/false);
+  
+  return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire");
+}
+
+static llvm::Constant *getGuardReleaseFn(CodeGenFunction &CGF) {
+  // void __cxa_guard_release(__int64_t *guard_object);
+  
+  const llvm::Type *Int64PtrTy = 
+    llvm::Type::getInt64PtrTy(CGF.getLLVMContext());
+  
+  std::vector<const llvm::Type*> Args(1, Int64PtrTy);
+  
+  const llvm::FunctionType *FTy =
+  llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
+                          Args, /*isVarArg=*/false);
+  
+  return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release");
+}
+
+static llvm::Constant *getGuardAbortFn(CodeGenFunction &CGF) {
+  // void __cxa_guard_abort(__int64_t *guard_object);
+  
+  const llvm::Type *Int64PtrTy = 
+    llvm::Type::getInt64PtrTy(CGF.getLLVMContext());
+  
+  std::vector<const llvm::Type*> Args(1, Int64PtrTy);
+  
+  const llvm::FunctionType *FTy =
+  llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
+                          Args, /*isVarArg=*/false);
+  
+  return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort");
+}
+
 void
 CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
                                                llvm::GlobalVariable *GV) {
-  // FIXME: This should use __cxa_guard_{acquire,release}?
-
-  assert(!getContext().getLangOptions().ThreadsafeStatics &&
-         "thread safe statics are currently not supported!");
-
+  bool ThreadsafeStatics = getContext().getLangOptions().ThreadsafeStatics;
+  
   llvm::SmallString<256> GuardVName;
   CGM.getMangleContext().mangleGuardVariable(&D, GuardVName);
 
   // Create the guard variable.
-  llvm::GlobalValue *GuardV =
-    new llvm::GlobalVariable(CGM.getModule(), llvm::Type::getInt64Ty(VMContext),
+  const llvm::Type *Int64Ty = llvm::Type::getInt64Ty(VMContext);
+  llvm::GlobalValue *GuardVariable =
+    new llvm::GlobalVariable(CGM.getModule(), Int64Ty,
                              false, GV->getLinkage(),
-                llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)),
+                             llvm::Constant::getNullValue(Int64Ty),
                              GuardVName.str());
 
   // Load the first byte of the guard variable.
   const llvm::Type *PtrTy
     = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
-  llvm::Value *V = Builder.CreateLoad(Builder.CreateBitCast(GuardV, PtrTy),
-                                      "tmp");
+  llvm::Value *V = 
+    Builder.CreateLoad(Builder.CreateBitCast(GuardVariable, PtrTy), "tmp");
 
-  // Compare it against 0.
-  llvm::Value *nullValue
-    = llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext));
-  llvm::Value *ICmp = Builder.CreateICmpEQ(V, nullValue , "tobool");
-
-  llvm::BasicBlock *InitBlock = createBasicBlock("init");
+  llvm::BasicBlock *InitCheckBlock = createBasicBlock("init.check");
   llvm::BasicBlock *EndBlock = createBasicBlock("init.end");
 
-  // If the guard variable is 0, jump to the initializer code.
-  Builder.CreateCondBr(ICmp, InitBlock, EndBlock);
+  // Check if the first byte of the guard variable is zero.
+  Builder.CreateCondBr(Builder.CreateIsNull(V, "tobool"), 
+                       InitCheckBlock, EndBlock);
 
-  EmitBlock(InitBlock);
+  EmitBlock(InitCheckBlock);
+
+  if (ThreadsafeStatics) {
+    // Call __cxa_guard_acquire.
+    V = Builder.CreateCall(getGuardAcquireFn(*this), GuardVariable);
+               
+    llvm::BasicBlock *InitBlock = createBasicBlock("init");
+  
+    Builder.CreateCondBr(Builder.CreateIsNotNull(V, "tobool"),
+                         InitBlock, EndBlock);
+  
+    EmitBlock(InitBlock);
+
+    if (Exceptions) {
+      EHCleanupBlock Cleanup(*this);
+    
+      // Call __cxa_guard_abort.
+      Builder.CreateCall(getGuardAbortFn(*this), GuardVariable);
+    }
+  }
 
   if (D.getType()->isReferenceType()) {
     QualType T = D.getType();
@@ -232,9 +290,14 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
   } else
     EmitDeclInit(*this, D, GV);
 
-  Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext),
-                                             1),
-                      Builder.CreateBitCast(GuardV, PtrTy));
+  if (ThreadsafeStatics) {
+    // Call __cxa_guard_release.
+    Builder.CreateCall(getGuardReleaseFn(*this), GuardVariable);
+  } else {
+    llvm::Value *One = 
+      llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 1);
+    Builder.CreateStore(One, Builder.CreateBitCast(GuardVariable, PtrTy));
+  }
 
   EmitBlock(EndBlock);
 }
index 6c0616d370aaaec258e750283d07ed692a35ac92..2aa71163be62e32c098f977420c5f5fec2d7f307 100644 (file)
@@ -1013,6 +1013,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
                     isSignedCharDefault(getToolChain().getTriple())))
     CmdArgs.push_back("-fno-signed-char");
 
+  // -fthreadsafe-static is default.
+  if (!Args.hasFlag(options::OPT_fthreadsafe_statics, 
+                    options::OPT_fno_threadsafe_statics))
+    CmdArgs.push_back("-fno-threadsafe-statics");
+
   // -fms-extensions=0 is default.
   if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
                    getToolChain().getTriple().getOS() == llvm::Triple::Win32))
index 464c9938c8bfc98bdf5c46ed5530d038bd7855aa..5b64c7e639c389e6e3829e2e247d030004e13f50 100644 (file)
@@ -480,8 +480,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
     Res.push_back("-fno-builtin");
   if (!Opts.AssumeSaneOperatorNew)
     Res.push_back("-fno-assume-sane-operator-new");
-  if (Opts.ThreadsafeStatics)
-    llvm::llvm_report_error("FIXME: Not yet implemented!");
+  if (!Opts.ThreadsafeStatics)
+    Res.push_back("-fno-threadsafe-statics");
   if (Opts.POSIXThreads)
     Res.push_back("-pthread");
   if (Opts.Blocks)
@@ -1155,7 +1155,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
   Opts.Microsoft = Args.hasArg(OPT_fms_extensions);
   Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings);
   if (Args.hasArg(OPT_fno_lax_vector_conversions))
-      Opts.LaxVectorConversions = 0;
+    Opts.LaxVectorConversions = 0;
+  if (Args.hasArg(OPT_fno_threadsafe_statics))
+    Opts.ThreadsafeStatics = 0;  
   Opts.Exceptions = Args.hasArg(OPT_fexceptions);
   Opts.RTTI = !Args.hasArg(OPT_fno_rtti);
   Opts.Blocks = Args.hasArg(OPT_fblocks);
index 45cd930ba0aaab7bfe25ca6dc335cee1d7712d64..1cdfde3488be7197eb5bc20bedfffc699ea60249 100644 (file)
@@ -3005,7 +3005,6 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity,
                                   bool IsCopy) {
   switch (Entity.getKind()) {
   case InitializedEntity::EK_Result:
-  case InitializedEntity::EK_Exception:
   case InitializedEntity::EK_ArrayElement:
   case InitializedEntity::EK_Member:
     return !IsCopy;
@@ -3014,6 +3013,7 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity,
   case InitializedEntity::EK_Variable:
   case InitializedEntity::EK_Base:
   case InitializedEntity::EK_VectorElement:
+  case InitializedEntity::EK_Exception:
     return false;
     
   case InitializedEntity::EK_Parameter:
diff --git a/test/CodeGenCXX/threadsafe-statics.cpp b/test/CodeGenCXX/threadsafe-statics.cpp
new file mode 100644 (file)
index 0000000..65ebc43
--- /dev/null
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck -check-prefix=WITH-TSS %s
+// RUN: %clang_cc1 -emit-llvm -o - %s -fno-threadsafe-statics | FileCheck -check-prefix=NO-TSS %s
+
+int f();
+
+// WITH-TSS: define void @_Z1gv() nounwind
+// WITH-TSS: call i32 @__cxa_guard_acquire
+// WITH-TSS: call void @__cxa_guard_release
+// WITH-TSS: ret void
+void g() { 
+  static int a = f();
+}
+
+// NO-TSS: define void @_Z1gv() nounwind
+// NO-TSS-NOT: call i32 @__cxa_guard_acquire
+// NO-TSS-NOT: call void @__cxa_guard_release
+// NO-TSS: ret void