Skip to content

Commit f75a796

Browse files
mcinallyCameron McInally
authored andcommitted
[flang] Add support for -mrecip[=<list>] (llvm#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 <[email protected]>
1 parent 281e1e1 commit f75a796

File tree

18 files changed

+256
-147
lines changed

18 files changed

+256
-147
lines changed

clang/include/clang/Driver/CommonArgs.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,14 @@ void handleVectorizeSLPArgs(const llvm::opt::ArgList &Args,
273273

274274
// Parse -mprefer-vector-width=. Return the Value string if well-formed.
275275
// Otherwise, return an empty string and issue a diagnosic message if needed.
276-
StringRef ParseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags,
276+
StringRef parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags,
277277
const llvm::opt::ArgList &Args);
278278

279+
// Parse -mrecip. Return the Value string if well-formed.
280+
// Otherwise, return an empty string and issue a diagnosic message if needed.
281+
StringRef parseMRecipOption(clang::DiagnosticsEngine &Diags,
282+
const llvm::opt::ArgList &Args);
283+
279284
} // end namespace tools
280285
} // end namespace driver
281286
} // end namespace clang

clang/include/clang/Driver/Options.td

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5477,9 +5477,10 @@ def mno_implicit_float : Flag<["-"], "mno-implicit-float">, Group<m_Group>,
54775477
HelpText<"Don't generate implicit floating point or vector instructions">;
54785478
def mimplicit_float : Flag<["-"], "mimplicit-float">, Group<m_Group>;
54795479
def mrecip : Flag<["-"], "mrecip">, Group<m_Group>,
5480+
Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
54805481
HelpText<"Equivalent to '-mrecip=all'">;
54815482
def mrecip_EQ : CommaJoined<["-"], "mrecip=">, Group<m_Group>,
5482-
Visibility<[ClangOption, CC1Option]>,
5483+
Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
54835484
HelpText<"Control use of approximate reciprocal and reciprocal square root instructions followed by <n> iterations of "
54845485
"Newton-Raphson refinement. "
54855486
"<value> = ( ['!'] ['vec-'] ('rcp'|'sqrt') [('h'|'s'|'d')] [':'<n>] ) | 'all' | 'default' | 'none'">,

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 4 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -125,145 +125,6 @@ forAllAssociatedToolChains(Compilation &C, const JobAction &JA,
125125
//
126126
}
127127

