Skip to content

Commit b40c534

Browse files
zahiraamjhuber6gryppnbpateljrtc27
authored
[clang] Add support for -fcx-limited-range, #pragma CX_LIMITED_RANGE and -fcx-fortran-rules. (#70244)
This patch adds the #pragma CX_LIMITED_RANGE defined in the C specification. It also adds the options -f[no]cx-limited-range and -f[no]cx-fortran-rules. -fcx-limited-range enables algebraic formulas for complex multiplication and division. This option is enabled with -ffast-math. -fcx-fortran-rules enables algebraic formulas for complex multiplication and enables Smith’s algorithm for complex division (SMITH, R. L. Algorithm 116: Complex division. Commun. ACM 5, 8 (1962)). --------- Signed-off-by: Med Ismail Bennani <[email protected]> Co-authored-by: Joseph Huber <[email protected]> Co-authored-by: Guray Ozen <[email protected]> Co-authored-by: Nishant Patel <[email protected]> Co-authored-by: Jessica Clarke <[email protected]> Co-authored-by: Petr Hosek <[email protected]> Co-authored-by: Joseph Huber <[email protected]> Co-authored-by: Craig Topper <[email protected]> Co-authored-by: Alexander Yermolovich <[email protected]> Co-authored-by: Usama Hameed <[email protected]> Co-authored-by: Philip Reames <[email protected]> Co-authored-by: Evgenii Kudriashov <[email protected]> Co-authored-by: Fangrui Song <[email protected]> Co-authored-by: Aart Bik <[email protected]> Co-authored-by: Valentin Clement <[email protected]> Co-authored-by: Youngsuk Kim <[email protected]> Co-authored-by: Arthur Eubanks <[email protected]> Co-authored-by: Jan Svoboda <[email protected]> Co-authored-by: Walter Erquinigo <[email protected]> Co-authored-by: Eric <[email protected]> Co-authored-by: Fazlay Rabbi <[email protected]> Co-authored-by: Pete Lawrence <[email protected]> Co-authored-by: Jonas Devlieghere <[email protected]> Co-authored-by: Adrian Prantl <[email protected]> Co-authored-by: Owen Pan <[email protected]> Co-authored-by: LLVM GN Syncbot <[email protected]> Co-authored-by: Med Ismail Bennani <[email protected]> Co-authored-by: Congcong Cai <[email protected]> Co-authored-by: Rik Huijzer <[email protected]> Co-authored-by: Wang Pengcheng <[email protected]> Co-authored-by: Yuanfang Chen <[email protected]> Co-authored-by: Kazu Hirata <[email protected]> Co-authored-by: Mehdi Amini <[email protected]> Co-authored-by: Aiden Grossman <[email protected]> Co-authored-by: Rana Pratap Reddy <[email protected]> Co-authored-by: Yingwei Zheng <[email protected]> Co-authored-by: Piotr Zegar <[email protected]> Co-authored-by: KAWASHIMA Takahiro <[email protected]> Co-authored-by: Tobias Hieta <[email protected]> Co-authored-by: Luke Lau <[email protected]> Co-authored-by: Shivam Gupta <[email protected]> Co-authored-by: cor3ntin <[email protected]> Co-authored-by: Yeting Kuo <[email protected]> Co-authored-by: Stanislav Mekhanoshin <[email protected]> Co-authored-by: David Spickett <[email protected]> Co-authored-by: Matthew Devereau <[email protected]> Co-authored-by: Martin Storsjö <[email protected]> Co-authored-by: Qiu Chaofan <[email protected]> Co-authored-by: Pierre van Houtryve <[email protected]> Co-authored-by: Mikael Holmen <[email protected]> Co-authored-by: Uday Bondhugula <[email protected]> Co-authored-by: Nikita Popov <[email protected]> Co-authored-by: Johannes Reifferscheid <[email protected]> Co-authored-by: Benjamin Kramer <[email protected]> Co-authored-by: Oliver Stannard <[email protected]> Co-authored-by: Dmitry Vyukov <[email protected]> Co-authored-by: Benjamin Maxwell <[email protected]> Co-authored-by: Piotr Sobczak <[email protected]> Co-authored-by: Simon Pilgrim <[email protected]> Co-authored-by: Timm Bäder <[email protected]> Co-authored-by: Sunil Kuravinakop <[email protected]> Co-authored-by: zhongyunde 00443407 <[email protected]> Co-authored-by: Christudasan Devadasan <[email protected]> Co-authored-by: bjacob <[email protected]> Co-authored-by: Weining Lu <[email protected]> Co-authored-by: Andrzej Warzyński <[email protected]> Co-authored-by: Jay Foad <[email protected]> Co-authored-by: Markus Mützel <[email protected]> Co-authored-by: Erik Jonsson <[email protected]> Co-authored-by: Pete Steinfeld <[email protected]> Co-authored-by: Alexey Bataev <[email protected]> Co-authored-by: Louis Dionne <[email protected]> Co-authored-by: Qizhi Hu <[email protected]>
1 parent 8b5af31 commit b40c534

