r232906 - MS ABI: Implement driver-level support for thread-safe statics

David Majnemer david.majnemer at gmail.com
Sun Mar 22 01:39:22 PDT 2015


Author: majnemer
Date: Sun Mar 22 03:39:22 2015
New Revision: 232906

URL: http://llvm.org/viewvc/llvm-project?rev=232906&view=rev
Log:
MS ABI: Implement driver-level support for thread-safe statics

Decide whether or not to use thread-safe statics depending on whether or
not we have an explicit request from the driver.  If we don't have an
explicit request, infer which behavior to use depending on the
compatibility version we are targeting.

N.B. CodeGen support is still ongoing.

Modified:
    cfe/trunk/include/clang/Basic/VersionTuple.h
    cfe/trunk/include/clang/Driver/CLCompatOptions.td
    cfe/trunk/lib/Basic/VersionTuple.cpp
    cfe/trunk/lib/Driver/Tools.cpp
    cfe/trunk/lib/Frontend/CompilerInvocation.cpp
    cfe/trunk/test/Driver/cl-options.c
    cfe/trunk/test/Driver/msc-version.c

Modified: cfe/trunk/include/clang/Basic/VersionTuple.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/VersionTuple.h?rev=232906&r1=232905&r2=232906&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/VersionTuple.h (original)
+++ cfe/trunk/include/clang/Basic/VersionTuple.h Sun Mar 22 03:39:22 2015
@@ -22,40 +22,48 @@
 
 namespace clang {
 
-/// \brief Represents a version number in the form major[.minor[.subminor]].
+/// \brief Represents a version number in the form major[.minor[.subminor[.build]]].
 class VersionTuple {
   unsigned Major : 31;
   unsigned Minor : 31;
   unsigned Subminor : 31;
+  unsigned Build : 31;
   unsigned HasMinor : 1;
   unsigned HasSubminor : 1;
+  unsigned HasBuild : 1;
   unsigned UsesUnderscores : 1;
 
 public:
-  VersionTuple() 
-    : Major(0), Minor(0), Subminor(0), HasMinor(false), HasSubminor(false),
-      UsesUnderscores(false) { }
+  VersionTuple()
+      : Major(0), Minor(0), Subminor(0), Build(0), HasMinor(false),
+        HasSubminor(false), HasBuild(false), UsesUnderscores(false) {}
 
   explicit VersionTuple(unsigned Major)
-    : Major(Major), Minor(0), Subminor(0), HasMinor(false), HasSubminor(false),
-      UsesUnderscores(false)
-  { }
+      : Major(Major), Minor(0), Subminor(0), Build(0), HasMinor(false),
+        HasSubminor(false), HasBuild(false), UsesUnderscores(false) {}
 
   explicit VersionTuple(unsigned Major, unsigned Minor,
                         bool UsesUnderscores = false)
-    : Major(Major), Minor(Minor), Subminor(0), HasMinor(true), 
-      HasSubminor(false), UsesUnderscores(UsesUnderscores)
-  { }
+      : Major(Major), Minor(Minor), Subminor(0), Build(0), HasMinor(true),
+        HasSubminor(false), HasBuild(false), UsesUnderscores(UsesUnderscores) {}
 
   explicit VersionTuple(unsigned Major, unsigned Minor, unsigned Subminor,
                         bool UsesUnderscores = false)
-    : Major(Major), Minor(Minor), Subminor(Subminor), HasMinor(true), 
-      HasSubminor(true), UsesUnderscores(UsesUnderscores)
-  { }
-  
+      : Major(Major), Minor(Minor), Subminor(Subminor), Build(0),
+        HasMinor(true), HasSubminor(true), HasBuild(false),
+        UsesUnderscores(UsesUnderscores) {}
+
+  explicit VersionTuple(unsigned Major, unsigned Minor, unsigned Subminor,
+                        unsigned Build, bool UsesUnderscores = false)
+      : Major(Major), Minor(Minor), Subminor(Subminor), Build(Build),
+        HasMinor(true), HasSubminor(true), HasBuild(true),
+        UsesUnderscores(UsesUnderscores) {}
+
   /// \brief Determine whether this version information is empty
   /// (e.g., all version components are zero).
-  bool empty() const { return Major == 0 && Minor == 0 && Subminor == 0; }
+  bool empty() const {
+    return Major == 0 && Minor == 0 && Subminor == 0 && Build == 0;
+  }
 
   /// \brief Retrieve the major version number.
   unsigned getMajor() const { return Major; }
@@ -74,6 +82,13 @@ public:
     return Subminor;
   }
 
+  /// \brief Retrieve the build version number, if provided.
+  Optional<unsigned> getBuild() const {
+    if (!HasBuild)
+      return None;
+    return Build;
+  }
+
   bool usesUnderscores() const {
     return UsesUnderscores;
   }
@@ -85,7 +100,8 @@ public:
   /// \brief Determine if two version numbers are equivalent. If not
   /// provided, minor and subminor version numbers are considered to be zero.
   friend bool operator==(const VersionTuple& X, const VersionTuple &Y) {
-    return X.Major == Y.Major && X.Minor == Y.Minor && X.Subminor == Y.Subminor;
+    return X.Major == Y.Major && X.Minor == Y.Minor &&
+           X.Subminor == Y.Subminor && X.Build == Y.Build;
   }
 
   /// \brief Determine if two version numbers are not equivalent.
@@ -101,8 +117,8 @@ public:
   /// If not provided, minor and subminor version numbers are considered to be
   /// zero.
   friend bool operator<(const VersionTuple &X, const VersionTuple &Y) {
-    return std::tie(X.Major, X.Minor, X.Subminor) <
-           std::tie(Y.Major, Y.Minor, Y.Subminor);
+    return std::tie(X.Major, X.Minor, X.Subminor, X.Build) <
+           std::tie(Y.Major, Y.Minor, Y.Subminor, Y.Build);
   }
 
   /// \brief Determine whether one version number follows another.
@@ -136,7 +152,7 @@ public:
 
   /// \brief Try to parse the given string as a version number.
   /// \returns \c true if the string does not match the regular expression
-  ///   [0-9]+(\.[0-9]+(\.[0-9]+))
+  ///   [0-9]+(\.[0-9]+){0,3}
   bool tryParse(StringRef string);
 };
 