128-
/// This is a helper function for validating the optional refinement step
129-
/// parameter in reciprocal argument strings. Return false if there is an error
130-
/// parsing the refinement step. Otherwise, return true and set the Position
131-
/// of the refinement step in the input string.
132-
static bool getRefinementStep(StringRef In, const Driver &D,
133-
const Arg &A, size_t &Position) {
134-
const char RefinementStepToken = ':';
135-
Position = In.find(RefinementStepToken);
136-
if (Position != StringRef::npos) {
137-
StringRef Option = A.getOption().getName();
138-
StringRef RefStep = In.substr(Position + 1);
139-
// Allow exactly one numeric character for the additional refinement
140-
// step parameter. This is reasonable for all currently-supported
141-
// operations and architectures because we would expect that a larger value
142-
// of refinement steps would cause the estimate "optimization" to
143-
// under-perform the native operation. Also, if the estimate does not
144-
// converge quickly, it probably will not ever converge, so further
145-
// refinement steps will not produce a better answer.
146-
if (RefStep.size() != 1) {
147-
D.Diag(diag::err_drv_invalid_value) << Option << RefStep;
148-
return false;
149-
}
150-
char RefStepChar = RefStep[0];
151-
if (RefStepChar < '0' || RefStepChar > '9') {
152-
D.Diag(diag::err_drv_invalid_value) << Option << RefStep;
153-
return false;
154-
}
155-
}
156-
return true;
157-
}
158-
159-
/// The -mrecip flag requires processing of many optional parameters.
160-
static void ParseMRecip(const Driver &D, const ArgList &Args,
161-
ArgStringList &OutStrings) {
162-
StringRef DisabledPrefixIn = "!";
163-
StringRef DisabledPrefixOut = "!";
164-
StringRef EnabledPrefixOut = "";
165-
StringRef Out = "-mrecip=";
166-
167-
Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ);
168-
if (!A)
169-
return;
170-
171-
unsigned NumOptions = A->getNumValues();
172-
if (NumOptions == 0) {
173-
// No option is the same as "all".
174-
OutStrings.push_back(Args.MakeArgString(Out + "all"));
175-
return;
176-
}
177-
178-
// Pass through "all", "none", or "default" with an optional refinement step.
179-
if (NumOptions == 1) {
180-
StringRef Val = A->getValue(0);
181-
size_t RefStepLoc;
182-
if (!getRefinementStep(Val, D, *A, RefStepLoc))
183-
return;
184-
StringRef ValBase = Val.slice(0, RefStepLoc);
185-
if (ValBase == "all" || ValBase == "none" || ValBase == "default") {
186-
OutStrings.push_back(Args.MakeArgString(Out + Val));
187-
return;
188-
}
189-
}
190-
191-
// Each reciprocal type may be enabled or disabled individually.
192-
// Check each input value for validity, concatenate them all back together,
193-
// and pass through.
194-
195-
llvm::StringMap<bool> OptionStrings;
196-
OptionStrings.insert(std::make_pair("divd", false));
197-
OptionStrings.insert(std::make_pair("divf", false));
198-
OptionStrings.insert(std::make_pair("divh", false));
199-
OptionStrings.insert(std::make_pair("vec-divd", false));
200-
OptionStrings.insert(std::make_pair("vec-divf", false));
201-
OptionStrings.insert(std::make_pair("vec-divh", false));
202-
OptionStrings.insert(std::make_pair("sqrtd", false));
203-
OptionStrings.insert(std::make_pair("sqrtf", false));
204-
OptionStrings.insert(std::make_pair("sqrth", false));
205-
OptionStrings.insert(std::make_pair("vec-sqrtd", false));
206-
OptionStrings.insert(std::make_pair("vec-sqrtf", false));
207-
OptionStrings.insert(std::make_pair("vec-sqrth", false));
208-
209-
for (unsigned i = 0; i != NumOptions; ++i) {
210-
StringRef Val = A->getValue(i);
211-
212-
bool IsDisabled = Val.starts_with(DisabledPrefixIn);
213-
// Ignore the disablement token for string matching.
214-
if (IsDisabled)
215-
Val = Val.substr(1);
216-
217-
size_t RefStep;
218-
if (!getRefinementStep(Val, D, *A, RefStep))
219-
return;
220-
221-
StringRef ValBase = Val.slice(0, RefStep);
222-
llvm::StringMap<bool>::iterator OptionIter = OptionStrings.find(ValBase);
223-
if (OptionIter == OptionStrings.end()) {
224-
// Try again specifying float suffix.
225-
OptionIter = OptionStrings.find(ValBase.str() + 'f');
226-
if (OptionIter == OptionStrings.end()) {
227-
// The input name did not match any known option string.
228-
D.Diag(diag::err_drv_unknown_argument) << Val;
229-
return;
230-
}
231-
// The option was specified without a half or float or double suffix.
232-
// Make sure that the double or half entry was not already specified.
233-
// The float entry will be checked below.
234-
if (OptionStrings[ValBase.str() + 'd'] ||
235-
OptionStrings[ValBase.str() + 'h']) {
236-
D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Val;
237-
return;
238-
}
239-
}
240-
241-
if (OptionIter->second == true) {
242-
// Duplicate option specified.
243-
D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Val;
244-
return;
245-
}
246-
247-
// Mark the matched option as found. Do not allow duplicate specifiers.
248-
OptionIter->second = true;
249-
250-
// If the precision was not specified, also mark the double and half entry
251-
// as found.
252-
if (ValBase.back() != 'f' && ValBase.back() != 'd' && ValBase.back() != 'h') {
253-
OptionStrings[ValBase.str() + 'd'] = true;
254-
OptionStrings[ValBase.str() + 'h'] = true;
255-
}
256-
257-
// Build the output string.
258-
StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut;
259-
Out = Args.MakeArgString(Out + Prefix + Val);
260-
if (i != NumOptions - 1)
261-
Out = Args.MakeArgString(Out + ",");
262-
}
263-
264-
OutStrings.push_back(Args.MakeArgString(Out));
265-
}
266-
267128
static bool
268129
shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime,
269130
const llvm::Triple &Triple) {
@@ -3490,7 +3351,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
34903351
CmdArgs.push_back(Args.MakeArgString("-fbfloat16-excess-precision=" +
34913352
BFloat16ExcessPrecision));
34923353

3493-
ParseMRecip(D, Args, CmdArgs);
3354+
StringRef Recip = parseMRecipOption(D.getDiags(), Args);
3355+
if (!Recip.empty())
3356+
CmdArgs.push_back(Args.MakeArgString("-mrecip=" + Recip));
34943357

34953358
// -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the
34963359
// individual features enabled by -ffast-math instead of the option itself as
@@ -7588,7 +7451,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
75887451
handleVectorizeLoopsArgs(Args, CmdArgs);
75897452
handleVectorizeSLPArgs(Args, CmdArgs);
75907453

7591-
StringRef VecWidth = ParseMPreferVectorWidthOption(D.getDiags(), Args);
7454+
StringRef VecWidth = parseMPreferVectorWidthOption(D.getDiags(), Args);
75927455
if (!VecWidth.empty())
75937456
CmdArgs.push_back(Args.MakeArgString("-mprefer-vector-width=" + VecWidth));
75947457

clang/lib/Driver/ToolChains/CommonArgs.cpp

Lines changed: 142 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3170,7 +3170,7 @@ void tools::handleInterchangeLoopsArgs(const ArgList &Args,
31703170

31713171
// Parse -mprefer-vector-width=. Return the Value string if well-formed.
31723172
// Otherwise, return an empty string and issue a diagnosic message if needed.
3173-
StringRef tools::ParseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags,
3173+
StringRef tools::parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags,
31743174
const llvm::opt::ArgList &Args) {
31753175
Arg *A = Args.getLastArg(clang::driver::options::OPT_mprefer_vector_width_EQ);
31763176
if (!A)
@@ -3189,3 +3189,144 @@ StringRef tools::ParseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags,
31893189

31903190
return Value;
31913191
}
3192+
3193+
// This is a helper function for validating the optional refinement step
3194+
// parameter in reciprocal argument strings. Return false if there is an error
3195+
// parsing the refinement step. Otherwise, return true and set the Position
3196+
// of the refinement step in the input string.
3197+
static bool getRefinementStep(StringRef In, clang::DiagnosticsEngine &Diags,
3198+
const Arg &A, size_t &Position) {
3199+
const char RefinementStepToken = ':';
3200+
Position = In.find(RefinementStepToken);
3201+
if (Position != StringRef::npos) {
3202+
StringRef Option = A.getOption().getName();
3203+
StringRef RefStep = In.substr(Position + 1);
3204+
// Allow exactly one numeric character for the additional refinement
3205+
// step parameter. This is reasonable for all currently-supported
3206+
// operations and architectures because we would expect that a larger value
3207+
// of refinement steps would cause the estimate "optimization" to
3208+
// under-perform the native operation. Also, if the estimate does not
3209+
// converge quickly, it probably will not ever converge, so further
3210+
// refinement steps will not produce a better answer.
3211+
if (RefStep.size() != 1) {
3212+
Diags.Report(diag::err_drv_invalid_value) << Option << RefStep;
3213+
return false;
3214+
}
3215+
char RefStepChar = RefStep[0];
3216+
if (RefStepChar < '0' || RefStepChar > '9') {
3217+
Diags.Report(diag::err_drv_invalid_value) << Option << RefStep;
3218+
return false;
3219+
}
3220+
}
3221+
return true;
3222+
}
3223+
3224+
// Parse -mrecip. Return the Value string if well-formed.
3225+
// Otherwise, return an empty string and issue a diagnosic message if needed.
3226+
StringRef tools::parseMRecipOption(clang::DiagnosticsEngine &Diags,
3227+
const ArgList &Args) {
3228+
StringRef DisabledPrefixIn = "!";
3229+
StringRef DisabledPrefixOut = "!";
3230+
StringRef EnabledPrefixOut = "";
3231+
StringRef Out = "";
3232+
3233+
Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ);
3234+
if (!A)
3235+
return "";
3236+
3237+
unsigned NumOptions = A->getNumValues();
3238+
if (NumOptions == 0) {
3239+
// No option is the same as "all".
3240+
return "all";
3241+
}
3242+
3243+
// Pass through "all", "none", or "default" with an optional refinement step.
3244+
if (NumOptions == 1) {
3245+
StringRef Val = A->getValue(0);
3246+
size_t RefStepLoc;
3247+
if (!getRefinementStep(Val, Diags, *A, RefStepLoc))
3248+
return "";
3249+
StringRef ValBase = Val.slice(0, RefStepLoc);
3250+
if (ValBase == "all" || ValBase == "none" || ValBase == "default") {
3251+
return Val;
3252+
}
3253+
}
3254+
3255+
// Each reciprocal type may be enabled or disabled individually.
3256+
// Check each input value for validity, concatenate them all back together,
3257+
// and pass through.
3258+
3259+
llvm::StringMap<bool> OptionStrings;
3260+
OptionStrings.insert(std::make_pair("divd", false));
3261+
OptionStrings.insert(std::make_pair("divf", false));
3262+
OptionStrings.insert(std::make_pair("divh", false));
3263+
OptionStrings.insert(std::make_pair("vec-divd", false));
3264+
OptionStrings.insert(std::make_pair("vec-divf", false));
3265+
OptionStrings.insert(std::make_pair("vec-divh", false));
3266+
OptionStrings.insert(std::make_pair("sqrtd", false));
3267+
OptionStrings.insert(std::make_pair("sqrtf", false));
3268+
OptionStrings.insert(std::make_pair("sqrth", false));
3269+
OptionStrings.insert(std::make_pair("vec-sqrtd", false));
3270+
OptionStrings.insert(std::make_pair("vec-sqrtf", false));
3271+
OptionStrings.insert(std::make_pair("vec-sqrth", false));
3272+
3273+
for (unsigned i = 0; i != NumOptions; ++i) {
3274+
StringRef Val = A->getValue(i);
3275+
3276+
bool IsDisabled = Val.starts_with(DisabledPrefixIn);
3277+
// Ignore the disablement token for string matching.
3278+
if (IsDisabled)
3279+
Val = Val.substr(1);
3280+
3281+
size_t RefStep;
3282+
if (!getRefinementStep(Val, Diags, *A, RefStep))
3283+
return "";
3284+
3285+
StringRef ValBase = Val.slice(0, RefStep);
3286+
llvm::StringMap<bool>::iterator OptionIter = OptionStrings.find(ValBase);
3287+
if (OptionIter == OptionStrings.end()) {
3288+
// Try again specifying float suffix.
3289+
OptionIter = OptionStrings.find(ValBase.str() + 'f');
3290+
if (OptionIter == OptionStrings.end()) {
3291+
// The input name did not match any known option string.
3292+
Diags.Report(diag::err_drv_unknown_argument) << Val;
3293+
return "";
3294+
}
3295+
// The option was specified without a half or float or double suffix.
3296+
// Make sure that the double or half entry was not already specified.
3297+
// The float entry will be checked below.
3298+
if (OptionStrings[ValBase.str() + 'd'] ||
3299+
OptionStrings[ValBase.str() + 'h']) {
3300+
Diags.Report(diag::err_drv_invalid_value)
3301+
<< A->getOption().getName() << Val;
3302+
return "";
3303+
}
3304+
}
3305+
3306+
if (OptionIter->second == true) {
3307+
// Duplicate option specified.
3308+
Diags.Report(diag::err_drv_invalid_value)
3309+
<< A->getOption().getName() << Val;
3310+
return "";
3311+
}
3312+
3313+
// Mark the matched option as found. Do not allow duplicate specifiers.
3314+
OptionIter->second = true;
3315+
3316+
// If the precision was not specified, also mark the double and half entry
3317+
// as found.
3318+
if (ValBase.back() != 'f' && ValBase.back() != 'd' &&
3319+
ValBase.back() != 'h') {
3320+
OptionStrings[ValBase.str() + 'd'] = true;
3321+
OptionStrings[ValBase.str() + 'h'] = true;
3322+
}
3323+
3324+
// Build the output string.
3325+
StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut;
3326+
Out = Args.MakeArgString(Out + Prefix + Val);
3327+
if (i != NumOptions - 1)
3328+
Out = Args.MakeArgString(Out + ",");
3329+
}
3330+
3331+
return Out;
3332+
}

