Skip to content

Commit e7c6025

Browse files
author
Cameron McInally
committed
[flang] Add support for -mrecip[=<list>]
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.
1 parent f8d3bdf commit e7c6025

File tree

14 files changed

+231
-2
lines changed

14 files changed

+231
-2
lines changed

clang/include/clang/Driver/Options.td

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

flang/include/flang/Frontend/CodeGenOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ class CodeGenOptions : public CodeGenOptionsBase {
5656
// 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.

flang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,6 +1251,164 @@ static bool parseIntegerOverflowArgs(CompilerInvocation &invoc,
12511251
return true;
12521252
}
12531253

1254+
/// This is a helper function for validating the optional refinement step
1255+
/// parameter in reciprocal argument strings. Return false if there is an error
1256+
/// parsing the refinement step. Otherwise, return true and set the Position
1257+
/// of the refinement step in the input string.
1258+
///
1259+
/// \param [in] in The input string
1260+
/// \param [in] a The compiler invocation arguments to parse
1261+
/// \param [out] position The position of the refinement step in input string
1262+
/// \param [out] diags DiagnosticsEngine to report erros with
1263+
static bool getRefinementStep(llvm::StringRef in, const llvm::opt::Arg &a,
1264+
size_t &position,
1265+
clang::DiagnosticsEngine &diags) {
1266+
const char refinementStepToken = ':';
1267+
position = in.find(refinementStepToken);
1268+
if (position != llvm::StringRef::npos) {
1269+
llvm::StringRef option = a.getOption().getName();
1270+
llvm::StringRef refStep = in.substr(position + 1);
1271+
// Allow exactly one numeric character for the additional refinement
1272+
// step parameter. This is reasonable for all currently-supported
1273+
// operations and architectures because we would expect that a larger value
1274+
// of refinement steps would cause the estimate "optimization" to
1275+
// under-perform the native operation. Also, if the estimate does not
1276+
// converge quickly, it probably will not ever converge, so further
1277+
// refinement steps will not produce a better answer.
1278+
if (refStep.size() != 1) {
1279+
diags.Report(clang::diag::err_drv_invalid_value) << option << refStep;
1280+
return false;
1281+
}
1282+
char refStepChar = refStep[0];
1283+
if (refStepChar < '0' || refStepChar > '9') {
1284+
diags.Report(clang::diag::err_drv_invalid_value) << option << refStep;
1285+
return false;
1286+
}
1287+
}
1288+
return true;
1289+
}
1290+
1291+
/// Parses all -mrecip=<list> arguments and populates the
1292+
/// CompilerInvocation accordingly. Returns false if new errors are generated.
1293+
///
1294+
/// \param [out] invoc Stores the processed arguments
1295+
/// \param [in] args The compiler invocation arguments to parse
1296+
/// \param [out] diags DiagnosticsEngine to report erros with
1297+
static bool parseMRecip(CompilerInvocation &invoc, llvm::opt::ArgList &args,
1298+
clang::DiagnosticsEngine &diags) {
1299+
llvm::StringRef disabledPrefixIn = "!";
1300+
llvm::StringRef disabledPrefixOut = "!";
1301+
llvm::StringRef enabledPrefixOut = "";
1302+
llvm::StringRef out = "";
1303+
Fortran::frontend::CodeGenOptions &opts = invoc.getCodeGenOpts();
1304+
1305+
const llvm::opt::Arg *a =
1306+
args.getLastArg(clang::driver::options::OPT_mrecip,
1307+
clang::driver::options::OPT_mrecip_EQ);
1308+
if (!a)
1309+
return true;
1310+
1311+
unsigned numOptions = a->getNumValues();
1312+
if (numOptions == 0) {
1313+
// No option is the same as "all".
1314+
opts.Reciprocals = "all";
1315+
return true;
1316+
}
1317+
1318+
// Pass through "all", "none", or "default" with an optional refinement step.
1319+
if (numOptions == 1) {
1320+
llvm::StringRef val = a->getValue(0);
1321+
size_t refStepLoc;
1322+
if (!getRefinementStep(val, *a, refStepLoc, diags))
1323+
return false;
1324+
llvm::StringRef valBase = val.slice(0, refStepLoc);
1325+
if (valBase == "all" || valBase == "none" || valBase == "default") {
1326+
opts.Reciprocals = args.MakeArgString(val);
1327+
return true;
1328+
}
1329+
}
1330+
1331+
// Each reciprocal type may be enabled or disabled individually.
1332+
// Check each input value for validity, concatenate them all back together,
1333+
// and pass through.
1334+
1335+
llvm::StringMap<bool> optionStrings;
1336+
optionStrings.insert(std::make_pair("divd", false));
1337+
optionStrings.insert(std::make_pair("divf", false));
1338+
optionStrings.insert(std::make_pair("divh", false));
1339+
optionStrings.insert(std::make_pair("vec-divd", false));
1340+
optionStrings.insert(std::make_pair("vec-divf", false));
1341+
optionStrings.insert(std::make_pair("vec-divh", false));
1342+
optionStrings.insert(std::make_pair("sqrtd", false));
1343+
optionStrings.insert(std::make_pair("sqrtf", false));
1344+
optionStrings.insert(std::make_pair("sqrth", false));
1345+
optionStrings.insert(std::make_pair("vec-sqrtd", false));
1346+
optionStrings.insert(std::make_pair("vec-sqrtf", false));
1347+
optionStrings.insert(std::make_pair("vec-sqrth", false));
1348+
1349+
for (unsigned i = 0; i != numOptions; ++i) {
1350+
llvm::StringRef val = a->getValue(i);
1351+
1352+
bool isDisabled = val.starts_with(disabledPrefixIn);
1353+
// Ignore the disablement token for string matching.
1354+
if (isDisabled)
1355+
val = val.substr(1);
1356+
1357+
size_t refStep;
1358+
if (!getRefinementStep(val, *a, refStep, diags))
1359+
return false;
1360+
1361+
llvm::StringRef valBase = val.slice(0, refStep);
1362+
llvm::StringMap<bool>::iterator optionIter = optionStrings.find(valBase);
1363+
if (optionIter == optionStrings.end()) {
1364+
// Try again specifying float suffix.
1365+
optionIter = optionStrings.find(valBase.str() + 'f');
1366+
if (optionIter == optionStrings.end()) {
1367+
// The input name did not match any known option string.
1368+
diags.Report(clang::diag::err_drv_invalid_value)
1369+
<< a->getOption().getName() << val;
1370+
return false;
1371+
}
1372+
// The option was specified without a half or float or double suffix.
1373+
// Make sure that the double or half entry was not already specified.
1374+
// The float entry will be checked below.
1375+
if (optionStrings[valBase.str() + 'd'] ||
1376+
optionStrings[valBase.str() + 'h']) {
1377+
diags.Report(clang::diag::err_drv_invalid_value)
1378+
<< a->getOption().getName() << val;
1379+
return false;
1380+
}
1381+
}
1382+
1383+
if (optionIter->second == true) {
1384+
// Duplicate option specified.
1385+
diags.Report(clang::diag::err_drv_invalid_value)
1386+
<< a->getOption().getName() << val;
1387+
return false;
1388+
}
1389+
1390+
// Mark the matched option as found. Do not allow duplicate specifiers.
1391+
optionIter->second = true;
1392+
1393+
// If the precision was not specified, also mark the double and half entry
1394+
// as found.
1395+
if (valBase.back() != 'f' && valBase.back() != 'd' &&
1396+
valBase.back() != 'h') {
1397+
optionStrings[valBase.str() + 'd'] = true;
1398+
optionStrings[valBase.str() + 'h'] = true;
1399+
}
1400+
1401+
// Build the output string.
1402+
llvm::StringRef prefix = isDisabled ? disabledPrefixOut : enabledPrefixOut;
1403+
out = args.MakeArgString(out + prefix + val);
1404+
if (i != numOptions - 1)
1405+
out = args.MakeArgString(out + ",");
1406+
}
1407+
1408+
opts.Reciprocals = args.MakeArgString(out); // Handle the rest.
1409+
return true;
1410+
}
1411+
12541412
/// Parses all floating point related arguments and populates the
12551413
/// CompilerInvocation accordingly.
12561414
/// Returns false if new errors are generated.
@@ -1398,6 +1556,7 @@ static bool parseLangOptionsArgs(CompilerInvocation &invoc,
13981556

13991557
success &= parseIntegerOverflowArgs(invoc, args, diags);
14001558
success &= parseFloatingPointArgs(invoc, args, diags);
1559+
success &= parseMRecip(invoc, args, diags);
14011560
success &= parseVScaleArgs(invoc, args, diags);
14021561

14031562
return success;

flang/lib/Frontend/FrontendActions.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,8 @@ void CodeGenAction::generateLLVMIR() {
743743

744744
config.PreferVectorWidth = opts.PreferVectorWidth;
745745

746+
config.Reciprocals = opts.Reciprocals;
747+
746748
if (ci.getInvocation().getFrontendOpts().features.IsEnabled(
747749
Fortran::common::LanguageFeature::OpenMP))
748750
config.EnableOpenMP = true;

flang/lib/Optimizer/Passes/Pipelines.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,8 @@ void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm,
358358
{framePointerKind, config.InstrumentFunctionEntry,
359359
config.InstrumentFunctionExit, config.NoInfsFPMath, config.NoNaNsFPMath,
360360
config.ApproxFuncFPMath, config.NoSignedZerosFPMath, config.UnsafeFPMath,
361-
config.PreferVectorWidth, /*tuneCPU=*/"", setNoCapture, setNoAlias}));
361+
config.Reciprocals, config.PreferVectorWidth, /*tuneCPU=*/"",
362+
setNoCapture, setNoAlias}));
362363

