[libcxx-commits] [libcxx] Complex range (PR #70244)

Zahira Ammarguellat via libcxx-commits libcxx-commits at lists.llvm.org
Thu Oct 26 06:30:13 PDT 2023


https://github.com/zahiraam updated https://github.com/llvm/llvm-project/pull/70244

>From 340e3777509f70b5b300adcb181261e84247cf1a Mon Sep 17 00:00:00 2001
From: Ammarguellat <zahira.ammarguellat at intel.com>
Date: Mon, 23 Oct 2023 12:51:21 -0700
Subject: [PATCH 01/11] Revert "[clang] Support fixed point types in C++
 (#67750)"

This reverts commit a3a7d6318027bb86e6614c022e77e0bd81aef6dc.

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
https://github.com/llvm/llvm-project/pull/67750#issuecomment-1775264907
---
 clang/include/clang/Basic/TokenKinds.def     |  6 +-
 clang/include/clang/Driver/Options.td        |  2 +-
 clang/lib/AST/ItaniumMangle.cpp              | 59 +-------------------
 clang/lib/Parse/ParseExpr.cpp                |  3 -
 clang/lib/Parse/ParseExprCXX.cpp             |  9 ---
 clang/lib/Parse/ParseTentative.cpp           |  6 --
 clang/test/CodeGenCXX/fixed-point-mangle.cpp | 45 ---------------
 clang/test/Frontend/fixed_point_errors.cpp   | 24 ++++----
 8 files changed, 15 insertions(+), 139 deletions(-)
 delete mode 100644 clang/test/CodeGenCXX/fixed-point-mangle.cpp

diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index bbae1200d376c0d..3ce317d318f9bb6 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -423,9 +423,9 @@ C23_KEYWORD(typeof                  , KEYGNU)
 C23_KEYWORD(typeof_unqual           , 0)
 
 // ISO/IEC JTC1 SC22 WG14 N1169 Extension
-KEYWORD(_Accum                      , KEYALL)
-KEYWORD(_Fract                      , KEYALL)
-KEYWORD(_Sat                        , KEYALL)
+KEYWORD(_Accum                      , KEYNOCXX)
+KEYWORD(_Fract                      , KEYNOCXX)
+KEYWORD(_Sat                        , KEYNOCXX)
 
 // GNU Extensions (in impl-reserved namespace)
 KEYWORD(_Decimal32                  , KEYALL)
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index e63158fb0e5333a..ca883689b05c28a 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2097,7 +2097,7 @@ defm fixed_point : BoolFOption<"fixed-point",
   LangOpts<"FixedPoint">, DefaultFalse,
   PosFlag<SetTrue, [], [ClangOption, CC1Option], "Enable">,
   NegFlag<SetFalse, [], [ClangOption], "Disable">,
-  BothFlags<[], [ClangOption], " fixed point types">>;
+  BothFlags<[], [ClangOption], " fixed point types">>, ShouldParseIf<!strconcat("!", cplusplus.KeyPath)>;
 defm cxx_static_destructors : BoolFOption<"c++-static-destructors",
   LangOpts<"RegisterStaticDestructors">, DefaultTrue,
   NegFlag<SetFalse, [], [ClangOption, CC1Option],
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 27e8cbf6dc3f41b..eafb121a8a4aa00 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -3050,17 +3050,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
   //                 ::= Di # char32_t
   //                 ::= Ds # char16_t
   //                 ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
-  //                 ::= [DS] DA  # N1169 fixed-point [_Sat] T _Accum
-  //                 ::= [DS] DR  # N1169 fixed-point [_Sat] T _Fract
   //                 ::= u <source-name>    # vendor extended type
-  //
-  //  <fixed-point-size>
-  //                 ::= s # short
-  //                 ::= t # unsigned short
-  //                 ::= i # plain
-  //                 ::= j # unsigned
-  //                 ::= l # long
-  //                 ::= m # unsigned long
   std::string type_name;
   // Normalize integer types as vendor extended types:
   // u<length>i<type size>
@@ -3205,77 +3195,30 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
     Out << "DF16_";
     break;
   case BuiltinType::ShortAccum:
-    Out << "DAs";
-    break;
   case BuiltinType::Accum:
-    Out << "DAi";
-    break;
   case BuiltinType::LongAccum:
-    Out << "DAl";
-    break;
   case BuiltinType::UShortAccum:
-    Out << "DAt";
-    break;
   case BuiltinType::UAccum:
-    Out << "DAj";
-    break;
   case BuiltinType::ULongAccum:
-    Out << "DAm";
-    break;
   case BuiltinType::ShortFract:
-    Out << "DRs";
-    break;
   case BuiltinType::Fract:
-    Out << "DRi";
-    break;
   case BuiltinType::LongFract:
-    Out << "DRl";
-    break;
   case BuiltinType::UShortFract:
-    Out << "DRt";
-    break;
   case BuiltinType::UFract:
-    Out << "DRj";
-    break;
   case BuiltinType::ULongFract:
-    Out << "DRm";
-    break;
   case BuiltinType::SatShortAccum:
-    Out << "DSDAs";
-    break;
   case BuiltinType::SatAccum:
-    Out << "DSDAi";
-    break;
   case BuiltinType::SatLongAccum:
-    Out << "DSDAl";
-    break;
   case BuiltinType::SatUShortAccum:
-    Out << "DSDAt";
-    break;
   case BuiltinType::SatUAccum:
-    Out << "DSDAj";
-    break;
   case BuiltinType::SatULongAccum:
-    Out << "DSDAm";
-    break;
   case BuiltinType::SatShortFract:
-    Out << "DSDRs";
-    break;
   case BuiltinType::SatFract:
-    Out << "DSDRi";
-    break;
   case BuiltinType::SatLongFract:
-    Out << "DSDRl";
-    break;
   case BuiltinType::SatUShortFract:
-    Out << "DSDRt";
-    break;
   case BuiltinType::SatUFract:
-    Out << "DSDRj";
-    break;
   case BuiltinType::SatULongFract:
-    Out << "DSDRm";
-    break;
+    llvm_unreachable("Fixed point types are disabled for c++");
   case BuiltinType::Half:
     Out << "Dh";
     break;
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 4d267c915ff2478..dd2d9400b7747e3 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1574,9 +1574,6 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
   case tok::kw_typename:
   case tok::kw_typeof:
   case tok::kw___vector:
-  case tok::kw__Accum:
-  case tok::kw__Fract:
-  case tok::kw__Sat:
 #define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t:
 #include "clang/Basic/OpenCLImageTypes.def"
   {
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 79db094e098f8e6..99b4931004546c1 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -2354,15 +2354,6 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
   case tok::kw_bool:
     DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID, Policy);
     break;
-  case tok::kw__Accum:
-    DS.SetTypeSpecType(DeclSpec::TST_accum, Loc, PrevSpec, DiagID, Policy);
-    break;
-  case tok::kw__Fract:
-    DS.SetTypeSpecType(DeclSpec::TST_fract, Loc, PrevSpec, DiagID, Policy);
-    break;
-  case tok::kw__Sat:
-    DS.SetTypeSpecSat(Loc, PrevSpec, DiagID);
-    break;
 #define GENERIC_IMAGE_TYPE(ImgType, Id)                                        \
   case tok::kw_##ImgType##_t:                                                  \
     DS.SetTypeSpecType(DeclSpec::TST_##ImgType##_t, Loc, PrevSpec, DiagID,     \
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 8b653b1c4f8eaf4..28decc4fc43f9b8 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -1775,9 +1775,6 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename,
   case tok::kw___ibm128:
   case tok::kw_void:
   case tok::annot_decltype:
-  case tok::kw__Accum:
-  case tok::kw__Fract:
-  case tok::kw__Sat:
 #define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t:
 #include "clang/Basic/OpenCLImageTypes.def"
     if (NextToken().is(tok::l_paren))
@@ -1897,9 +1894,6 @@ bool Parser::isCXXDeclarationSpecifierAType() {
   case tok::kw_void:
   case tok::kw___unknown_anytype:
   case tok::kw___auto_type:
-  case tok::kw__Accum:
-  case tok::kw__Fract:
-  case tok::kw__Sat:
 #define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t:
 #include "clang/Basic/OpenCLImageTypes.def"
     return true;
diff --git a/clang/test/CodeGenCXX/fixed-point-mangle.cpp b/clang/test/CodeGenCXX/fixed-point-mangle.cpp
deleted file mode 100644
index 103990a61316a9c..000000000000000
--- a/clang/test/CodeGenCXX/fixed-point-mangle.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-// RUN: %clang_cc1 -ffixed-point -S -emit-llvm %s -o - -triple=x86_64-unknown-linux-gnu | FileCheck %s
-
-// Primary fixed point types
-void func(signed short _Accum){}    // CHECK: @_Z4funcDAs
-void func(signed _Accum){}          // CHECK: @_Z4funcDAi
-void func(signed long _Accum){}     // CHECK: @_Z4funcDAl
-void func(unsigned short _Accum){}  // CHECK: @_Z4funcDAt
-void func(unsigned _Accum){}        // CHECK: @_Z4funcDAj
-void func(unsigned long _Accum){}   // CHECK: @_Z4funcDAm
-void func(signed short _Fract){}    // CHECK: @_Z4funcDRs
-void func(signed _Fract){}          // CHECK: @_Z4funcDRi
-void func(signed long _Fract){}     // CHECK: @_Z4funcDRl
-void func(unsigned short _Fract){}  // CHECK: @_Z4funcDRt
-void func(unsigned _Fract){}        // CHECK: @_Z4funcDRj
-void func(unsigned long _Fract){}   // CHECK: @_Z4funcDRm
-
-// Aliased
-void func2(short _Accum){}          // CHECK: @_Z5func2DAs
-void func2(_Accum){}                // CHECK: @_Z5func2DAi
-void func2(long _Accum){}           // CHECK: @_Z5func2DAl
-void func2(short _Fract){}          // CHECK: @_Z5func2DRs
-void func2(_Fract){}                // CHECK: @_Z5func2DRi
-void func2(long _Fract){}           // CHECK: @_Z5func2DRl
-
-// Primary saturated
-void func(_Sat signed short _Accum){}    // CHECK: @_Z4funcDSDAs
-void func(_Sat signed _Accum){}          // CHECK: @_Z4funcDSDAi
-void func(_Sat signed long _Accum){}     // CHECK: @_Z4funcDSDAl
-void func(_Sat unsigned short _Accum){}  // CHECK: @_Z4funcDSDAt
-void func(_Sat unsigned _Accum){}        // CHECK: @_Z4funcDSDAj
-void func(_Sat unsigned long _Accum){}   // CHECK: @_Z4funcDSDAm
-void func(_Sat signed short _Fract){}    // CHECK: @_Z4funcDSDRs
-void func(_Sat signed _Fract){}          // CHECK: @_Z4funcDSDRi
-void func(_Sat signed long _Fract){}     // CHECK: @_Z4funcDSDRl
-void func(_Sat unsigned short _Fract){}  // CHECK: @_Z4funcDSDRt
-void func(_Sat unsigned _Fract){}        // CHECK: @_Z4funcDSDRj
-void func(_Sat unsigned long _Fract){}   // CHECK: @_Z4funcDSDRm
-
-// Aliased saturated
-void func2(_Sat short _Accum){}          // CHECK: @_Z5func2DSDAs
-void func2(_Sat _Accum){}                // CHECK: @_Z5func2DSDAi
-void func2(_Sat long _Accum){}           // CHECK: @_Z5func2DSDAl
-void func2(_Sat short _Fract){}          // CHECK: @_Z5func2DSDRs
-void func2(_Sat _Fract){}                // CHECK: @_Z5func2DSDRi
-void func2(_Sat long _Fract){}           // CHECK: @_Z5func2DSDRl
diff --git a/clang/test/Frontend/fixed_point_errors.cpp b/clang/test/Frontend/fixed_point_errors.cpp
index 2264622a2e8c870..cdd90ceb7548f94 100644
--- a/clang/test/Frontend/fixed_point_errors.cpp
+++ b/clang/test/Frontend/fixed_point_errors.cpp
@@ -1,18 +1,14 @@
-// RUN: %clang_cc1 -x c++ %s -verify -DWITHOUT_FIXED_POINT
-// RUN: %clang_cc1 -x c++ %s -verify -ffixed-point
+// RUN: %clang_cc1 -x c++ %s -verify
+// RUN: %clang_cc1 -x c++ -ffixed-point %s -verify
 
-#ifdef WITHOUT_FIXED_POINT
-_Accum accum;                           // expected-error{{compile with '-ffixed-point' to enable fixed point types}}
-                                        // expected-error at -1{{a type specifier is required for all declarations}}
-_Fract fract;                           // expected-error{{compile with '-ffixed-point' to enable fixed point types}}
-                                        // expected-error at -1{{a type specifier is required for all declarations}}
-_Sat _Accum sat_accum;                  // expected-error 2{{compile with '-ffixed-point' to enable fixed point types}}
-                                        // expected-error at -1{{a type specifier is required for all declarations}}
-#endif
+// Name namgling is not provided for fixed point types in c++
+
+_Accum accum;                           // expected-error{{unknown type name '_Accum'}}
+_Fract fract;                           // expected-error{{unknown type name '_Fract'}}
+_Sat _Accum sat_accum;                  // expected-error{{unknown type name '_Sat'}}
+                                        // expected-error at -1{{expected ';' after top level declarator}}
 
 int accum_int = 10k;     // expected-error{{invalid suffix 'k' on integer constant}}
 int fract_int = 10r;     // expected-error{{invalid suffix 'r' on integer constant}}
-#ifdef WITHOUT_FIXED_POINT
-float accum_flt = 0.0k;  // expected-error{{invalid suffix 'k' on floating constant}}
-float fract_flt = 0.0r;  // expected-error{{invalid suffix 'r' on floating constant}}
-#endif
+float accum_flt = 10.0k; // expected-error{{invalid suffix 'k' on floating constant}}
+float fract_flt = 10.0r; // expected-error{{invalid suffix 'r' on floating constant}}

>From a9268af3c21a6dbb6bc70d607642cc698dbfc678 Mon Sep 17 00:00:00 2001
From: Ammarguellat <zahira.ammarguellat at intel.com>
Date: Mon, 23 Oct 2023 14:14:42 -0700
Subject: [PATCH 02/11] Fix format.

---
 clang/lib/AST/ItaniumMangle.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index eafb121a8a4aa00..c3be3366e66731c 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -3046,7 +3046,8 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
   // UNSUPPORTED:    ::= De # IEEE 754r decimal floating point (128 bits)
   // UNSUPPORTED:    ::= Df # IEEE 754r decimal floating point (32 bits)
   //                 ::= Dh # IEEE 754r half-precision floating point (16 bits)
-  //                 ::= DF <number> _ # ISO/IEC TS 18661 binary floating point type _FloatN (N bits);
+  //                 ::= DF <number> _ # ISO/IEC TS 18661 binary floating point
+  //                 type _FloatN (N bits);
   //                 ::= Di # char32_t
   //                 ::= Ds # char16_t
   //                 ::= Dn # std::nullptr_t (i.e., decltype(nullptr))

>From 14a8ea1566c6a2d172aafdf71fbb258609fa5014 Mon Sep 17 00:00:00 2001
From: Ammarguellat <zahira.ammarguellat at intel.com>
Date: Tue, 24 Oct 2023 05:21:58 -0700
Subject: [PATCH 03/11] Fix format.

---
 clang/lib/AST/ItaniumMangle.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index eafb121a8a4aa00..c3be3366e66731c 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -3046,7 +3046,8 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
   // UNSUPPORTED:    ::= De # IEEE 754r decimal floating point (128 bits)
   // UNSUPPORTED:    ::= Df # IEEE 754r decimal floating point (32 bits)
   //                 ::= Dh # IEEE 754r half-precision floating point (16 bits)
-  //                 ::= DF <number> _ # ISO/IEC TS 18661 binary floating point type _FloatN (N bits);
+  //                 ::= DF <number> _ # ISO/IEC TS 18661 binary floating point
+  //                 type _FloatN (N bits);
   //                 ::= Di # char32_t
   //                 ::= Ds # char16_t
   //                 ::= Dn # std::nullptr_t (i.e., decltype(nullptr))

>From 6f636b91d2acef1a4ced33d4517f300a324cd197 Mon Sep 17 00:00:00 2001
From: Ammarguellat <zahira.ammarguellat at intel.com>
Date: Tue, 10 Oct 2023 08:31:41 -0700
Subject: [PATCH 04/11] Add support for -fcx-limited-range and #pragma
 CX_LIMTED_RANGE.

---
 clang/include/clang/Basic/FPOptions.def      |  1 +
 clang/include/clang/Basic/LangOptions.def    |  2 +
 clang/include/clang/Basic/TokenKinds.def     |  5 ++
 clang/include/clang/Driver/Options.td        |  6 ++
 clang/include/clang/Parse/Parser.h           |  4 ++
 clang/include/clang/Sema/Sema.h              |  4 ++
 clang/lib/CodeGen/CGExprComplex.cpp          | 59 ++++++++++------
 clang/lib/Driver/ToolChains/Clang.cpp        |  2 +
 clang/lib/Parse/ParsePragma.cpp              | 40 ++++++++++-
 clang/lib/Parse/ParseStmt.cpp                | 10 +++
 clang/lib/Parse/Parser.cpp                   |  3 +
 clang/lib/Sema/SemaAttr.cpp                  |  7 ++
 clang/test/CodeGen/cx-full-range.c           | 22 ++++++
 clang/test/CodeGen/pragma-cx-limited-range.c | 73 ++++++++++++++++++++
 clang/test/CodeGenCXX/cx-limited-range.c     | 18 +++++
 15 files changed, 233 insertions(+), 23 deletions(-)
 create mode 100644 clang/test/CodeGen/cx-full-range.c
 create mode 100644 clang/test/CodeGen/pragma-cx-limited-range.c
 create mode 100644 clang/test/CodeGenCXX/cx-limited-range.c

diff --git a/clang/include/clang/Basic/FPOptions.def b/clang/include/clang/Basic/FPOptions.def
index 5b923a1944e509a..9e56d7fcf26fdcf 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(CxLimitedRange, bool, 1, MathErrno)
 #undef OPTION
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index c0ea4ecb9806a5b..47513522a0d7719 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -219,6 +219,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")
 
+LANGOPT(CxLimitedRange, 1, 0, "Enable use of algebraic expansions of 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/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 3ce317d318f9bb6..7886625e87cdf4b 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -905,6 +905,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 c6b1903a32a0621..2f75230f20d4fd0 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1008,6 +1008,12 @@ 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 some arithmetic operations involving "
+           "data of type COMPLEX are disabled.">,
+  MarshallingInfoFlag<LangOpts<"CxLimitedRange">>;
+
 // 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 79ac622fd03e24e..19e205e9a418aef 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -767,6 +767,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 1e9752345ffd173..a2f90b643b87bf0 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11001,6 +11001,10 @@ 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, bool IsEnabled);
+
   /// 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 f3cbd1d0451ebe4..f18fdb17090968b 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -761,6 +761,21 @@ ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) {
 
     CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Op.FPFeatures);
     if (Op.LHS.second && Op.RHS.second) {
+      // (a+ib)*(c+id) = (ac-bd)+i(bc+ad)
+      if (Op.FPFeatures.getCxLimitedRange() ||
+          CGF.getLangOpts().CxLimitedRange) {
+        llvm::Value *LHSr = Op.LHS.first, *LHSi = Op.LHS.second;
+        llvm::Value *RHSr = Op.RHS.first, *RHSi = Op.RHS.second;
+
+        llvm::Value *AC = Builder.CreateFMul(LHSr, RHSr); // ac
+        llvm::Value *BD = Builder.CreateFMul(LHSi, RHSi); // bd
+        llvm::Value *DSTr = Builder.CreateFSub(AC, BD);   // ac-bd
+
+        llvm::Value *BC = Builder.CreateFMul(LHSi, RHSr); // bc
+        llvm::Value *AD = Builder.CreateFMul(LHSr, RHSi); // ad
+        llvm::Value *DSTi = Builder.CreateFAdd(BC, AD);   // bc+ad
+        return ComplexPairTy(DSTr, DSTi);
+      }
       // If both operands are complex, emit the core math directly, and then
       // test for NaNs. If we find NaNs in the result, we delegate to a libcall
       // to carefully re-compute the correct infinity representation if
@@ -851,9 +866,30 @@ ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) {
 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()) {
+    CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Op.FPFeatures);
+    if (RHSi && (Op.FPFeatures.getCxLimitedRange() ||
+                 CGF.getLangOpts().CxLimitedRange)) {
+      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 if (RHSi && !CGF.getLangOpts().FastMath) {
     // 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
@@ -861,8 +897,6 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
     //
     // 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) {
       BinOpInfo LibCallOp = Op;
       // If LHS was a real, supply a null imaginary part.
       if (!LHSi)
@@ -884,25 +918,6 @@ 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!");
 
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 601bbfb927746fc..4b383024eecc6c6 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -2841,6 +2841,8 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
     CmdArgs.push_back("-mlimit-float-precision");
     CmdArgs.push_back(A->getValue());
   }
+  if (const Arg *A = Args.getLastArg(options::OPT_fcx_limited_range))
+    CmdArgs.push_back("-fcx-limited-range");
 
   for (const Arg *A : Args) {
     auto optID = A->getOption().getID();
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index b3178aef64d72d7..eae4b54ecfc545c 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);
   }
 };
 
@@ -846,6 +859,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()));
+
+  bool IsEnabled;
+  switch (OOS) {
+  case tok::OOS_ON:
+    IsEnabled = true;
+    break;
+  case tok::OOS_OFF:
+    IsEnabled = false;
+    break;
+  case tok::OOS_DEFAULT:
+      // According to ISO C99 standard chapter 7.3.4, the default value
+      // for the pragma is ``off'. In GCC, the option -fcx-limited-range
+      // controls the default setting of the pragma.
+    IsEnabled = getLangOpts().CxLimitedRange ? true : false;
+    break;
+  }
+
+  SourceLocation PragmaLoc = ConsumeAnnotationToken();
+  Actions.ActOnPragmaCXLimitedRange(PragmaLoc, IsEnabled);
+}
+
 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 2531147c23196ae..b6c987c4b046b41 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -447,6 +447,13 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
     ConsumeAnnotationToken();
     return StmtError();
 