clang/lib/Driver/ToolChains/Flang.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,10 @@ static void addFloatingPointOptions(const Driver &D, const ArgList &Args,
695695
A->claim();
696696
}
697697

698+
StringRef Recip = parseMRecipOption(D.getDiags(), Args);
699+
if (!Recip.empty())
700+
CmdArgs.push_back(Args.MakeArgString("-mrecip=" + Recip));
701+
698702
if (!HonorINFs && !HonorNaNs && AssociativeMath && ReciprocalMath &&
699703
ApproxFunc && !SignedZeros &&
700704
(FPContract == "fast" || FPContract.empty())) {

flang/include/flang/Frontend/CodeGenOptions.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,12 @@ class CodeGenOptions : public CodeGenOptionsBase {
5353
/// The paths to the pass plugins that were registered using -fpass-plugin.
5454
std::vector<std::string> LLVMPassPlugins;
5555

56-
// The prefered vector width, if requested by -mprefer-vector-width.
56+
/// The prefered vector width, if requested by -mprefer-vector-width.
5757
std::string PreferVectorWidth;
5858

59+
/// List of reciprocal estimate sub-options.
60+
std::string Reciprocals;
61+
5962
/// List of filenames passed in using the -fembed-offload-object option. These
6063
/// are offloading binaries containing device images and metadata.
6164
std::vector<std::string> OffloadObjects;

flang/include/flang/Optimizer/Transforms/Passes.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,9 @@ def FunctionAttr : Pass<"function-attr", "mlir::func::FuncOp"> {
429429
"module.">,
430430
Option<"unsafeFPMath", "unsafe-fp-math", "bool", /*default=*/"false",
431431
"Set the unsafe-fp-math attribute on functions in the module.">,
432+
Option<"reciprocals", "mrecip", "std::string", /*default=*/"",
433+
"Set the reciprocal-estimates attribute on functions in the "
434+
"module.">,
432435
Option<"preferVectorWidth", "prefer-vector-width", "std::string",
433436
/*default=*/"",
434437
"Set the prefer-vector-width attribute on functions in the "

flang/include/flang/Tools/CrossToolHelpers.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ struct MLIRToLLVMPassPipelineConfig : public FlangEPCallBacks {
102102
UnsafeFPMath = mathOpts.getAssociativeMath() &&
103103
mathOpts.getReciprocalMath() && NoSignedZerosFPMath &&
104104
ApproxFuncFPMath && mathOpts.getFPContractEnabled();
105+
Reciprocals = opts.Reciprocals;
105106
PreferVectorWidth = opts.PreferVectorWidth;
106107
if (opts.InstrumentFunctions) {
107108
InstrumentFunctionEntry = "__cyg_profile_func_enter";
@@ -127,6 +128,8 @@ struct MLIRToLLVMPassPipelineConfig : public FlangEPCallBacks {
127128
bool NoSignedZerosFPMath =
128129
false; ///< Set no-signed-zeros-fp-math attribute for functions.
129130
bool UnsafeFPMath = false; ///< Set unsafe-fp-math attribute for functions.
131+
std::string Reciprocals = ""; ///< Set reciprocal-estimate attribute for
132+
///< functions.
130133
std::string PreferVectorWidth = ""; ///< Set prefer-vector-width attribute for
131134
///< functions.
132135
bool NSWOnLoopVarInc = true; ///< Add nsw flag to loop variable increments.

0 commit comments

Comments
 (0)