File tree

21 files changed

+960
-136
lines changed

21 files changed

+960
-136
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,16 @@ New Compiler Flags
264264

265265
* ``-fopenacc`` was added as a part of the effort to support OpenACC in clang.
266266

267+
* ``-fcx-limited-range`` enables the naive mathematical formulas for complex
268+
division and multiplication with no NaN checking of results. The default is
269+
``-fno-cx-limited-range``, but this option is enabled by ``-ffast-math``.
270+
271+
* ``-fcx-fortran-rules`` enables the naive mathematical formulas for complex
272+
multiplication and enables application of Smith's algorithm for complex
273+
division. See SMITH, R. L. Algorithm 116: Complex division. Commun. ACM 5, 8
274+
(1962). The default is ``-fno-cx-fortran-rules``.
275+
276+
267277
Deprecated Compiler Flags
268278
-------------------------
269279

@@ -1002,6 +1012,9 @@ Floating Point Support in Clang
10021012
``__builtin_exp10f128`` builtins.
10031013
- Add ``__builtin_iszero``, ``__builtin_issignaling`` and
10041014
``__builtin_issubnormal``.
1015+
- Add support for C99's ``#pragma STDC CX_LIMITED_RANGE`` feature. This
1016+
enables the naive mathematical formulas for complex multiplication and
1017+
division, which are faster but do not correctly handle overflow and infinities.
10051018

10061019
AST Matchers
10071020
------------

clang/docs/UsersManual.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,6 +1468,7 @@ floating point semantic models: precise (the default), strict, and fast.
14681468
With the exception of ``-ffp-contract=fast``, using any of the options
14691469
below to disable any of the individual optimizations in ``-ffast-math``
14701470
will cause ``__FAST_MATH__`` to no longer be set.
1471+
``-ffast-math`` enables ``-fcx-limited-range``.
14711472

14721473
This option implies:
14731474

@@ -1834,6 +1835,20 @@ floating point semantic models: precise (the default), strict, and fast.
18341835
* ``16`` - Forces ``_Float16`` operations to be emitted without using excess
18351836
precision arithmetic.
18361837

1838+
.. option:: -fcx-limited-range:
1839+
1840+
This option enables the naive mathematical formulas for complex division and
1841+
multiplication with no NaN checking of results. The default is
1842+
``-fno-cx-limited-range``, but this option is enabled by the ``-ffast-math``
1843+
option.
1844+
1845+
.. option:: -fcx-fortran-rules:
1846+
1847+
This option enables the naive mathematical formulas for complex
1848+
multiplication and enables application of Smith's algorithm for complex
1849+
division. See SMITH, R. L. Algorithm 116: Complex division. Commun.
1850+
ACM 5, 8 (1962). The default is ``-fno-cx-fortran-rules``.
1851+
18371852
.. _floating-point-environment:
18381853

18391854
Accessing the floating point environment

clang/include/clang/Basic/FPOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,5 @@ OPTION(FPEvalMethod, LangOptions::FPEvalMethodKind, 2, AllowApproxFunc)
2828
OPTION(Float16ExcessPrecision, LangOptions::ExcessPrecisionKind, 2, FPEvalMethod)
2929
OPTION(BFloat16ExcessPrecision, LangOptions::ExcessPrecisionKind, 2, Float16ExcessPrecision)
3030
OPTION(MathErrno, bool, 1, BFloat16ExcessPrecision)
31+
OPTION(ComplexRange, LangOptions::ComplexRangeKind, 2, MathErrno)
3132
#undef OPTION

clang/include/clang/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo))
104104
FEATURE(swiftasynccc,
105105
PP.getTargetInfo().checkCallingConvention(CC_SwiftAsync) ==
106106
clang::TargetInfo::CCCR_OK)
107+
FEATURE(pragma_stdc_cx_limited_range, true)
107108
// Objective-C features
108109
FEATURE(objc_arr, LangOpts.ObjCAutoRefCount) // FIXME: REMOVE?
109110
FEATURE(objc_arc, LangOpts.ObjCAutoRefCount)

