]> granicus.if.org Git - clang/commitdiff
add the -mrecip driver flag and process its options (2nd try)
authorSanjay Patel <spatel@rotateright.com>
Tue, 2 Jun 2015 16:55:12 +0000 (16:55 +0000)
committerSanjay Patel <spatel@rotateright.com>
Tue, 2 Jun 2015 16:55:12 +0000 (16:55 +0000)
The first try to land this (r238055) was reverted due to bot failures
caused by the LLVM part of the patch. That was hopefully fixed by r238788,
and the LLVM patch was resubmitted at r238842.

This is the front-end counterpart to D8982.

The -mrecip option interface is based on maintaining compatibility with gcc:
https://gcc.gnu.org/onlinedocs/gcc-4.9.2/gcc/i386-and-x86-64-Options.html#index-mrecip_003dopt-1627
https://gcc.gnu.org/onlinedocs/gcc-4.9.2/gcc/RS_002f6000-and-PowerPC-Options.html#index-mrecip-2289

...while adding more functionality (allowing users to specify the number of refinement steps for each
estimate type).

Differential Revision: http://reviews.llvm.org/D8989

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

include/clang/Basic/TargetOptions.h
include/clang/Driver/Options.td
lib/CodeGen/BackendUtil.cpp
lib/Driver/Tools.cpp
lib/Frontend/CompilerInvocation.cpp
test/Driver/mrecip.c [new file with mode: 0644]

index 97825394202f9d3311e31ae52a5576c73ae5e1b7..ca0cca78bfc8e3fd9ad58bf7d930d6504a4cacbc 100644 (file)
@@ -45,6 +45,8 @@ public:
   /// The list of target specific features to enable or disable -- this should
   /// be a list of strings starting with by '+' or '-'.
   std::vector<std::string> Features;
+  
+  std::vector<std::string> Reciprocals;
 };
 
 }  // end namespace clang
index 7e39a9ae5b22e50f8f38864239842b5f10e62627..3ec5282518fed3e36564d6a47d505d97d540a412 100644 (file)
@@ -1338,6 +1338,8 @@ def msoft_float : Flag<["-"], "msoft-float">, Group<m_Group>, Flags<[CC1Option]>
 def mno_implicit_float : Flag<["-"], "mno-implicit-float">, Group<m_Group>,
   HelpText<"Don't generate implicit floating point instructions">;
 def mimplicit_float : Flag<["-"], "mimplicit-float">, Group<m_Group>;
+def mrecip : Flag<["-"], "mrecip">, Group<m_Group>;
+def mrecip_EQ : CommaJoined<["-"], "mrecip=">, Group<m_Group>, Flags<[CC1Option]>;
 def msse2 : Flag<["-"], "msse2">, Group<m_x86_Features_Group>;
 def msse3 : Flag<["-"], "msse3">, Group<m_x86_Features_Group>;
 def msse4a : Flag<["-"], "msse4a">, Group<m_x86_Features_Group>;
index 7f0c7bafc04678d96e09ce995a5041937fe479a8..672bf027ae576e9a05b0ecf8acb9b33b7ec6bdc9 100644 (file)
@@ -33,6 +33,7 @@
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Target/TargetMachine.h"
 #include "llvm/Target/TargetOptions.h"
+#include "llvm/Target/TargetRecip.h"
 #include "llvm/Target/TargetSubtargetInfo.h"
 #include "llvm/Transforms/IPO.h"
 #include "llvm/Transforms/IPO/PassManagerBuilder.h"
@@ -480,6 +481,9 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
 
   llvm::TargetOptions Options;
 
+  if (!TargetOpts.Reciprocals.empty())
+    Options.Reciprocals = TargetRecip(TargetOpts.Reciprocals);
+
   Options.ThreadModel =
     llvm::StringSwitch<llvm::ThreadModel::Model>(CodeGenOpts.ThreadModel)
       .Case("posix", llvm::ThreadModel::POSIX)
index 1dcb7596aefd129539745bac201566afb57ed29d..6f3f8f02c1f5c07c4246ea0c78126cd2a7b2a4b5 100644 (file)
@@ -1631,6 +1631,138 @@ static void AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args,
     CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=mcpu=") + CPU));
 }
 
