Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CLANG] Full support of complex multiplication and division. #81514

Merged
merged 23 commits into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
13fd739
[CLANG] Full support of complex multiplication and division.
zahiraam Feb 12, 2024
eb9a35c
Changed the names of the values for the option and added
zahiraam Feb 20, 2024
d3c4f78
Merge remote-tracking branch 'origin/main' into ComplexRange
zahiraam Feb 20, 2024
4aa0925
Fix LIT tests.
zahiraam Feb 21, 2024
fcd5665
Merge remote-tracking branch 'origin/main' into ComplexRange
zahiraam Feb 21, 2024
2ddba9a
Addressed only a few issue from reviewer's comment.
zahiraam Feb 22, 2024
e62c462
Fixed warnings.
zahiraam Feb 26, 2024
f635f94
Merge branch 'llvm:main' into ComplexRange
zahiraam Feb 26, 2024
1d61aa6
Fix format.
zahiraam Feb 26, 2024
148b6ce
Merge branch 'ComplexRange' of https://github.com/zahiraam/llvm-proje…
zahiraam Feb 26, 2024
5aa2711
Fix format.
zahiraam Feb 26, 2024
ba9a8da
Fixed LIT test nofpclass.c and fixed the type promotion.
zahiraam Feb 27, 2024
9098908
Addressed review comments. Fixed the warnings code in Clang.cpp
zahiraam Feb 27, 2024
52181c7
Added more tests to cx-complex-range.c
zahiraam Feb 28, 2024
a9449de
Set the default value of option to full.
zahiraam Feb 29, 2024
e20741e
Wrote a more general function to deal with next larger types
zahiraam Mar 4, 2024
0d97b9b
Addressed review comments.
zahiraam Mar 11, 2024
bc3fa4f
Fix format.
zahiraam Mar 11, 2024
ec6296f
Merge branch 'main' into ComplexRange
zahiraam Mar 12, 2024
3117dbd
Addressed some of the review comments and working on the rest.
zahiraam Mar 15, 2024
0a08598
Addressed a few more comments. The last issue still WIP is the
zahiraam Mar 15, 2024
a558d31
Added LIT tests.
zahiraam Mar 18, 2024
dec045b
Changed the type of FPHasBeenPromoted to bool.
zahiraam Mar 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 27 additions & 13 deletions clang/docs/UsersManual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1847,19 +1847,33 @@ floating point semantic models: precise (the default), strict, and fast.
* ``16`` - Forces ``_Float16`` operations to be emitted without using excess
precision arithmetic.

.. option:: -fcx-limited-range:

This option enables the naive mathematical formulas for complex division and
multiplication with no NaN checking of results. The default is
``-fno-cx-limited-range``, but this option is enabled by the ``-ffast-math``
option.

.. option:: -fcx-fortran-rules:

This option enables the naive mathematical formulas for complex
multiplication and enables application of Smith's algorithm for complex
division. See SMITH, R. L. Algorithm 116: Complex division. Commun.
ACM 5, 8 (1962). The default is ``-fno-cx-fortran-rules``.
.. option:: -fcomplex-arithmetic=<value>:

This option specifies the implementation for complex multiplication and division.

Valid values are: ``basic``, ``improved``, ``full`` and ``promoted``.

* ``basic`` Implementation of complex division and multiplication using
algebraic formulas at source precision. No special handling to avoid
overflow. NaN and infinite and values are not handled.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
overflow. NaN and infinite and values are not handled.
overflow. NaN and infinite values are not handled.

* ``improved`` Implementation of complex division using the Smith algorithm at
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure we should document this as being implemented using the Smith algorithm. That may be left as an implementation detail, particularly if we start generating intrinsics which are handled in the backend or by an offload target. I would prefer to just describe the characteristics this option is intended to provide -- improved handling for overflow, but no special handling for the "NaN + NaNi" cases.

source precision. Smith's algorithm for complex division.
See SMITH, R. L. Algorithm 116: Complex division. Commun. ACM 5, 8 (1962).
This value offers improved handling for overflow in intermediate calculations,
but overflow may occur. NaN and infinite and values are not handled in some
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"but overflow may occur" -- I'm getting a little bit over my head here, but I think the academic papers for the Smith algorithm say that it underflows but doesn't overflow. Or maybe that was a description of an improvement to Smith that I came across. If we're going to be technical here, we should be sure that our wording is accurate.

