[flang][driver] Accelerate complex division when -ffast-math is specified (#159689)

This patch accelerates complex division by passing
`-complex-range=basic` to the frontend when the `-ffast-math` option is
specified. This behavior is the same as `-fcomplex-arithmetic=basic`. A
warning is issued if a different value is specified for
`-fcomplex-arithmetic=`. The warning conditions will be unified with
clang.
This commit is contained in:
Shunsuke Watanabe 2025-10-01 13:03:23 +09:00 committed by GitHub
parent 89ed5255b9
commit fd4e77cf33
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 179 additions and 66 deletions

View File

@ -304,6 +304,11 @@ std::string complexRangeKindToStr(LangOptions::ComplexRangeKind Range);
// Render a frontend option corresponding to ComplexRangeKind.
std::string renderComplexRangeOption(LangOptions::ComplexRangeKind Range);
// Set the complex range and output a warning as needed.
void setComplexRange(const Driver &D, StringRef NewOpt,
LangOptions::ComplexRangeKind NewRange, StringRef &LastOpt,
LangOptions::ComplexRangeKind &Range);
} // end namespace tools
} // end namespace driver
} // end namespace clang

View File

@ -2723,42 +2723,6 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
}
}
static void EmitComplexRangeDiag(const Driver &D, StringRef LastOpt,
LangOptions::ComplexRangeKind Range,
StringRef NewOpt,
LangOptions::ComplexRangeKind NewRange) {
// Do not emit a warning if NewOpt overrides LastOpt in the following cases.
//
// | LastOpt | NewOpt |
// |-----------------------|-----------------------|
// | -fcx-limited-range | -fno-cx-limited-range |
// | -fno-cx-limited-range | -fcx-limited-range |
// | -fcx-fortran-rules | -fno-cx-fortran-rules |
// | -fno-cx-fortran-rules | -fcx-fortran-rules |
// | -ffast-math | -fno-fast-math |
// | -ffp-model= | -ffast-math |
// | -ffp-model= | -fno-fast-math |
// | -ffp-model= | -ffp-model= |
// | -fcomplex-arithmetic= | -fcomplex-arithmetic= |
if (LastOpt == NewOpt || NewOpt.empty() || LastOpt.empty() ||
(LastOpt == "-fcx-limited-range" && NewOpt == "-fno-cx-limited-range") ||
(LastOpt == "-fno-cx-limited-range" && NewOpt == "-fcx-limited-range") ||
(LastOpt == "-fcx-fortran-rules" && NewOpt == "-fno-cx-fortran-rules") ||
(LastOpt == "-fno-cx-fortran-rules" && NewOpt == "-fcx-fortran-rules") ||
(LastOpt == "-ffast-math" && NewOpt == "-fno-fast-math") ||
(LastOpt.starts_with("-ffp-model=") && NewOpt == "-ffast-math") ||
(LastOpt.starts_with("-ffp-model=") && NewOpt == "-fno-fast-math") ||
(LastOpt.starts_with("-ffp-model=") &&
NewOpt.starts_with("-ffp-model=")) ||
(LastOpt.starts_with("-fcomplex-arithmetic=") &&
NewOpt.starts_with("-fcomplex-arithmetic=")))
return;
D.Diag(clang::diag::warn_drv_overriding_complex_range)
<< LastOpt << NewOpt << complexRangeKindToStr(Range)
<< complexRangeKindToStr(NewRange);
}
static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
bool OFastEnabled, const ArgList &Args,
ArgStringList &CmdArgs,
@ -2815,27 +2779,19 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
std::string ComplexRangeStr;
StringRef LastComplexRangeOption;
auto setComplexRange = [&](StringRef NewOption,
LangOptions::ComplexRangeKind NewRange) {
// Warn if user overrides the previously set complex number
// multiplication/division option.
if (Range != LangOptions::ComplexRangeKind::CX_None && Range != NewRange)
EmitComplexRangeDiag(D, LastComplexRangeOption, Range, NewOption,
NewRange);
LastComplexRangeOption = NewOption;
Range = NewRange;
};
// Lambda to set fast-math options. This is also used by -ffp-model=fast
auto applyFastMath = [&](bool Aggressive, StringRef CallerOption) {
if (Aggressive) {
HonorINFs = false;
HonorNaNs = false;
setComplexRange(CallerOption, LangOptions::ComplexRangeKind::CX_Basic);
setComplexRange(D, CallerOption, LangOptions::ComplexRangeKind::CX_Basic,
LastComplexRangeOption, Range);
} else {
HonorINFs = true;
HonorNaNs = true;
setComplexRange(CallerOption, LangOptions::ComplexRangeKind::CX_Promoted);
setComplexRange(D, CallerOption,
LangOptions::ComplexRangeKind::CX_Promoted,
LastComplexRangeOption, Range);
}
MathErrno = false;
AssociativeMath = true;
@ -2887,18 +2843,24 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
default: continue;
case options::OPT_fcx_limited_range:
setComplexRange(A->getSpelling(),
LangOptions::ComplexRangeKind::CX_Basic);
setComplexRange(D, A->getSpelling(),
LangOptions::ComplexRangeKind::CX_Basic,
LastComplexRangeOption, Range);
break;
case options::OPT_fno_cx_limited_range:
setComplexRange(A->getSpelling(), LangOptions::ComplexRangeKind::CX_Full);
setComplexRange(D, A->getSpelling(),
LangOptions::ComplexRangeKind::CX_Full,
LastComplexRangeOption, Range);
break;
case options::OPT_fcx_fortran_rules:
setComplexRange(A->getSpelling(),
LangOptions::ComplexRangeKind::CX_Improved);
setComplexRange(D, A->getSpelling(),
LangOptions::ComplexRangeKind::CX_Improved,
LastComplexRangeOption, Range);
break;
case options::OPT_fno_cx_fortran_rules:
setComplexRange(A->getSpelling(), LangOptions::ComplexRangeKind::CX_Full);
setComplexRange(D, A->getSpelling(),
LangOptions::ComplexRangeKind::CX_Full,
LastComplexRangeOption, Range);
break;
case options::OPT_fcomplex_arithmetic_EQ: {
LangOptions::ComplexRangeKind RangeVal;
@ -2916,7 +2878,8 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
<< A->getSpelling() << Val;
break;
}
setComplexRange(Args.MakeArgString(A->getSpelling() + Val), RangeVal);
setComplexRange(D, Args.MakeArgString(A->getSpelling() + Val), RangeVal,
LastComplexRangeOption, Range);
break;
}
case options::OPT_ffp_model_EQ: {
@ -2956,8 +2919,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
FPModel = Val;
FPContract = "on";
LastFpContractOverrideOption = "-ffp-model=precise";
setComplexRange(Args.MakeArgString(A->getSpelling() + Val),
LangOptions::ComplexRangeKind::CX_Full);
setComplexRange(D, Args.MakeArgString(A->getSpelling() + Val),
LangOptions::ComplexRangeKind::CX_Full,
LastComplexRangeOption, Range);
} else if (Val == "strict") {
StrictFPModel = true;
FPExceptionBehavior = "strict";
@ -2966,8 +2930,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
LastFpContractOverrideOption = "-ffp-model=strict";
TrappingMath = true;
RoundingFPMath = true;
setComplexRange(Args.MakeArgString(A->getSpelling() + Val),
LangOptions::ComplexRangeKind::CX_Full);
setComplexRange(D, Args.MakeArgString(A->getSpelling() + Val),
LangOptions::ComplexRangeKind::CX_Full,
LastComplexRangeOption, Range);
} else
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getSpelling() << Val;
@ -3174,8 +3139,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
SignedZeros = true;
restoreFPContractState();
if (Range != LangOptions::ComplexRangeKind::CX_Full)
setComplexRange(A->getSpelling(),
LangOptions::ComplexRangeKind::CX_None);
setComplexRange(D, A->getSpelling(),
LangOptions::ComplexRangeKind::CX_None,
LastComplexRangeOption, Range);
else
Range = LangOptions::ComplexRangeKind::CX_None;
LastComplexRangeOption = "";