+  case tok::annot_pragma_cx_limited_range:
+    ProhibitAttributes(CXX11Attrs);
+    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);
@@ -1047,6 +1054,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 0f930248e77174b..befa6eba0885f29 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -836,6 +836,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 6dadf01ead4441b..602bc2e5ec62f3c 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -1340,6 +1340,13 @@ void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) {
   CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
 }
 
+void Sema::ActOnPragmaCXLimitedRange(SourceLocation Loc, bool IsEnabled) {
+  FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
+  NewFPFeatures.setCxLimitedRangeOverride(IsEnabled);
+  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/cx-full-range.c b/clang/test/CodeGen/cx-full-range.c
new file mode 100644
index 000000000000000..85386b84066ec6a
--- /dev/null
+++ b/clang/test/CodeGen/cx-full-range.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
+// RUN: -o - | FileCheck %s --check-prefix=FULL
+
+_Complex float pragma_off_mul(_Complex float a, _Complex float b) {
+#pragma STDC CX_LIMITED_RANGE OFF
+  // LABEL: define {{.*}} @pragma_on_mul
+  // LIMITED: %[[AC:[^ ]+]] = fmul
+  // LIMITED-NEXT: %[[BD:[^ ]+]] = fmul
+  // LIMITED-NEXT: %[[RR:[^ ]+]] = fsub
+  // LIMITED-NEXT: %[[BC:[^ ]+]] = fmul
+  // LIMITED-NEXT: %[[AD:[^ ]+]] = fmul
+  // LIMITED-NEXT: %[[RI:[^ ]+]] = fadd
+  // LIMITED: ret
+  return a * b;
+}
+
+_Complex float mul(_Complex float a, _Complex float b) {
+  // LABEL: define {{.*}} @mul
+  // FULL: call {{.*}} @__mulsc3(
+  // FULL: ret
+  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 000000000000000..78bed931b2ec400
--- /dev/null
+++ b/clang/test/CodeGen/pragma-cx-limited-range.c
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
+// RUN: -o - | FileCheck %s
+
+_Complex float pragma_on_mul(_Complex float a, _Complex float b) {
+#pragma STDC CX_LIMITED_RANGE ON
+  // LABEL: define {{.*}} @pragma_on_mul
+  // CHECK: %[[AC:[^ ]+]] = fmul
+  // CHECK-NEXT: %[[BD:[^ ]+]] = fmul
+  // CHECK-NEXT: %[[RR:[^ ]+]] = fsub
+  // CHECK-NEXT: %[[BC:[^ ]+]] = fmul
+  // CHECK-NEXT: %[[AD:[^ ]+]] = fmul
+  // CHECK-NEXT: %[[RI:[^ ]+]] = fadd
+  // CHECK: ret
+  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
+  // CHECK: %[[AC:[^ ]+]] = fmul
+  // CHECK-NEXT: %[[BD:[^ ]+]] = fmul
+  // CHECK-NEXT: %[[AD:[^ ]+]] = fmul
+  // CHECK-NEXT: %[[BC:[^ ]+]] = fmul
+  // CHECK-NEXT: %[[RR:[^ ]+]] = fsub
+  // CHECK-NEXT: %[[RI:[^ ]+]] = fadd
+  // CHECK: ret
+  return a * b;
+}
+
+_Complex float no_pragma_mul(_Complex float a, _Complex float b) {
+  // LABEL: define {{.*}} @pragma_off_mul
+  // CHECK: %[[AC:[^ ]+]] = fmul
+  // CHECK-NEXT: %[[BD:[^ ]+]] = fmul
+  // CHECK-NEXT: %[[AD:[^ ]+]] = fmul
+  // CHECK-NEXT: %[[BC:[^ ]+]] = fmul
+  // CHECK-NEXT: %[[RR:[^ ]+]] = fsub
+  // CHECK-NEXT: %[[RI:[^ ]+]] = fadd
+  // CHECK: ret
+  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
+  // CHECK: [[AC:%.*]] = fmul
+  // CHECK: [[BD:%.*]] = fmul
+  // CHECK: [[ACpBD:%.*]] = fadd
+  // CHECK: [[CC:%.*]] = fmul
+  // CHECK: [[DD:%.*]] = fmul
+  // CHECK: [[CCpDD:%.*]] = fadd
+  // CHECK: [[BC:%.*]] = fmul
+  // CHECK: [[AD:%.*]] = fmul
+  // CHECK: [[BCmAD:%.*]] = fsub
+  // CHECK: fdiv
+  // CHECK: fdiv
+  // CHECK: ret
+  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
+  // CHECK: call {{.*}} @__divsc3(
+  // CHECK: ret
+  return a / b;
+}
+
+_Complex float no_pragma_div(_Complex float a, _Complex float b) {
+  // LABEL: define {{.*}} @no_prama_div
+  // CHECK: call {{.*}} @__divsc3(
+  // CHECK: ret
+  return a / b;
+}
diff --git a/clang/test/CodeGenCXX/cx-limited-range.c b/clang/test/CodeGenCXX/cx-limited-range.c
new file mode 100644
index 000000000000000..fce0ee413fb02c9
--- /dev/null
+++ b/clang/test/CodeGenCXX/cx-limited-range.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
+// RUN: -fcx-limited-range -o - | FileCheck %s
+// RUN %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown -fuse-complex-intrinsics -fcx-range=nonan -o - | FileCheck %s --check-prefixes=CHECK-COMMON,CHECK-NO-NAN
+// RUN %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown -fuse-complex-intrinsics -fcx-range=full -o - | FileCheck %s --check-prefixes=CHECK-COMMON,CHECK-FULL
+
+_Complex float f1(_Complex float a, _Complex float b) {
+#pragma STDC CX_LIMITED_RANGE ON
+  // CHECK: fdiv float
+  // CHECK: fdiv float
+  return a / b;
+}
+
+_Complex float f2(_Complex float a, _Complex float b) {
+#pragma STDC CX_LIMITED_RANGE ON
+  // CHECK: fdiv float
+  // CHECK: fdiv float
+  return a * b;
+}

>From ea7caab46cee291554c52b81c7dfdf182805d00c Mon Sep 17 00:00:00 2001
From: Ammarguellat <zahira.ammarguellat at intel.com>
Date: Wed, 11 Oct 2023 12:28:16 -0700
Subject: [PATCH 05/11] Fix LIT test failing.

---
 clang/lib/CodeGen/CGExprComplex.cpp           | 47 ++++++++++++-------
 .../cx-limited-range.c                        | 17 +++++--
 2 files changed, 44 insertions(+), 20 deletions(-)
 rename clang/test/{CodeGenCXX => CodeGen}/cx-limited-range.c (64%)

diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index f18fdb17090968b..5b2d23acb410061 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -275,6 +275,8 @@ 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 EmitComplexBinOpLibCall(StringRef LibCallName,
                                         const BinOpInfo &Op);
@@ -861,11 +863,34 @@ 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) {
+  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);
+}
+
 // 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()) {
     CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Op.FPFeatures);
