Index: include/clang/Basic/TargetOptions.h =================================================================== --- include/clang/Basic/TargetOptions.h +++ include/clang/Basic/TargetOptions.h @@ -45,6 +45,8 @@ /// The list of target specific features to enable or disable -- this should /// be a list of strings starting with by '+' or '-'. std::vector Features; + + std::vector Reciprocals; }; } // end namespace clang Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -1323,6 +1323,8 @@ def mno_implicit_float : Flag<["-"], "mno-implicit-float">, Group, HelpText<"Don't generate implicit floating point instructions">; def mimplicit_float : Flag<["-"], "mimplicit-float">, Group; +def mrecip : Flag<["-"], "mrecip">, Group; +def mrecip_EQ : CommaJoined<["-"], "mrecip=">, Group, Flags<[CC1Option]>; def msse2 : Flag<["-"], "msse2">, Group; def msse3 : Flag<["-"], "msse3">, Group; def msse4a : Flag<["-"], "msse4a">, Group; Index: lib/CodeGen/BackendUtil.cpp =================================================================== --- lib/CodeGen/BackendUtil.cpp +++ lib/CodeGen/BackendUtil.cpp @@ -470,6 +470,9 @@ llvm::TargetOptions Options; + if (!TargetOpts.Reciprocals.empty()) + Options.Reciprocals = TargetRecip(TargetOpts.Reciprocals); + Options.ThreadModel = llvm::StringSwitch(CodeGenOpts.ThreadModel) .Case("posix", llvm::ThreadModel::POSIX) Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -1588,6 +1588,101 @@ 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. +static bool hasRefinementStepOrNot(const StringRef &In) { + const char REF_STEP_TOKEN = '.'; + size_t Position = In.find(REF_STEP_TOKEN); + if (Position == std::string::npos) + return true; + + StringRef RefStepString = In.substr(Position + 1); + // Allow exactly one numeric character for the additional refinement + // step parameter. + if (RefStepString.size() != 1) + return false; + char RefStepChar = RefStepString[0]; + if (RefStepChar < '0' || RefStepChar > '9') + return false; + return true; +} + +/// The -mrecip flag requires processing of many optional parameters. +static void ParseMRecip(const Driver &D, const ArgList &Args, + ArgStringList &Features) { + Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ); + if (!A) + return; + + const char *OptionStrings[] = { + "divf", + "vec-divf", + "sqrtf", + "vec-sqrtf", + "divd", + "vec-divd", + "sqrtd", + "vec-sqrtd" + }; + + unsigned NumOptions = A->getNumValues(); + unsigned NumStrings = llvm::array_lengthof(OptionStrings); + + if (NumOptions > NumStrings) { + D.Diag(diag::err_drv_argument_not_allowed_with) + << A->getOption().getName() << "Too many options specified."; + } + + // No option is the same as "all". + if (NumOptions == 0) { + Features.push_back(Args.MakeArgString("-mrecip=all")); + return; + } + + // Pass through "all", "none", or "default" with an optional refinement step. + if (NumOptions == 1) { + StringRef Val = A->getValue(0); + if (Val.startswith("all") || + Val.startswith("none") || + Val.startswith("default")) { + if (hasRefinementStepOrNot(Val)) { + Features.push_back(Args.MakeArgString("-mrecip=" + 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. + StringRef Out = "-mrecip="; + for (unsigned i = 0; i != NumOptions; ++i) { + StringRef Val = A->getValue(i); + // Ignore the '-' or optional '+' in string comparison. + bool IsNegative = (Val[0] == '-'); + if (IsNegative) + Val = Val.substr(1); + else if (Val[0] == '+') + Val = Val.substr(1); + bool Found = false; + for (unsigned j = 0; j != NumStrings; ++j) { + if (Val.startswith(OptionStrings[j]) && hasRefinementStepOrNot(Val)) { + StringRef Prefix = IsNegative ? "-" : "+"; + Out = Args.MakeArgString(Out + Prefix + Val); + Found = true; + break; + } + } + if (!Found) { + D.Diag(diag::err_drv_unsupported_option_argument) << + A->getOption().getName() << Val; + } + if (i != NumOptions - 1) + Out = Args.MakeArgString(Out + ","); + } + Features.push_back(Args.MakeArgString(Out)); +} + static void getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, std::vector &Features) { @@ -3104,6 +3199,8 @@ 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: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -1823,7 +1823,7 @@ 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(); Index: test/Driver/mrecip.c =================================================================== --- test/Driver/mrecip.c +++ test/Driver/mrecip.c @@ -0,0 +1,56 @@ +//// +//// 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 individual option types. + +// RUN: %clang -### -S %s -mrecip=vec-sqrtd 2>&1 | FileCheck --check-prefix=RECIP4 %s +// RECIP4: "-mrecip=+vec-sqrtd" + +// RUN: %clang -### -S %s -mrecip=-divf 2>&1 | FileCheck --check-prefix=RECIP5 %s +// RECIP5: "-mrecip=-divf" + +// RUN: %clang -### -S %s -mrecip=divf,sqrtd,vec-divd,vec-sqrtf 2>&1 | FileCheck --check-prefix=RECIP6 %s +// RECIP6: "-mrecip=+divf,+sqrtd,+vec-divd,+vec-sqrtf" + +//// Check optional refinement step specifiers. + +// RUN: %clang -### -S %s -mrecip=all.1 2>&1 | FileCheck --check-prefix=RECIP7 %s +// RECIP7: "-mrecip=all.1" + +// RUN: %clang -### -S %s -mrecip=sqrtf.3 2>&1 | FileCheck --check-prefix=RECIP8 %s +// RECIP8: "-mrecip=+sqrtf.3" + +// RUN: %clang -### -S %s -mrecip=divd.1,sqrtf.2,vec-divf.9,vec-sqrtd.0 2>&1 | FileCheck --check-prefix=RECIP9 %s +// RECIP9: "-mrecip=+divd.1,+sqrtf.2,+vec-divf.9,+vec-sqrtd.0" + +//// Check invalid parameters. + +// RUN: %clang -### -S %s -mrecip=divf,divf,divf,divf,divf,divf,divf,divf,divf 2>&1 | FileCheck --check-prefix=RECIP10 %s +// RECIP10: error: invalid argument + +// RUN: %clang -### -S %s -mrecip=+default.10 2>&1 | FileCheck --check-prefix=RECIP11 %s +// RECIP11: error: unsupported argument + +// RUN: %clang -### -S %s -mrecip=-vec-divd. 2>&1 | FileCheck --check-prefix=RECIP12 %s +// RECIP12: error: unsupported argument + +// RUN: %clang -### -S %s -mrecip=bogus 2>&1 | FileCheck --check-prefix=RECIP13 %s +// RECIP13: error: unsupported argument +