@@ -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;
0 commit comments