[flang-commits] [flang] cde1035 - [flang] Add support for -mrecip[=<list>] (#143418)
via flang-commits
flang-commits at lists.llvm.org
Tue Jun 10 07:25:37 PDT 2025
Author: Cameron McInally
Date: 2025-06-10T08:25:33-06:00
New Revision: cde1035a2fc6d472168ce6c6e117f16c76c5bbc4
URL: https://github.com/llvm/llvm-project/commit/cde1035a2fc6d472168ce6c6e117f16c76c5bbc4
DIFF: https://github.com/llvm/llvm-project/commit/cde1035a2fc6d472168ce6c6e117f16c76c5bbc4.diff
LOG: [flang] Add support for -mrecip[=<list>] (#143418)
This patch adds support for the -mrecip command line option. The parsing
of this options is equivalent to Clang's and it is implemented by
setting the "reciprocal-estimates" function attribute.
Also move the ParseMRecip(...) function to CommonArgs, so that Flang is
able to make use of it as well.
---------
Co-authored-by: Cameron McInally <cmcinally at nvidia.com>
Added:
flang/test/Driver/mrecip.f90
mlir/test/Target/LLVMIR/Import/mrecip.ll
mlir/test/Target/LLVMIR/mrecip.mlir
Modified:
clang/include/clang/Driver/CommonArgs.h
clang/include/clang/Driver/Options.td
clang/lib/Driver/ToolChains/Clang.cpp
clang/lib/Driver/ToolChains/CommonArgs.cpp
clang/lib/Driver/ToolChains/Flang.cpp
flang/include/flang/Frontend/CodeGenOptions.h
flang/include/flang/Optimizer/Transforms/Passes.td
flang/include/flang/Tools/CrossToolHelpers.h
flang/lib/Frontend/CompilerInvocation.cpp
flang/lib/Frontend/FrontendActions.cpp
flang/lib/Optimizer/Passes/Pipelines.cpp
flang/lib/Optimizer/Transforms/FunctionAttr.cpp
mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
mlir/lib/Target/LLVMIR/ModuleImport.cpp
mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Driver/CommonArgs.h b/clang/include/clang/Driver/CommonArgs.h
index 59b68030a4d65..ddb21c1e8a8b8 100644
--- a/clang/include/clang/Driver/CommonArgs.h
+++ b/clang/include/clang/Driver/CommonArgs.h
@@ -273,9 +273,14 @@ void handleVectorizeSLPArgs(const llvm::opt::ArgList &Args,
// Parse -mprefer-vector-width=. Return the Value string if well-formed.
// Otherwise, return an empty string and issue a diagnosic message if needed.
-StringRef ParseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags,
+StringRef parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags,
const llvm::opt::ArgList &Args);
+// Parse -mrecip. Return the Value string if well-formed.
+// Otherwise, return an empty string and issue a diagnosic message if needed.
+StringRef parseMRecipOption(clang::DiagnosticsEngine &Diags,
+ const llvm::opt::ArgList &Args);
+
} // end namespace tools
} // end namespace driver
} // end namespace clang
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 834aa708f5051..66d3dc921816d 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -5477,9 +5477,10 @@ def mno_implicit_float : Flag<["-"], "mno-implicit-float">, Group<m_Group>,
HelpText<"Don't generate implicit floating point or vector instructions">;
def mimplicit_float : Flag<["-"], "mimplicit-float">, Group<m_Group>;
def mrecip : Flag<["-"], "mrecip">, Group<m_Group>,
+ Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
HelpText<"Equivalent to '-mrecip=all'">;
def mrecip_EQ : CommaJoined<["-"], "mrecip=">, Group<m_Group>,
- Visibility<[ClangOption, CC1Option]>,
+ Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
HelpText<"Control use of approximate reciprocal and reciprocal square root instructions followed by <n> iterations of "
"Newton-Raphson refinement. "
"<value> = ( ['!'] ['vec-'] ('rcp'|'sqrt') [('h'|'s'|'d')] [':'<n>] ) | 'all' | 'default' | 'none'">,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index a3ca55e138ca2..2d676aa0b9c8e 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -125,145 +125,6 @@ forAllAssociatedToolChains(Compilation &C, const JobAction &JA,
//
}
-/// 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(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) {
- StringRef DisabledPrefixIn = "!";
- StringRef DisabledPrefixOut = "!";
- StringRef EnabledPrefixOut = "";
- 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("divh", false));
- OptionStrings.insert(std::make_pair("vec-divd", false));
- OptionStrings.insert(std::make_pair("vec-divf", false));
- OptionStrings.insert(std::make_pair("vec-divh", false));
- OptionStrings.insert(std::make_pair("sqrtd", false));
- OptionStrings.insert(std::make_pair("sqrtf", false));
- OptionStrings.insert(std::make_pair("sqrth", false));
- OptionStrings.insert(std::make_pair("vec-sqrtd", false));
- OptionStrings.insert(std::make_pair("vec-sqrtf", false));
- OptionStrings.insert(std::make_pair("vec-sqrth", false));
-
- for (unsigned i = 0; i != NumOptions; ++i) {
- StringRef Val = A->getValue(i);
-
- bool IsDisabled = Val.starts_with(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 half or float or double suffix.
- // Make sure that the double or half entry was not already specified.
- // The float entry will be checked below.
- if (OptionStrings[ValBase.str() + 'd'] ||
- OptionStrings[ValBase.str() + 'h']) {
- 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 and half entry
- // as found.
- if (ValBase.back() != 'f' && ValBase.back() != 'd' && ValBase.back() != 'h') {
- OptionStrings[ValBase.str() + 'd'] = true;
- OptionStrings[ValBase.str() + 'h'] = true;
- }
-
- // Build the output string.
- StringRef 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 bool
shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime,
const llvm::Triple &Triple) {
@@ -3490,7 +3351,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
CmdArgs.push_back(Args.MakeArgString("-fbfloat16-excess-precision=" +
BFloat16ExcessPrecision));
- ParseMRecip(D, Args, CmdArgs);
+ StringRef Recip = parseMRecipOption(D.getDiags(), Args);
+ if (!Recip.empty())
+ CmdArgs.push_back(Args.MakeArgString("-mrecip=" + Recip));
// -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the
// individual features enabled by -ffast-math instead of the option itself as
@@ -7588,7 +7451,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
handleVectorizeLoopsArgs(Args, CmdArgs);
handleVectorizeSLPArgs(Args, CmdArgs);
- StringRef VecWidth = ParseMPreferVectorWidthOption(D.getDiags(), Args);
+ StringRef VecWidth = parseMPreferVectorWidthOption(D.getDiags(), Args);
if (!VecWidth.empty())
CmdArgs.push_back(Args.MakeArgString("-mprefer-vector-width=" + VecWidth));
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 02b6e23835486..d5b2c5c1e199e 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -3170,7 +3170,7 @@ void tools::handleInterchangeLoopsArgs(const ArgList &Args,
// Parse -mprefer-vector-width=. Return the Value string if well-formed.
// Otherwise, return an empty string and issue a diagnosic message if needed.
-StringRef tools::ParseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags,
+StringRef tools::parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags,
const llvm::opt::ArgList &Args) {
Arg *A = Args.getLastArg(clang::driver::options::OPT_mprefer_vector_width_EQ);
if (!A)
@@ -3189,3 +3189,144 @@ StringRef tools::ParseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags,
return Value;
}
+
+// 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(StringRef In, clang::DiagnosticsEngine &Diags,
+ 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) {
+ Diags.Report(diag::err_drv_invalid_value) << Option << RefStep;
+ return false;
+ }
+ char RefStepChar = RefStep[0];
+ if (RefStepChar < '0' || RefStepChar > '9') {
+ Diags.Report(diag::err_drv_invalid_value) << Option << RefStep;
+ return false;
+ }
+ }
+ return true;
+}
+
+// Parse -mrecip. Return the Value string if well-formed.
+// Otherwise, return an empty string and issue a diagnosic message if needed.
+StringRef tools::parseMRecipOption(clang::DiagnosticsEngine &Diags,
+ const ArgList &Args) {
+ StringRef DisabledPrefixIn = "!";
+ StringRef DisabledPrefixOut = "!";
+ StringRef EnabledPrefixOut = "";
+ StringRef Out = "";
+
+ 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".
+ return "all";
+ }
+
+ // 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, Diags, *A, RefStepLoc))
+ return "";
+ StringRef ValBase = Val.slice(0, RefStepLoc);
+ if (ValBase == "all" || ValBase == "none" || ValBase == "default") {
+ return Val;
+ }
+ }
+
+ // 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("divh", false));
+ OptionStrings.insert(std::make_pair("vec-divd", false));
+ OptionStrings.insert(std::make_pair("vec-divf", false));
+ OptionStrings.insert(std::make_pair("vec-divh", false));
+ OptionStrings.insert(std::make_pair("sqrtd", false));
+ OptionStrings.insert(std::make_pair("sqrtf", false));
+ OptionStrings.insert(std::make_pair("sqrth", false));
+ OptionStrings.insert(std::make_pair("vec-sqrtd", false));
+ OptionStrings.insert(std::make_pair("vec-sqrtf", false));
+ OptionStrings.insert(std::make_pair("vec-sqrth", false));
+
+ for (unsigned i = 0; i != NumOptions; ++i) {
+ StringRef Val = A->getValue(i);
+
+ bool IsDisabled = Val.starts_with(DisabledPrefixIn);
+ // Ignore the disablement token for string matching.
+ if (IsDisabled)
+ Val = Val.substr(1);
+
+ size_t RefStep;
+ if (!getRefinementStep(Val, Diags, *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.
+ Diags.Report(diag::err_drv_unknown_argument) << Val;
+ return "";
+ }
+ // The option was specified without a half or float or double suffix.
+ // Make sure that the double or half entry was not already specified.
+ // The float entry will be checked below.
+ if (OptionStrings[ValBase.str() + 'd'] ||
+ OptionStrings[ValBase.str() + 'h']) {
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getOption().getName() << Val;
+ return "";
+ }
+ }
+
+ if (OptionIter->second == true) {
+ // Duplicate option specified.
+ Diags.Report(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 and half entry
+ // as found.
+ if (ValBase.back() != 'f' && ValBase.back() != 'd' &&
+ ValBase.back() != 'h') {
+ OptionStrings[ValBase.str() + 'd'] = true;
+ OptionStrings[ValBase.str() + 'h'] = true;
+ }
+
+ // Build the output string.
+ StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut;
+ Out = Args.MakeArgString(Out + Prefix + Val);
+ if (i != NumOptions - 1)
+ Out = Args.MakeArgString(Out + ",");
+ }
+
+ return Out;
+}
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index e0a366bfb9225..a20879dad94d4 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -695,6 +695,10 @@ static void addFloatingPointOptions(const Driver &D, const ArgList &Args,
A->claim();
}
+ StringRef Recip = parseMRecipOption(D.getDiags(), Args);
+ if (!Recip.empty())
+ CmdArgs.push_back(Args.MakeArgString("-mrecip=" + Recip));
+
if (!HonorINFs && !HonorNaNs && AssociativeMath && ReciprocalMath &&
ApproxFunc && !SignedZeros &&
(FPContract == "fast" || FPContract.empty())) {
diff --git a/flang/include/flang/Frontend/CodeGenOptions.h b/flang/include/flang/Frontend/CodeGenOptions.h
index 61e56e51c4bbb..e939f10f3c3e7 100644
--- a/flang/include/flang/Frontend/CodeGenOptions.h
+++ b/flang/include/flang/Frontend/CodeGenOptions.h
@@ -53,9 +53,12 @@ class CodeGenOptions : public CodeGenOptionsBase {
/// The paths to the pass plugins that were registered using -fpass-plugin.
std::vector<std::string> LLVMPassPlugins;
- // The prefered vector width, if requested by -mprefer-vector-width.
+ /// The prefered vector width, if requested by -mprefer-vector-width.
std::string PreferVectorWidth;
+ /// List of reciprocal estimate sub-options.
+ std::string Reciprocals;
+
/// List of filenames passed in using the -fembed-offload-object option. These
/// are offloading binaries containing device images and metadata.
std::vector<std::string> OffloadObjects;
diff --git a/flang/include/flang/Optimizer/Transforms/Passes.td b/flang/include/flang/Optimizer/Transforms/Passes.td
index 1b1970412676d..34842f9785942 100644
--- a/flang/include/flang/Optimizer/Transforms/Passes.td
+++ b/flang/include/flang/Optimizer/Transforms/Passes.td
@@ -429,6 +429,9 @@ def FunctionAttr : Pass<"function-attr", "mlir::func::FuncOp"> {
"module.">,
Option<"unsafeFPMath", "unsafe-fp-math", "bool", /*default=*/"false",
"Set the unsafe-fp-math attribute on functions in the module.">,
+ Option<"reciprocals", "mrecip", "std::string", /*default=*/"",
+ "Set the reciprocal-estimates attribute on functions in the "
+ "module.">,
Option<"preferVectorWidth", "prefer-vector-width", "std::string",
/*default=*/"",
"Set the prefer-vector-width attribute on functions in the "
diff --git a/flang/include/flang/Tools/CrossToolHelpers.h b/flang/include/flang/Tools/CrossToolHelpers.h
index 058024a4a04c5..337685c82af5f 100644
--- a/flang/include/flang/Tools/CrossToolHelpers.h
+++ b/flang/include/flang/Tools/CrossToolHelpers.h
@@ -102,6 +102,7 @@ struct MLIRToLLVMPassPipelineConfig : public FlangEPCallBacks {
UnsafeFPMath = mathOpts.getAssociativeMath() &&
mathOpts.getReciprocalMath() && NoSignedZerosFPMath &&
ApproxFuncFPMath && mathOpts.getFPContractEnabled();
+ Reciprocals = opts.Reciprocals;
PreferVectorWidth = opts.PreferVectorWidth;
if (opts.InstrumentFunctions) {
InstrumentFunctionEntry = "__cyg_profile_func_enter";
@@ -127,6 +128,8 @@ struct MLIRToLLVMPassPipelineConfig : public FlangEPCallBacks {
bool NoSignedZerosFPMath =
false; ///< Set no-signed-zeros-fp-math attribute for functions.
bool UnsafeFPMath = false; ///< Set unsafe-fp-math attribute for functions.
+ std::string Reciprocals = ""; ///< Set reciprocal-estimate attribute for
+ ///< functions.
std::string PreferVectorWidth = ""; ///< Set prefer-vector-width attribute for
///< functions.
bool NSWOnLoopVarInc = true; ///< Add nsw flag to loop variable increments.
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index 5e156b480faf5..15bcff254756e 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -307,8 +307,10 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts,
for (auto *a : args.filtered(clang::driver::options::OPT_fpass_plugin_EQ))
opts.LLVMPassPlugins.push_back(a->getValue());
+ opts.Reciprocals = clang::driver::tools::parseMRecipOption(diags, args);
+
opts.PreferVectorWidth =
- clang::driver::tools::ParseMPreferVectorWidthOption(diags, args);
+ clang::driver::tools::parseMPreferVectorWidthOption(diags, args);
// -fembed-offload-object option
for (auto *a :
diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index 012d0fdfe645f..1c8a419188b89 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -741,6 +741,7 @@ void CodeGenAction::generateLLVMIR() {
config.VScaleMax = vsr->second;
}
+ config.Reciprocals = opts.Reciprocals;
config.PreferVectorWidth = opts.PreferVectorWidth;
if (ci.getInvocation().getFrontendOpts().features.IsEnabled(
diff --git a/flang/lib/Optimizer/Passes/Pipelines.cpp b/flang/lib/Optimizer/Passes/Pipelines.cpp
index c28c8dd1730b0..70f57bdeddd3f 100644
--- a/flang/lib/Optimizer/Passes/Pipelines.cpp
+++ b/flang/lib/Optimizer/Passes/Pipelines.cpp
@@ -369,7 +369,8 @@ void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm,
{framePointerKind, config.InstrumentFunctionEntry,
config.InstrumentFunctionExit, config.NoInfsFPMath, config.NoNaNsFPMath,
config.ApproxFuncFPMath, config.NoSignedZerosFPMath, config.UnsafeFPMath,
- config.PreferVectorWidth, /*tuneCPU=*/"", setNoCapture, setNoAlias}));
+ config.Reciprocals, config.PreferVectorWidth, /*tuneCPU=*/"",
+ setNoCapture, setNoAlias}));
if (config.EnableOpenMP) {
pm.addNestedPass<mlir::func::FuncOp>(
diff --git a/flang/lib/Optimizer/Transforms/FunctionAttr.cpp b/flang/lib/Optimizer/Transforms/FunctionAttr.cpp
index 041aa8717d20e..5ac4ed8a93b6b 100644
--- a/flang/lib/Optimizer/Transforms/FunctionAttr.cpp
+++ b/flang/lib/Optimizer/Transforms/FunctionAttr.cpp
@@ -107,6 +107,10 @@ void FunctionAttrPass::runOnOperation() {
func->setAttr(
mlir::LLVM::LLVMFuncOp::getUnsafeFpMathAttrName(llvmFuncOpName),
mlir::BoolAttr::get(context, true));
+ if (!reciprocals.empty())
+ func->setAttr(
+ mlir::LLVM::LLVMFuncOp::getReciprocalEstimatesAttrName(llvmFuncOpName),
+ mlir::StringAttr::get(context, reciprocals));
if (!preferVectorWidth.empty())
func->setAttr(
mlir::LLVM::LLVMFuncOp::getPreferVectorWidthAttrName(llvmFuncOpName),
diff --git a/flang/test/Driver/mrecip.f90 b/flang/test/Driver/mrecip.f90
new file mode 100644
index 0000000000000..aed7cfad4c2a7
--- /dev/null
+++ b/flang/test/Driver/mrecip.f90
@@ -0,0 +1,52 @@
+! Test that -mrecip[=<list>] works as expected.
+
+! RUN: %flang -### -o - %s 2>&1| FileCheck %s --check-prefixes=CHECK-FLANG,CHECK-FLANG-OMIT
+! RUN: %flang -mrecip -### -o - %s 2>&1| FileCheck %s --check-prefixes=CHECK-FLANG,CHECK-FLANG-NOARG
+! RUN: %flang -mrecip=all -### -o - %s 2>&1| FileCheck %s --check-prefixes=CHECK-FLANG,CHECK-FLANG-ALL
+! RUN: %flang -mrecip=none -### -o - %s 2>&1| FileCheck %s --check-prefixes=CHECK-FLANG,CHECK-FLANG-NONE
+! RUN: %flang -mrecip=default -### -o - %s 2>&1| FileCheck %s --check-prefixes=CHECK-FLANG,CHECK-FLANG-DEF
+! RUN: %flang -mrecip=divd,divf,divh,vec-divd,vec-divf,vec-divh,sqrtd,sqrtf,sqrth,vec-sqrtd,vec-sqrtf,vec-sqrth -### -o - %s 2>&1| FileCheck %s --check-prefixes=CHECK-FLANG,CHECK-FLANG-POS
+! RUN: %flang -mrecip=!divd,!divf,!divh,!vec-divd,!vec-divf,!vec-divh,!sqrtd,!sqrtf,!sqrth,!vec-sqrtd,!vec-sqrtf,!vec-sqrth -### -o - %s 2>&1| FileCheck %s --check-prefixes=CHECK-FLANG,CHECK-FLANG-NEG
+! RUN: %flang -mrecip=!divd,divf,!divh,sqrtd,!sqrtf,sqrth -### -o - %s 2>&1| FileCheck %s --check-prefixes=CHECK-FLANG,CHECK-FLANG-MIX
+! RUN: not %flang -mrecip=xxx -### -o - %s 2>&1| FileCheck %s --check-prefixes=CHECK-FLANG-INV
+! RUN: not %flang -mrecip=divd,divd -### -o - %s 2>&1| FileCheck %s --check-prefixes=CHECK-FLANG-DUP
+
+! RUN: %flang_fc1 -emit-llvm -o - %s 2>&1| FileCheck %s --check-prefix=CHECK-FC1-OMIT
+! RUN: %flang_fc1 -mrecip -emit-llvm -o - %s 2>&1| FileCheck %s --check-prefixes=CHECK-FC1,CHECK-FC1-NOARG
+! RUN: %flang_fc1 -mrecip=all -emit-llvm -o - %s 2>&1| FileCheck %s --check-prefixes=CHECK-FC1,CHECK-FC1-ALL
+! RUN: %flang_fc1 -mrecip=none -emit-llvm -o - %s 2>&1| FileCheck %s --check-prefixes=CHECK-FC1,CHECK-FC1-NONE
+! RUN: %flang_fc1 -mrecip=default -emit-llvm -o - %s 2>&1| FileCheck %s --check-prefixes=CHECK-FC1,CHECK-FC1-DEF
+! RUN: %flang_fc1 -mrecip=divd,divf,divh,vec-divd,vec-divf,vec-divh,sqrtd,sqrtf,sqrth,vec-sqrtd,vec-sqrtf,vec-sqrth -emit-llvm -o - %s 2>&1| FileCheck %s --check-prefixes=CHECK-FC1,CHECK-FC1-POS
+! RUN: %flang_fc1 -mrecip=!divd,!divf,!divh,!vec-divd,!vec-divf,!vec-divh,!sqrtd,!sqrtf,!sqrth,!vec-sqrtd,!vec-sqrtf,!vec-sqrth
+! -emit-llvm -o - %s 2>&1| FileCheck %s --check-prefixes=CHECK-FC1,CHECK-FC1-NEG
+! RUN: %flang_fc1 -mrecip=!divd,divf,!divh,sqrtd,!sqrtf,sqrth -emit-llvm -o - %s 2>&1| FileCheck %s --check-prefixes=CHECK-FC1,CHECK-FC1-MIX
+! RUN: not %flang_fc1 -mrecip=xxx -emit-llvm -o - %s 2>&1| FileCheck %s --check-prefixes=CHECK-FC1-INV
+! RUN: not %flang_fc1 -mrecip=divd,divd -emit-llvm -o - %s 2>&1| FileCheck %s --check-prefixes=CHECK-FC1-DUP
+
+subroutine func
+end subroutine func
+
+! CHECK-FLANG: "-fc1"
+! CHECK-FLANG-OMIT-NOT: "-mrecip="
+! CHECK-FLANG-NOARG-SAME: "-mrecip=all"
+! CHECK-FLANG-ALL-SAME: "-mrecip=all"
+! CHECK-FLANG-NONE-SAME: "-mrecip=none"
+! CHECK-FLANG-DEF-SAME: "-mrecip=default"
+! CHECK-FLANG-POS-SAME: "-mrecip=divd,divf,divh,vec-divd,vec-divf,vec-divh,sqrtd,sqrtf,sqrth,vec-sqrtd,vec-sqrtf,vec-sqrth"
+! CHECK-FLANG-NEG-SAME: "-mrecip=!divd,!divf,!divh,!vec-divd,!vec-divf,!vec-divh,!sqrtd,!sqrtf,!sqrth,!vec-sqrtd,!vec-sqrtf,!vec-sqrth"
+! CHECK-FLANG-MIX-SAME: "-mrecip=!divd,divf,!divh,sqrtd,!sqrtf,sqrth"
+! CHECK-FLANG-INV: error: unknown argument: 'xxx'
+! CHECK-FLANG-DUP: error: invalid value 'divd' in 'mrecip='
+
+! CHECK-FC1: define {{.+}} @func{{.*}} #[[ATTRS:[0-9]+]]
+! CHECK-FC1: attributes #[[ATTRS]] =
+! CHECK-FC1-OMIT-NOT: "reciprocal-estimates"
+! CHECK-FC1-NOARG-SAME: "reciprocal-estimates"="all"
+! CHECK-FC1-ALL-SAME: "reciprocal-estimates"="all"
+! CHECK-FC1-NONE-SAME: "reciprocal-estimates"="none"
+! CHECK-FC1-DEF-SAME: "reciprocal-estimates"="default"
+! CHECK-FC1-POS-SAME: "reciprocal-estimates"="divd,divf,divh,vec-divd,vec-divf,vec-divh,sqrtd,sqrtf,sqrth,vec-sqrtd,vec-sqrtf,vec-sqrth"
+! CHECK-FC1-NEG-SAME: "reciprocal-estimates"="!divd,!divf,!divh,!vec-divd,!vec-divf,!vec-divh,!sqrtd,!sqrtf,!sqrth,!vec-sqrtd,!vec-sqrtf,!vec-sqrth"
+! CHECK-FC1-MIX-SAME: "reciprocal-estimates"="!divd,divf,!divh,sqrtd,!sqrtf,sqrth"
+! CHECK-FC1-INV: error: unknown argument: 'xxx'
+! CHECK-FC1-DUP: error: invalid value 'divd' in 'mrecip='
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index c0324d561b77b..eda1d544cd81c 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -1893,6 +1893,7 @@ def LLVM_LLVMFuncOp : LLVM_Op<"func", [
OptionalAttr<FramePointerKindAttr>:$frame_pointer,
OptionalAttr<StrAttr>:$target_cpu,
OptionalAttr<StrAttr>:$tune_cpu,
+ OptionalAttr<StrAttr>:$reciprocal_estimates,
OptionalAttr<StrAttr>:$prefer_vector_width,
OptionalAttr<LLVM_TargetFeaturesAttr>:$target_features,
OptionalAttr<BoolAttr>:$unsafe_fp_math,
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index 85417da798b22..803ecb39f4daf 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -2636,6 +2636,11 @@ void ModuleImport::processFunctionAttributes(llvm::Function *func,
funcOp.setTargetFeaturesAttr(
LLVM::TargetFeaturesAttr::get(context, attr.getValueAsString()));
+ if (llvm::Attribute attr = func->getFnAttribute("reciprocal-estimates");
+ attr.isStringAttribute())
+ funcOp.setReciprocalEstimatesAttr(
+ StringAttr::get(context, attr.getValueAsString()));
+
if (llvm::Attribute attr = func->getFnAttribute("prefer-vector-width");
attr.isStringAttribute())
funcOp.setPreferVectorWidth(attr.getValueAsString());
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index 22b391b7d20f8..2702b7aa544da 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -1547,6 +1547,9 @@ LogicalResult ModuleTranslation::convertOneFunction(LLVMFuncOp func) {
if (auto tuneCpu = func.getTuneCpu())
llvmFunc->addFnAttr("tune-cpu", *tuneCpu);
+ if (auto reciprocalEstimates = func.getReciprocalEstimates())
+ llvmFunc->addFnAttr("reciprocal-estimates", *reciprocalEstimates);
+
if (auto preferVectorWidth = func.getPreferVectorWidth())
llvmFunc->addFnAttr("prefer-vector-width", *preferVectorWidth);
diff --git a/mlir/test/Target/LLVMIR/Import/mrecip.ll b/mlir/test/Target/LLVMIR/Import/mrecip.ll
new file mode 100644
index 0000000000000..01814cce70059
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/Import/mrecip.ll
@@ -0,0 +1,9 @@
+; RUN: mlir-translate -import-llvm -split-input-file %s | FileCheck %s
+
+; CHECK-LABEL: llvm.func @reciprocal_estimates()
+; CHECK-SAME: reciprocal_estimates = "all"
+define void @reciprocal_estimates() #0 {
+ ret void
+}
+
+attributes #0 = { "reciprocal-estimates" = "all" }
diff --git a/mlir/test/Target/LLVMIR/mrecip.mlir b/mlir/test/Target/LLVMIR/mrecip.mlir
new file mode 100644
index 0000000000000..e0bc66c272f6a
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/mrecip.mlir
@@ -0,0 +1,8 @@
+// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s
+
+// CHECK: define void @reciprocal_estimates() #[[ATTRS:.*]] {
+// CHECK: attributes #[[ATTRS]] = { "reciprocal-estimates"="all" }
+
+llvm.func @reciprocal_estimates() attributes {reciprocal_estimates = "all"} {
+ llvm.return
+}
More information about the flang-commits
mailing list