363364
if (config.EnableOpenMP) {
364365
pm.addNestedPass<mlir::func::FuncOp>(

flang/lib/Optimizer/Transforms/FunctionAttr.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ void FunctionAttrPass::runOnOperation() {
107107
func->setAttr(
108108
mlir::LLVM::LLVMFuncOp::getUnsafeFpMathAttrName(llvmFuncOpName),
109109
mlir::BoolAttr::get(context, true));
110+
if (!reciprocals.empty())
111+
func->setAttr(
112+
mlir::LLVM::LLVMFuncOp::getReciprocalEstimatesAttrName(llvmFuncOpName),
113+
mlir::StringAttr::get(context, reciprocals));
110114
if (!preferVectorWidth.empty())
111115
func->setAttr(
112116
mlir::LLVM::LLVMFuncOp::getPreferVectorWidthAttrName(llvmFuncOpName),

flang/test/Driver/mrecip.f90

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
! Test that -mrecip[=<list>] works as expected.
2+
3+
! RUN: %flang_fc1 -emit-llvm -o - %s 2>&1| FileCheck %s --check-prefix=CHECK-OMIT
4+
! RUN: %flang_fc1 -mrecip -emit-llvm -o - %s 2>&1| FileCheck %s --check-prefix=CHECK-NOARG
5+
! RUN: %flang_fc1 -mrecip=all -emit-llvm -o - %s 2>&1| FileCheck %s --check-prefix=CHECK-ALL
6+
! RUN: %flang_fc1 -mrecip=none -emit-llvm -o - %s 2>&1| FileCheck %s --check-prefix=CHECK-NONE
7+
! RUN: %flang_fc1 -mrecip=default -emit-llvm -o - %s 2>&1| FileCheck %s --check-prefix=CHECK-DEF
8+
! 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-prefix=CHECK-POS
9+
! RUN: %flang_fc1 -mrecip=!divd,!divf,!divh,!vec-divd,!vec-divf,!vec-divh,!sqrtd,!sqrtf,!sqrth,!vec-sqrtd,!vec-sqrtf,!vec-sqrth
10+
! -emit-llvm -o - %s 2>&1| FileCheck %s --check-prefix=CHECK-NEG
11+
! RUN: %flang_fc1 -mrecip=!divd,divf,!divh,sqrtd,!sqrtf,sqrth -emit-llvm -o - %s 2>&1| FileCheck %s --check-prefix=CHECK-MIX
12+
! RUN: not %flang_fc1 -mrecip=xxx -emit-llvm -o - %s 2>&1| FileCheck %s --check-prefix=CHECK-INV
13+
! RUN: not %flang_fc1 -mrecip=divd,divd -emit-llvm -o - %s 2>&1| FileCheck %s --check-prefix=CHECK-DUP
14+
15+
subroutine func
16+
end subroutine func
17+
18+
! CHECK-OMIT-NOT: attributes #0 = { "reciprocal-estimates"={{.*}} }
19+
! CHECK-NOARG: attributes #0 = { "reciprocal-estimates"="all" }
20+
! CHECK-ALL: attributes #0 = { "reciprocal-estimates"="all" }
21+
! CHECK-NONE: attributes #0 = { "reciprocal-estimates"="none" }
22+
! CHECK-DEF: attributes #0 = { "reciprocal-estimates"="default" }
23+
! CHECK-POS: attributes #0 = { "reciprocal-estimates"="divd,divf,divh,vec-divd,vec-divf,vec-divh,sqrtd,sqrtf,sqrth,vec-sqrtd,vec-sqrtf,vec-sqrth" }
24+
! CHECK-NEG: attributes #0 = { "reciprocal-estimates"="!divd,!divf,!divh,!vec-divd,!vec-divf,!vec-divh,!sqrtd,!sqrtf,!sqrth,!vec-sqrtd,!vec-sqrtf,!vec-sqrth" }
25+
! CHECK-MIX: attributes #0 = { "reciprocal-estimates"="!divd,divf,!divh,sqrtd,!sqrtf,sqrth" }
26+
! CHECK-INV: error: invalid value 'xxx' in 'mrecip='
27+
! CHECK-DUP: error: invalid value 'divd' in 'mrecip='

mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1895,6 +1895,7 @@ def LLVM_LLVMFuncOp : LLVM_Op<"func", [
18951895
OptionalAttr<StrAttr>:$tune_cpu,
18961896
OptionalAttr<StrAttr>:$prefer_vector_width,
18971897
OptionalAttr<LLVM_TargetFeaturesAttr>:$target_features,
1898+
OptionalAttr<StrAttr>:$reciprocal_estimates,
18981899
OptionalAttr<BoolAttr>:$unsafe_fp_math,
18991900
OptionalAttr<BoolAttr>:$no_infs_fp_math,
19001901
OptionalAttr<BoolAttr>:$no_nans_fp_math,

0 commit comments

Comments
 (0)