Modified: cfe/trunk/include/clang/Driver/CLCompatOptions.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CLCompatOptions.td?rev=232906&r1=232905&r2=232906&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/CLCompatOptions.td (original)
+++ cfe/trunk/include/clang/Driver/CLCompatOptions.td Sun Mar 22 03:39:22 2015
@@ -137,6 +137,12 @@ def _SLASH_vd : CLJoined<"vd">, HelpText
 def _SLASH_Zc_strictStrings : CLFlag<"Zc:strictStrings">,
   HelpText<"Treat string literals as const">, Alias<W_Joined>,
   AliasArgs<["error=c++11-compat-deprecated-writable-strings"]>;
+def _SLASH_Zc_threadSafeInit : CLFlag<"Zc:threadSafeInit">,
+  HelpText<"Enable thread-safe initialization of static variables">,
+  Alias<fthreadsafe_statics>;
+def _SLASH_Zc_threadSafeInit_ : CLFlag<"Zc:threadSafeInit-">,
+  HelpText<"Disable thread-safe initialization of static variables">,
+  Alias<fno_threadsafe_statics>;
 def _SLASH_Zc_trigraphs : CLFlag<"Zc:trigraphs">,
   HelpText<"Enable trigraphs">, Alias<ftrigraphs>;
 def _SLASH_Zc_trigraphs_off : CLFlag<"Zc:trigraphs-">,