clang/include/clang/Basic/LangOptions.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,8 @@ BENIGN_LANGOPT(NoSignedZero , 1, 0, "Permit Floating Point optimization wit
220220
BENIGN_LANGOPT(AllowRecip , 1, 0, "Permit Floating Point reciprocal")
221221
BENIGN_LANGOPT(ApproxFunc , 1, 0, "Permit Floating Point approximation")
222222

223+
ENUM_LANGOPT(ComplexRange, ComplexRangeKind, 2, CX_Full, "Enable use of range reduction for complex arithmetics.")
224+
223225
BENIGN_LANGOPT(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for __weak/__strong ivars")
224226

225227
BENIGN_LANGOPT(AccessControl , 1, 1, "C++ access control")

clang/include/clang/Basic/LangOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,8 @@ class LangOptions : public LangOptionsBase {
392392
IncompleteOnly = 3,
393393
};
394394

395+
enum ComplexRangeKind { CX_Full, CX_Limited, CX_Fortran };
396+
395397
public:
396398
/// The used language standard.
397399
LangStandard::Kind LangStd;
@@ -741,6 +743,7 @@ class FPOptions {
741743
setAllowFEnvAccess(true);
742744
else
743745
setAllowFEnvAccess(LangOptions::FPM_Off);
746+
setComplexRange(LO.getComplexRange());
744747
}
745748

746749
bool allowFPContractWithinStatement() const {

clang/include/clang/Basic/TokenKinds.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,11 @@ PRAGMA_ANNOTATION(pragma_fenv_access_ms)
911911
// handles them.
912912
PRAGMA_ANNOTATION(pragma_fenv_round)
913913

914+
// Annotation for #pragma STDC CX_LIMITED_RANGE
915+
// The lexer produces these so that they only take effect when the parser
916+
// handles them.
917+
PRAGMA_ANNOTATION(pragma_cx_limited_range)
918+
914919
// Annotation for #pragma float_control
915920
// The lexer produces these so that they only take effect when the parser
916921
// handles them.

clang/include/clang/Driver/Options.td

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,30 @@ defm offload_uniform_block : BoolFOption<"offload-uniform-block",
10101010
NegFlag<SetFalse, [], [ClangOption, CC1Option], "Don't assume">,
10111011
BothFlags<[], [ClangOption], " that kernels are launched with uniform block sizes (default true for CUDA/HIP and false otherwise)">>;
10121012

1013+
def fcx_limited_range : Joined<["-"], "fcx-limited-range">,
1014+
Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
1015+
HelpText<"Basic algebraic expansions of complex arithmetic operations "
1016+
"involving are enabled.">;
1017+
1018+
def fno_cx_limited_range : Joined<["-"], "fno-cx-limited-range">,
1019+
Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
1020+
HelpText<"Basic algebraic expansions of complex arithmetic operations "
1021+
"involving are disabled.">;
1022+
1023+
def fcx_fortran_rules : Joined<["-"], "fcx-fortran-rules">,
1024+
Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
1025+
HelpText<"Range reduction is enabled for complex arithmetic operations.">;
1026+
1027+
def fno_cx_fortran_rules : Joined<["-"], "fno-cx-fortran-rules">,
1028+
Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
1029+
HelpText<"Range reduction is disabled for complex arithmetic operations.">;
1030+
1031+
def complex_range_EQ : Joined<["-"], "complex-range=">, Group<f_Group>,
1032+
Visibility<[CC1Option]>,
1033+
Values<"full,limited,fortran">, NormalizedValuesScope<"LangOptions">,
1034+
NormalizedValues<["CX_Full", "CX_Limited", "CX_Fortran"]>,
1035+
MarshallingInfoEnum<LangOpts<"ComplexRange">, "CX_Full">;
1036+
10131037
// OpenCL-only Options
10141038
def cl_opt_disable : Flag<["-"], "cl-opt-disable">, Group<opencl_Group>,
10151039
Visibility<[ClangOption, CC1Option]>,

clang/include/clang/Parse/Parser.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,10 @@ class Parser : public CodeCompletionHandler {
769769
/// #pragma STDC FENV_ROUND...
770770
void HandlePragmaFEnvRound();
771771

772+
/// Handle the annotation token produced for
773+
/// #pragma STDC CX_LIMITED_RANGE...
774+
void HandlePragmaCXLimitedRange();
775+
772776
/// Handle the annotation token produced for
773777
/// #pragma float_control
774778
void HandlePragmaFloatControl();

clang/include/clang/Sema/Sema.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11023,6 +11023,11 @@ class Sema final {
1102311023
/// \#pragma STDC FENV_ACCESS
1102411024
void ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled);
1102511025

11026+
/// ActOnPragmaCXLimitedRange - Called on well formed
11027+
/// \#pragma STDC CX_LIMITED_RANGE
11028+
void ActOnPragmaCXLimitedRange(SourceLocation Loc,
11029+
LangOptions::ComplexRangeKind Range);
11030+
1102611031
/// Called on well formed '\#pragma clang fp' that has option 'exceptions'.
1102711032
void ActOnPragmaFPExceptions(SourceLocation Loc,
1102811033
LangOptions::FPExceptionModeKind);

clang/lib/CodeGen/CGExprComplex.cpp

Lines changed: 134 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,10 @@ class ComplexExprEmitter
275275
ComplexPairTy EmitBinSub(const BinOpInfo &Op);
276276
ComplexPairTy EmitBinMul(const BinOpInfo &Op);
277277
ComplexPairTy EmitBinDiv(const BinOpInfo &Op);
278+
ComplexPairTy EmitAlgebraicDiv(llvm::Value *A, llvm::Value *B, llvm::Value *C,
279+
llvm::Value *D);
280+
ComplexPairTy EmitRangeReductionDiv(llvm::Value *A, llvm::Value *B,
281+
llvm::Value *C, llvm::Value *D);
278282

279283
ComplexPairTy EmitComplexBinOpLibCall(StringRef LibCallName,
280284
const BinOpInfo &Op);
@@ -781,6 +785,10 @@ ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) {
781785
ResR = Builder.CreateFSub(AC, BD, "mul_r");
782786
ResI = Builder.CreateFAdd(AD, BC, "mul_i");
783787

788+
if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Limited ||
789+
Op.FPFeatures.getComplexRange() == LangOptions::CX_Fortran)
790+
return ComplexPairTy(ResR, ResI);
791+
784792
// Emit the test for the real part becoming NaN and create a branch to
785793
// handle it. We test for NaN by comparing the number to itself.
786794
Value *IsRNaN = Builder.CreateFCmpUNO(ResR, ResR, "isnan_cmp");
@@ -846,23 +854,139 @@ ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) {
846854
return ComplexPairTy(ResR, ResI);
847855
}
848856

857+
ComplexPairTy ComplexExprEmitter::EmitAlgebraicDiv(llvm::Value *LHSr,
858+
llvm::Value *LHSi,
859+
llvm::Value *RHSr,
860+
llvm::Value *RHSi) {
861+
// (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
862+
llvm::Value *DSTr, *DSTi;
863+
864+
llvm::Value *AC = Builder.CreateFMul(LHSr, RHSr); // a*c
865+
llvm::Value *BD = Builder.CreateFMul(LHSi, RHSi); // b*d
866+
llvm::Value *ACpBD = Builder.CreateFAdd(AC, BD); // ac+bd
867+
868+
llvm::Value *CC = Builder.CreateFMul(RHSr, RHSr); // c*c
869+
llvm::Value *DD = Builder.CreateFMul(RHSi, RHSi); // d*d
870+
llvm::Value *CCpDD = Builder.CreateFAdd(CC, DD); // cc+dd
871+
872+
llvm::Value *BC = Builder.CreateFMul(LHSi, RHSr); // b*c
873+
llvm::Value *AD = Builder.CreateFMul(LHSr, RHSi); // a*d
874+
llvm::Value *BCmAD = Builder.CreateFSub(BC, AD); // bc-ad
875+
876+
DSTr = Builder.CreateFDiv(ACpBD, CCpDD);
877+
DSTi = Builder.CreateFDiv(BCmAD, CCpDD);
878+
return ComplexPairTy(DSTr, DSTi);
879+
}
880+
881+
// EmitFAbs - Emit a call to @llvm.fabs.
882+
static llvm::Value *EmitllvmFAbs(CodeGenFunction &CGF, llvm::Value *Value) {
883+
llvm::Function *Func =
884+
CGF.CGM.getIntrinsic(llvm::Intrinsic::fabs, Value->getType());
885+
llvm::Value *Call = CGF.Builder.CreateCall(Func, Value);
886+
return Call;
887+
}
888+
889+
// EmitRangeReductionDiv - Implements Smith's algorithm for complex division.
890+
// SMITH, R. L. Algorithm 116: Complex division. Commun. ACM 5, 8 (1962).
891+
ComplexPairTy ComplexExprEmitter::EmitRangeReductionDiv(llvm::Value *LHSr,
892+
llvm::Value *LHSi,
893+
llvm::Value *RHSr,
894+
llvm::Value *RHSi) {
895+
// (a + ib) / (c + id) = (e + if)
896+
llvm::Value *FAbsRHSr = EmitllvmFAbs(CGF, RHSr); // |c|
897+
llvm::Value *FAbsRHSi = EmitllvmFAbs(CGF, RHSi); // |d|
898+
// |c| >= |d|
899+
llvm::Value *IsR = Builder.CreateFCmpUGT(FAbsRHSr, FAbsRHSi, "abs_cmp");
900+
901+
llvm::BasicBlock *TrueBB =
902+
CGF.createBasicBlock("abs_rhsr_greater_or_equal_abs_rhsi");
903+
llvm::BasicBlock *FalseBB =
904+
CGF.createBasicBlock("abs_rhsr_less_than_abs_rhsi");
905+
llvm::BasicBlock *ContBB = CGF.createBasicBlock("complex_div");
906+
Builder.CreateCondBr(IsR, TrueBB, FalseBB);
907+
908+
CGF.EmitBlock(TrueBB);
909+
// abs(c) >= abs(d)
910+
// r = d/c
911+
// tmp = c + rd
912+
// e = (a + br)/tmp
913+
// f = (b - ar)/tmp
914+
llvm::Value *DdC = Builder.CreateFDiv(RHSi, RHSr); // r=d/c
915+
916+
llvm::Value *RD = Builder.CreateFMul(DdC, RHSi); // rd
917+
llvm::Value *CpRD = Builder.CreateFAdd(RHSr, RD); // tmp=c+rd
918+
919+
llvm::Value *T3 = Builder.CreateFMul(LHSi, DdC); // br
920+
llvm::Value *T4 = Builder.CreateFAdd(LHSr, T3); // a+br
921+
llvm::Value *DSTTr = Builder.CreateFDiv(T4, CpRD); // (a+br)/tmp
922+
923+
llvm::Value *T5 = Builder.CreateFMul(LHSr, DdC); // ar
924+
llvm::Value *T6 = Builder.CreateFSub(LHSi, T5); // b-ar
925+
llvm::Value *DSTTi = Builder.CreateFDiv(T6, CpRD); // (b-ar)/tmp
926+
Builder.CreateBr(ContBB);
927+
928+
CGF.EmitBlock(FalseBB);
929+
// abs(c) < abs(d)
930+
// r = c/d
931+
// tmp = d + rc
932+
// e = (ar + b)/tmp
933+
// f = (br - a)/tmp
934+
llvm::Value *CdD = Builder.CreateFDiv(RHSr, RHSi); // r=c/d
935+
936+
llvm::Value *RC = Builder.CreateFMul(CdD, RHSr); // rc
937+
llvm::Value *DpRC = Builder.CreateFAdd(RHSi, RC); // tmp=d+rc
938+
939+
llvm::Value *T7 = Builder.CreateFMul(LHSr, RC); // ar
940+
llvm::Value *T8 = Builder.CreateFAdd(T7, LHSi); // ar+b
941+
llvm::Value *DSTFr = Builder.CreateFDiv(T8, DpRC); // (ar+b)/tmp
942+
943+
llvm::Value *T9 = Builder.CreateFMul(LHSi, CdD); // br
944+
llvm::Value *T10 = Builder.CreateFSub(T9, LHSr); // br-a
945+
llvm::Value *DSTFi = Builder.CreateFDiv(T10, DpRC); // (br-a)/tmp
946+
Builder.CreateBr(ContBB);
947+
948+
// Phi together the computation paths.
949+
CGF.EmitBlock(ContBB);
950+
llvm::PHINode *VALr = Builder.CreatePHI(DSTTr->getType(), 2);
951+
VALr->addIncoming(DSTTr, TrueBB);
952+
VALr->addIncoming(DSTFr, FalseBB);
953+
llvm::PHINode *VALi = Builder.CreatePHI(DSTTi->getType(), 2);
954+
VALi->addIncoming(DSTTi, TrueBB);
955+
VALi->addIncoming(DSTFi, FalseBB);
956+
return ComplexPairTy(VALr, VALi);
957+
}
958+
849959
// See C11 Annex G.5.1 for the semantics of multiplicative operators on complex
850960
// typed values.
851961
ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
852962
llvm::Value *LHSr = Op.LHS.first, *LHSi = Op.LHS.second;
853963
llvm::Value *RHSr = Op.RHS.first, *RHSi = Op.RHS.second;
854-
855964
llvm::Value *DSTr, *DSTi;
856965
if (LHSr->getType()->isFloatingPointTy()) {
857-
// If we have a complex operand on the RHS and FastMath is not allowed, we
858-
// delegate to a libcall to handle all of the complexities and minimize
859-
// underflow/overflow cases. When FastMath is allowed we construct the
860-
// divide inline using the same algorithm as for integer operands.
861-
//
862-
// FIXME: We would be able to avoid the libcall in many places if we
863-
// supported imaginary types in addition to complex types.
864966
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Op.FPFeatures);
865-
if (RHSi && !CGF.getLangOpts().FastMath) {
967+
if (!RHSi) {
968+
assert(LHSi && "Can have at most one non-complex operand!");
969+
970+
DSTr = Builder.CreateFDiv(LHSr, RHSr);
971+
DSTi = Builder.CreateFDiv(LHSi, RHSr);
972+
return ComplexPairTy(DSTr, DSTi);
973+
}
974+
llvm::Value *OrigLHSi = LHSi;
975+
if (!LHSi)
976+
LHSi = llvm::Constant::getNullValue(RHSi->getType());
977+
if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Fortran)
978+
return EmitRangeReductionDiv(LHSr, LHSi, RHSr, RHSi);
979+
else if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Limited)
980+
return EmitAlgebraicDiv(LHSr, LHSi, RHSr, RHSi);
981+
else if (!CGF.getLangOpts().FastMath) {
982+
LHSi = OrigLHSi;
983+
// If we have a complex operand on the RHS and FastMath is not allowed, we
984+
// delegate to a libcall to handle all of the complexities and minimize
985+
// underflow/overflow cases. When FastMath is allowed we construct the
986+
// divide inline using the same algorithm as for integer operands.
987+
//
988+
// FIXME: We would be able to avoid the libcall in many places if we
989+
// supported imaginary types in addition to complex types.
866990
BinOpInfo LibCallOp = Op;
867991
// If LHS was a real, supply a null imaginary part.
868992
if (!LHSi)
@@ -884,30 +1008,8 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
8841008
case llvm::Type::FP128TyID:
8851009
return EmitComplexBinOpLibCall("__divtc3", LibCallOp);
8861010
}
887-
} else if (RHSi) {
888-
if (!LHSi)
889-
LHSi = llvm::Constant::getNullValue(RHSi->getType());
890-
891-
// (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
892-
llvm::Value *AC = Builder.CreateFMul(LHSr, RHSr); // a*c
893-
llvm::Value *BD = Builder.CreateFMul(LHSi, RHSi); // b*d
894-
llvm::Value *ACpBD = Builder.CreateFAdd(AC, BD); // ac+bd
895-
896-
llvm::Value *CC = Builder.CreateFMul(RHSr, RHSr); // c*c
897-
llvm::Value *DD = Builder.CreateFMul(RHSi, RHSi); // d*d
898-
llvm::Value *CCpDD = Builder.CreateFAdd(CC, DD); // cc+dd
899-
900-
llvm::Value *BC = Builder.CreateFMul(LHSi, RHSr); // b*c
901-
llvm::Value *AD = Builder.CreateFMul(LHSr, RHSi); // a*d
902-
llvm::Value *BCmAD = Builder.CreateFSub(BC, AD); // bc-ad
903-
904-
DSTr = Builder.CreateFDiv(ACpBD, CCpDD);
905-
DSTi = Builder.CreateFDiv(BCmAD, CCpDD);
9061011
} else {
907-
assert(LHSi && "Can have at most one non-complex operand!");
908-
909-
DSTr = Builder.CreateFDiv(LHSr, RHSr);
910-
DSTi = Builder.CreateFDiv(LHSi, RHSr);
1012+
return EmitAlgebraicDiv(LHSr, LHSi, RHSr, RHSi);
9111013
}
9121014
} else {
9131015
assert(Op.LHS.second && Op.RHS.second &&

0 commit comments

Comments
 (0)