[clang] Add support for -fcx-limited-range and #pragma CX_LIMITED_RANGE. (PR #68820)

Zahira Ammarguellat via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 11 12:28:41 PDT 2023


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

>From 91de35737b74233f29da76573b4099bf64e8bdd4 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 1/2] 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 94db56a9fd5d78c..5cd81a66ab57bc1 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -904,6 +904,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 ff2130c93f28ea0..a871bea6cf14cd4 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1001,6 +1001,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 0e969f341bbe19f..8f2b4d50fd59e5b 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 5bef0335f7891c9..f206f5de1310e1b 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -10948,6 +10948,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 129adfb9fcc74d1..40d66713d34040e 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -2812,6 +2812,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 bd65a2d7181a01eb6357a5b24db1a265a8e28c26 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 2/2] 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;
 }



More information about the cfe-commits mailing list