+/// This is a helper function for validating the optional refinement step
+/// parameter in reciprocal argument strings. Return false if there is an error
+/// parsing the refinement step. Otherwise, return true and set the Position
+/// of the refinement step in the input string.
+static bool getRefinementStep(const StringRef &In, const Driver &D,
+                                const Arg &A, size_t &Position) {
+  const char RefinementStepToken = ':';
+  Position = In.find(RefinementStepToken);
+  if (Position != StringRef::npos) {
+    StringRef Option = A.getOption().getName();
+    StringRef RefStep = In.substr(Position + 1);
+    // Allow exactly one numeric character for the additional refinement
+    // step parameter. This is reasonable for all currently-supported
+    // operations and architectures because we would expect that a larger value
+    // of refinement steps would cause the estimate "optimization" to
+    // under-perform the native operation. Also, if the estimate does not
+    // converge quickly, it probably will not ever converge, so further
+    // refinement steps will not produce a better answer.
+    if (RefStep.size() != 1) {
+      D.Diag(diag::err_drv_invalid_value) << Option << RefStep;
+      return false;
+    }
+    char RefStepChar = RefStep[0];
+    if (RefStepChar < '0' || RefStepChar > '9') {
+      D.Diag(diag::err_drv_invalid_value) << Option << RefStep;
+      return false;
+    }
+  }
+  return true;
+}
+
+/// The -mrecip flag requires processing of many optional parameters.
+static void ParseMRecip(const Driver &D, const ArgList &Args,
+                        ArgStringList &OutStrings) {
+  static const char DisabledPrefixIn = '!';
+  static const char DisabledPrefixOut = '!';
+  static const char EnabledPrefixOut = '\0';
+  StringRef Out = "-mrecip=";
+
+  Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ);
+  if (!A)
+    return;
+
+  unsigned NumOptions = A->getNumValues();
+  if (NumOptions == 0) {
+    // No option is the same as "all".
+    OutStrings.push_back(Args.MakeArgString(Out + "all"));
+    return;
+  }
+
+  // Pass through "all", "none", or "default" with an optional refinement step.
+  if (NumOptions == 1) {
+    StringRef Val = A->getValue(0);
+    size_t RefStepLoc;
+    if (!getRefinementStep(Val, D, *A, RefStepLoc))
+      return;
+    StringRef ValBase = Val.slice(0, RefStepLoc);
+    if (ValBase == "all" || ValBase == "none" || ValBase == "default") {
+      OutStrings.push_back(Args.MakeArgString(Out + Val));
+      return;
+    }
+  }
+
+  // Each reciprocal type may be enabled or disabled individually.
+  // Check each input value for validity, concatenate them all back together,
+  // and pass through.
+
+  llvm::StringMap<bool> OptionStrings;
+  OptionStrings.insert(std::make_pair("divd",       false));
+  OptionStrings.insert(std::make_pair("divf",       false));
+  OptionStrings.insert(std::make_pair("vec-divd",   false));
+  OptionStrings.insert(std::make_pair("vec-divf",   false));
+  OptionStrings.insert(std::make_pair("sqrtd",      false));
+  OptionStrings.insert(std::make_pair("sqrtf",      false));
+  OptionStrings.insert(std::make_pair("vec-sqrtd",  false));
+  OptionStrings.insert(std::make_pair("vec-sqrtf",  false));
+
+  for (unsigned i = 0; i != NumOptions; ++i) {
+    StringRef Val = A->getValue(i);
+
+    bool IsDisabled = Val[0] == DisabledPrefixIn;
+    // Ignore the disablement token for string matching.
+    if (IsDisabled)
+      Val = Val.substr(1);
+
+    size_t RefStep;
+    if (!getRefinementStep(Val, D, *A, RefStep))
+      return;
+
+    StringRef ValBase = Val.slice(0, RefStep);
+    llvm::StringMap<bool>::iterator OptionIter = OptionStrings.find(ValBase);
+    if (OptionIter == OptionStrings.end()) {
+      // Try again specifying float suffix.
+      OptionIter = OptionStrings.find(ValBase.str() + 'f');
+      if (OptionIter == OptionStrings.end()) {
+        // The input name did not match any known option string.
+        D.Diag(diag::err_drv_unknown_argument) << Val;
+        return;
+      }
+      // The option was specified without a float or double suffix.
+      // Make sure that the double entry was not already specified.
+      // The float entry will be checked below.
+      if (OptionStrings[ValBase.str() + 'd']) {
+        D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Val;
+        return;
+      }
+    }
+    
+    if (OptionIter->second == true) {
+      // Duplicate option specified.
+      D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Val;
+      return;
+    }
+
+    // Mark the matched option as found. Do not allow duplicate specifiers.
+    OptionIter->second = true;
+
+    // If the precision was not specified, also mark the double entry as found.
+    if (ValBase.back() != 'f' && ValBase.back() != 'd')
+      OptionStrings[ValBase.str() + 'd'] = true;
+
+    // Build the output string.
+    const char *Prefix = IsDisabled ?
+      &DisabledPrefixOut : &EnabledPrefixOut;
+    Out = Args.MakeArgString(Out + Prefix + Val);
+    if (i != NumOptions - 1)
+      Out = Args.MakeArgString(Out + ",");
+  }
+
+  OutStrings.push_back(Args.MakeArgString(Out));
+}
+
 static void getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
                                  const ArgList &Args,
                                  std::vector<const char *> &Features) {
@@ -3192,6 +3324,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
       CmdArgs.push_back(Args.MakeArgString("-ffp-contract=fast"));
     }
   }