Modified: cfe/trunk/lib/Basic/VersionTuple.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/VersionTuple.cpp?rev=232906&r1=232905&r2=232906&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/VersionTuple.cpp (original)
+++ cfe/trunk/lib/Basic/VersionTuple.cpp Sun Mar 22 03:39:22 2015
@@ -32,6 +32,8 @@ raw_ostream& clang::operator<<(raw_ostre
     Out << (V.usesUnderscores() ? '_' : '.') << *Minor;
   if (Optional<unsigned> Subminor = V.getSubminor())
     Out << (V.usesUnderscores() ? '_' : '.') << *Subminor;
+  if (Optional<unsigned> Build = V.getBuild())
+    Out << (V.usesUnderscores() ? '_' : '.') << *Build;
   return Out;
 }
 
@@ -55,7 +57,7 @@ static bool parseInt(StringRef &input, u
 }
 
 bool VersionTuple::tryParse(StringRef input) {
-  unsigned major = 0, minor = 0, micro = 0;
+  unsigned major = 0, minor = 0, micro = 0, build = 0;
 
   // Parse the major version, [0-9]+
   if (parseInt(input, major)) return true;
@@ -80,9 +82,19 @@ bool VersionTuple::tryParse(StringRef in
   input = input.substr(1);
   if (parseInt(input, micro)) return true;
 
+  if (input.empty()) {
+    *this = VersionTuple(major, minor, micro);
+    return false;
+  }
+
+  // If we're not done, parse the micro version, \.[0-9]+
+  if (input[0] != '.') return true;
+  input = input.substr(1);
+  if (parseInt(input, build)) return true;
+
   // If we have characters left over, it's an error.
   if (!input.empty()) return true;
 
-  *this = VersionTuple(major, minor, micro);
+  *this = VersionTuple(major, minor, micro, build);
   return false;
 }

Modified: cfe/trunk/lib/Driver/Tools.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=232906&r1=232905&r2=232906&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Tools.cpp (original)
+++ cfe/trunk/lib/Driver/Tools.cpp Sun Mar 22 03:39:22 2015
@@ -2483,24 +2483,17 @@ static void addDashXForInput(const ArgLi
     CmdArgs.push_back(types::getTypeName(Input.getType()));
 }
 
-static std::string getMSCompatibilityVersion(const char *VersionStr) {
-  unsigned Version;
-  if (StringRef(VersionStr).getAsInteger(10, Version))
-    return "0";
-
+static VersionTuple getMSCompatibilityVersion(unsigned Version) {
   if (Version < 100)
-    return llvm::utostr_32(Version) + ".0";
+    return VersionTuple(Version);
 
   if (Version < 10000)
-    return llvm::utostr_32(Version / 100) + "." +
-        llvm::utostr_32(Version % 100);
+    return VersionTuple(Version / 100, Version % 100);
 
   unsigned Build = 0, Factor = 1;
   for ( ; Version > 10000; Version = Version / 10, Factor = Factor * 10)
     Build = Build + (Version % 10) * Factor;
-  return llvm::utostr_32(Version / 100) + "." +
-      llvm::utostr_32(Version % 100) + "." +
-      llvm::utostr_32(Build);
+  return VersionTuple(Version / 100, Version % 100, Build);
 }
 
 // Claim options we don't want to warn if they are unused. We do this for
@@ -4067,11 +4060,6 @@ void Clang::ConstructJob(Compilation &C,
                     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");
-
   // -fuse-cxa-atexit is default.
   if (!Args.hasFlag(options::OPT_fuse_cxa_atexit,
                     options::OPT_fno_use_cxa_atexit,
@@ -4099,9 +4087,11 @@ void Clang::ConstructJob(Compilation &C,
                                                   true))))
     CmdArgs.push_back("-fms-compatibility");
 
-  // -fms-compatibility-version=17.00 is default.
+  // -fms-compatibility-version=18.00 is default.
+  VersionTuple MSVT;
   if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
-                   IsWindowsMSVC) || Args.hasArg(options::OPT_fmsc_version) ||
+                   IsWindowsMSVC) ||
+      Args.hasArg(options::OPT_fmsc_version) ||
       Args.hasArg(options::OPT_fms_compatibility_version)) {
     const Arg *MSCVersion = Args.getLastArg(options::OPT_fmsc_version);
     const Arg *MSCompatibilityVersion =
@@ -4112,16 +4102,23 @@ void Clang::ConstructJob(Compilation &C,
           << MSCVersion->getAsString(Args)
           << MSCompatibilityVersion->getAsString(Args);
 
-    std::string Ver;
-    if (MSCompatibilityVersion)
-      Ver = Args.getLastArgValue(options::OPT_fms_compatibility_version);
-    else if (MSCVersion)
-      Ver = getMSCompatibilityVersion(MSCVersion->getValue());
+    if (MSCompatibilityVersion) {
+      if (MSVT.tryParse(MSCompatibilityVersion->getValue()))
+        D.Diag(diag::err_drv_invalid_value)
+            << MSCompatibilityVersion->getAsString(Args)
+            << MSCompatibilityVersion->getValue();
+    } else if (MSCVersion) {
+      unsigned Version = 0;
+      if (StringRef(MSCVersion->getValue()).getAsInteger(10, Version))
+        D.Diag(diag::err_drv_invalid_value) << MSCVersion->getAsString(Args)
+                                            << MSCVersion->getValue();
+      MSVT = getMSCompatibilityVersion(Version);
+    } else {
+      MSVT = VersionTuple(18);
+    }
 
-    if (Ver.empty())
-      CmdArgs.push_back("-fms-compatibility-version=18.00");
-    else
-      CmdArgs.push_back(Args.MakeArgString("-fms-compatibility-version=" + Ver));
+    CmdArgs.push_back(
+        Args.MakeArgString("-fms-compatibility-version=" + MSVT.getAsString()));
   }
 
   // -fno-borland-extensions is default.
@@ -4129,6 +4126,13 @@ void Clang::ConstructJob(Compilation &C,
                    options::OPT_fno_borland_extensions, false))
     CmdArgs.push_back("-fborland-extensions");
 