Copy link
Contributor Author

@zahiraam zahiraam Feb 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I don't mention the Smith's algorithm here, then I wouldn't have to add that. But this is what the Smith's algorithm comment indicates:
"The method used here tends to avoid arithmetic overflow or underflow. Such spills could otherwise occur when squaring the component parts of the denominator if the usual method were used.”

cases.
* ``full`` Implementation of complex division and multiplication using a
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are we doing with fast-math flags in these expansions? In the case of complex multiplication, if the 'nnan' and 'ninf' flags are set on the generated instructions, the "full" implementation will be optimized to the "basic" implementation. I think that's probably what we want since "full" is going to be the default. It may warrant a warning if we see an explicit "-fcomplex-arithmetic=full" on the command line with any of the options that sets either 'nnan' or 'ninf'.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-ffast-math implies "basic".
-ffast-math -fcomplex-arithmetic=full generates this warning:
" overriding '-fcomplex-arithmetic=basic' option with '-fcomplex-arithmetic=full'
-fcomplex-arithmetic=full -ffast-math doesn't generate any warning. I can add one mentioning the presence of nnan/ninf and "full" option.

In the case of complex multiplication, if the 'nnan' and 'ninf' flags are set on the generated instructions, the "full" implementation will be optimized to the "basic" implementation.

This is not the case currently. I will add that.

call to runtime library functions (generally the case, but the BE might
sometimes replace the library call if it knows enough about the potential
range of the inputs). Overflow and non-finite values are handled by the
library implementation.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the case of multiplication, the library call is only needed to handle non-finite values. Overflow occurs in accordance with normal floating-point rules. That is, even if we promoted to a higher precision type, the same overflow would occur when we truncate back to the source type. This isn't true for division because of the nature of the intermediate calculations.

* ``promoted`` Implementation of complex division using algebraic formulas at
higher precision. Overflow is handled. Non-finite values are handled in some
cases. If the target hardware does not have native support for a higher precision
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
cases. If the target hardware does not have native support for a higher precision
cases. If the target does not have native support for a higher precision

I suggest removing "hardware" since the target may be SPIRV with unknown hardware.

I'm not sure what we should do in the case of soft-float targets. Probably "full" makes most sense there, but I'd like to hear from someone who works with one of those targets.

data type, an implementation for the complex operation will be used to provide
improved guards against intermediate overflow, but overflow and underflow may
still occur in some cases. NaN and infinite and values are not handled.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
still occur in some cases. NaN and infinite and values are not handled.
still occur in some cases. NaN and infinite values are not handled.

This is the default value.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think for many users this would make sense as the default value, but "full" is required for conformance to the C standard. Can we use this as the default if we're targeting pre-C99 but use "full" with C99 and later? I'm not sure what C++ expects, but probably "full" there too.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would perhaps be surprising for C89 to use "promoted" and C99 and later to use "full", I think they should probably all use "full" consistently (same with C++, otherwise you get subtle differences with code that lives in header files depending on whether the header is consumed in C or C++ mode).

CC @jcranmer-intel for other opinions

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C89 doesn't have complex types, do we even support _Complex in -std=gnu89 mode?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we support it as a conforming extension: https://godbolt.org/z/PvdhrTeYx

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that gcc uses a runtime library call with both c89 and c99. That seems like a reasonable way to go.


.. _floating-point-environment:

Expand Down
36 changes: 35 additions & 1 deletion clang/include/clang/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,41 @@ class LangOptionsBase {
IncompleteOnly = 3,
};

