-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[CLANG] Full support of complex multiplication and division. #81514
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
Changes from all commits
13fd739
eb9a35c
d3c4f78
4aa0925
fcd5665
2ddba9a
e62c462
f635f94
1d61aa6
148b6ce
5aa2711
ba9a8da
9098908
52181c7
a9449de
e20741e
0d97b9b
bc3fa4f
ec6296f
3117dbd
0a08598
a558d31
dec045b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1046,30 +1046,29 @@ 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">, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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: This warning is a bit mis-leading and doesn't reflect the option used in the command line. Not sure this can be corrected. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes there is a way of doing that:
That still produces the misleading warning for: -fcx-limited-range -fcomplex-arithmetic=improved There was a problem hiding this comment. Choose a reason for hiding this commentThe 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">; | ||
|
||
defm cx_limited_range: BoolOptionWithoutMarshalling<"f", "cx-limited-range", | ||
PosFlag<SetTrue, [], [ClangOption, CC1Option], "Basic algebraic expansions of " | ||
"complex arithmetic operations involving are enabled.">, | ||
NegFlag<SetFalse, [], [ClangOption, CC1Option], "Basic algebraic expansions " | ||
"of complex arithmetic operations involving are disabled.">>; | ||
|
||
defm cx_fortran_rules: BoolOptionWithoutMarshalling<"f", "cx-fortran-rules", | ||
PosFlag<SetTrue, [], [ClangOption, CC1Option], "Range reduction is enabled for " | ||
"complex arithmetic operations.">, | ||
NegFlag<SetFalse, [], [ClangOption, CC1Option], "Range reduction is disabled " | ||
"for complex arithmetic operations">>; | ||
|
||
// OpenCL-only Options | ||
def cl_opt_disable : Flag<["-"], "cl-opt-disable">, Group<opencl_Group>, | ||
Visibility<[ClangOption, CC1Option]>, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -51,11 +51,12 @@ class ComplexExprEmitter | |
CGBuilderTy &Builder; | ||
bool IgnoreReal; | ||
bool IgnoreImag; | ||
public: | ||
ComplexExprEmitter(CodeGenFunction &cgf, bool ir=false, bool ii=false) | ||
: CGF(cgf), Builder(CGF.Builder), IgnoreReal(ir), IgnoreImag(ii) { | ||
} | ||
bool FPHasBeenPromoted; | ||
|
||
public: | ||
ComplexExprEmitter(CodeGenFunction &cgf, bool ir = false, bool ii = false) | ||
: CGF(cgf), Builder(CGF.Builder), IgnoreReal(ir), IgnoreImag(ii), | ||
FPHasBeenPromoted(false) {} | ||
|
||
//===--------------------------------------------------------------------===// | ||
// Utilities | ||
|
@@ -287,9 +288,54 @@ class ComplexExprEmitter | |
ComplexPairTy EmitComplexBinOpLibCall(StringRef LibCallName, | ||
const BinOpInfo &Op); | ||
|
||
QualType getPromotionType(QualType Ty) { | ||
QualType GetHigherPrecisionFPType(QualType ElementType) { | ||
const auto *CurrentBT = dyn_cast<BuiltinType>(ElementType); | ||
switch (CurrentBT->getKind()) { | ||
case BuiltinType::Kind::Float16: | ||
return CGF.getContext().FloatTy; | ||
case BuiltinType::Kind::Float: | ||
case BuiltinType::Kind::BFloat16: | ||
return CGF.getContext().DoubleTy; | ||
case BuiltinType::Kind::Double: | ||
return CGF.getContext().LongDoubleTy; | ||
default: | ||
return ElementType; | ||
} | ||
} | ||
|
||
QualType HigherPrecisionTypeForComplexArithmetic(QualType ElementType, | ||
bool IsDivOpCode) { | ||
QualType HigherElementType = GetHigherPrecisionFPType(ElementType); | ||
const llvm::fltSemantics &ElementTypeSemantics = | ||
CGF.getContext().getFloatTypeSemantics(ElementType); | ||
const llvm::fltSemantics &HigherElementTypeSemantics = | ||
CGF.getContext().getFloatTypeSemantics(HigherElementType); | ||
// Check that the promoted type can handle the intermediate values without | ||
// overflowing. This can be interpreted as: | ||
// (SmallerType.LargestFiniteVal * SmallerType.LargestFiniteVal) * 2 <= | ||
// LargerType.LargestFiniteVal. | ||
// In terms of exponent it gives this formula: | ||
// (SmallerType.LargestFiniteVal * SmallerType.LargestFiniteVal | ||
// doubles the exponent of SmallerType.LargestFiniteVal) | ||
if (llvm::APFloat::semanticsMaxExponent(ElementTypeSemantics) * 2 + 1 <= | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd appreciate a comment here explaining why this is the correct check, so that future people reading this code can understand why this is being doing. |
||
llvm::APFloat::semanticsMaxExponent(HigherElementTypeSemantics)) { | ||
return CGF.getContext().getComplexType(HigherElementType); | ||
} else { | ||
FPHasBeenPromoted = true; | ||
DiagnosticsEngine &Diags = CGF.CGM.getDiags(); | ||
Diags.Report(diag::warn_next_larger_fp_type_same_size_than_fp); | ||
return CGF.getContext().getComplexType(ElementType); | ||
} | ||
} | ||
|
||
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); | ||
} | ||
|
@@ -300,11 +346,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; \ | ||
} | ||
|
||
|
@@ -794,8 +841,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 | ||
|
@@ -986,14 +1034,17 @@ 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) | ||
QualType ComplexElementTy = Op.Ty->castAs<ComplexType>()->getElementType(); | ||
if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Improved || | ||
(Op.FPFeatures.getComplexRange() == LangOptions::CX_Promoted && | ||
FPHasBeenPromoted)) | ||
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 || | ||
// '-ffast-math' is used in the command line but followed by an | ||
// '-fno-cx-limited-range'. | ||
Op.FPFeatures.getComplexRange() == LangOptions::CX_Full) { | ||
// '-ffast-math' is used in the command line but followed by an | ||
// '-fno-cx-limited-range' or '-fcomplex-arithmetic=full'. | ||
else if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Full) { | ||
LHSi = OrigLHSi; | ||
// If we have a complex operand on the RHS and FastMath is not allowed, we | ||
// delegate to a libcall to handle all of the complexities and minimize | ||
|
Uh oh!
There was an error while loading. Please reload this page.