-
Notifications
You must be signed in to change notification settings - Fork 15.1k
[clang] Add support for -fcx-limited-range, #pragma CX_LIMITED_RANGE and -fcx-fortran-rules. #70244
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
Conversation
This reverts commit a3a7d63. When compiling with MSVC2022 in C++32 mode this is giving an error. Compiling this simple test case: t1.cpp: with -std=c++23 will give the following error: In file included from C:\Users\zahiraam\t1.cpp:1: c:\Program files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.35.32215\include\vector:3329:16: error: compile with '-ffixed-point' to enable fixed point types 3329 | _Vbase _Accum = 0; | ^ c:\Program files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.35.32215\include\vector:3329:23: error: expected unqualified-id 3329 | _Vbase _Accum = 0; | ^ Please full error in llvm#67750 (comment)
✅ With the latest revision this PR passed the C/C++ code formatter. |
Summary: This should be `kind` and not `arch`.
This PR fixes the incorrect `mov` instruction in PTX. We actually move a predicate here, not u32, so the correct instruction should be `mov.pred`.
If gpu.alloc has no asyn deependency ( in case if gpu.alloc has hostShared allocation), create a new stream & synchronize. This PR is follow up to llvm#66401
When a target sets LLVM_ENABLE_RUNTIMES, we should only generate proxy targets for those runtimes rather than using the global list which may contain runtimes that are not supported by that particular target.
…70229) Summary: This patch simply adds the `-fconvergent-functions` flag to the GPU compilation. This is in relation to the behaviour of SIMT architectures under divergence. With the flag, we assume every function is convergent by default and rely on the compiler's divergence analysis to transform it if possible. Fixes: llvm#63853
…tion (llvm#70228) Summary: While this is technically a no-op for AMDGPU hardware, in cases where the user would see fit to add an explicit wavefront sync on Nvidia hardware, we should also inform the LLVM optimizer that this control flow is convergent so we do not reorder blocks.
This includes support for using GPRs, FPRs, and stack.
…et (llvm#69399) This is pre-cursor patch to enabling type units with DWARF5 acceleration tables. With this change it allows for entries to contain offsets directly, this way type units do not need to be preserved until .debug_names is written out.
…with F/D extensions. (llvm#69804) This a simple patch to get initial FP support started.
…with F/D extensions. (llvm#69805) This includes the plumbing for ValueMapping and PartialMapping.
…#69388) [lldb] Refactor InstrumentationRuntimeAsan and add a new plugin InstrumentationRuntimeLibsanitizers. This commit refactors InstrumentationRuntimeASan by pulling out reusable code into a separate ReportRetriever class. The purpose of the refactoring is to allow reuse of the ReportRetriever class in another plugin. The commit also adds InstrumentationRuntimeASanLibsanitizers, a new runtime plugin for ASan. The plugin provides the same functionality as InstrumentationRuntimeASan, but provides a different set of symbols/library names to search for while activating the plugin. rdar://112491689
"The PR summary seems to say that -ffast-math enables -fcx-fortran-rules, but the GCC documentations says that it enables -fcx-limited-range. Also, where is that implemented? Should the pragma override it?" |
clang/lib/CodeGen/CGExprComplex.cpp
Outdated
llvm::Value *AD = Builder.CreateFMul(LHSr, RHSi); // ad | ||
llvm::Value *DSTi = Builder.CreateFAdd(BC, AD); // bc+ad | ||
return ComplexPairTy(DSTr, DSTi); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we just do this as a check in the code below right after we emit ResR
and ResI
? Everything before that seems to be the same.
clang/lib/CodeGen/CGExprComplex.cpp
Outdated
// supported imaginary types in addition to complex types. | ||
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Op.FPFeatures); | ||
if (RHSi && !CGF.getLangOpts().FastMath) { | ||
if (RHSi && Op.FPFeatures.getComplexRange() == LangOptions::CX_Fortran) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we just hoist the !RHSi
case up here? That would simplify a lot of these conditions. And if you have it early-exit, you can also have a single check for !LHSi
instead of repeating it in every block.
clang/docs/ReleaseNotes.rst
Outdated
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``, but this option is enabled by | ||
``-ffast-math``. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we also talk about this in the main documentation, and not just the release notes?
clang/docs/ReleaseNotes.rst
Outdated
``__builtin_issubnormal``. | ||
- ``#pragma STDC CX_LIMITED_RANGE on-off-switch`` enables the naive mathematical | ||
formulas for complex division and multiplication with no NaN checking of | ||
results. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion:
- Add support for C99's ``#pragma STDC CX_LIMITED_RANGE` feature. This
enables the naive mathematical formulas for complex multiplication and division,
which are faster but do not correctly handle overflow and infinities.
I think we should add a __has_feature
check for this and document it here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The feature would be the pragma?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Code should be able to check for whether the pragma is supported.
@rjmccall Aaron has objected to the change I made in Pragma.cpp:992 (call to DiscardUntilEndOfDirective) but I think it's correct (I have put it back)? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, the refactor in division looks a lot better. My comment about the multiplication path still stands. Otherwise, I think this is pretty close. Aaron, are your concerns addressed?
Sorry! I missed that. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Please give the other reviewers a day or two in case they have more feedback.
Thank you! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
@zahiraam I'd suggest you edit the commit message next time when you merge, all the merged commits should not be mentioned in the co-authored-by list. |
@arichardson Sorry I didn't notice that. Is there something I can do at this point? |
No it's in the repository now so effectively immutable. It's not a big deal just letting you know for future patches. |
Thanks! will watch for it next time. |
@llvm/pr-subscribers-clang Author: Zahira Ammarguellat (zahiraam) ChangesThis patch adds the #pragma CX_LIMITED_RANGE defined in the C specification. Patch is 54.66 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/70244.diff 21 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 52c9d6eb69617..6566cc33e3a4a 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -243,6 +243,16 @@ New Compiler Flags
* ``-fopenacc`` was added as a part of the effort to support OpenACC in clang.
+* ``-fcx-limited-range`` 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 ``-ffast-math``.
+
+* ``-fcx-fortran-rules`` 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``.
+
+
Deprecated Compiler Flags
-------------------------
@@ -872,6 +882,9 @@ Floating Point Support in Clang
``__builtin_exp10f128`` builtins.
- Add ``__builtin_iszero``, ``__builtin_issignaling`` and
``__builtin_issubnormal``.
+- Add support for C99's ``#pragma STDC CX_LIMITED_RANGE`` feature. This
+ enables the naive mathematical formulas for complex multiplication and
+ division, which are faster but do not correctly handle overflow and infinities.
AST Matchers
------------
diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index 2e658557b0e31..f5e348bba9d8a 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -1468,6 +1468,7 @@ floating point semantic models: precise (the default), strict, and fast.
With the exception of ``-ffp-contract=fast``, using any of the options
below to disable any of the individual optimizations in ``-ffast-math``
will cause ``__FAST_MATH__`` to no longer be set.
+ ``-ffast-math`` enables ``-fcx-limited-range``.
This option implies:
@@ -1834,6 +1835,20 @@ 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``.
+
.. _floating-point-environment:
Accessing the floating point environment
diff --git a/clang/include/clang/Basic/FPOptions.def b/clang/include/clang/Basic/FPOptions.def
index 5b923a1944e50..79f04c89c9fed 100644
--- a/clang/include/clang/Basic/FPOptions.def
+++ b/clang/include/clang/Basic/FPOptions.def
@@ -28,4 +28,5 @@ OPTION(FPEvalMethod, LangOptions::FPEvalMethodKind, 2, AllowApproxFunc)
OPTION(Float16ExcessPrecision, LangOptions::ExcessPrecisionKind, 2, FPEvalMethod)
OPTION(BFloat16ExcessPrecision, LangOptions::ExcessPrecisionKind, 2, Float16ExcessPrecision)
OPTION(MathErrno, bool, 1, BFloat16ExcessPrecision)
+OPTION(ComplexRange, LangOptions::ComplexRangeKind, 2, MathErrno)
#undef OPTION
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index adaf2e413f2f6..c3d1a312f0d91 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -102,6 +102,7 @@ FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo))
FEATURE(swiftasynccc,
PP.getTargetInfo().checkCallingConvention(CC_SwiftAsync) ==
clang::TargetInfo::CCCR_OK)
+FEATURE(pragma_stdc_cx_limited_range, true)
// Objective-C features
FEATURE(objc_arr, LangOpts.ObjCAutoRefCount) // FIXME: REMOVE?
FEATURE(objc_arc, LangOpts.ObjCAutoRefCount)
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index cd77b22bf3ace..9730e2730da65 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -220,6 +220,8 @@ BENIGN_LANGOPT(NoSignedZero , 1, 0, "Permit Floating Point optimization wit
BENIGN_LANGOPT(AllowRecip , 1, 0, "Permit Floating Point reciprocal")
BENIGN_LANGOPT(ApproxFunc , 1, 0, "Permit Floating Point approximation")
+ENUM_LANGOPT(ComplexRange, ComplexRangeKind, 2, CX_Full, "Enable use of range reduction for complex arithmetics.")
+
BENIGN_LANGOPT(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for __weak/__strong ivars")
BENIGN_LANGOPT(AccessControl , 1, 1, "C++ access control")
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 2d167dd2bdf12..aa7b8306e1c36 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -391,6 +391,8 @@ class LangOptions : public LangOptionsBase {
IncompleteOnly = 3,
};
+ enum ComplexRangeKind { CX_Full, CX_Limited, CX_Fortran };
+
public:
/// The used language standard.
LangStandard::Kind LangStd;
@@ -740,6 +742,7 @@ class FPOptions {
setAllowFEnvAccess(true);
else
setAllowFEnvAccess(LangOptions::FPM_Off);
+ setComplexRange(LO.getComplexRange());
}
bool allowFPContractWithinStatement() const {
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 3ab420821d82b..47738a71c8144 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -908,6 +908,11 @@ PRAGMA_ANNOTATION(pragma_fenv_access_ms)
// handles them.
PRAGMA_ANNOTATION(pragma_fenv_round)
+// Annotation for #pragma STDC CX_LIMITED_RANGE
+// The lexer produces these so that they only take effect when the parser
+// handles them.
+PRAGMA_ANNOTATION(pragma_cx_limited_range)
+
// Annotation for #pragma float_control
// The lexer produces these so that they only take effect when the parser
// handles them.
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index df12ba8fbcb29..24aee940d7cd8 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1010,6 +1010,30 @@ 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">,
+ 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 complex_range_EQ : Joined<["-"], "complex-range=">, Group<f_Group>,
+ Visibility<[CC1Option]>,
+ Values<"full,limited,fortran">, NormalizedValuesScope<"LangOptions">,
+ NormalizedValues<["CX_Full", "CX_Limited", "CX_Fortran"]>,
+ MarshallingInfoEnum<LangOpts<"ComplexRange">, "CX_Full">;
+
// OpenCL-only Options
def cl_opt_disable : Flag<["-"], "cl-opt-disable">, Group<opencl_Group>,
Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index d20a26dbf2562..cca012f8e23d6 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -772,6 +772,10 @@ class Parser : public CodeCompletionHandler {
/// #pragma STDC FENV_ROUND...
void HandlePragmaFEnvRound();
+ /// Handle the annotation token produced for
+ /// #pragma STDC CX_LIMITED_RANGE...
+ void HandlePragmaCXLimitedRange();
+
/// Handle the annotation token produced for
/// #pragma float_control
void HandlePragmaFloatControl();
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 63a9f9d4cffe2..9f54415d70331 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -10997,6 +10997,11 @@ class Sema final {
/// \#pragma STDC FENV_ACCESS
void ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled);
+ /// ActOnPragmaCXLimitedRange - Called on well formed
+ /// \#pragma STDC CX_LIMITED_RANGE
+ void ActOnPragmaCXLimitedRange(SourceLocation Loc,
+ LangOptions::ComplexRangeKind Range);
+
/// Called on well formed '\#pragma clang fp' that has option 'exceptions'.
void ActOnPragmaFPExceptions(SourceLocation Loc,
LangOptions::FPExceptionModeKind);
diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index f3cbd1d0451eb..e532794b71bdb 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -275,6 +275,10 @@ class ComplexExprEmitter
ComplexPairTy EmitBinSub(const BinOpInfo &Op);
ComplexPairTy EmitBinMul(const BinOpInfo &Op);
ComplexPairTy EmitBinDiv(const BinOpInfo &Op);
+ ComplexPairTy EmitAlgebraicDiv(llvm::Value *A, llvm::Value *B, llvm::Value *C,
+ llvm::Value *D);
+ ComplexPairTy EmitRangeReductionDiv(llvm::Value *A, llvm::Value *B,
+ llvm::Value *C, llvm::Value *D);
ComplexPairTy EmitComplexBinOpLibCall(StringRef LibCallName,
const BinOpInfo &Op);
@@ -781,6 +785,10 @@ 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)
+ return ComplexPairTy(ResR, ResI);
+
// Emit the test for the real part becoming NaN and create a branch to
// handle it. We test for NaN by comparing the number to itself.
Value *IsRNaN = Builder.CreateFCmpUNO(ResR, ResR, "isnan_cmp");
@@ -846,23 +854,139 @@ ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) {
return ComplexPairTy(ResR, ResI);
}
+ComplexPairTy ComplexExprEmitter::EmitAlgebraicDiv(llvm::Value *LHSr,
+ llvm::Value *LHSi,
+ llvm::Value *RHSr,
+ llvm::Value *RHSi) {
+ // (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
+ llvm::Value *DSTr, *DSTi;
+
+ llvm::Value *AC = Builder.CreateFMul(LHSr, RHSr); // a*c
+ llvm::Value *BD = Builder.CreateFMul(LHSi, RHSi); // b*d
+ llvm::Value *ACpBD = Builder.CreateFAdd(AC, BD); // ac+bd
+
+ llvm::Value *CC = Builder.CreateFMul(RHSr, RHSr); // c*c
+ llvm::Value *DD = Builder.CreateFMul(RHSi, RHSi); // d*d
+ llvm::Value *CCpDD = Builder.CreateFAdd(CC, DD); // cc+dd
+
+ llvm::Value *BC = Builder.CreateFMul(LHSi, RHSr); // b*c
+ llvm::Value *AD = Builder.CreateFMul(LHSr, RHSi); // a*d
+ llvm::Value *BCmAD = Builder.CreateFSub(BC, AD); // bc-ad
+
+ DSTr = Builder.CreateFDiv(ACpBD, CCpDD);
+ DSTi = Builder.CreateFDiv(BCmAD, CCpDD);
+ return ComplexPairTy(DSTr, DSTi);
+}
+
+// EmitFAbs - Emit a call to @llvm.fabs.
+static llvm::Value *EmitllvmFAbs(CodeGenFunction &CGF, llvm::Value *Value) {
+ llvm::Function *Func =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::fabs, Value->getType());
+ llvm::Value *Call = CGF.Builder.CreateCall(Func, Value);
+ return Call;
+}
+
+// EmitRangeReductionDiv - Implements Smith's algorithm for complex division.
+// SMITH, R. L. Algorithm 116: Complex division. Commun. ACM 5, 8 (1962).
+ComplexPairTy ComplexExprEmitter::EmitRangeReductionDiv(llvm::Value *LHSr,
+ llvm::Value *LHSi,
+ llvm::Value *RHSr,
+ llvm::Value *RHSi) {
+ // (a + ib) / (c + id) = (e + if)
+ llvm::Value *FAbsRHSr = EmitllvmFAbs(CGF, RHSr); // |c|
+ llvm::Value *FAbsRHSi = EmitllvmFAbs(CGF, RHSi); // |d|
+ // |c| >= |d|
+ llvm::Value *IsR = Builder.CreateFCmpUGT(FAbsRHSr, FAbsRHSi, "abs_cmp");
+
+ llvm::BasicBlock *TrueBB =
+ CGF.createBasicBlock("abs_rhsr_greater_or_equal_abs_rhsi");
+ llvm::BasicBlock *FalseBB =
+ CGF.createBasicBlock("abs_rhsr_less_than_abs_rhsi");
+ llvm::BasicBlock *ContBB = CGF.createBasicBlock("complex_div");
+ Builder.CreateCondBr(IsR, TrueBB, FalseBB);
+
+ CGF.EmitBlock(TrueBB);
+ // abs(c) >= abs(d)
+ // r = d/c
+ // tmp = c + rd
+ // e = (a + br)/tmp
+ // f = (b - ar)/tmp
+ llvm::Value *DdC = Builder.CreateFDiv(RHSi, RHSr); // r=d/c
+
+ llvm::Value *RD = Builder.CreateFMul(DdC, RHSi); // rd
+ llvm::Value *CpRD = Builder.CreateFAdd(RHSr, RD); // tmp=c+rd
+
+ llvm::Value *T3 = Builder.CreateFMul(LHSi, DdC); // br
+ llvm::Value *T4 = Builder.CreateFAdd(LHSr, T3); // a+br
+ llvm::Value *DSTTr = Builder.CreateFDiv(T4, CpRD); // (a+br)/tmp
+
+ llvm::Value *T5 = Builder.CreateFMul(LHSr, DdC); // ar
+ llvm::Value *T6 = Builder.CreateFSub(LHSi, T5); // b-ar
+ llvm::Value *DSTTi = Builder.CreateFDiv(T6, CpRD); // (b-ar)/tmp
+ Builder.CreateBr(ContBB);
+
+ CGF.EmitBlock(FalseBB);
+ // abs(c) < abs(d)
+ // r = c/d
+ // tmp = d + rc
+ // e = (ar + b)/tmp
+ // f = (br - a)/tmp
+ llvm::Value *CdD = Builder.CreateFDiv(RHSr, RHSi); // r=c/d
+
+ llvm::Value *RC = Builder.CreateFMul(CdD, RHSr); // rc
+ llvm::Value *DpRC = Builder.CreateFAdd(RHSi, RC); // tmp=d+rc
+
+ llvm::Value *T7 = Builder.CreateFMul(LHSr, RC); // ar
+ llvm::Value *T8 = Builder.CreateFAdd(T7, LHSi); // ar+b
+ llvm::Value *DSTFr = Builder.CreateFDiv(T8, DpRC); // (ar+b)/tmp
+
+ llvm::Value *T9 = Builder.CreateFMul(LHSi, CdD); // br
+ llvm::Value *T10 = Builder.CreateFSub(T9, LHSr); // br-a
+ llvm::Value *DSTFi = Builder.CreateFDiv(T10, DpRC); // (br-a)/tmp
+ Builder.CreateBr(ContBB);
+
+ // Phi together the computation paths.
+ CGF.EmitBlock(ContBB);
+ llvm::PHINode *VALr = Builder.CreatePHI(DSTTr->getType(), 2);
+ VALr->addIncoming(DSTTr, TrueBB);
+ VALr->addIncoming(DSTFr, FalseBB);
+ llvm::PHINode *VALi = Builder.CreatePHI(DSTTi->getType(), 2);
+ VALi->addIncoming(DSTTi, TrueBB);
+ VALi->addIncoming(DSTFi, FalseBB);
+ return ComplexPairTy(VALr, VALi);
+}
+
// See C11 Annex G.5.1 for the semantics of multiplicative operators on complex
// typed values.
ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
llvm::Value *LHSr = Op.LHS.first, *LHSi = Op.LHS.second;
llvm::Value *RHSr = Op.RHS.first, *RHSi = Op.RHS.second;
-
llvm::Value *DSTr, *DSTi;
if (LHSr->getType()->isFloatingPointTy()) {
- // 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
- // underflow/overflow cases. When FastMath is allowed we construct the
- // divide inline using the same algorithm as for integer operands.
- //
- // FIXME: We would be able to avoid the libcall in many places if we
- // supported imaginary types in addition to complex types.
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Op.FPFeatures);
- if (RHSi && !CGF.getLangOpts().FastMath) {
+ if (!RHSi) {
+ assert(LHSi && "Can have at most one non-complex operand!");
+
+ DSTr = Builder.CreateFDiv(LHSr, RHSr);
+ DSTi = Builder.CreateFDiv(LHSi, RHSr);
+ return ComplexPairTy(DSTr, DSTi);
+ }
+ llvm::Value *OrigLHSi = LHSi;
+ if (!LHSi)
+ LHSi = llvm::Constant::getNullValue(RHSi->getType());
+ if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Fortran)
+ return EmitRangeReductionDiv(LHSr, LHSi, RHSr, RHSi);
+ else if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Limited)
+ return EmitAlgebraicDiv(LHSr, LHSi, RHSr, RHSi);
+ else if (!CGF.getLangOpts().FastMath) {
+ 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
+ // underflow/overflow cases. When FastMath is allowed we construct the
+ // divide inline using the same algorithm as for integer operands.
+ //
+ // FIXME: We would be able to avoid the libcall in many places if we
+ // supported imaginary types in addition to complex types.
BinOpInfo LibCallOp = Op;
// If LHS was a real, supply a null imaginary part.
if (!LHSi)
@@ -884,30 +1008,8 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
case llvm::Type::FP128TyID:
return EmitComplexBinOpLibCall("__divtc3", LibCallOp);
}
- } else if (RHSi) {
- if (!LHSi)
- LHSi = llvm::Constant::getNullValue(RHSi->getType());
-
- // (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
- llvm::Value *AC = Builder.CreateFMul(LHSr, RHSr); // a*c
- llvm::Value *BD = Builder.CreateFMul(LHSi, RHSi); // b*d
- llvm::Value *ACpBD = Builder.CreateFAdd(AC, BD); // ac+bd
-
- llvm::Value *CC = Builder.CreateFMul(RHSr, RHSr); // c*c
- llvm::Value *DD = Builder.CreateFMul(RHSi, RHSi); // d*d
- llvm::Value *CCpDD = Builder.CreateFAdd(CC, DD); // cc+dd
-
- llvm::Value *BC = Builder.CreateFMul(LHSi, RHSr); // b*c
- llvm::Value *AD = Builder.CreateFMul(LHSr, RHSi); // a*d
- llvm::Value *BCmAD = Builder.CreateFSub(BC, AD); // bc-ad
-
- DSTr = Builder.CreateFDiv(ACpBD, CCpDD);
- DSTi = Builder.CreateFDiv(BCmAD, CCpDD);
} else {
- assert(LHSi && "Can have at most one non-complex operand!");
-
- DSTr = Builder.CreateFDiv(LHSr, RHSr);
- DSTi = Builder.CreateFDiv(LHSi, RHSr);
+ return EmitAlgebraicDiv(LHSr, LHSi, RHSr, RHSi);
}
} else {
assert(Op.LHS.second && Op.RHS.second &&
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 6dec117aed105..ac456352ec5cf 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -2790,6 +2790,35 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
}
}
+static StringRef EnumComplexRangeToStr(LangOptions::ComplexRangeKind Range) {
+ StringRef RangeStr = "";
+ switch (Range) {
+ case LangOptions::ComplexRangeKind::CX_Limited:
+ return "-fcx-limited-range";
+ break;
+ case LangOptions::ComplexRangeKind::CX_Fortran:
+ return "-fcx-fortran-rules";
+ break;
+ default:
+ return RangeStr;
+ break;
+ }
+}
+
+static void EmitComplexRangeDiag(const Driver &D,
+ LangOptions::ComplexRangeKind Range1,
+ LangOptions::ComplexRangeKind Range2) {
+ if (Range1 != LangOptions::ComplexRangeKind::CX_Full)
+ D.Diag(clang::diag::warn_drv_overriding_option)
+ << EnumComplexRangeToStr(Range1) << EnumComplexRangeToStr(Range2);
+}
+
+static std::string RenderComplexRangeOption(std::string Range) {
+ std::string ComplexRangeStr = "-complex-range=";
+ ComplexRangeStr += Range;
+ return ComplexRangeStr;
+}
+
static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
bool OFastEnabled, const ArgList &Args,
ArgStringList &CmdArgs,
@@ -2836,6 +2865,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
bool StrictFPModel = false;
StringRef Float16ExcessPrecision = "";
StringRef BFloat16ExcessPrecision = "";
+ LangOptions::ComplexRangeKind Range = LangOptions::ComplexRangeKind::CX_Full;
if (const Arg *A = Args.getLastArg(options::OPT_f...
[truncated]
|
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)).