enum ComplexRangeKind { CX_Full, CX_Limited, CX_Fortran, CX_None };
/// Controls the various implementations for complex multiplication and
// division.
enum ComplexRangeKind {
/// Implementation of complex division and multiplication using a call to
/// runtime library functions(generally the case, but the BE might
/// sometimes replace the library call if it knows enough about the
/// potential range of the inputs). Overflow and non -finite values are
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// potential range of the inputs). Overflow and non -finite values are
/// potential range of the inputs). Overflow and non-finite values are

/// handled by the library implementation.
CX_Full,

/// Implementation of complex division using the Smith algorithm at
/// source precision. Smith's algorithm for complex division.
/// See SMITH, R. L. Algorithm 116: Complex division. Commun. ACM 5, 8
/// (1962). This value offers improved handling for overflow in intermediate
/// calculations, but overflow may occur. NaN and infinite and values are
/// not handled in some cases.
CX_Improved,

/// Implementation of complex division using algebraic formulas at
/// higher precision. Overflow is handled. Non-finite values are handled in
/// some cases. If the target hardware does not have native support for a
/// higher precision data type, an implementation for the complex operation
/// will be used to provide improved guards against intermediate overflow,
/// but overflow and underflow may still occur in some cases. NaN and
/// infinite and values are not handled. This is the default value.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// infinite and values are not handled. This is the default value.
/// infinite values are not handled. This is the default value.

Be sure to update this comment if switching the default to "full".

CX_Promoted,

/// Implementation of complex division and multiplication using
/// algebraic formulas at source precision.No special handling to avoid
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// algebraic formulas at source precision.No special handling to avoid
/// algebraic formulas at source precision. No special handling to avoid

/// overflow.NaN and infinite and values are not handled.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// overflow.NaN and infinite and values are not handled.
/// overflow. NaN and infinite values are not handled.

CX_Basic,

/// No range rule is enabled.
CX_None
};

// Define simple language options (with no accessors).
#define LANGOPT(Name, Bits, Default, Description) unsigned Name : Bits;
Expand Down
25 changes: 6 additions & 19 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1039,28 +1039,15 @@ defm offload_uniform_block : BoolFOption<"offload-uniform-block",
NegFlag<SetFalse, [], [ClangOption, CC1Option], "Don't assume">,
BothFlags<[], [ClangOption], " that kernels are launched with uniform block sizes (default true for CUDA/HIP and false otherwise)">>;

def fcx_limited_range : Joined<["-"], "fcx-limited-range">,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't realize these had made it into the 18.0 release when I suggested that we could remove them. We would need at least one release where they are marked as deprecated, but since they are standard gcc options, maybe it makes sense to just keep them and have them alias to the new option as:

-fcx-limited-range --> -fcomplex-arithmetic=basic
-fcx-fortran-rules --> -fcomplex-arithmetic=improved
-fno-cx-limited-range --> -fcomplex-arithmetic=full
-fno-cx-fortran-rules --> -fcomplex-arithmetic=full

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem with aliasing is that the user would be allowed to write something like this:
-fcx-limited-range -fcomplex-arithmetic=improved
This will generate a warning like this:
warning: overriding '-fcomplex-arithmetic=basic' option with '-fcomplex-arithmetic=improved' [-Woverriding-option]

This warning is a bit mis-leading and doesn't reflect the option used in the command line. Not sure this can be corrected.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry. I meant "aliasing" in the non-technical sense of "having the same meaning." How that gets implemented is another matter. I think the driver could translate them to the same cc1 option.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes there is a way of doing that:

def fcx_limited_range : Flag<["-"], "fcx-limited-range">,
  Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
  HelpText<"Basic algebraic expansions of complex arithmetic operations "
           "involving are enabled.">,
  Alias<fcomplex_arithmetic_EQ>, AliasArgs<["basic"]>;

That still produces the misleading warning for: -fcx-limited-range -fcomplex-arithmetic=improved

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I meant to suggest is that you can leave the driver-level options as if they were independent, but when we process them in RenderFloatingPointOptions, -fcx-limited-range and -fcomplex-arithmetic=basic (for example), would add the same cc1 option. Since the warning is generated from the RenderFloatingPointOptions we should be able to make that report the expected output.

Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
HelpText<"Basic algebraic expansions of complex arithmetic operations "
"involving are enabled.">;

def fno_cx_limited_range : Joined<["-"], "fno-cx-limited-range">,
Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
HelpText<"Basic algebraic expansions of complex arithmetic operations "
"involving are disabled.">;

def fcx_fortran_rules : Joined<["-"], "fcx-fortran-rules">,
Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
HelpText<"Range reduction is enabled for complex arithmetic operations.">;

def fno_cx_fortran_rules : Joined<["-"], "fno-cx-fortran-rules">,
Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
HelpText<"Range reduction is disabled for complex arithmetic operations.">;
def fcomplex_arithmetic_EQ : Joined<["-"], "fcomplex-arithmetic=">, Group<f_Group>,
Visibility<[ClangOption, CC1Option]>,
Values<"full,improved,promoted,basic">, NormalizedValuesScope<"LangOptions">,
NormalizedValues<["CX_Full", "CX_Improved", "CX_Promoted", "CX_Basic"]>;