@@ -873,22 +898,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
                  CGF.getLangOpts().CxLimitedRange)) {
       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);
+      return EmitAlgebraicDiv(LHSr, LHSi, RHSr, RHSi);
     } else if (RHSi && !CGF.getLangOpts().FastMath) {
     // 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
@@ -918,6 +928,11 @@ 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());
+
+      return EmitAlgebraicDiv(LHSr, LHSi, RHSr, RHSi);
     } else {
       assert(LHSi && "Can have at most one non-complex operand!");
 
diff --git a/clang/test/CodeGenCXX/cx-limited-range.c b/clang/test/CodeGen/cx-limited-range.c
similarity index 64%
rename from clang/test/CodeGenCXX/cx-limited-range.c
rename to clang/test/CodeGen/cx-limited-range.c
index fce0ee413fb02c9..91ba0b3225080ce 100644
--- a/clang/test/CodeGenCXX/cx-limited-range.c
+++ b/clang/test/CodeGen/cx-limited-range.c
@@ -1,18 +1,27 @@
 // RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
 // RUN: -fcx-limited-range -o - | FileCheck %s
+
 // RUN %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown -fuse-complex-intrinsics -fcx-range=nonan -o - | FileCheck %s --check-prefixes=CHECK-COMMON,CHECK-NO-NAN
+
 // RUN %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown -fuse-complex-intrinsics -fcx-range=full -o - | FileCheck %s --check-prefixes=CHECK-COMMON,CHECK-FULL
 
 _Complex float f1(_Complex float a, _Complex float b) {
 #pragma STDC CX_LIMITED_RANGE ON
+  // LABEL: define {{.*}} @f1
   // CHECK: fdiv float
-  // CHECK: fdiv float
+  // CHECK-NEXT: fdiv float
   return a / b;
 }
 
 _Complex float f2(_Complex float a, _Complex float b) {
-#pragma STDC CX_LIMITED_RANGE ON
-  // CHECK: fdiv float
-  // CHECK: fdiv float
+#pragma STDC CX_LIMITED_RANGE OFF
+  // LABEL: define {{.*}} @f2
+  // CHECK: %[[AC:[^ ]+]] = fmul
+  // CHECK-NEXT: %[[BD:[^ ]+]] = fmul
+  // CHECK-NEXT: %[[RR:[^ ]+]] = fsub
+  // CHECK-NEXT: %[[BC:[^ ]+]] = fmul
+  // CHECK-NEXT: %[[AD:[^ ]+]] = fmul
+  // CHECK-NEXT: %[[RI:[^ ]+]] = fadd
+  // CHECK: ret
   return a * b;
 }

>From 8b0af1094815452d42aac38224124ee8a2d0426a Mon Sep 17 00:00:00 2001
From: Ammarguellat <zahira.ammarguellat at intel.com>
Date: Mon, 16 Oct 2023 12:17:31 -0700
Subject: [PATCH 06/11] Fixed  LIT test and added fno-cx-limited-range.

---
 clang/include/clang/Driver/Options.td        |   8 +-
 clang/lib/Driver/ToolChains/Clang.cpp        |   2 +
 clang/test/CodeGen/cx-limited-range.c        |  27 ++---
 clang/test/CodeGen/pragma-cx-limited-range.c | 118 +++++++++++--------
 4 files changed, 87 insertions(+), 68 deletions(-)

diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 2f75230f20d4fd0..45cb7567e0eeb71 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1010,9 +1010,13 @@ defm offload_uniform_block : BoolFOption<"offload-uniform-block",
 
 def fcx_limited_range : Joined<["-"], "fcx-limited-range">,
   Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
-  HelpText<"Basic algebraic expansions of some arithmetic operations involving "
-           "data of type COMPLEX are disabled.">,
+  HelpText<"Basic algebraic expansions of complex arithmetic operations "
+           "involving are enabled.">,
   MarshallingInfoFlag<LangOpts<"CxLimitedRange">>;
+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 enabled.">;
 
 // OpenCL-only Options
 def cl_opt_disable : Flag<["-"], "cl-opt-disable">, Group<opencl_Group>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 4b383024eecc6c6..0a5f785d56915a2 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -2843,6 +2843,8 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
   }
   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_fno_cx_limited_range))
