[clang] b40c534 - [clang] Add support for -fcx-limited-range, #pragma CX_LIMITED_RANGE and -fcx-fortran-rules. (#70244)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Dec 11 07:03:33 PST 2023
Author: Zahira Ammarguellat
Date: 2023-12-11T10:03:27-05:00
New Revision: b40c53465650456bfd364c123b1001e025353a33
URL: https://github.com/llvm/llvm-project/commit/b40c53465650456bfd364c123b1001e025353a33
DIFF: https://github.com/llvm/llvm-project/commit/b40c53465650456bfd364c123b1001e025353a33.diff
LOG: [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 <ismail at bennani.ma>
Co-authored-by: Joseph Huber <jhuber6 at vols.utk.edu>
Co-authored-by: Guray Ozen <guray.ozen at gmail.com>
Co-authored-by: Nishant Patel <nishant.b.patel at intel.com>
Co-authored-by: Jessica Clarke <jrtc27 at jrtc27.com>
Co-authored-by: Petr Hosek <phosek at google.com>
Co-authored-by: Joseph Huber <35342157+jhuber6 at users.noreply.github.com>
Co-authored-by: Craig Topper <craig.topper at sifive.com>
Co-authored-by: Alexander Yermolovich <43973793+ayermolo at users.noreply.github.com>
Co-authored-by: Usama Hameed <u_hameed at apple.com>
Co-authored-by: Philip Reames <preames at rivosinc.com>
Co-authored-by: Evgenii Kudriashov <evgenii.kudriashov at intel.com>
Co-authored-by: Fangrui Song <i at maskray.me>
Co-authored-by: Aart Bik <39774503+aartbik at users.noreply.github.com>
Co-authored-by: Valentin Clement <clementval at gmail.com>
Co-authored-by: Youngsuk Kim <youngsuk.kim at hpe.com>
Co-authored-by: Arthur Eubanks <aeubanks at google.com>
Co-authored-by: Jan Svoboda <jan_svoboda at apple.com>
Co-authored-by: Walter Erquinigo <a20012251 at gmail.com>
Co-authored-by: Eric <eric at efcs.ca>
Co-authored-by: Fazlay Rabbi <106703039+mdfazlay at users.noreply.github.com>
Co-authored-by: Pete Lawrence <plawrence at apple.com>
Co-authored-by: Jonas Devlieghere <jonas at devlieghere.com>
Co-authored-by: Adrian Prantl <aprantl at apple.com>
Co-authored-by: Owen Pan <owenpiano at gmail.com>
Co-authored-by: LLVM GN Syncbot <llvmgnsyncbot at gmail.com>
Co-authored-by: Med Ismail Bennani <ismail at bennani.ma>
Co-authored-by: Congcong Cai <congcongcai0907 at 163.com>
Co-authored-by: Rik Huijzer <github at huijzer.xyz>
Co-authored-by: Wang Pengcheng <wangpengcheng.pp at bytedance.com>
Co-authored-by: Yuanfang Chen <tabloid.adroit at gmail.com>
Co-authored-by: Kazu Hirata <kazu at google.com>
Co-authored-by: Mehdi Amini <joker.eph at gmail.com>
Co-authored-by: Aiden Grossman <agrossman154 at yahoo.com>
Co-authored-by: Rana Pratap Reddy <109514914+ranapratap55 at users.noreply.github.com>
Co-authored-by: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Co-authored-by: Piotr Zegar <me at piotrzegar.pl>
Co-authored-by: KAWASHIMA Takahiro <t-kawashima at fujitsu.com>
Co-authored-by: Tobias Hieta <tobias at hieta.se>
Co-authored-by: Luke Lau <luke at igalia.com>
Co-authored-by: Shivam Gupta <shivam98.tkg at gmail.com>
Co-authored-by: cor3ntin <corentinjabot at gmail.com>
Co-authored-by: Yeting Kuo <46629943+yetingk at users.noreply.github.com>
Co-authored-by: Stanislav Mekhanoshin <rampitec at users.noreply.github.com>
Co-authored-by: David Spickett <david.spickett at linaro.org>
Co-authored-by: Matthew Devereau <matthew.devereau at arm.com>
Co-authored-by: Martin Storsjö <martin at martin.st>
Co-authored-by: Qiu Chaofan <qiucofan at cn.ibm.com>
Co-authored-by: Pierre van Houtryve <pierre.vanhoutryve at amd.com>
Co-authored-by: Mikael Holmen <mikael.holmen at ericsson.com>
Co-authored-by: Uday Bondhugula <uday at polymagelabs.com>
Co-authored-by: Nikita Popov <npopov at redhat.com>
Co-authored-by: Johannes Reifferscheid <jreiffers at google.com>
Co-authored-by: Benjamin Kramer <benny.kra at googlemail.com>
Co-authored-by: Oliver Stannard <oliver.stannard at arm.com>
Co-authored-by: Dmitry Vyukov <dvyukov at google.com>
Co-authored-by: Benjamin Maxwell <benjamin.maxwell at arm.com>
Co-authored-by: Piotr Sobczak <piotr.sobczak at amd.com>
Co-authored-by: Simon Pilgrim <llvm-dev at redking.me.uk>
Co-authored-by: Timm Bäder <tbaeder at redhat.com>
Co-authored-by: Sunil Kuravinakop <koops at hpe.com>
Co-authored-by: zhongyunde 00443407 <zhongyunde at huawei.com>
Co-authored-by: Christudasan Devadasan <Christudasan.Devadasan at amd.com>
Co-authored-by: bjacob <jacob.benoit.1 at gmail.com>
Co-authored-by: Weining Lu <luweining at loongson.cn>
Co-authored-by: Andrzej Warzyński <andrzej.warzynski at arm.com>
Co-authored-by: Jay Foad <jay.foad at amd.com>
Co-authored-by: Markus Mützel <markus.muetzel at gmx.de>
Co-authored-by: Erik Jonsson <erik.j.jonsson at ericsson.com>
Co-authored-by: Pete Steinfeld <47540744+psteinfeld at users.noreply.github.com>
Co-authored-by: Alexey Bataev <a.bataev at outlook.com>
Co-authored-by: Louis Dionne <ldionne.2 at gmail.com>
Co-authored-by: Qizhi Hu <836744285 at qq.com>
Added:
clang/test/CodeGen/cx-complex-range.c
clang/test/CodeGen/pragma-cx-limited-range.c
clang/test/Driver/range.c
Modified:
clang/docs/ReleaseNotes.rst
clang/docs/UsersManual.rst
clang/include/clang/Basic/FPOptions.def
clang/include/clang/Basic/Features.def
clang/include/clang/Basic/LangOptions.def
clang/include/clang/Basic/LangOptions.h
clang/include/clang/Basic/TokenKinds.def
clang/include/clang/Driver/Options.td
clang/include/clang/Parse/Parser.h
clang/include/clang/Sema/Sema.h
clang/lib/CodeGen/CGExprComplex.cpp
clang/lib/Driver/ToolChains/Clang.cpp
clang/lib/Parse/ParsePragma.cpp
clang/lib/Parse/ParseStmt.cpp
clang/lib/Parse/Parser.cpp
clang/lib/Sema/SemaAttr.cpp
clang/test/CodeGen/complex-math.c
clang/test/Preprocessor/pragma_unknown.c
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index bc3acf165f0759..6e4009deaf8746 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -264,6 +264,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
-------------------------
@@ -1002,6 +1012,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 f1b344ef5109b5..7c30570437e8b0 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 5b923a1944e509..79f04c89c9fedc 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 df1eff8cbcc9f0..7473e00a7bd86b 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -104,6 +104,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 c3d5399905a3fd..152d9f65f86dbe 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 c4979b9a38c0cf..9f986fce2d4418 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -392,6 +392,8 @@ class LangOptions : public LangOptionsBase {
IncompleteOnly = 3,
};
+ enum ComplexRangeKind { CX_Full, CX_Limited, CX_Fortran };
+
public:
/// The used language standard.
LangStandard::Kind LangStd;
@@ -741,6 +743,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 5f9915d210221c..3f0e1e1a7d45ad 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -911,6 +911,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 cf969cb0b318a6..25c76cf2ad2c84 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 06634982351647..2dbe090bd0932f 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -769,6 +769,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 f45e0a7d3d52d4..1902d098f3c25e 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11023,6 +11023,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 f3cbd1d0451ebe..e532794b71bdb4 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 eb26bfade47b7a..f95f3227aba7d0 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -2660,6 +2660,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,
@@ -2706,6 +2735,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_flimited_precision_EQ)) {
CmdArgs.push_back("-mlimit-float-precision");
@@ -2718,6 +2748,28 @@ 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;
+ std::string ComplexRangeStr = RenderComplexRangeOption("limited");
+ if (!ComplexRangeStr.empty())
+ CmdArgs.push_back(Args.MakeArgString(ComplexRangeStr));
+ break;
+ }
+ case options::OPT_fno_cx_limited_range:
+ Range = LangOptions::ComplexRangeKind::CX_Full;
+ break;
+ case options::OPT_fcx_fortran_rules: {
+ EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Fortran);
+ Range = LangOptions::ComplexRangeKind::CX_Fortran;
+ std::string ComplexRangeStr = RenderComplexRangeOption("fortran");
+ if (!ComplexRangeStr.empty())
+ CmdArgs.push_back(Args.MakeArgString(ComplexRangeStr));
+ break;
+ }
+ case options::OPT_fno_cx_fortran_rules:
+ Range = LangOptions::ComplexRangeKind::CX_Full;
+ break;
case options::OPT_ffp_model_EQ: {
// If -ffp-model= is seen, reset to fno-fast-math
HonorINFs = true;
@@ -2772,7 +2824,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getSpelling() << Val;
break;
- }
+ }
}
switch (optID) {
@@ -2971,7 +3023,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
if (!OFastEnabled)
continue;
[[fallthrough]];
- case options::OPT_ffast_math:
+ case options::OPT_ffast_math: {
HonorINFs = false;
HonorNaNs = false;
MathErrno = false;
@@ -2985,7 +3037,13 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
// If fast-math is set then set the fp-contract mode to fast.
FPContract = "fast";
SeenUnsafeMathModeOption = true;
+ // ffast-math enables fortran rules for complex multiplication and
+ // division.
+ std::string ComplexRangeStr = RenderComplexRangeOption("limited");
+ if (!ComplexRangeStr.empty())
+ CmdArgs.push_back(Args.MakeArgString(ComplexRangeStr));
break;
+ }
case options::OPT_fno_fast_math:
HonorINFs = true;
HonorNaNs = true;
@@ -3139,6 +3197,15 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
if (Args.hasFlag(options::OPT_fno_strict_float_cast_overflow,
options::OPT_fstrict_float_cast_overflow, false))
CmdArgs.push_back("-fno-strict-float-cast-overflow");
+
+ if (const Arg *A = Args.getLastArg(options::OPT_fcx_limited_range))
+ CmdArgs.push_back("-fcx-limited-range");
+ if (const Arg *A = Args.getLastArg(options::OPT_fcx_fortran_rules))
+ CmdArgs.push_back("-fcx-fortran-rules");
+ if (const Arg *A = Args.getLastArg(options::OPT_fno_cx_limited_range))
+ CmdArgs.push_back("-fno-cx-limited-range");
+ if (const Arg *A = Args.getLastArg(options::OPT_fno_cx_fortran_rules))
+ CmdArgs.push_back("-fno-cx-fortran-rules");
}
static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs,
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index efdf7c90f977fb..730ac1a0fee5cc 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -137,7 +137,20 @@ struct PragmaSTDC_CX_LIMITED_RANGEHandler : public PragmaHandler {
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
Token &Tok) override {
tok::OnOffSwitch OOS;
- PP.LexOnOffSwitch(OOS);
+ if (PP.LexOnOffSwitch(OOS))
+ return;
+
+ MutableArrayRef<Token> Toks(
+ PP.getPreprocessorAllocator().Allocate<Token>(1), 1);
+
+ Toks[0].startToken();
+ Toks[0].setKind(tok::annot_pragma_cx_limited_range);
+ Toks[0].setLocation(Tok.getLocation());
+ Toks[0].setAnnotationEndLoc(Tok.getLocation());
+ Toks[0].setAnnotationValue(
+ reinterpret_cast<void *>(static_cast<uintptr_t>(OOS)));
+ PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,
+ /*IsReinject=*/false);
}
};
@@ -888,6 +901,31 @@ void Parser::HandlePragmaFEnvRound() {
Actions.ActOnPragmaFEnvRound(PragmaLoc, RM);
}
+void Parser::HandlePragmaCXLimitedRange() {
+ assert(Tok.is(tok::annot_pragma_cx_limited_range));
+ tok::OnOffSwitch OOS = static_cast<tok::OnOffSwitch>(
+ reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
+
+ LangOptions::ComplexRangeKind Range;
+ switch (OOS) {
+ case tok::OOS_ON:
+ Range = LangOptions::CX_Limited;
+ 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.
+ Range = getLangOpts().getComplexRange();
+ break;
+ }
+
+ SourceLocation PragmaLoc = ConsumeAnnotationToken();
+ Actions.ActOnPragmaCXLimitedRange(PragmaLoc, Range);
+}
+
StmtResult Parser::HandlePragmaCaptured()
{
assert(Tok.is(tok::annot_pragma_captured));
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 918afdc2baea38..d0ff33bd1379ab 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -444,6 +444,14 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
ConsumeAnnotationToken();
return StmtError();
+ case tok::annot_pragma_cx_limited_range:
+ ProhibitAttributes(CXX11Attrs);
+ ProhibitAttributes(GNUAttrs);
+ Diag(Tok, diag::err_pragma_file_or_compound_scope)
+ << "STDC CX_LIMITED_RANGE";
+ ConsumeAnnotationToken();
+ return StmtError();
+
case tok::annot_pragma_float_control:
ProhibitAttributes(CXX11Attrs);
ProhibitAttributes(GNUAttrs);
@@ -1066,6 +1074,9 @@ void Parser::ParseCompoundStatementLeadingPragmas() {
case tok::annot_pragma_fenv_round:
HandlePragmaFEnvRound();
break;
+ case tok::annot_pragma_cx_limited_range:
+ HandlePragmaCXLimitedRange();
+ break;
case tok::annot_pragma_float_control:
HandlePragmaFloatControl();
break;
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 1baeb2aeb021fa..ec67faf7dcaf86 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -844,6 +844,9 @@ Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
case tok::annot_pragma_fenv_round:
HandlePragmaFEnvRound();
return nullptr;
+ case tok::annot_pragma_cx_limited_range:
+ HandlePragmaCXLimitedRange();
+ return nullptr;
case tok::annot_pragma_float_control:
HandlePragmaFloatControl();
return nullptr;
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 79271c87262731..0dcf42e4899713 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -1352,6 +1352,14 @@ void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) {
CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
}
+void Sema::ActOnPragmaCXLimitedRange(SourceLocation Loc,
+ LangOptions::ComplexRangeKind Range) {
+ FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
+ NewFPFeatures.setComplexRangeOverride(Range);
+ FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
+ CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
+}
+
void Sema::ActOnPragmaFPExceptions(SourceLocation Loc,
LangOptions::FPExceptionModeKind FPE) {
setExceptionMode(Loc, FPE);
diff --git a/clang/test/CodeGen/complex-math.c b/clang/test/CodeGen/complex-math.c
index c59baaa452369d..a44aa0014a6587 100644
--- a/clang/test/CodeGen/complex-math.c
+++ b/clang/test/CodeGen/complex-math.c
@@ -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 -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=fortran -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) {
@@ -135,24 +135,68 @@ float _Complex div_float_rc(float a, float _Complex b) {
// SPIR: call spir_func {{.*}} @__divsc3(
- // a / b = (A+iB) / (C+iD) = ((AC+BD)/(CC+DD)) + i((BC-AD)/(CC+DD))
+ // a / b = (A+iB) / (C+iD) = (E+iF)
+ // if (|C| >= |D|)
+ // DdC = D/C
+ // CpRD = C+DdC*D
+ // E = (A+B*DdC)/CpRD
+ // F = (B-A*DdC)/CpRD
+ // else
+ // CdD = C/D
+ // DpRC= D+CdD*C
+ // E = (A*CdD+B)/DpRC
+ // F = (B*CdD-A)/DpRC
// AARCH64-FASTMATH-LABEL: @div_float_rc(float noundef nofpclass(nan inf) %a, [2 x float] noundef nofpclass(nan inf) alignstack(8) %b.coerce)
- // A = a
- // B = 0
- //
- // AARCH64-FASTMATH: [[AC:%.*]] = fmul fast float
- // BD = 0
- // ACpBD = AC
- //
- // AARCH64-FASTMATH: [[CC:%.*]] = fmul fast float
- // AARCH64-FASTMATH: [[DD:%.*]] = fmul fast float
- // AARCH64-FASTMATH: [[CCpDD:%.*]] = fadd fast float
- //
- // BC = 0
- // AARCH64-FASTMATH: [[AD:%.*]] = fmul fast float
- //
- // AARCH64-FASTMATH: fdiv fast float
- // AARCH64-FASTMATH: fdiv fast float
+ // |C|
+ // AARCH64-FASTMATH: call {{.*}}float @llvm.fabs.f32(float {{.*}})
+ // |D|
+ // AARCH64-FASTMATH-NEXT: call {{.*}}float @llvm.fabs.f32(float {{.*}})
+ // AARCH64-FASTMATH-NEXT: fcmp {{.*}}ugt float
+ // AARCH64-FASTMATH-NEXT: br i1 {{.*}}, label
+ // AARCH64-FASTMATH: abs_rhsr_greater_or_equal_abs_rhsi:
+
+ // |C| >= |D|
+ // DdC=D/C
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float
+
+ // CpRD=C+CdC*D
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}float
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}float
+
+ // A+BR/CpRD
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}float
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}float
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float
+
+ // B-AR/CpRD
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}float
+ // AARCH64-FASTMATH-NEXT: fsub {{.*}}float
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float
+ // AARCH64-FASTMATH-NEXT: br label
+ // AARCH64-FASTMATH: abs_rhsr_less_than_abs_rhsi:
+
+ // |C| < |D|
+ // CdD=C/D
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float
+
+ // DpRC=D+CdD*C
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}float
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}float
+
+ // (A*CdD+B)/DpRC
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}float
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}float
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float
+
+ // (BCdD-A)/DpRC
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}float
+ // AARCH64-FASTMATH-NEXT: fsub {{.*}}float
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float
+
+ // AARCH64-FASTMATH-NEXT: br label
+ // AARCH64-FASTMATH: complex_div:
+ // AARCH64-FASTMATH-NEXT: phi {{.*}}float
+ // AARCH64-FASTMATH-NEXT: phi {{.*}}float
// AARCH64-FASTMATH: ret
return a / b;
}
@@ -164,24 +208,68 @@ float _Complex div_float_cc(float _Complex a, float _Complex b) {
// SPIR: call spir_func {{.*}} @__divsc3(
- // a / b = (A+iB) / (C+iD) = ((AC+BD)/(CC+DD)) + i((BC-AD)/(CC+DD))
+ // a / b = (A+iB) / (C+iD) = (E+iF)
+ // if (|C| >= |D|)
+ // DdC = D/C
+ // CpRD = C+DdC*D
+ // E = (A+B*DdC)/CpRD
+ // F = (B-A*DdC)/CpRD
+ // else
+ // CdD = C/D
+ // DpRC= D+CdD*C
+ // E = (A*CdD+B)/DpRC
+ // F = (B*CdD-A)/DpRC
// AARCH64-FASTMATH-LABEL: @div_float_cc([2 x float] noundef nofpclass(nan inf) alignstack(8) %a.coerce, [2 x float] noundef nofpclass(nan inf) alignstack(8) %b.coerce)
- //
- // AARCH64-FASTMATH: [[AC:%.*]] = fmul fast float
- // AARCH64-FASTMATH: [[BD:%.*]] = fmul fast float
- // AARCH64-FASTMATH: [[ACpBD:%.*]] = fadd fast float
- //
- // AARCH64-FASTMATH: [[CC:%.*]] = fmul fast float
- // AARCH64-FASTMATH: [[DD:%.*]] = fmul fast float
- // AARCH64-FASTMATH: [[CCpDD:%.*]] = fadd fast float
- //
- // AARCH64-FASTMATH: [[BC:%.*]] = fmul fast float
- // AARCH64-FASTMATH: [[AD:%.*]] = fmul fast float
- // AARCH64-FASTMATH: [[BCmAD:%.*]] = fsub fast float
- //
- // AARCH64-FASTMATH: fdiv fast float
- // AARCH64-FASTMATH: fdiv fast float
- // AARCH64-FASTMATH: ret
+ // |C|
+ // AARCH64-FASTMATH: call {{.*}}float @llvm.fabs.f32(float {{.*}})
+ // |D|
+ // AARCH64-FASTMATH-NEXT: call {{.*}}float @llvm.fabs.f32(float {{.*}})
+ // AARCH64-FASTMATH-NEXT: fcmp {{.*}}ugt float
+ // AARCH64-FASTMATH-NEXT: br i1 {{.*}}, label
+ // AARCH64-FASTMATH: abs_rhsr_greater_or_equal_abs_rhsi:
+
+ // |C| >= |D|
+ // DdC=D/C
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float
+
+ // CpRD=C+CdC*D
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}float
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}float
+
+ // A+BR/CpRD
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}float
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}float
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float
+
+ // B-AR/CpRD
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}float
+ // AARCH64-FASTMATH-NEXT: fsub {{.*}}float
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float
+ // AARCH64-FASTMATH-NEXT: br label
+ // AARCH64-FASTMATH: abs_rhsr_less_than_abs_rhsi:
+
+ // |C| < |D|
+ // CdD=C/D
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float
+
+ // DpRC=D+CdD*C
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}float
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}float
+
+ // (A*CdD+B)/DpRC
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}float
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}float
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float
+
+ // (BCdD-A)/DpRC
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}float
+ // AARCH64-FASTMATH-NEXT: fsub {{.*}}float
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}float
+
+ // AARCH64-FASTMATH-NEXT: br label
+ // AARCH64-FASTMATH: complex_div:
+ // AARCH64-FASTMATH-NEXT: phi {{.*}}float
+ // AARCH64-FASTMATH-NEXT: phi {{.*}}float
return a / b;
}
@@ -312,24 +400,68 @@ double _Complex div_double_rc(double a, double _Complex b) {
// SPIR: call spir_func {{.*}} @__divdc3(
- // a / b = (A+iB) / (C+iD) = ((AC+BD)/(CC+DD)) + i((BC-AD)/(CC+DD))
+ // a / b = (A+iB) / (C+iD) = (E+iF)
+ // if (|C| >= |D|)
+ // DdC = D/C
+ // CpRD = C+DdC*D
+ // E = (A+B*DdC)/CpRD
+ // F = (B-A*DdC)/CpRD
+ // else
+ // CdD = C/D
+ // DpRC= D+CdD*C
+ // E = (A*CdD+B)/DpRC
+ // F = (B*CdD-A)/DpRC
// AARCH64-FASTMATH-LABEL: @div_double_rc(double noundef nofpclass(nan inf) %a, [2 x double] noundef nofpclass(nan inf) alignstack(8) %b.coerce)
- // A = a
- // B = 0
- //
- // AARCH64-FASTMATH: [[AC:%.*]] = fmul fast double
- // BD = 0
- // ACpBD = AC
- //
- // AARCH64-FASTMATH: [[CC:%.*]] = fmul fast double
- // AARCH64-FASTMATH: [[DD:%.*]] = fmul fast double
- // AARCH64-FASTMATH: [[CCpDD:%.*]] = fadd fast double
- //
- // BC = 0
- // AARCH64-FASTMATH: [[AD:%.*]] = fmul fast double
- //
- // AARCH64-FASTMATH: fdiv fast double
- // AARCH64-FASTMATH: fdiv fast double
+ // |C|
+ // AARCH64-FASTMATH: call {{.*}}double @llvm.fabs.f64(double {{.*}})
+ // |D|
+ // AARCH64-FASTMATH-NEXT: call {{.*}}double @llvm.fabs.f64(double {{.*}})
+ // AARCH64-FASTMATH-NEXT: fcmp {{.*}}ugt double
+ // AARCH64-FASTMATH-NEXT: br i1 {{.*}}, label
+ // AARCH64-FASTMATH: abs_rhsr_greater_or_equal_abs_rhsi:
+
+ // |C| >= |D|
+ // DdC=D/C
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double
+
+ // CpRD=C+CdC*D
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}double
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}double
+
+ // A+BR/CpRD
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}double
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}double
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double
+
+ // B-AR/CpRD
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}double
+ // AARCH64-FASTMATH-NEXT: fsub {{.*}}double
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double
+ // AARCH64-FASTMATH-NEXT: br label
+ // AARCH64-FASTMATH: abs_rhsr_less_than_abs_rhsi:
+
+ // |C| < |D|
+ // CdD=C/D
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double
+
+ // DpRC=D+CdD*C
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}double
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}double
+
+ // (A*CdD+B)/DpRC
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}double
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}double
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double
+
+ // (BCdD-A)/DpRC
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}double
+ // AARCH64-FASTMATH-NEXT: fsub {{.*}}double
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double
+
+ // AARCH64-FASTMATH-NEXT: br label
+ // AARCH64-FASTMATH: complex_div:
+ // AARCH64-FASTMATH-NEXT: phi {{.*}}double
+ // AARCH64-FASTMATH-NEXT: phi {{.*}}double
// AARCH64-FASTMATH: ret
return a / b;
}
@@ -341,23 +473,68 @@ double _Complex div_double_cc(double _Complex a, double _Complex b) {
// SPIR: call spir_func {{.*}} @__divdc3(
- // a / b = (A+iB) / (C+iD) = ((AC+BD)/(CC+DD)) + i((BC-AD)/(CC+DD))
+ // a / b = (A+iB) / (C+iD) = (E+iF)
+ // if (|C| >= |D|)
+ // DdC = D/C
+ // CpRD = C+DdC*D
+ // E = (A+B*DdC)/CpRD
+ // F = (B-A*DdC)/CpRD
+ // else
+ // CdD = C/D
+ // DpRC= D+CdD*C
+ // E = (A*CdD+B)/DpRC
+ // F = (B*CdD-A)/DpRC
// AARCH64-FASTMATH-LABEL: @div_double_cc([2 x double] noundef nofpclass(nan inf) alignstack(8) %a.coerce, [2 x double] noundef nofpclass(nan inf) alignstack(8) %b.coerce)
- //
- // AARCH64-FASTMATH: [[AC:%.*]] = fmul fast double
- // AARCH64-FASTMATH: [[BD:%.*]] = fmul fast double
- // AARCH64-FASTMATH: [[ACpBD:%.*]] = fadd fast double
- //
- // AARCH64-FASTMATH: [[CC:%.*]] = fmul fast double
- // AARCH64-FASTMATH: [[DD:%.*]] = fmul fast double
- // AARCH64-FASTMATH: [[CCpDD:%.*]] = fadd fast double
- //
- // AARCH64-FASTMATH: [[BC:%.*]] = fmul fast double
- // AARCH64-FASTMATH: [[AD:%.*]] = fmul fast double
- // AARCH64-FASTMATH: [[BCmAD:%.*]] = fsub fast double
- //
- // AARCH64-FASTMATH: fdiv fast double
- // AARCH64-FASTMATH: fdiv fast double
+ // |C|
+ // AARCH64-FASTMATH: call {{.*}}double @llvm.fabs.f64(double {{.*}})
+ // |D|
+ // AARCH64-FASTMATH-NEXT: call {{.*}}double @llvm.fabs.f64(double {{.*}})
+ // AARCH64-FASTMATH-NEXT: fcmp {{.*}}ugt double
+ // AARCH64-FASTMATH-NEXT: br i1 {{.*}}, label
+ // AARCH64-FASTMATH: abs_rhsr_greater_or_equal_abs_rhsi:
+
+ // |C| >= |D|
+ // DdC=D/C
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double
+
+ // CpRD=C+CdC*D
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}double
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}double
+
+ // A+BR/CpRD
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}double
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}double
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double
+
+ // B-AR/CpRD
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}double
+ // AARCH64-FASTMATH-NEXT: fsub {{.*}}double
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double
+ // AARCH64-FASTMATH-NEXT: br label
+ // AARCH64-FASTMATH: abs_rhsr_less_than_abs_rhsi:
+
+ // |C| < |D|
+ // CdD=C/D
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double
+
+ // DpRC=D+CdD*C
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}double
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}double
+
+ // (A*CdD+B)/DpRC
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}double
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}double
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double
+
+ // (BCdD-A)/DpRC
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}double
+ // AARCH64-FASTMATH-NEXT: fsub {{.*}}double
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}double
+
+ // AARCH64-FASTMATH-NEXT: br label
+ // AARCH64-FASTMATH: complex_div:
+ // AARCH64-FASTMATH-NEXT: phi {{.*}}double
+ // AARCH64-FASTMATH-NEXT: phi {{.*}}double
// AARCH64-FASTMATH: ret
return a / b;
}
@@ -505,24 +682,68 @@ long double _Complex div_long_double_rc(long double a, long double _Complex b) {
// PPC: ret
// SPIR: call spir_func {{.*}} @__divdc3(
- // a / b = (A+iB) / (C+iD) = ((AC+BD)/(CC+DD)) + i((BC-AD)/(CC+DD))
+ // a / b = (A+iB) / (C+iD) = (E+iF)
+ // if (|C| >= |D|)
+ // DdC = D/C
+ // CpRD = C+DdC*D
+ // E = (A+B*DdC)/CpRD
+ // F = (B-A*DdC)/CpRD
+ // else
+ // CdD = C/D
+ // DpRC= D+CdD*C
+ // E = (A*CdD+B)/DpRC
+ // F = (B*CdD-A)/DpRC
// AARCH64-FASTMATH-LABEL: @div_long_double_rc(fp128 noundef nofpclass(nan inf) %a, [2 x fp128] noundef nofpclass(nan inf) alignstack(16) %b.coerce)
- // A = a
- // B = 0
- //
- // AARCH64-FASTMATH: [[AC:%.*]] = fmul fast fp128
- // BD = 0
- // ACpBD = AC
- //
- // AARCH64-FASTMATH: [[CC:%.*]] = fmul fast fp128
- // AARCH64-FASTMATH: [[DD:%.*]] = fmul fast fp128
- // AARCH64-FASTMATH: [[CCpDD:%.*]] = fadd fast fp128
- //
- // BC = 0
- // AARCH64-FASTMATH: [[AD:%.*]] = fmul fast fp128
- //
- // AARCH64-FASTMATH: fdiv fast fp128
- // AARCH64-FASTMATH: fdiv fast fp128
+ // |C|
+ // AARCH64-FASTMATH: call {{.*}}fp128 @llvm.fabs.f128(fp128 {{.*}})
+ // |D|
+ // AARCH64-FASTMATH-NEXT: call {{.*}}fp128 @llvm.fabs.f128(fp128 {{.*}})
+ // AARCH64-FASTMATH-NEXT: fcmp {{.*}}ugt fp128
+ // AARCH64-FASTMATH-NEXT: br i1 {{.*}}, label
+ // AARCH64-FASTMATH: abs_rhsr_greater_or_equal_abs_rhsi:
+
+ // |C| >= |D|
+ // DdC=D/C
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128
+
+ // CpRD=C+CdC*D
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}fp128
+
+ // A+BR/CpRD
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128
+
+ // B-AR/CpRD
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: fsub {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: br label
+ // AARCH64-FASTMATH: abs_rhsr_less_than_abs_rhsi:
+
+ // |C| < |D|
+ // CdD=C/D
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128
+
+ // DpRC=D+CdD*C
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}fp128
+
+ // (A*CdD+B)/DpRC
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128
+
+ // (BCdD-A)/DpRC
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: fsub {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128
+
+ // AARCH64-FASTMATH-NEXT: br label
+ // AARCH64-FASTMATH: complex_div:
+ // AARCH64-FASTMATH-NEXT: phi {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: phi {{.*}}fp128
// AARCH64-FASTMATH: ret
return a / b;
}
@@ -537,23 +758,68 @@ long double _Complex div_long_double_cc(long double _Complex a, long double _Com
// PPC: ret
// SPIR: call spir_func {{.*}} @__divdc3(
- // a / b = (A+iB) / (C+iD) = ((AC+BD)/(CC+DD)) + i((BC-AD)/(CC+DD))
+ // a / b = (A+iB) / (C+iD) = (E+iF)
+ // if (|C| >= |D|)
+ // DdC = D/C
+ // CpRD = C+DdC*D
+ // E = (A+B*DdC)/CpRD
+ // F = (B-A*DdC)/CpRD
+ // else
+ // CdD = C/D
+ // DpRC= D+CdD*C
+ // E = (A*CdD+B)/DpRC
+ // F = (B*CdD-A)/DpRC
// AARCH64-FASTMATH-LABEL: @div_long_double_cc([2 x fp128] noundef nofpclass(nan inf) alignstack(16) %a.coerce, [2 x fp128] noundef nofpclass(nan inf) alignstack(16) %b.coerce)
- //
- // AARCH64-FASTMATH: [[AC:%.*]] = fmul fast fp128
- // AARCH64-FASTMATH: [[BD:%.*]] = fmul fast fp128
- // AARCH64-FASTMATH: [[ACpBD:%.*]] = fadd fast fp128
- //
- // AARCH64-FASTMATH: [[CC:%.*]] = fmul fast fp128
- // AARCH64-FASTMATH: [[DD:%.*]] = fmul fast fp128
- // AARCH64-FASTMATH: [[CCpDD:%.*]] = fadd fast fp128
- //
- // AARCH64-FASTMATH: [[BC:%.*]] = fmul fast fp128
- // AARCH64-FASTMATH: [[AD:%.*]] = fmul fast fp128
- // AARCH64-FASTMATH: [[BCmAD:%.*]] = fsub fast fp128
- //
- // AARCH64-FASTMATH: fdiv fast fp128
- // AARCH64-FASTMATH: fdiv fast fp128
+ // |C|
+ // AARCH64-FASTMATH: call {{.*}}fp128 @llvm.fabs.f128(fp128 {{.*}})
+ // |D|
+ // AARCH64-FASTMATH-NEXT: call {{.*}}fp128 @llvm.fabs.f128(fp128 {{.*}})
+ // AARCH64-FASTMATH-NEXT: fcmp {{.*}}ugt fp128
+ // AARCH64-FASTMATH-NEXT: br i1 {{.*}}, label
+ // AARCH64-FASTMATH: abs_rhsr_greater_or_equal_abs_rhsi:
+
+ // |C| >= |D|
+ // DdC=D/C
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128
+
+ // CpRD=C+CdC*D
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}fp128
+
+ // A+BR/CpRD
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128
+
+ // B-AR/CpRD
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: fsub {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: br label
+ // AARCH64-FASTMATH: abs_rhsr_less_than_abs_rhsi:
+
+ // |C| < |D|
+ // CdD=C/D
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128
+
+ // DpRC=D+CdD*C
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}fp128
+
+ // (A*CdD+B)/DpRC
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: fadd {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128
+
+ // (BCdD-A)/DpRC
+ // AARCH64-FASTMATH-NEXT: fmul {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: fsub {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: fdiv {{.*}}fp128
+
+ // AARCH64-FASTMATH-NEXT: br label
+ // AARCH64-FASTMATH: complex_div:
+ // AARCH64-FASTMATH-NEXT: phi {{.*}}fp128
+ // AARCH64-FASTMATH-NEXT: phi {{.*}}fp128
// AARCH64-FASTMATH: ret
return a / b;
}
diff --git a/clang/test/CodeGen/cx-complex-range.c b/clang/test/CodeGen/cx-complex-range.c
new file mode 100644
index 00000000000000..8368fa611335cc
--- /dev/null
+++ b/clang/test/CodeGen/cx-complex-range.c
@@ -0,0 +1,108 @@
+// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
+// RUN: -o - | FileCheck %s --check-prefix=FULL
+
+// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
+// RUN: -complex-range=limited -o - | FileCheck %s --check-prefix=LMTD
+
+// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
+// RUN: -fno-cx-limited-range -o - | FileCheck %s --check-prefix=FULL
+
+// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
+// RUN: -complex-range=fortran -o - | FileCheck %s --check-prefix=FRTRN
+
+// Fast math
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu \
+// RUN: -ffast-math -complex-range=limited -emit-llvm -o - %s \
+// RUN: | FileCheck %s --check-prefix=LMTD-FAST
+
+// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
+// RUN: -fno-cx-fortran-rules -o - | FileCheck %s --check-prefix=FULL
+
+_Complex float div(_Complex float a, _Complex float b) {
+ // LABEL: define {{.*}} @div(
+ // FULL: call {{.*}} @__divsc3
+
+ // LMTD: fmul float
+ // LMTD-NEXT: fmul float
+ // LMTD-NEXT: fadd float
+ // LMTD-NEXT: fmul float
+ // LMTD-NEXT: fmul float
+ // LMTD-NEXT: fadd float
+ // LMTD-NEXT: fmul float
+ // LMTD-NEXT: fmul float
+ // LMTD-NEXT: fsub float
+ // LMTD-NEXT: fdiv float
+ // LMTD-NEXT: fdiv float
+
+ // FRTRN: call {{.*}}float @llvm.fabs.f32(float {{.*}})
+ // FRTRN-NEXT: call {{.*}}float @llvm.fabs.f32(float {{.*}})
+ // FRTRN-NEXT: fcmp {{.*}}ugt float
+ // FRTRN-NEXT: br i1 {{.*}}, label
+ // FRTRN: abs_rhsr_greater_or_equal_abs_rhsi:
+ // FRTRN-NEXT: fdiv {{.*}}float
+ // FRTRN-NEXT: fmul {{.*}}float
+ // FRTRN-NEXT: fadd {{.*}}float
+ // FRTRN-NEXT: fmul {{.*}}float
+ // FRTRN-NEXT: fadd {{.*}}float
+ // FRTRN-NEXT: fdiv {{.*}}float
+ // FRTRN-NEXT: fmul {{.*}}float
+ // FRTRN-NEXT: fsub {{.*}}float
+ // FRTRN-NEXT: fdiv {{.*}}float
+ // FRTRN-NEXT: br label
+ // FRTRN: abs_rhsr_less_than_abs_rhsi:
+ // FRTRN-NEXT: fdiv {{.*}}float
+ // FRTRN-NEXT: fmul {{.*}}float
+ // FRTRN-NEXT: fadd {{.*}}float
+ // FRTRN-NEXT: fmul {{.*}}float
+ // FRTRN-NEXT: fadd {{.*}}float
+ // FRTRN-NEXT: fdiv {{.*}}float
+ // FRTRN-NEXT: fmul {{.*}}float
+ // FRTRN-NEXT: fsub {{.*}}float
+ // FRTRN-NEXT: fdiv {{.*}}float
+ // FRTRN-NEXT: br label
+ // FRTRN: complex_div:
+ // FRTRN-NEXT: phi {{.*}}float
+ // FRTRN-NEXT: phi {{.*}}float
+
+ // LMTD-FAST: fmul {{.*}} float
+ // LMTD-FAST-NEXT: fmul {{.*}} float
+ // LMTD-FAST-NEXT: fadd {{.*}} float
+ // LMTD-FAST-NEXT: fmul {{.*}} float
+ // LMTD-FAST-NEXT: fmul {{.*}} float
+ // LMTD-FAST-NEXT: fadd {{.*}} float
+ // LMTD-FAST-NEXT: fmul {{.*}} float
+ // LMTD-FAST-NEXT: fmul {{.*}} float
+ // LMTD-FAST-NEXT: fsub {{.*}} float
+ // LMTD-FAST-NEXT: fdiv {{.*}} float
+ // LMTD-FAST-NEXT: fdiv {{.*}} float
+
+ return a / b;
+}
+
+_Complex float mul(_Complex float a, _Complex float b) {
+ // LABEL: define {{.*}} @mul(
+ // FULL: call {{.*}} @__mulsc3
+
+ // LMTD: fmul float
+ // LMTD-NEXT: fmul float
+ // LMTD-NEXT: fmul float
+ // LMTD-NEXT: fmul float
+ // LMTD-NEXT: fsub float
+ // LMTD-NEXT: fadd float
+
+ // FRTRN: fmul {{.*}}float
+ // FRTRN-NEXT: fmul {{.*}}float
+ // FRTRN-NEXT: fmul {{.*}}float
+ // FRTRN-NEXT: fmul {{.*}}float
+ // FRTRN-NEXT: fsub {{.*}}float
+ // FRTRN-NEXT: fadd {{.*}}float
+
+ // LMTD-FAST: fmul {{.*}} float
+ // LMTD-FAST-NEXT: fmul {{.*}} float
+ // LMTD-FAST-NEXT: fmul {{.*}} float
+ // LMTD-FAST-NEXT: fmul {{.*}} float
+ // LMTD-FAST-NEXT: fsub {{.*}} float
+ // LMTD-FAST-NEXT: fadd {{.*}} float
+
+ return a * b;
+}
diff --git a/clang/test/CodeGen/pragma-cx-limited-range.c b/clang/test/CodeGen/pragma-cx-limited-range.c
new file mode 100644
index 00000000000000..926da8afbee558
--- /dev/null
+++ b/clang/test/CodeGen/pragma-cx-limited-range.c
@@ -0,0 +1,107 @@
+// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
+// RUN: -o - | FileCheck %s --check-prefix=FULL
+
+// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
+// RUN: -complex-range=limited -o - | FileCheck --check-prefix=LMTD %s
+
+// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
+// RUN: -fno-cx-limited-range -o - | FileCheck %s --check-prefix=FULL
+
+// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
+// RUN: -complex-range=fortran -o - | FileCheck --check-prefix=FRTRN %s
+
+// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
+// RUN: -fno-cx-fortran-rules -o - | FileCheck --check-prefix=FULL %s
+
+_Complex float pragma_on_mul(_Complex float a, _Complex float b) {
+#pragma STDC CX_LIMITED_RANGE ON
+ // LABEL: define {{.*}} @pragma_on_mul(
+ // FULL: fmul float
+ // FULL-NEXT: fmul float
+ // FULL-NEXT: fmul float
+ // FULL-NEXT: fmul float
+ // FULL-NEXT: fsub float
+ // FULL-NEXT: fadd float
+
+ // LMTD: fmul float
+ // LMTD-NEXT: fmul float
+ // LMTD-NEXT: fmul float
+ // LMTD-NEXT: fmul float
+ // LMTD-NEXT: fsub float
+ // LMTD-NEXT: fadd float
+
+ // FRTRN: fmul float
+ // FRTRN-NEXT: fmul float
+ // FRTRN-NEXT: fmul float
+ // FRTRN-NEXT: fmul float
+ // FRTRN-NEXT: fsub float
+ // FRTRN-NEXT: fadd float
+
+ return a * b;
+}
+
+_Complex float pragma_off_mul(_Complex float a, _Complex float b) {
+#pragma STDC CX_LIMITED_RANGE OFF
+ // LABEL: define {{.*}} @pragma_off_mul(
+ // FULL: call {{.*}} @__mulsc3
+
+ // LMTD: call {{.*}} @__mulsc3
+
+ // FRTRN: call {{.*}} @__mulsc3
+
+ return a * b;
+}
+
+_Complex float pragma_on_div(_Complex float a, _Complex float b) {
+#pragma STDC CX_LIMITED_RANGE ON
+ // LABEL: define {{.*}} @pragma_on_div(
+ // FULL: fmul float
+ // FULL-NEXT: fmul float
+ // FULL-NEXT: fadd float
+ // FULL-NEXT: fmul float
+ // FULL-NEXT: fmul float
+ // FULL-NEXT: fadd float
+ // FULL-NEXT: fmul float
+ // FULL-NEXT: fmul float
+ // FULL-NEXT: fsub float
+ // FULL-NEXT: fdiv float
+ // FULL: fdiv float
+
+ // LMTD: fmul float
+ // LMTD-NEXT: fmul float
+ // LMTD-NEXT: fadd float
+ // LMTD-NEXT: fmul float
+ // LMTD-NEXT: fmul float
+ // LMTD-NEXT: fadd float
+ // LMTD-NEXT: fmul float
+ // LMTD-NEXT: fmul float
+ // LMTD-NEXT: fsub float
+ // LMTD-NEXT: fdiv float
+ // LMTD-NEXT: fdiv float
+
+ // FRTRN: fmul float
+ // FRTRN-NEXT: fmul float
+ // FRTRN-NEXT: fadd float
+ // FRTRN-NEXT: fmul float
+ // FRTRN-NEXT: fmul float
+ // FRTRN-NEXT: fadd float
+ // FRTRN-NEXT: fmul float
+ // FRTRN-NEXT: fmul float
+ // FRTRN-NEXT: fsub float
+ // FRTRN-NEXT: fdiv float
+ // FRTRN-NEXT: fdiv float
+
+ return a / b;
+}
+
+_Complex float pragma_off_div(_Complex float a, _Complex float b) {
+#pragma STDC CX_LIMITED_RANGE OFF
+ // LABEL: define {{.*}} @pragma_off_div(
+ // FULL: call {{.*}} @__divsc3
+
+ // LMTD: call {{.*}} @__divsc3
+
+ // FRTRN: call {{.*}} @__divsc3
+
+ return a / b;
+}
diff --git a/clang/test/Driver/range.c b/clang/test/Driver/range.c
new file mode 100644
index 00000000000000..8d456a997d6967
--- /dev/null
+++ b/clang/test/Driver/range.c
@@ -0,0 +1,39 @@
+// Test range options for complex multiplication and division.
+
+// RUN: %clang -### -target x86_64 -fcx-limited-range -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=LMTD %s
+
+// RUN: %clang -### -target x86_64 -fno-cx-limited-range -c %s 2>&1 \
+// RUN: | FileCheck %s
+
+// RUN: %clang -### -target x86_64 -fcx-fortran-rules -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=FRTRN %s
+
+// RUN: %clang -### -target x86_64 -fno-cx-fortran-rules -c %s 2>&1 \
+// RUN: | FileCheck %s
+
+// RUN: %clang -### -target x86_64 -fcx-limited-range \
+// RUN: -fcx-fortran-rules -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=WARN1 %s
+
+// RUN: %clang -### -target x86_64 -fcx-fortran-rules \
+// RUN: -fcx-limited-range -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=WARN2 %s
+
+// RUN: %clang -### -target x86_64 -ffast-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=LMTD %s
+
+// RUN: %clang -### -target x86_64 -ffast-math -fcx-limited-range -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=LMTD %s
+
+// RUN: %clang -### -target x86_64 -fcx-limited-range -ffast-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=LMTD %s
+
+// LMTD: -complex-range=limited
+// LMTD-NOT: -complex-range=fortran
+// CHECK-NOT: -complex-range=limited
+// FRTRN: -complex-range=fortran
+// FRTRN-NOT: -complex-range=limited
+// CHECK-NOT: -complex-range=fortran
+// WARN1: warning: overriding '-fcx-limited-range' option with '-fcx-fortran-rules' [-Woverriding-option]
+// WARN2: warning: overriding '-fcx-fortran-rules' option with '-fcx-limited-range' [-Woverriding-option]
diff --git a/clang/test/Preprocessor/pragma_unknown.c b/clang/test/Preprocessor/pragma_unknown.c
index a7c4829c279dd1..1d39f8229eb53b 100644
--- a/clang/test/Preprocessor/pragma_unknown.c
+++ b/clang/test/Preprocessor/pragma_unknown.c
@@ -27,6 +27,8 @@
#pragma STDC CX_LIMITED_RANGE // expected-warning {{expected 'ON' or 'OFF' or 'DEFAULT' in pragma}}
#pragma STDC CX_LIMITED_RANGE ON FULL POWER // expected-warning {{expected end of directive in pragma}}
+//expected-error at -1 {{unknown type name 'POWER'}}
+//expected-error at -2 {{expected identifier or '('}}
// CHECK: {{^}}#pragma STDC CX_LIMITED_RANGE{{$}}
// CHECK: {{^}}#pragma STDC CX_LIMITED_RANGE ON FULL POWER{{$}}
More information about the cfe-commits
mailing list