def complex_range_EQ : Joined<["-"], "complex-range=">, Group<f_Group>,
Visibility<[CC1Option]>,
Values<"full,limited,fortran">, NormalizedValuesScope<"LangOptions">,
NormalizedValues<["CX_Full", "CX_Limited", "CX_Fortran"]>,
Values<"full,improved,promoted,basic">, NormalizedValuesScope<"LangOptions">,
NormalizedValues<["CX_Full", "CX_Improved", "CX_Promoted", "CX_Basic"]>,
MarshallingInfoEnum<LangOpts<"ComplexRange">, "CX_Full">;

// OpenCL-only Options
Expand Down
58 changes: 50 additions & 8 deletions clang/lib/CodeGen/CGExprComplex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,9 +283,48 @@ class ComplexExprEmitter
ComplexPairTy EmitComplexBinOpLibCall(StringRef LibCallName,
const BinOpInfo &Op);

QualType getPromotionType(QualType Ty) {
QualType HigherPrecisionTypeForComplexArithmetic(QualType ElementType,
bool IsDivOpCode) {
const TargetInfo &TI = CGF.getContext().getTargetInfo();
if (const auto *BT = dyn_cast<BuiltinType>(ElementType)) {
switch (BT->getKind()) {
case BuiltinType::Kind::Float16:
case BuiltinType::Kind::BFloat16: {
return CGF.getContext().getComplexType(CGF.getContext().FloatTy);
}
case BuiltinType::Kind::Float:
return CGF.getContext().getComplexType(CGF.getContext().DoubleTy);
case BuiltinType::Kind::Double:
if (TI.hasLongDoubleType()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens with targets where double and long double are the same size?

return CGF.getContext().getComplexType(CGF.getContext().LongDoubleTy);
} else {
return QualType();
}
case BuiltinType::Kind::LongDouble:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more complicated than what you have here. The C "long double" type may be 64-bit, 80-bit, or 128-bit, depending on the target. You can get the size from LangOpts::LongDoubleSize if that's accessible here.

if (TI.getTriple().isOSLinux()) {
if (TI.hasFloat128Type() && !TI.hasLongDoubleType())
return CGF.getContext().getComplexType(CGF.getContext().Float128Ty);
else
return CGF.getContext().getComplexType(
CGF.getContext().LongDoubleTy);
}
if (TI.getTriple().isOSWindows())
return CGF.getContext().getComplexType(CGF.getContext().LongDoubleTy);
default:
return QualType();
}
}
return QualType();
}

QualType getPromotionType(QualType Ty, bool IsDivOpCode = false) {
if (auto *CT = Ty->getAs<ComplexType>()) {
QualType ElementType = CT->getElementType();
if (IsDivOpCode && ElementType->isFloatingType() &&
CGF.getLangOpts().getComplexRange() ==
LangOptions::ComplexRangeKind::CX_Promoted)
return HigherPrecisionTypeForComplexArithmetic(ElementType,
IsDivOpCode);
if (ElementType.UseExcessPrecision(CGF.getContext()))
return CGF.getContext().getComplexType(CGF.getContext().FloatTy);
}
Expand All @@ -296,11 +335,12 @@ class ComplexExprEmitter

#define HANDLEBINOP(OP) \
ComplexPairTy VisitBin##OP(const BinaryOperator *E) { \
QualType promotionTy = getPromotionType(E->getType()); \
QualType promotionTy = getPromotionType( \
E->getType(), \
(E->getOpcode() == BinaryOperatorKind::BO_Div) ? true : false); \
ComplexPairTy result = EmitBin##OP(EmitBinOps(E, promotionTy)); \
if (!promotionTy.isNull()) \
result = \
CGF.EmitUnPromotedValue(result, E->getType()); \
result = CGF.EmitUnPromotedValue(result, E->getType()); \
return result; \
}

Expand Down Expand Up @@ -790,8 +830,9 @@ ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) {
ResR = Builder.CreateFSub(AC, BD, "mul_r");
ResI = Builder.CreateFAdd(AD, BC, "mul_i");

if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Limited ||
Op.FPFeatures.getComplexRange() == LangOptions::CX_Fortran)
if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Basic ||
Op.FPFeatures.getComplexRange() == LangOptions::CX_Improved ||
Op.FPFeatures.getComplexRange() == LangOptions::CX_Promoted)
return ComplexPairTy(ResR, ResI);