View File

@ -3557,3 +3557,51 @@ tools::renderComplexRangeOption(LangOptionsBase::ComplexRangeKind Range) {
return "-complex-range=" + ComplexRangeStr;
return ComplexRangeStr;
}
static void emitComplexRangeDiag(const Driver &D, StringRef LastOpt,
LangOptions::ComplexRangeKind Range,
StringRef NewOpt,
LangOptions::ComplexRangeKind NewRange) {
// Do not emit a warning if NewOpt overrides LastOpt in the following cases.
//
// | LastOpt | NewOpt |
// |-----------------------|-----------------------|
// | -fcx-limited-range | -fno-cx-limited-range |
// | -fno-cx-limited-range | -fcx-limited-range |
// | -fcx-fortran-rules | -fno-cx-fortran-rules |
// | -fno-cx-fortran-rules | -fcx-fortran-rules |
// | -ffast-math | -fno-fast-math |
// | -ffp-model= | -ffast-math |
// | -ffp-model= | -fno-fast-math |
// | -ffp-model= | -ffp-model= |
// | -fcomplex-arithmetic= | -fcomplex-arithmetic= |
if (LastOpt == NewOpt || NewOpt.empty() || LastOpt.empty() ||
(LastOpt == "-fcx-limited-range" && NewOpt == "-fno-cx-limited-range") ||
(LastOpt == "-fno-cx-limited-range" && NewOpt == "-fcx-limited-range") ||
(LastOpt == "-fcx-fortran-rules" && NewOpt == "-fno-cx-fortran-rules") ||
(LastOpt == "-fno-cx-fortran-rules" && NewOpt == "-fcx-fortran-rules") ||
(LastOpt == "-ffast-math" && NewOpt == "-fno-fast-math") ||
(LastOpt.starts_with("-ffp-model=") && NewOpt == "-ffast-math") ||
(LastOpt.starts_with("-ffp-model=") && NewOpt == "-fno-fast-math") ||
(LastOpt.starts_with("-ffp-model=") &&
NewOpt.starts_with("-ffp-model=")) ||
(LastOpt.starts_with("-fcomplex-arithmetic=") &&
NewOpt.starts_with("-fcomplex-arithmetic=")))
return;
D.Diag(clang::diag::warn_drv_overriding_complex_range)
<< LastOpt << NewOpt << complexRangeKindToStr(Range)
<< complexRangeKindToStr(NewRange);
}
void tools::setComplexRange(const Driver &D, StringRef NewOpt,
LangOptions::ComplexRangeKind NewRange,
StringRef &LastOpt,
LangOptions::ComplexRangeKind &Range) {
// Warn if user overrides the previously set complex number
// multiplication/division option.
if (Range != LangOptions::ComplexRangeKind::CX_None && Range != NewRange)
emitComplexRangeDiag(D, LastOpt, Range, NewOpt, NewRange);
LastOpt = NewOpt;
Range = NewRange;
}