+    CmdArgs.push_back("-fno-cx-limited-range");
 
   for (const Arg *A : Args) {
     auto optID = A->getOption().getID();
diff --git a/clang/test/CodeGen/cx-limited-range.c b/clang/test/CodeGen/cx-limited-range.c
index 91ba0b3225080ce..d4d40a563139925 100644
--- a/clang/test/CodeGen/cx-limited-range.c
+++ b/clang/test/CodeGen/cx-limited-range.c
@@ -1,27 +1,20 @@
 // RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
 // RUN: -fcx-limited-range -o - | FileCheck %s
 
-// RUN %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown -fuse-complex-intrinsics -fcx-range=nonan -o - | FileCheck %s --check-prefixes=CHECK-COMMON,CHECK-NO-NAN
-
-// RUN %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown -fuse-complex-intrinsics -fcx-range=full -o - | FileCheck %s --check-prefixes=CHECK-COMMON,CHECK-FULL
-
 _Complex float f1(_Complex float a, _Complex float b) {
-#pragma STDC CX_LIMITED_RANGE ON
   // LABEL: define {{.*}} @f1
-  // CHECK: fdiv float
-  // CHECK-NEXT: fdiv float
-  return a / b;
+  // CHECK: fmul
+  // CHECK-NEXT: fmul
+  // CHECK-NEXT: fsub
+  // CHECK-NEXT: fmul
+  // CHECK-NEXT: fmul
+  // CHECK-NEXT: fadd
+  return a * b;
 }
 
 _Complex float f2(_Complex float a, _Complex float b) {
-#pragma STDC CX_LIMITED_RANGE OFF
   // LABEL: define {{.*}} @f2
-  // CHECK: %[[AC:[^ ]+]] = fmul
-  // CHECK-NEXT: %[[BD:[^ ]+]] = fmul
-  // CHECK-NEXT: %[[RR:[^ ]+]] = fsub
-  // CHECK-NEXT: %[[BC:[^ ]+]] = fmul
-  // CHECK-NEXT: %[[AD:[^ ]+]] = fmul
-  // CHECK-NEXT: %[[RI:[^ ]+]] = fadd
-  // CHECK: ret
-  return a * b;
+  // CHECK: fdiv float
+  // CHECK-NEXT: fdiv float
+  return a / b;
 }
diff --git a/clang/test/CodeGen/pragma-cx-limited-range.c b/clang/test/CodeGen/pragma-cx-limited-range.c
index 78bed931b2ec400..9afbb9cf741d55a 100644
--- a/clang/test/CodeGen/pragma-cx-limited-range.c
+++ b/clang/test/CodeGen/pragma-cx-limited-range.c
@@ -1,73 +1,93 @@
 // RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
 // RUN: -o - | FileCheck %s
 
+// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
+// RUN: -fcx-limited-range -o - | FileCheck --check-prefix=OPT-CXLMT %s
+
+// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
+// RUN: -fno-cx-limited-range -o - | FileCheck %s
+
 _Complex float pragma_on_mul(_Complex float a, _Complex float b) {
 #pragma STDC CX_LIMITED_RANGE ON
-  // LABEL: define {{.*}} @pragma_on_mul
-  // CHECK: %[[AC:[^ ]+]] = fmul
-  // CHECK-NEXT: %[[BD:[^ ]+]] = fmul
-  // CHECK-NEXT: %[[RR:[^ ]+]] = fsub
-  // CHECK-NEXT: %[[BC:[^ ]+]] = fmul
-  // CHECK-NEXT: %[[AD:[^ ]+]] = fmul
-  // CHECK-NEXT: %[[RI:[^ ]+]] = fadd
-  // CHECK: ret
+  // CHECK-LABEL: define {{.*}} @pragma_on_mul(
+  // CHECK: fmul float
+  // CHECK-NEXT: fmul float
+  // CHECK-NEXT: fsub float
+  // CHECK-NEXT: fmul float
+  // CHECK-NEXT: fmul float
+  // CHECK-NEXT: fadd float
+
+  // OPT-CXLMT-LABEL: define {{.*}} @pragma_on_mul(
+  // OPT-CXLMT: fmul float
+  // OPT-CXLMT-NEXT: fmul float
+  // OPT-CXLMT-NEXT: fsub float
+  // OPT-CXLMT-NEXT: fmul float
+  // OPT-CXLMT-NEXT: fmul float
+  // OPT-CXLMT-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
-  // CHECK: %[[AC:[^ ]+]] = fmul
-  // CHECK-NEXT: %[[BD:[^ ]+]] = fmul
-  // CHECK-NEXT: %[[AD:[^ ]+]] = fmul
-  // CHECK-NEXT: %[[BC:[^ ]+]] = fmul
-  // CHECK-NEXT: %[[RR:[^ ]+]] = fsub
-  // CHECK-NEXT: %[[RI:[^ ]+]] = fadd
-  // CHECK: ret
-  return a * b;
-}
+  // CHECK-LABEL: define {{.*}} @pragma_off_mul(
+  // CHECK: call {{.*}} @__mulsc3
 
-_Complex float no_pragma_mul(_Complex float a, _Complex float b) {
-  // LABEL: define {{.*}} @pragma_off_mul
-  // CHECK: %[[AC:[^ ]+]] = fmul
-  // CHECK-NEXT: %[[BD:[^ ]+]] = fmul
-  // CHECK-NEXT: %[[AD:[^ ]+]] = fmul
-  // CHECK-NEXT: %[[BC:[^ ]+]] = fmul
-  // CHECK-NEXT: %[[RR:[^ ]+]] = fsub
-  // CHECK-NEXT: %[[RI:[^ ]+]] = fadd
-  // CHECK: ret
+  // OPT-CXLMT-LABEL: define {{.*}} @pragma_off_mul(
+  // OPT-CXLMT: fmul float
+  // OPT-CXLMT-NEXT: fmul float
+  // OPT-CXLMT-NEXT: fsub float
+  // OPT-CXLMT-NEXT: fmul float
+  // OPT-CXLMT-NEXT: fmul float
+  // OPT-CXLMT-NEXT: fadd float
   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
-  // CHECK: [[AC:%.*]] = fmul
-  // CHECK: [[BD:%.*]] = fmul
-  // CHECK: [[ACpBD:%.*]] = fadd
-  // CHECK: [[CC:%.*]] = fmul
-  // CHECK: [[DD:%.*]] = fmul
-  // CHECK: [[CCpDD:%.*]] = fadd
-  // CHECK: [[BC:%.*]] = fmul
-  // CHECK: [[AD:%.*]] = fmul
-  // CHECK: [[BCmAD:%.*]] = fsub
-  // CHECK: fdiv
-  // CHECK: fdiv
-  // CHECK: ret
+  // CHECK-LABEL: define {{.*}} @pragma_on_div(
+  // CHECK: fmul float
+  // CHECK-NEXT: fmul float
+  // CHECK-NEXT: fadd float
+  // CHECK-NEXT: fmul float
+  // CHECK-NEXT: fmul float
+  // CHECK-NEXT: fadd float
+  // CHECK-NEXT: fmul float
+  // CHECK-NEXT: fmul float
+  // CHECK-NEXT: fsub float
+  // CHECK-NEXT: fdiv float
+  // CHECK: fdiv float
+
+  // OPT-CXLMT-LABEL: define {{.*}} @pragma_on_div(
+  // OPT-CXLMT: fmul float
+  // OPT-CXLMT-NEXT: fmul float
+  // OPT-CXLMT-NEXT: fadd float
+  // OPT-CXLMT-NEXT: fmul float
+  // OPT-CXLMT-NEXT: fmul float
+  // OPT-CXLMT-NEXT: fadd float
+  // OPT-CXLMT-NEXT: fmul float
+  // OPT-CXLMT-NEXT: fmul float
+  // OPT-CXLMT-NEXT: fsub float
+  // OPT-CXLMT-NEXT: fdiv float
+  // OPT-CXLMT-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
-  // CHECK: call {{.*}} @__divsc3(
-  // CHECK: ret
-  return a / b;
-}
+  // CHECK-LABEL: define {{.*}} @pragma_off_div(
+  // CHECK: call {{.*}} @__divsc3
 
-_Complex float no_pragma_div(_Complex float a, _Complex float b) {
-  // LABEL: define {{.*}} @no_prama_div
-  // CHECK: call {{.*}} @__divsc3(
-  // CHECK: ret
+  // OPT-CXLMT-LABEL: define {{.*}} @pragma_off_div(
+  // OPT-CXLMT: fmul float
+  // OPT-CXLMT-NEXT: fmul float
+  // OPT-CXLMT-NEXT: fadd float
+  // OPT-CXLMT-NEXT: fmul float
+  // OPT-CXLMT-NEXT: fmul float
+  // OPT-CXLMT-NEXT: fadd float
+  // OPT-CXLMT-NEXT: fmul float
+  // OPT-CXLMT-NEXT: fmul float
+  // OPT-CXLMT-NEXT: fsub float
+  // OPT-CXLMT-NEXT: fdiv float
+  // OPT-CXLMT-NEXT: fdiv float
   return a / b;
 }

>From f36341192a21f820146b780ef00dfa02f5df1b37 Mon Sep 17 00:00:00 2001
From: Ammarguellat <zahira.ammarguellat at intel.com>
Date: Wed, 18 Oct 2023 07:06:35 -0700
Subject: [PATCH 07/11] Fixed a few things.

---
 clang/include/clang/Basic/FPOptions.def   |  1 +
 clang/include/clang/Basic/LangOptions.def |  1 +
 clang/include/clang/Driver/Options.td     |  7 +++++
 clang/lib/CodeGen/CGExprComplex.cpp       | 29 ++++++++++++++++-
 clang/lib/Driver/ToolChains/Clang.cpp     | 38 ++++++++++++++++++++---
 5 files changed, 71 insertions(+), 5 deletions(-)

diff --git a/clang/include/clang/Basic/FPOptions.def b/clang/include/clang/Basic/FPOptions.def
index 9e56d7fcf26fdcf..b633004386eb0c2 100644
--- a/clang/include/clang/Basic/FPOptions.def
+++ b/clang/include/clang/Basic/FPOptions.def
@@ -29,4 +29,5 @@ OPTION(Float16ExcessPrecision, LangOptions::ExcessPrecisionKind, 2, FPEvalMethod
 OPTION(BFloat16ExcessPrecision, LangOptions::ExcessPrecisionKind, 2, Float16ExcessPrecision)
 OPTION(MathErrno, bool, 1, BFloat16ExcessPrecision)
 OPTION(CxLimitedRange, bool, 1, MathErrno)
+OPTION(CxFortranRules, bool, 1, CxLimitedRange)
 #undef OPTION
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 47513522a0d7719..5ac0b9143e22331 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -220,6 +220,7 @@ BENIGN_LANGOPT(AllowRecip        , 1, 0, "Permit Floating Point reciprocal")
 BENIGN_LANGOPT(ApproxFunc        , 1, 0, "Permit Floating Point approximation")
 
 LANGOPT(CxLimitedRange, 1, 0, "Enable use of algebraic expansions of complex arithmetics.")
+LANGOPT(CxFortranRules, 1, 0, "Enable use of range reduction for complex arithmetics.")
 
 BENIGN_LANGOPT(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for __weak/__strong ivars")
 
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 45cb7567e0eeb71..80e78e938e51edb 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1017,6 +1017,13 @@ 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 enabled.">;
+def fcx_fortran_rules : Joined<["-"], "fcx-fortran-rules">,
+  Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
+  HelpText<"Range reduction is enabled for complex arithmetic operations.">,
+  MarshallingInfoFlag<LangOpts<"CxFortranRules">>;
+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.">;
 
 // OpenCL-only Options
 def cl_opt_disable : Flag<["-"], "cl-opt-disable">, Group<opencl_Group>,
diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index 5b2d23acb410061..2a82b9ccde85757 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -277,6 +277,8 @@ class ComplexExprEmitter
   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);
@@ -867,6 +869,7 @@ 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
@@ -885,6 +888,28 @@ ComplexPairTy ComplexExprEmitter::EmitAlgebraicDiv(llvm::Value *LHSr,
   return ComplexPairTy(DSTr, DSTi);
 }
 
+ComplexPairTy ComplexExprEmitter::EmitRangeReductionDiv(llvm::Value *LHSr,
+                                                        llvm::Value *LHSi,
+                                                        llvm::Value *RHSr,
+                                                        llvm::Value *RHSi) {
+  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);
+}
+
 // See C11 Annex G.5.1 for the semantics of multiplicative operators on complex
 // typed values.
 ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
@@ -894,7 +919,9 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
   llvm::Value *DSTr, *DSTi;
   if (LHSr->getType()->isFloatingPointTy()) {
     CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Op.FPFeatures);
-    if (RHSi && (Op.FPFeatures.getCxLimitedRange() ||
+    if (RHSi && CGF.getLangOpts().CxFortranRules) {
+      return EmitRangeReductionDiv(LHSr, LHSi, RHSr, RHSi);
+    } else if (RHSi && (Op.FPFeatures.getCxLimitedRange() ||
                  CGF.getLangOpts().CxLimitedRange)) {
       if (!LHSi)
         LHSi = llvm::Constant::getNullValue(RHSi->getType());
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 0a5f785d56915a2..f10912d772bd6c8 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -2836,15 +2836,14 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
   bool StrictFPModel = false;
   StringRef Float16ExcessPrecision = "";
   StringRef BFloat16ExcessPrecision = "";
+  StringRef CxLimitedRange = "NoCxLimiteRange";
+  StringRef CxFortranRules = "NoCxFortranRules";
+  StringRef Range = "";
 
   if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
     CmdArgs.push_back("-mlimit-float-precision");
     CmdArgs.push_back(A->getValue());
   }
-  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_fno_cx_limited_range))
-    CmdArgs.push_back("-fno-cx-limited-range");
 
   for (const Arg *A : Args) {
     auto optID = A->getOption().getID();
@@ -2852,6 +2851,28 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
     switch (optID) {
     default:
       break;
+    case options::OPT_fcx_limited_range: {
+      if (Range == "")
+        Range = "CxLimitedRange";
+      else
+        D.Diag(clang::diag::err_drv_incompatible_options)
+            << "fcx-limited-range" << Range;
+      break;
+    }
+    case options::OPT_fno_cx_limited_range:
+      Range = "NoCxLimitedRange";
+      break;
+    case options::OPT_fcx_fortran_rules: {
+      if (Range == "")
+        Range = "CxFortranRules";
+      else
+        D.Diag(clang::diag::err_drv_incompatible_options)
+            << "fcx-fortan-rules" << Range;
+      break;
+    }
+    case options::OPT_fno_cx_fortran_rules:
+      CxFortranRules = "NoCxFortranRules";
+      break;
     case options::OPT_ffp_model_EQ: {
       // If -ffp-model= is seen, reset to fno-fast-math
       HonorINFs = true;
@@ -3273,6 +3294,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,

>From 2aa766352db0c3010991b4bc53ded7a2d1693bfd Mon Sep 17 00:00:00 2001
From: Ammarguellat <zahira.ammarguellat at intel.com>
Date: Wed, 25 Oct 2023 10:51:04 -0700
Subject: [PATCH 08/11] Fixed a few things.

---
 clang/lib/CodeGen/CGExprComplex.cpp          | 105 +++++++---
 clang/lib/Parse/ParsePragma.cpp              |   6 +-
 clang/test/CodeGen/cx-complex-range.c        |  79 ++++++++
 clang/test/CodeGen/cx-full-range.c           |  22 ---
 clang/test/CodeGen/cx-limited-range.c        |  20 --
 clang/test/CodeGen/pragma-cx-limited-range.c | 193 ++++++++++++-------
 6 files changed, 287 insertions(+), 138 deletions(-)
 create mode 100644 clang/test/CodeGen/cx-complex-range.c
 delete mode 100644 clang/test/CodeGen/cx-full-range.c
 delete mode 100644 clang/test/CodeGen/cx-limited-range.c

diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index 2a82b9ccde85757..4b559a5dc747962 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -871,7 +871,8 @@ ComplexPairTy ComplexExprEmitter::EmitAlgebraicDiv(llvm::Value *LHSr,
                                                    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 *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
 
@@ -888,26 +889,79 @@ ComplexPairTy ComplexExprEmitter::EmitAlgebraicDiv(llvm::Value *LHSr,
   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;
+}
+
 ComplexPairTy ComplexExprEmitter::EmitRangeReductionDiv(llvm::Value *LHSr,
                                                         llvm::Value *LHSi,
                                                         llvm::Value *RHSr,
                                                         llvm::Value *RHSi) {
-  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);
+  // (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("true_bb_name");
+  llvm::BasicBlock *FalseBB = CGF.createBasicBlock("false_bb_name");
+  llvm::BasicBlock *ContBB = CGF.createBasicBlock("cont_bb");
+  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); // d/c
+
+  llvm::Value *RD = Builder.CreateFMul(DdC, RHSi);   // (d/c)d
+  llvm::Value *CpRD = Builder.CreateFAdd(RHSr, RD);  // c+((d/c)d)
+
+  llvm::Value *T3 = Builder.CreateFMul(LHSi, DdC);   // b(d/c)
+  llvm::Value *T4 = Builder.CreateFAdd(LHSr, T3);    // a+b(d/c)
+  llvm::Value *DSTTr = Builder.CreateFDiv(T4, CpRD); // (a+b(d/c))/(c+(d/c)d)
+
+  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-a(d/c))/(c+(d/c)d)
+  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);  // c/d
+
+  llvm::Value *RC = Builder.CreateFMul(CdD, RHSr);    // (c/d)c
+  llvm::Value *DpRC = Builder.CreateFAdd(RHSi, RC);   // d+(c/d)c
+
+  llvm::Value *T7 = Builder.CreateFAdd(CdD, RHSi);    // (c/d)+b
+  llvm::Value *T8 = Builder.CreateFMul(LHSr, T7);     // a((c/d)+b)
+  llvm::Value *DSTFr = Builder.CreateFDiv(T8, DpRC);  // (a((c/d)+b)/(d+(c/d)c))
+
+  llvm::Value *T9 = Builder.CreateFSub(CdD, LHSr);    // (c/d)-a
+  llvm::Value *T10 = Builder.CreateFMul(RHSi, T9);    // b((c/d)-a)
+  llvm::Value *DSTFi =
+      Builder.CreateFDiv(T10, DpRC); // (b((c/d)-a))/(d+(c/d)c))
+  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
@@ -919,7 +973,8 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
   llvm::Value *DSTr, *DSTi;
   if (LHSr->getType()->isFloatingPointTy()) {
     CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Op.FPFeatures);
-    if (RHSi && CGF.getLangOpts().CxFortranRules) {
+    if (RHSi && CGF.getLangOpts().CxFortranRules &&
+        !Op.FPFeatures.getCxLimitedRange()) {
       return EmitRangeReductionDiv(LHSr, LHSi, RHSr, RHSi);
     } else if (RHSi && (Op.FPFeatures.getCxLimitedRange() ||
                  CGF.getLangOpts().CxLimitedRange)) {
@@ -927,13 +982,13 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
         LHSi = llvm::Constant::getNullValue(RHSi->getType());
       return EmitAlgebraicDiv(LHSr, LHSi, RHSr, RHSi);
     } else if (RHSi && !CGF.getLangOpts().FastMath) {
-    // 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.
+      // 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)
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index eae4b54ecfc545c..6e4db5da9fdbc49 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -873,9 +873,9 @@ void Parser::HandlePragmaCXLimitedRange() {
     IsEnabled = false;
     break;
   case tok::OOS_DEFAULT:
-      // According to ISO C99 standard chapter 7.3.4, the default value
-      // for the pragma is ``off'. In GCC, the option -fcx-limited-range
-      // controls the default setting of the pragma.
+    // According to ISO C99 standard chapter 7.3.4, the default value
+    // for the pragma is ``off'. In GCC, the option -fcx-limited-range
+    // controls the default setting of the pragma.
     IsEnabled = getLangOpts().CxLimitedRange ? true : false;
     break;
   }
diff --git a/clang/test/CodeGen/cx-complex-range.c b/clang/test/CodeGen/cx-complex-range.c
new file mode 100644
index 000000000000000..921abd74ecbb631
--- /dev/null
+++ b/clang/test/CodeGen/cx-complex-range.c
@@ -0,0 +1,79 @@
+// 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: -fcx-limited-range -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: -fcx-fortran-rules -o - | FileCheck %s --check-prefix=FRTRN
+
+// 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:      true_bb_name:
+  // 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:      false_bb_name:
+  // FRTRN-NEXT: fdiv float
+  // FRTRN-NEXT: fmul float
+  // FRTRN-NEXT: fadd float
+  // FRTRN-NEXT: fadd float
+  // FRTRN-NEXT: fmul float
+  // FRTRN-NEXT: fdiv float
+  // FRTRN-NEXT: fsub float
+  // FRTRN-NEXT: fmul float
+  // FRTRN-NEXT: fdiv float
+  // FRTRN-NEXT: br label
+  // FRTRN:      cont_bb:
+  // FRTRN-NEXT: phi float
+  // FRTRN-NEXT: phi 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: fsub float
+  // LMTD-NEXT: fmul float
+  // LMTD-NEXT: fmul float
+  // LMTD-NEXT: fadd float
+
+  // FRTRN: call <2 x float> @__mulsc3
+
+  return a * b;
+}
diff --git a/clang/test/CodeGen/cx-full-range.c b/clang/test/CodeGen/cx-full-range.c
deleted file mode 100644
index 85386b84066ec6a..000000000000000
--- a/clang/test/CodeGen/cx-full-range.c
+++ /dev/null
@@ -1,22 +0,0 @@
-// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
-// RUN: -o - | FileCheck %s --check-prefix=FULL
-
-_Complex float pragma_off_mul(_Complex float a, _Complex float b) {
-#pragma STDC CX_LIMITED_RANGE OFF
-  // LABEL: define {{.*}} @pragma_on_mul
-  // LIMITED: %[[AC:[^ ]+]] = fmul
-  // LIMITED-NEXT: %[[BD:[^ ]+]] = fmul
-  // LIMITED-NEXT: %[[RR:[^ ]+]] = fsub
-  // LIMITED-NEXT: %[[BC:[^ ]+]] = fmul
-  // LIMITED-NEXT: %[[AD:[^ ]+]] = fmul
-  // LIMITED-NEXT: %[[RI:[^ ]+]] = fadd
-  // LIMITED: ret
-  return a * b;
-}
-
-_Complex float mul(_Complex float a, _Complex float b) {
-  // LABEL: define {{.*}} @mul
-  // FULL: call {{.*}} @__mulsc3(
-  // FULL: ret
-  return a * b;
-}
diff --git a/clang/test/CodeGen/cx-limited-range.c b/clang/test/CodeGen/cx-limited-range.c
deleted file mode 100644
index d4d40a563139925..000000000000000
--- a/clang/test/CodeGen/cx-limited-range.c
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
-// RUN: -fcx-limited-range -o - | FileCheck %s
-
-_Complex float f1(_Complex float a, _Complex float b) {
-  // LABEL: define {{.*}} @f1
-  // CHECK: fmul
-  // CHECK-NEXT: fmul
-  // CHECK-NEXT: fsub
-  // CHECK-NEXT: fmul
-  // CHECK-NEXT: fmul
-  // CHECK-NEXT: fadd
-  return a * b;
-}
-
-_Complex float f2(_Complex float a, _Complex float b) {
-  // LABEL: define {{.*}} @f2
-  // CHECK: fdiv float
-  // CHECK-NEXT: fdiv float
-  return a / b;
-}
diff --git a/clang/test/CodeGen/pragma-cx-limited-range.c b/clang/test/CodeGen/pragma-cx-limited-range.c
index 9afbb9cf741d55a..9490750e6e85c71 100644
--- a/clang/test/CodeGen/pragma-cx-limited-range.c
+++ b/clang/test/CodeGen/pragma-cx-limited-range.c
@@ -1,93 +1,150 @@
 // RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
-// RUN: -o - | FileCheck %s
+// RUN: -o - | FileCheck %s --check-prefix=FULL
 
 // RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
-// RUN: -fcx-limited-range -o - | FileCheck --check-prefix=OPT-CXLMT %s
+// RUN: -fcx-limited-range -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
+// RUN: -fno-cx-limited-range -o - | FileCheck %s --check-prefix=FULL
+
+// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
+// RUN: -fcx-fortran-rules -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
-  // CHECK-LABEL: define {{.*}} @pragma_on_mul(
-  // CHECK: fmul float
-  // CHECK-NEXT: fmul float
-  // CHECK-NEXT: fsub float
-  // CHECK-NEXT: fmul float
-  // CHECK-NEXT: fmul float
-  // CHECK-NEXT: fadd float
-
-  // OPT-CXLMT-LABEL: define {{.*}} @pragma_on_mul(
-  // OPT-CXLMT: fmul float
-  // OPT-CXLMT-NEXT: fmul float
-  // OPT-CXLMT-NEXT: fsub float
-  // OPT-CXLMT-NEXT: fmul float
-  // OPT-CXLMT-NEXT: fmul float
-  // OPT-CXLMT-NEXT: fadd float
+  // LABEL: define {{.*}} @pragma_on_mul(
+  // FULL: fmul float
+  // FULL-NEXT: fmul float
+  // FULL-NEXT: fsub float
+  // FULL-NEXT: fmul float
+  // FULL-NEXT: fmul float
+  // FULL-NEXT: fadd float
+
+  // LMTD: fmul float
+  // LMTD-NEXT: fmul float
+  // LMTD-NEXT: fsub float
+  // LMTD-NEXT: fmul float
+  // LMTD-NEXT: fmul float
+  // LMTD-NEXT: fadd float
+
+  // FRTRN: fmul float
+  // FRTRN-NEXT: fmul float
+  // FRTRN-NEXT: fsub float
+  // FRTRN-NEXT: fmul float
+  // FRTRN-NEXT: fmul 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
-  // CHECK-LABEL: define {{.*}} @pragma_off_mul(
-  // CHECK: call {{.*}} @__mulsc3
-
-  // OPT-CXLMT-LABEL: define {{.*}} @pragma_off_mul(
-  // OPT-CXLMT: fmul float
-  // OPT-CXLMT-NEXT: fmul float
-  // OPT-CXLMT-NEXT: fsub float
-  // OPT-CXLMT-NEXT: fmul float
-  // OPT-CXLMT-NEXT: fmul float
-  // OPT-CXLMT-NEXT: fadd float
+  // LABEL: define {{.*}} @pragma_off_mul(
+  // FULL: call {{.*}} @__mulsc3
+
+  // LMTD: fmul float
+  // LMTD-NEXT: fmul float
+  // LMTD-NEXT: fsub float
+  // LMTD-NEXT: fmul float
+  // LMTD-NEXT: fmul float
+  // LMTD-NEXT: fadd float
+
+  // FRTRN: call {{.*}} @__mulsc3
+
   return a * b;
 }
 
 _Complex float pragma_on_div(_Complex float a, _Complex float b) {
 #pragma STDC CX_LIMITED_RANGE ON
-  // CHECK-LABEL: define {{.*}} @pragma_on_div(
-  // CHECK: fmul float
-  // CHECK-NEXT: fmul float
-  // CHECK-NEXT: fadd float
-  // CHECK-NEXT: fmul float
-  // CHECK-NEXT: fmul float
-  // CHECK-NEXT: fadd float
-  // CHECK-NEXT: fmul float
-  // CHECK-NEXT: fmul float
-  // CHECK-NEXT: fsub float
-  // CHECK-NEXT: fdiv float
-  // CHECK: fdiv float
-
-  // OPT-CXLMT-LABEL: define {{.*}} @pragma_on_div(
-  // OPT-CXLMT: fmul float
-  // OPT-CXLMT-NEXT: fmul float
-  // OPT-CXLMT-NEXT: fadd float
-  // OPT-CXLMT-NEXT: fmul float
-  // OPT-CXLMT-NEXT: fmul float
-  // OPT-CXLMT-NEXT: fadd float
-  // OPT-CXLMT-NEXT: fmul float
-  // OPT-CXLMT-NEXT: fmul float
-  // OPT-CXLMT-NEXT: fsub float
-  // OPT-CXLMT-NEXT: fdiv float
-  // OPT-CXLMT-NEXT: fdiv float
+  // 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
-  // CHECK-LABEL: define {{.*}} @pragma_off_div(
-  // CHECK: call {{.*}} @__divsc3
-
-  // OPT-CXLMT-LABEL: define {{.*}} @pragma_off_div(
-  // OPT-CXLMT: fmul float
-  // OPT-CXLMT-NEXT: fmul float
-  // OPT-CXLMT-NEXT: fadd float
-  // OPT-CXLMT-NEXT: fmul float
-  // OPT-CXLMT-NEXT: fmul float
-  // OPT-CXLMT-NEXT: fadd float
-  // OPT-CXLMT-NEXT: fmul float
-  // OPT-CXLMT-NEXT: fmul float
-  // OPT-CXLMT-NEXT: fsub float
-  // OPT-CXLMT-NEXT: fdiv float
-  // OPT-CXLMT-NEXT: fdiv float
+  // LABEL: define {{.*}} @pragma_off_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:      true_bb_name:
+  // 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:      false_bb_name:
+  // FRTRN-NEXT: fdiv float
+  // FRTRN-NEXT: fmul float
+  // FRTRN-NEXT: fadd float
+  // FRTRN-NEXT: fadd float
+  // FRTRN-NEXT: fmul float
+  // FRTRN-NEXT: fdiv float
+  // FRTRN-NEXT: fsub float
+  // FRTRN-NEXT: fmul float
+  // FRTRN-NEXT: fdiv float
+  // FRTRN-NEXT: br label
+  // FRTRN:      cont_bb:
+  // FRTRN-NEXT: phi float
+  // FRTRN-NEXT: phi float
+
   return a / b;
 }

>From a616aaeea9f6e7fcdbf561f1e389c3ad736e9350 Mon Sep 17 00:00:00 2001
From: Ammarguellat <zahira.ammarguellat at intel.com>
Date: Wed, 25 Oct 2023 12:28:11 -0700
Subject: [PATCH 09/11] Fix format.

---
 clang/lib/CodeGen/CGExprComplex.cpp   | 22 +++++++++++-----------
 clang/lib/Driver/ToolChains/Clang.cpp |  4 ++--
 2 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index 4b559a5dc747962..f73dd0538e78751 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -920,8 +920,8 @@ ComplexPairTy ComplexExprEmitter::EmitRangeReductionDiv(llvm::Value *LHSr,
   // f = (b - ar)/tmp
   llvm::Value *DdC = Builder.CreateFDiv(RHSi, RHSr); // d/c
 
-  llvm::Value *RD = Builder.CreateFMul(DdC, RHSi);   // (d/c)d
-  llvm::Value *CpRD = Builder.CreateFAdd(RHSr, RD);  // c+((d/c)d)
+  llvm::Value *RD = Builder.CreateFMul(DdC, RHSi);  // (d/c)d
+  llvm::Value *CpRD = Builder.CreateFAdd(RHSr, RD); // c+((d/c)d)
 
   llvm::Value *T3 = Builder.CreateFMul(LHSi, DdC);   // b(d/c)
   llvm::Value *T4 = Builder.CreateFAdd(LHSr, T3);    // a+b(d/c)
@@ -938,17 +938,17 @@ ComplexPairTy ComplexExprEmitter::EmitRangeReductionDiv(llvm::Value *LHSr,
   // tmp = d + rc
   // e = (ar + b)/tmp
   // f = (br - a)/tmp
-  llvm::Value *CdD = Builder.CreateFDiv(RHSr, RHSi);  // c/d
+  llvm::Value *CdD = Builder.CreateFDiv(RHSr, RHSi); // c/d
 
-  llvm::Value *RC = Builder.CreateFMul(CdD, RHSr);    // (c/d)c
-  llvm::Value *DpRC = Builder.CreateFAdd(RHSi, RC);   // d+(c/d)c
+  llvm::Value *RC = Builder.CreateFMul(CdD, RHSr);  // (c/d)c
+  llvm::Value *DpRC = Builder.CreateFAdd(RHSi, RC); // d+(c/d)c
 
-  llvm::Value *T7 = Builder.CreateFAdd(CdD, RHSi);    // (c/d)+b
-  llvm::Value *T8 = Builder.CreateFMul(LHSr, T7);     // a((c/d)+b)
-  llvm::Value *DSTFr = Builder.CreateFDiv(T8, DpRC);  // (a((c/d)+b)/(d+(c/d)c))
+  llvm::Value *T7 = Builder.CreateFAdd(CdD, RHSi);   // (c/d)+b
+  llvm::Value *T8 = Builder.CreateFMul(LHSr, T7);    // a((c/d)+b)
+  llvm::Value *DSTFr = Builder.CreateFDiv(T8, DpRC); // (a((c/d)+b)/(d+(c/d)c))
 
-  llvm::Value *T9 = Builder.CreateFSub(CdD, LHSr);    // (c/d)-a
-  llvm::Value *T10 = Builder.CreateFMul(RHSi, T9);    // b((c/d)-a)
+  llvm::Value *T9 = Builder.CreateFSub(CdD, LHSr); // (c/d)-a
+  llvm::Value *T10 = Builder.CreateFMul(RHSi, T9); // b((c/d)-a)
   llvm::Value *DSTFi =
       Builder.CreateFDiv(T10, DpRC); // (b((c/d)-a))/(d+(c/d)c))
   Builder.CreateBr(ContBB);
@@ -977,7 +977,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
         !Op.FPFeatures.getCxLimitedRange()) {
       return EmitRangeReductionDiv(LHSr, LHSi, RHSr, RHSi);
     } else if (RHSi && (Op.FPFeatures.getCxLimitedRange() ||
-                 CGF.getLangOpts().CxLimitedRange)) {
+                        CGF.getLangOpts().CxLimitedRange)) {
       if (!LHSi)
         LHSi = llvm::Constant::getNullValue(RHSi->getType());
       return EmitAlgebraicDiv(LHSr, LHSi, RHSr, RHSi);
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index f10912d772bd6c8..b915062bd59734c 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -3296,11 +3296,11 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
     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");
+    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");
+      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");
 }

>From 2898d3078f552b35130eceeb60f0bc796dcf420b Mon Sep 17 00:00:00 2001
From: Ammarguellat <zahira.ammarguellat at intel.com>
Date: Wed, 25 Oct 2023 12:56:18 -0700
Subject: [PATCH 10/11] Fix format again.

---
 clang/lib/Driver/ToolChains/Clang.cpp | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index b915062bd59734c..ca414b1956f5b02 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -3295,14 +3295,14 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
                    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))