// Emit the test for the real part becoming NaN and create a branch to
Expand Down Expand Up @@ -982,9 +1023,10 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
llvm::Value *OrigLHSi = LHSi;
if (!LHSi)
LHSi = llvm::Constant::getNullValue(RHSi->getType());
if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Fortran)
if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Improved)
return EmitRangeReductionDiv(LHSr, LHSi, RHSr, RHSi);
else if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Limited)
else if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Basic ||
Op.FPFeatures.getComplexRange() == LangOptions::CX_Promoted)
return EmitAlgebraicDiv(LHSr, LHSi, RHSr, RHSi);
else if (!CGF.getLangOpts().FastMath ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should remove the fast-math check here. The driver handling of fast-math sets the complex arithmetic option. This check has always been problematic because disabling just one component of fast-math (such as enabling signed zeros) causes this to be false.

// '-ffast-math' is used in the command line but followed by an
Expand Down
91 changes: 42 additions & 49 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2687,45 +2687,42 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
}
}

static StringRef EnumComplexRangeToStr(LangOptions::ComplexRangeKind Range) {
StringRef RangeStr = "";
static std::string ComplexRangeKindToStr(LangOptions::ComplexRangeKind Range) {
switch (Range) {
case LangOptions::ComplexRangeKind::CX_Limited:
return "-fcx-limited-range";
case LangOptions::ComplexRangeKind::CX_Full:
return "full";
break;
case LangOptions::ComplexRangeKind::CX_Fortran:
return "-fcx-fortran-rules";
case LangOptions::ComplexRangeKind::CX_Basic:
return "basic";
break;
default:
return RangeStr;
case LangOptions::ComplexRangeKind::CX_Improved:
return "improved";
break;
case LangOptions::ComplexRangeKind::CX_Promoted:
return "promoted";
break;
default:
return "";
}
}

static std::string ComplexArithmeticStr(LangOptions::ComplexRangeKind Range) {
return "-fcomplex-arithmetic=" + ComplexRangeKindToStr(Range);
}

static void EmitComplexRangeDiag(const Driver &D,
LangOptions::ComplexRangeKind Range1,
LangOptions::ComplexRangeKind Range2) {
if (Range1 != Range2 && Range1 != LangOptions::ComplexRangeKind::CX_None)
D.Diag(clang::diag::warn_drv_overriding_option)
<< EnumComplexRangeToStr(Range1) << EnumComplexRangeToStr(Range2);
<< ComplexArithmeticStr(Range1) << ComplexArithmeticStr(Range2);
}

static std::string
RenderComplexRangeOption(LangOptions::ComplexRangeKind Range) {
std::string ComplexRangeStr = "-complex-range=";
switch (Range) {
case LangOptions::ComplexRangeKind::CX_Full:
ComplexRangeStr += "full";
break;
case LangOptions::ComplexRangeKind::CX_Limited:
ComplexRangeStr += "limited";
break;
case LangOptions::ComplexRangeKind::CX_Fortran:
ComplexRangeStr += "fortran";
break;
default:
assert(0 && "Unexpected range option");
}
std::string ComplexRangeStr = ComplexRangeKindToStr(Range);
if (!ComplexRangeStr.empty())
return "-complex-range=" + ComplexRangeStr;
return ComplexRangeStr;
}

Expand Down Expand Up @@ -2794,7 +2791,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
FPContract = "fast";
// ffast-math enables limited range rules for complex multiplication and
// division.
Range = LangOptions::ComplexRangeKind::CX_Limited;
Range = LangOptions::ComplexRangeKind::CX_Basic;
SeenUnsafeMathModeOption = true;
};