View File

@ -693,6 +693,7 @@ static void addFloatingPointOptions(const Driver &D, const ArgList &Args,
bool AssociativeMath = false;
bool ReciprocalMath = false;
StringRef LastComplexRangeOption;
LangOptions::ComplexRangeKind Range = LangOptions::ComplexRangeKind::CX_None;
if (const Arg *A = Args.getLastArg(options::OPT_ffp_contract)) {
@ -720,17 +721,22 @@ static void addFloatingPointOptions(const Driver &D, const ArgList &Args,
continue;
case options::OPT_fcomplex_arithmetic_EQ: {
LangOptions::ComplexRangeKind NewRange;
StringRef Val = A->getValue();
if (Val == "full")
Range = LangOptions::ComplexRangeKind::CX_Full;
NewRange = LangOptions::ComplexRangeKind::CX_Full;
else if (Val == "improved")
Range = LangOptions::ComplexRangeKind::CX_Improved;
NewRange = LangOptions::ComplexRangeKind::CX_Improved;
else if (Val == "basic")
Range = LangOptions::ComplexRangeKind::CX_Basic;
NewRange = LangOptions::ComplexRangeKind::CX_Basic;
else {
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getSpelling() << Val;
break;
}
setComplexRange(D, Args.MakeArgString(A->getSpelling() + Val), NewRange,
LastComplexRangeOption, Range);
break;
}
case options::OPT_fhonor_infinities:
@ -779,6 +785,9 @@ static void addFloatingPointOptions(const Driver &D, const ArgList &Args,
ApproxFunc = true;
SignedZeros = false;
FPContract = "fast";
setComplexRange(D, A->getSpelling(),
LangOptions::ComplexRangeKind::CX_Basic,
LastComplexRangeOption, Range);
break;
case options::OPT_fno_fast_math:
HonorINFs = true;
@ -792,6 +801,9 @@ static void addFloatingPointOptions(const Driver &D, const ArgList &Args,
// --ffp-contract=off -fno-fast-math --> -ffp-contract=off
if (FPContract == "fast")
FPContract = "";
setComplexRange(D, A->getSpelling(),
LangOptions::ComplexRangeKind::CX_None,
LastComplexRangeOption, Range);
break;
}

View File

@ -93,7 +93,9 @@ While [the same option in clang][2] allows specifying `promoted`, this is not
implemented in Flang. Also, in the case of `improved`, clang does not handle NaN
and infinite values, but Flang does. These behavioral differences arise because
the transformation of complex division calculations depends on the implementation
of ComplexToStandard, which may change in the future.
of ComplexToStandard, which may change in the future. If you specify
`-ffast-math`, the lowering is the same as specifiying
`-fcomplex-arithmetic=basic`.
[1]: https://discourse.llvm.org/t/rfc-change-lowering-of-fortran-math-intrinsics/63971
[2]: https://clang.llvm.org/docs/UsersManual.html#cmdoption-fcomplex-arithmetic

View File

@ -573,6 +573,9 @@ documentation for more details.
These correspond to LLVM IR Fast Math attributes:
https://llvm.org/docs/LangRef.html#fast-math-flags
In addition to the above, `-ffast-math` also enables
`-fcomplex-arithmetic=basic`.
When `-ffast-math` is specified, any linker steps generated by the compiler
driver will also link to `crtfastmath.o`, which adds a static constructor
that sets the FTZ/DAZ bits in MXCSR, affecting not only the current only the

View File

@ -15,6 +15,83 @@
! RUN: not %flang -### -fcomplex-arithmetic=foo -c %s 2>&1 \
! RUN: | FileCheck %s --check-prefix=ERR
! RUN: %flang -### -ffast-math -c %s 2>&1 \
! RUN: | FileCheck %s --check-prefix=BASIC
! RUN: %flang -### -fno-fast-math -c %s 2>&1 \
! RUN: | FileCheck %s --check-prefix=RANGE
! RUN: %flang -### -Werror -ffast-math -fno-fast-math -c %s 2>&1 \
! RUN: | FileCheck --check-prefixes=RANGE %s
! RUN: %flang -### -ffast-math -fcomplex-arithmetic=full -c %s 2>&1 \
! RUN: | FileCheck --check-prefixes=FULL,ARITH-FULL-OVERRIDING,FAST-OVERRIDDEN %s
! RUN: %flang -### -ffast-math -fcomplex-arithmetic=improved -c %s 2>&1 \
! RUN: | FileCheck --check-prefixes=IMPRVD,ARITH-IMPROVED-OVERRIDING,FAST-OVERRIDDEN %s
! RUN: %flang -### -Werror -ffast-math -fcomplex-arithmetic=basic -c %s 2>&1 \
! RUN: | FileCheck --check-prefixes=BASIC %s
! RUN: %flang -### -Werror -fno-fast-math -ffast-math -c %s 2>&1 \
! RUN: | FileCheck --check-prefixes=BASIC %s
! RUN: %flang -### -Werror -fno-fast-math -fcomplex-arithmetic=full -c %s 2>&1 \
! RUN: | FileCheck --check-prefixes=FULL %s
! RUN: %flang -### -Werror -fno-fast-math -fcomplex-arithmetic=improved -c %s 2>&1 \
! RUN: | FileCheck --check-prefixes=IMPRVD %s
! RUN: %flang -### -Werror -fno-fast-math -fcomplex-arithmetic=basic -c %s 2>&1 \
! RUN: | FileCheck --check-prefixes=BASIC %s
! RUN: %flang -### -fcomplex-arithmetic=full -ffast-math -c %s 2>&1 \
! RUN: | FileCheck --check-prefixes=BASIC,FAST-OVERRIDING,ARITH-FULL-OVERRIDDEN %s
! RUN: %flang -### -Werror -fcomplex-arithmetic=full -fno-fast-math -c %s 2>&1 \
! RUN: | FileCheck --check-prefixes=RANGE %s
! RUN: %flang -### -Werror -fcomplex-arithmetic=full -fcomplex-arithmetic=improved -c %s 2>&1 \
! RUN: | FileCheck --check-prefixes=IMPRVD %s
! RUN: %flang -### -Werror -fcomplex-arithmetic=full -fcomplex-arithmetic=basic -c %s 2>&1 \
! RUN: | FileCheck --check-prefixes=BASIC %s
! RUN: %flang -### -fcomplex-arithmetic=improved -ffast-math -c %s 2>&1 \
! RUN: | FileCheck --check-prefixes=BASIC,FAST-OVERRIDING,ARITH-IMPROVED-OVERRIDDEN %s
! RUN: %flang -### -fcomplex-arithmetic=improved -fno-fast-math -c %s 2>&1 \
! RUN: | FileCheck --check-prefixes=RANGE,NOFAST-OVERRIDING,ARITH-IMPROVED-OVERRIDDEN %s
! RUN: %flang -### -Werror -fcomplex-arithmetic=improved -fcomplex-arithmetic=full -c %s 2>&1 \
! RUN: | FileCheck --check-prefixes=FULL %s
! RUN: %flang -### -Werror -fcomplex-arithmetic=improved -fcomplex-arithmetic=basic -c %s 2>&1 \
! RUN: | FileCheck --check-prefixes=BASIC %s
! RUN: %flang -### -Werror -fcomplex-arithmetic=basic -ffast-math -c %s 2>&1 \
! RUN: | FileCheck --check-prefixes=BASIC %s
! RUN: %flang -### -fcomplex-arithmetic=basic -fno-fast-math -c %s 2>&1 \
! RUN: | FileCheck --check-prefixes=RANGE,NOFAST-OVERRIDING,ARITH-BASIC-OVERRIDDEN %s
! RUN: %flang -### -Werror -fcomplex-arithmetic=basic -fcomplex-arithmetic=full -c %s 2>&1 \
! RUN: | FileCheck --check-prefixes=FULL %s
! RUN: %flang -### -Werror -fcomplex-arithmetic=basic -fcomplex-arithmetic=improved -c %s 2>&1 \
! RUN: | FileCheck --check-prefixes=IMPRVD %s
! FAST-OVERRIDING: warning: '-ffast-math' sets complex range to "basic"
! NOFAST-OVERRIDING: warning: '-fno-fast-math' sets complex range to "none"
! ARITH-FULL-OVERRIDING: warning: '-fcomplex-arithmetic=full' sets complex range to "full"
! ARITH-IMPROVED-OVERRIDING: warning: '-fcomplex-arithmetic=improved' sets complex range to "improved"
! FAST-OVERRIDDEN: overriding the setting of "basic" that was implied by '-ffast-math' [-Woverriding-complex-range]
! ARITH-FULL-OVERRIDDEN: overriding the setting of "full" that was implied by '-fcomplex-arithmetic=full' [-Woverriding-complex-range]
! ARITH-IMPROVED-OVERRIDDEN: overriding the setting of "improved" that was implied by '-fcomplex-arithmetic=improved' [-Woverriding-complex-range]
! ARITH-BASIC-OVERRIDDEN: overriding the setting of "basic" that was implied by '-fcomplex-arithmetic=basic' [-Woverriding-complex-range]
! RANGE-NOT: -complex-range=
! FULL: -complex-range=full
! IMPRVD: -complex-range=improved