+  // -fthreadsafe-static is default, except for MSVC compatibility versions less
+  // than 19.
+  if (!Args.hasFlag(options::OPT_fthreadsafe_statics,
+                    options::OPT_fno_threadsafe_statics,
+                    !IsWindowsMSVC || MSVT.getMajor() >= 19))
+    CmdArgs.push_back("-fno-threadsafe-statics");
+
   // -fno-delayed-template-parsing is default, except for Windows where MSVC STL
   // needs it.
   if (Args.hasFlag(options::OPT_fdelayed_template_parsing,

Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=232906&r1=232905&r2=232906&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Sun Mar 22 03:39:22 2015
@@ -1282,43 +1282,6 @@ static Visibility parseVisibility(Arg *a
   return DefaultVisibility;
 }
 
-static unsigned parseMSCVersion(ArgList &Args, DiagnosticsEngine &Diags) {
-  auto Arg = Args.getLastArg(OPT_fms_compatibility_version);
-  if (!Arg)
-    return 0;
-
-  // The MSC versioning scheme involves four versioning components:
-  //  - Major
-  //  - Minor
-  //  - Build
-  //  - Patch
-  //
-  // We accept either the old style (_MSC_VER) value, or a _MSC_FULL_VER value.
-  // Additionally, the value may be provided in the form of a more readable
-  // MM.mm.bbbbb.pp version.
-  //
-  // Unfortunately, due to the bit-width limitations, we cannot currently encode
-  // the value for the patch level.
-
-  unsigned VC[4] = {0};
-  StringRef Value = Arg->getValue();
-  SmallVector<StringRef, 4> Components;
-
-  Value.split(Components, ".", llvm::array_lengthof(VC));
-  for (unsigned CI = 0,
-                CE = std::min(Components.size(), llvm::array_lengthof(VC));
-       CI < CE; ++CI) {
-    if (Components[CI].getAsInteger(10, VC[CI])) {
-      Diags.Report(diag::err_drv_invalid_value)
-        << Arg->getAsString(Args) << Value;
-      return 0;
-    }
-  }
-
-  // FIXME we cannot encode the patch level
-  return VC[0] * 10000000 + VC[1] * 100000 + VC[2];
-}
-
 static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
                           DiagnosticsEngine &Diags) {
   // FIXME: Cleanup per-file based stuff.
@@ -1489,7 +1452,16 @@ static void ParseLangArgs(LangOptions &O
   Opts.MSVCCompat = Args.hasArg(OPT_fms_compatibility);
   Opts.MicrosoftExt = Opts.MSVCCompat || Args.hasArg(OPT_fms_extensions);
   Opts.AsmBlocks = Args.hasArg(OPT_fasm_blocks) || Opts.MicrosoftExt;
-  Opts.MSCompatibilityVersion = parseMSCVersion(Args, Diags);
+  Opts.MSCompatibilityVersion = 0;
+  if (const Arg *A = Args.getLastArg(OPT_fms_compatibility_version)) {
+    VersionTuple VT;
+    if (VT.tryParse(A->getValue()))
+      Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args)
+                                                << A->getValue();
+    Opts.MSCompatibilityVersion = VT.getMajor() * 10000000 +
+                                  VT.getMinor().getValueOr(0) * 100000 +
+                                  VT.getSubminor().getValueOr(0);
+  }
 
   // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs
   // is specified, or -std is set to a conforming mode.

Modified: cfe/trunk/test/Driver/cl-options.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/cl-options.c?rev=232906&r1=232905&r2=232906&view=diff
==============================================================================
--- cfe/trunk/test/Driver/cl-options.c (original)
+++ cfe/trunk/test/Driver/cl-options.c Sun Mar 22 03:39:22 2015
@@ -317,6 +317,14 @@
 // RTTI-NOT: "-fno-rtti-data"
 // RTTI-NOT: "-fno-rtti"
 
+// thread safe statics are off for versions < 19.
+// RUN: %clang_cl /c -### -- %s 2>&1 | FileCheck -check-prefix=NoThreadSafeStatics %s
+// RUN: %clang_cl /Zc:threadSafeInit /Zc:threadSafeInit- /c -### -- %s 2>&1 | FileCheck -check-prefix=NoThreadSafeStatics %s
+// NoThreadSafeStatics: "-fno-threadsafe-statics"
+
+// RUN: %clang_cl /Zc:threadSafeInit /c -### -- %s 2>&1 | FileCheck -check-prefix=ThreadSafeStatics %s
+// ThreadSafeStatics-NOT: "-fno-threadsafe-statics"
+
 // Accept "core" clang options.
 // (/Zs is for syntax-only)
 // RUN: %clang_cl \

Modified: cfe/trunk/test/Driver/msc-version.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/msc-version.c?rev=232906&r1=232905&r2=232906&view=diff
==============================================================================
--- cfe/trunk/test/Driver/msc-version.c (original)
+++ cfe/trunk/test/Driver/msc-version.c Sun Mar 22 03:39:22 2015
@@ -54,7 +54,7 @@
 // RUN: %clang -### -target i686-windows -fms-compatibility -fmsc-version=17 -E - </dev/null -o /dev/null 2>&1 | FileCheck %s -check-prefix CHECK-MSC-17
 
 // CHECK-MSC-17-NOT: "-fmsc-version=1700"
-// CHECK-MSC-17: "-fms-compatibility-version=17.0"
+// CHECK-MSC-17: "-fms-compatibility-version=17"
 
 // RUN: %clang -### -target i686-windows -fms-compatibility -fmsc-version=1600 -E - </dev/null -o /dev/null 2>&1 | FileCheck %s -check-prefix CHECK-MSC-16
 





More information about the cfe-commits mailing list