Expand All @@ -2809,24 +2806,24 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
switch (optID) {
default:
break;
case options::OPT_fcx_limited_range: {
EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Limited);
Range = LangOptions::ComplexRangeKind::CX_Limited;
break;
}
case options::OPT_fno_cx_limited_range:
EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Full);
Range = LangOptions::ComplexRangeKind::CX_Full;
break;
case options::OPT_fcx_fortran_rules: {
EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Fortran);
Range = LangOptions::ComplexRangeKind::CX_Fortran;
case options::OPT_fcomplex_arithmetic_EQ: {
LangOptions::ComplexRangeKind RangeVal;
StringRef Val = A->getValue();
if (Val.equals("full"))
RangeVal = LangOptions::ComplexRangeKind::CX_Full;
else if (Val.equals("improved"))
RangeVal = LangOptions::ComplexRangeKind::CX_Improved;
else if (Val.equals("promoted"))
RangeVal = LangOptions::ComplexRangeKind::CX_Promoted;
else if (Val.equals("basic"))
RangeVal = LangOptions::ComplexRangeKind::CX_Basic;
else
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getSpelling() << LangOptions::ComplexRangeKind::CX_None;
EmitComplexRangeDiag(D, Range, RangeVal);
Range = RangeVal;
break;
}
case options::OPT_fno_cx_fortran_rules:
EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Full);
Range = LangOptions::ComplexRangeKind::CX_Full;
break;
case options::OPT_ffp_model_EQ: {
// If -ffp-model= is seen, reset to fno-fast-math
HonorINFs = true;
Expand Down Expand Up @@ -3239,16 +3236,12 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,

if (Range != LangOptions::ComplexRangeKind::CX_None)
ComplexRangeStr = RenderComplexRangeOption(Range);
if (!ComplexRangeStr.empty())
if (!ComplexRangeStr.empty()) {
CmdArgs.push_back(Args.MakeArgString(ComplexRangeStr));
if (Args.hasArg(options::OPT_fcx_limited_range))
CmdArgs.push_back("-fcx-limited-range");
if (Args.hasArg(options::OPT_fcx_fortran_rules))
CmdArgs.push_back("-fcx-fortran-rules");
if (Args.hasArg(options::OPT_fno_cx_limited_range))
CmdArgs.push_back("-fno-cx-limited-range");
if (Args.hasArg(options::OPT_fno_cx_fortran_rules))
CmdArgs.push_back("-fno-cx-fortran-rules");
if (Args.hasArg(options::OPT_fcomplex_arithmetic_EQ))
CmdArgs.push_back(Args.MakeArgString("-fcomplex-arithmetic=" +
ComplexRangeKindToStr(Range)));
}
}

static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs,
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Parse/ParsePragma.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -909,15 +909,15 @@ void Parser::HandlePragmaCXLimitedRange() {
LangOptions::ComplexRangeKind Range;
switch (OOS) {
case tok::OOS_ON:
Range = LangOptions::CX_Limited;
Range = LangOptions::CX_Basic;
break;
case tok::OOS_OFF:
Range = LangOptions::CX_Full;
break;
case tok::OOS_DEFAULT:
// According to ISO C99 standard chapter 7.3.4, the default value
// for the pragma is ``off'. -fcx-limited-range and -fcx-fortran-rules
// control the default value of these pragmas.
// for the pragma is ``off'. -fcomplex-arithmetic controls the default value
// of these pragmas.
Range = getLangOpts().getComplexRange();
break;
}
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CodeGen/complex-math.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// RUN: %clang_cc1 %s -O0 -emit-llvm -triple armv7-none-linux-gnueabi -o - | FileCheck %s --check-prefix=ARM
// RUN: %clang_cc1 %s -O0 -emit-llvm -triple armv7-none-linux-gnueabihf -o - | FileCheck %s --check-prefix=ARMHF
// RUN: %clang_cc1 %s -O0 -emit-llvm -triple thumbv7k-apple-watchos2.0 -o - -target-abi aapcs16 | FileCheck %s --check-prefix=ARM7K
// RUN: %clang_cc1 %s -O0 -emit-llvm -triple aarch64-unknown-unknown -ffast-math -ffp-contract=fast -complex-range=fortran -o - | FileCheck %s --check-prefix=AARCH64-FASTMATH
// RUN: %clang_cc1 %s -O0 -emit-llvm -triple aarch64-unknown-unknown -ffast-math -ffp-contract=fast -complex-range=improved -o - | FileCheck %s --check-prefix=AARCH64-FASTMATH
// RUN: %clang_cc1 %s -O0 -emit-llvm -triple spir -o - | FileCheck %s --check-prefix=SPIR

float _Complex add_float_rr(float a, float b) {
Expand Down
Loading
Loading