+  
+  ParseMRecip(getToolChain().getDriver(), Args, CmdArgs);
 
   // We separately look for the '-ffast-math' and '-ffinite-math-only' flags,
   // and if we find them, tell the frontend to provide the appropriate
index 948576759ed401db3b6b6e061a89bf8384a5f4a3..802612cae31f2c47d1aabd8240e992a8d07bce96 100644 (file)
@@ -1846,7 +1846,7 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) {
   Opts.FeaturesAsWritten = Args.getAllArgValues(OPT_target_feature);
   Opts.LinkerVersion = Args.getLastArgValue(OPT_target_linker_version);
   Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple));
-
+  Opts.Reciprocals = Args.getAllArgValues(OPT_mrecip_EQ);
   // Use the default target triple if unspecified.
   if (Opts.Triple.empty())
     Opts.Triple = llvm::sys::getDefaultTargetTriple();
diff --git a/test/Driver/mrecip.c b/test/Driver/mrecip.c
new file mode 100644 (file)
index 0000000..4e99b15
--- /dev/null
@@ -0,0 +1,70 @@
+////
+//// Verify that valid options for the -mrecip flag are passed through and invalid options cause an error.
+////
+
+//// If there are no options, convert to 'all'.
+
+// RUN: %clang -### -S %s -mrecip  2>&1 | FileCheck --check-prefix=RECIP0 %s
+// RECIP0: "-mrecip=all"
+
+//// Check options that cover all types.
+
+// RUN: %clang -### -S %s -mrecip=all  2>&1 | FileCheck --check-prefix=RECIP1 %s
+// RECIP1: "-mrecip=all"
+
+// RUN: %clang -### -S %s -mrecip=default  2>&1 | FileCheck --check-prefix=RECIP2 %s
+// RECIP2: "-mrecip=default"
+
+// RUN: %clang -### -S %s -mrecip=none  2>&1 | FileCheck --check-prefix=RECIP3 %s
+// RECIP3: "-mrecip=none"
+
+//// Check options that do not specify float or double.
+
+// RUN: %clang -### -S %s -mrecip=vec-sqrt  2>&1 | FileCheck --check-prefix=RECIP4 %s
+// RECIP4: "-mrecip=vec-sqrt"
+
+// RUN: %clang -### -S %s -mrecip=!div,vec-div  2>&1 | FileCheck --check-prefix=RECIP5 %s
+// RECIP5: "-mrecip=!div,vec-div"
+
+//// Check individual option types.
+
+// RUN: %clang -### -S %s -mrecip=vec-sqrtd  2>&1 | FileCheck --check-prefix=RECIP6 %s
+// RECIP6: "-mrecip=vec-sqrtd"
+
+// RUN: %clang -### -S %s -mrecip=!divf  2>&1 | FileCheck --check-prefix=RECIP7 %s
+// RECIP7: "-mrecip=!divf"
+
+// RUN: %clang -### -S %s -mrecip=divf,sqrtd,vec-divd,vec-sqrtf  2>&1 | FileCheck --check-prefix=RECIP8 %s
+// RECIP8: "-mrecip=divf,sqrtd,vec-divd,vec-sqrtf"
+
+//// Check optional refinement step specifiers.
+
+// RUN: %clang -### -S %s -mrecip=all:1  2>&1 | FileCheck --check-prefix=RECIP9 %s
+// RECIP9: "-mrecip=all:1"
+
+// RUN: %clang -### -S %s -mrecip=sqrtf:3  2>&1 | FileCheck --check-prefix=RECIP10 %s
+// RECIP10: "-mrecip=sqrtf:3"
+
+// RUN: %clang -### -S %s -mrecip=div:5  2>&1 | FileCheck --check-prefix=RECIP11 %s
+// RECIP11: "-mrecip=div:5"
+
+// RUN: %clang -### -S %s -mrecip=divd:1,!sqrtf:2,vec-divf:9,vec-sqrtd:0  2>&1 | FileCheck --check-prefix=RECIP12 %s
+// RECIP12: "-mrecip=divd:1,!sqrtf:2,vec-divf:9,vec-sqrtd:0"
+
+//// Check invalid parameters.
+
+// RUN: %clang -### -S %s -mrecip=bogus  2>&1 | FileCheck --check-prefix=RECIP13 %s
+// RECIP13: error: unknown argument
+
+// RUN: %clang -### -S %s -mrecip=divd:1,divd  2>&1 | FileCheck --check-prefix=RECIP14 %s
+// RECIP14: error: invalid value 
+
+// RUN: %clang -### -S %s -mrecip=sqrt,sqrtf  2>&1 | FileCheck --check-prefix=RECIP15 %s
+// RECIP15: error: invalid value 
+
+// RUN: %clang -### -S %s -mrecip=+default:10  2>&1 | FileCheck --check-prefix=RECIP16 %s
+// RECIP16: error: invalid value 
+
+// RUN: %clang -### -S %s -mrecip=!vec-divd:  2>&1 | FileCheck --check-prefix=RECIP17 %s
+// RECIP17: error: invalid value 
+