+  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");
+  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,

>From 0441590540241bf5b4fe6a26a79870ca30ae4246 Mon Sep 17 00:00:00 2001
From: Ammarguellat <zahira.ammarguellat at intel.com>
Date: Thu, 26 Oct 2023 06:28:43 -0700
Subject: [PATCH 11/11] Fix format and error (pragma_unknow.c).

---
 clang/include/clang/Basic/DiagnosticParseKinds.td | 2 +-
 clang/lib/Lex/Pragma.cpp                          | 4 +++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index d6652e6a610c1be..902fbf4a0d692c0 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1349,7 +1349,7 @@ def warn_omp_extra_tokens_at_eol : Warning<
   "extra tokens at the end of '#pragma omp %0' are ignored">,
   InGroup<ExtraTokens>;
 def err_omp_multiple_step_or_linear_modifier : Error<
-  "multiple %select{'step size'|'linear modifier'}0 found in linear clause">; 
+  "multiple %select{'step size'|'linear modifier'}0 found in linear clause">;
 def warn_pragma_expected_colon_r_paren : Warning<
   "missing ':' or ')' after %0 - ignoring">, InGroup<IgnoredPragmas>;
 def err_omp_unknown_directive : Error<
diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp
index 35ab42cb6b5ef85..a01959077b8fa56 100644
--- a/clang/lib/Lex/Pragma.cpp
+++ b/clang/lib/Lex/Pragma.cpp
@@ -987,8 +987,10 @@ bool Preprocessor::LexOnOffSwitch(tok::OnOffSwitch &Result) {
 
   // Verify that this is followed by EOD.
   LexUnexpandedToken(Tok);
-  if (Tok.isNot(tok::eod))
+  if (Tok.isNot(tok::eod)) {
     Diag(Tok, diag::ext_pragma_syntax_eod);
+    DiscardUntilEndOfDirective();
+  }
   return false;
 }
 



More information about the libcxx-commits mailing list