[clang] 364a5b5 - Fix a bug in implementation of Smith's algorithm used in complex div. (#78330)

via cfe-commits cfe-commits at lists.llvm.org
Mon Jan 22 12:50:29 PST 2024


Author: Zahira Ammarguellat
Date: 2024-01-22T15:50:24-05:00
New Revision: 364a5b5b850a4f3e564da4bde080567a5d1e14d2

URL: https://github.com/llvm/llvm-project/commit/364a5b5b850a4f3e564da4bde080567a5d1e14d2
DIFF: https://github.com/llvm/llvm-project/commit/364a5b5b850a4f3e564da4bde080567a5d1e14d2.diff

LOG: Fix a bug in implementation of Smith's algorithm used in complex div. (#78330)

This patch fixes a bug in Smith's algorithm (thanks to @andykaylor who
detected it) and makes sure that last option in command line rules.

Added: 
    clang/test/CodeGen/smiths-complex-div.c

Modified: 
    clang/include/clang/Basic/LangOptions.def
    clang/include/clang/Basic/LangOptions.h
    clang/lib/CodeGen/CGExprComplex.cpp
    clang/lib/Driver/ToolChains/Clang.cpp
    clang/test/CodeGen/cx-complex-range.c
    clang/test/Driver/range.c

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index c0ab6b97dd8dbe..47cbd3d30f8478 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -220,7 +220,7 @@ BENIGN_LANGOPT(NoSignedZero      , 1, 0, "Permit Floating Point optimization wit
 BENIGN_LANGOPT(AllowRecip        , 1, 0, "Permit Floating Point reciprocal")
 BENIGN_LANGOPT(ApproxFunc        , 1, 0, "Permit Floating Point approximation")
 
-ENUM_LANGOPT(ComplexRange, ComplexRangeKind, 2, CX_Full, "Enable use of range reduction for complex arithmetics.")
+ENUM_LANGOPT(ComplexRange, ComplexRangeKind, 2, CX_None, "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/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 79947431e4e2cc..c1cc5548ef10c0 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -414,7 +414,7 @@ class LangOptions : public LangOptionsBase {
     IncompleteOnly = 3,
   };
 
-  enum ComplexRangeKind { CX_Full, CX_Limited, CX_Fortran };
+  enum ComplexRangeKind { CX_Full, CX_Limited, CX_Fortran, CX_None };
 
 public:
   /// The used language standard.

diff  --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index e532794b71bdb4..839fe16cd77253 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -892,6 +892,9 @@ ComplexPairTy ComplexExprEmitter::EmitRangeReductionDiv(llvm::Value *LHSr,
                                                         llvm::Value *LHSi,
                                                         llvm::Value *RHSr,
                                                         llvm::Value *RHSi) {
+  // FIXME: This could eventually be replaced by an LLVM intrinsic to
+  // avoid this long IR sequence.
+
   // (a + ib) / (c + id) = (e + if)
   llvm::Value *FAbsRHSr = EmitllvmFAbs(CGF, RHSr); // |c|
   llvm::Value *FAbsRHSi = EmitllvmFAbs(CGF, RHSi); // |d|
@@ -936,7 +939,7 @@ ComplexPairTy ComplexExprEmitter::EmitRangeReductionDiv(llvm::Value *LHSr,
   llvm::Value *RC = Builder.CreateFMul(CdD, RHSr);  // rc
   llvm::Value *DpRC = Builder.CreateFAdd(RHSi, RC); // tmp=d+rc
 
-  llvm::Value *T7 = Builder.CreateFMul(LHSr, RC);    // ar
+  llvm::Value *T7 = Builder.CreateFMul(LHSr, CdD);   // ar
   llvm::Value *T8 = Builder.CreateFAdd(T7, LHSi);    // ar+b
   llvm::Value *DSTFr = Builder.CreateFDiv(T8, DpRC); // (ar+b)/tmp
 
@@ -978,7 +981,10 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
       return EmitRangeReductionDiv(LHSr, LHSi, RHSr, RHSi);
     else if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Limited)
       return EmitAlgebraicDiv(LHSr, LHSi, RHSr, RHSi);
-    else if (!CGF.getLangOpts().FastMath) {
+    else if (!CGF.getLangOpts().FastMath ||
+             // '-ffast-math' is used in the command line but followed by an
+             // '-fno-cx-limited-range'.
+             Op.FPFeatures.getComplexRange() == LangOptions::CX_Full) {
       LHSi = OrigLHSi;
       // If we have a complex operand on the RHS and FastMath is not allowed, we
       // delegate to a libcall to handle all of the complexities and minimize

diff  --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index f80f8e44de1c43..776a13b958893d 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -2712,9 +2712,22 @@ static void EmitComplexRangeDiag(const Driver &D,
         << EnumComplexRangeToStr(Range1) << EnumComplexRangeToStr(Range2);
 }
 
-static std::string RenderComplexRangeOption(std::string Range) {
+static std::string
+RenderComplexRangeOption(LangOptions::ComplexRangeKind Range) {
   std::string ComplexRangeStr = "-complex-range=";
-  ComplexRangeStr += Range;
+  switch (Range) {
+  case LangOptions::ComplexRangeKind::CX_Full:
+    ComplexRangeStr += "full";
+    break;
+  case LangOptions::ComplexRangeKind::CX_Limited:
+    ComplexRangeStr += "limited";
+    break;
+  case LangOptions::ComplexRangeKind::CX_Fortran:
+    ComplexRangeStr += "fortran";
+    break;
+  default:
+    assert("Unexpected range option");
+  }
   return ComplexRangeStr;
 }
 
@@ -2764,7 +2777,8 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
   bool StrictFPModel = false;
   StringRef Float16ExcessPrecision = "";
   StringRef BFloat16ExcessPrecision = "";
-  LangOptions::ComplexRangeKind Range = LangOptions::ComplexRangeKind::CX_Full;
+  LangOptions::ComplexRangeKind Range = LangOptions::ComplexRangeKind::CX_None;
+  std::string ComplexRangeStr = "";
 
   if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
     CmdArgs.push_back("-mlimit-float-precision");
@@ -2780,23 +2794,19 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
     case options::OPT_fcx_limited_range: {
       EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Limited);
       Range = LangOptions::ComplexRangeKind::CX_Limited;
-      std::string ComplexRangeStr = RenderComplexRangeOption("limited");
-      if (!ComplexRangeStr.empty())
-        CmdArgs.push_back(Args.MakeArgString(ComplexRangeStr));
       break;
     }
     case options::OPT_fno_cx_limited_range:
+      EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Full);
       Range = LangOptions::ComplexRangeKind::CX_Full;
       break;
     case options::OPT_fcx_fortran_rules: {
       EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Fortran);
       Range = LangOptions::ComplexRangeKind::CX_Fortran;
-      std::string ComplexRangeStr = RenderComplexRangeOption("fortran");
-      if (!ComplexRangeStr.empty())
-        CmdArgs.push_back(Args.MakeArgString(ComplexRangeStr));
       break;
     }
     case options::OPT_fno_cx_fortran_rules:
+      EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Full);
       Range = LangOptions::ComplexRangeKind::CX_Full;
       break;
     case options::OPT_ffp_model_EQ: {
@@ -3068,9 +3078,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
       SeenUnsafeMathModeOption = true;
       // ffast-math enables fortran rules for complex multiplication and
       // division.
-      std::string ComplexRangeStr = RenderComplexRangeOption("limited");
-      if (!ComplexRangeStr.empty())
-        CmdArgs.push_back(Args.MakeArgString(ComplexRangeStr));
+      Range = LangOptions::ComplexRangeKind::CX_Limited;
       break;
     }
     case options::OPT_fno_fast_math:
@@ -3227,6 +3235,10 @@ 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 (Range != LangOptions::ComplexRangeKind::CX_None)
+    ComplexRangeStr = RenderComplexRangeOption(Range);
+  if (!ComplexRangeStr.empty())
+    CmdArgs.push_back(Args.MakeArgString(ComplexRangeStr));
   if (Args.hasArg(options::OPT_fcx_limited_range))
     CmdArgs.push_back("-fcx-limited-range");
   if (Args.hasArg(options::OPT_fcx_fortran_rules))

diff  --git a/clang/test/CodeGen/cx-complex-range.c b/clang/test/CodeGen/cx-complex-range.c
index 8368fa611335cc..2d8507c710f202 100644
--- a/clang/test/CodeGen/cx-complex-range.c
+++ b/clang/test/CodeGen/cx-complex-range.c
@@ -15,9 +15,25 @@
 // RUN: -ffast-math -complex-range=limited -emit-llvm -o - %s \
 // RUN: | FileCheck %s --check-prefix=LMTD-FAST
 
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu \
+// RUN: -ffast-math -complex-range=full -emit-llvm -o - %s \
+// RUN: | FileCheck %s --check-prefix=FULL
+
 // RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
 // RUN: -fno-cx-fortran-rules -o - | FileCheck %s --check-prefix=FULL
 
+// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
+// RUN: -fcx-limited-range -fno-cx-limited-range -o - \
+// RUN: | FileCheck %s --check-prefix=FULL
+
+// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
+// RUN: -fno-cx-limited-range -fcx-limited-range -o - \
+// RUN: | FileCheck %s --check-prefix=FULL
+
+// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
+// RUN: -fno-cx-fortran-rules -fcx-fortran-rules -o - \
+// RUN: | FileCheck %s --check-prefix=FULL
+
 _Complex float div(_Complex float a, _Complex float b) {
   // LABEL: define {{.*}} @div(
   // FULL:  call {{.*}} @__divsc3

diff  --git a/clang/test/CodeGen/smiths-complex-div.c b/clang/test/CodeGen/smiths-complex-div.c
new file mode 100644
index 00000000000000..75775675c92381
--- /dev/null
+++ b/clang/test/CodeGen/smiths-complex-div.c
@@ -0,0 +1,59 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 4
+// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown \
+// RUN: -complex-range=fortran -o - | FileCheck %s --check-prefix=FRTRN
+
+// FRTRN-LABEL: define dso_local <2 x float> @div(
+// FRTRN-SAME: <2 x float> noundef [[A_COERCE:%.*]], <2 x float> noundef [[B_COERCE:%.*]]) #[[ATTR0:[0-9]+]] {
+// FRTRN-NEXT:  entry:
+// FRTRN-NEXT:    [[RETVAL:%.*]] = alloca { float, float }, align 4
+// FRTRN-NEXT:    [[A:%.*]] = alloca { float, float }, align 4
+// FRTRN-NEXT:    [[B:%.*]] = alloca { float, float }, align 4
+// FRTRN-NEXT:    store <2 x float> [[A_COERCE]], ptr [[A]], align 4
+// FRTRN-NEXT:    store <2 x float> [[B_COERCE]], ptr [[B]], align 4
+// FRTRN-NEXT:    [[A_REALP:%.*]] = getelementptr inbounds { float, float }, ptr [[A]], i32 0, i32 0
+// FRTRN-NEXT:    [[A_REAL:%.*]] = load float, ptr [[A_REALP]], align 4
+// FRTRN-NEXT:    [[A_IMAGP:%.*]] = getelementptr inbounds { float, float }, ptr [[A]], i32 0, i32 1
+// FRTRN-NEXT:    [[A_IMAG:%.*]] = load float, ptr [[A_IMAGP]], align 4
+// FRTRN-NEXT:    [[B_REALP:%.*]] = getelementptr inbounds { float, float }, ptr [[B]], i32 0, i32 0
+// FRTRN-NEXT:    [[B_REAL:%.*]] = load float, ptr [[B_REALP]], align 4
+// FRTRN-NEXT:    [[B_IMAGP:%.*]] = getelementptr inbounds { float, float }, ptr [[B]], i32 0, i32 1
+// FRTRN-NEXT:    [[B_IMAG:%.*]] = load float, ptr [[B_IMAGP]], align 4
+// FRTRN-NEXT:    [[TMP0:%.*]] = call float @llvm.fabs.f32(float [[B_REAL]])
+// FRTRN-NEXT:    [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[B_IMAG]])
+// FRTRN-NEXT:    [[ABS_CMP:%.*]] = fcmp ugt float [[TMP0]], [[TMP1]]
+// FRTRN-NEXT:    br i1 [[ABS_CMP]], label [[ABS_RHSR_GREATER_OR_EQUAL_ABS_RHSI:%.*]], label [[ABS_RHSR_LESS_THAN_ABS_RHSI:%.*]]
+// FRTRN:       abs_rhsr_greater_or_equal_abs_rhsi:
+// FRTRN-NEXT:    [[TMP2:%.*]] = fdiv float [[B_IMAG]], [[B_REAL]]
+// FRTRN-NEXT:    [[TMP3:%.*]] = fmul float [[TMP2]], [[B_IMAG]]
+// FRTRN-NEXT:    [[TMP4:%.*]] = fadd float [[B_REAL]], [[TMP3]]
+// FRTRN-NEXT:    [[TMP5:%.*]] = fmul float [[A_IMAG]], [[TMP2]]
+// FRTRN-NEXT:    [[TMP6:%.*]] = fadd float [[A_REAL]], [[TMP5]]
+// FRTRN-NEXT:    [[TMP7:%.*]] = fdiv float [[TMP6]], [[TMP4]]
+// FRTRN-NEXT:    [[TMP8:%.*]] = fmul float [[A_REAL]], [[TMP2]]
+// FRTRN-NEXT:    [[TMP9:%.*]] = fsub float [[A_IMAG]], [[TMP8]]
+// FRTRN-NEXT:    [[TMP10:%.*]] = fdiv float [[TMP9]], [[TMP4]]
+// FRTRN-NEXT:    br label [[COMPLEX_DIV:%.*]]
+// FRTRN:       abs_rhsr_less_than_abs_rhsi:
+// FRTRN-NEXT:    [[TMP11:%.*]] = fdiv float [[B_REAL]], [[B_IMAG]]
+// FRTRN-NEXT:    [[TMP12:%.*]] = fmul float [[TMP11]], [[B_REAL]]
+// FRTRN-NEXT:    [[TMP13:%.*]] = fadd float [[B_IMAG]], [[TMP12]]
+// FRTRN-NEXT:    [[TMP14:%.*]] = fmul float [[A_REAL]], [[TMP11]]
+// FRTRN-NEXT:    [[TMP15:%.*]] = fadd float [[TMP14]], [[A_IMAG]]
+// FRTRN-NEXT:    [[TMP16:%.*]] = fdiv float [[TMP15]], [[TMP13]]
+// FRTRN-NEXT:    [[TMP17:%.*]] = fmul float [[A_IMAG]], [[TMP11]]
+// FRTRN-NEXT:    [[TMP18:%.*]] = fsub float [[TMP17]], [[A_REAL]]
+// FRTRN-NEXT:    [[TMP19:%.*]] = fdiv float [[TMP18]], [[TMP13]]
+// FRTRN-NEXT:    br label [[COMPLEX_DIV]]
+// FRTRN:       complex_div:
+// FRTRN-NEXT:    [[TMP20:%.*]] = phi float [ [[TMP7]], [[ABS_RHSR_GREATER_OR_EQUAL_ABS_RHSI]] ], [ [[TMP16]], [[ABS_RHSR_LESS_THAN_ABS_RHSI]] ]
+// FRTRN-NEXT:    [[TMP21:%.*]] = phi float [ [[TMP10]], [[ABS_RHSR_GREATER_OR_EQUAL_ABS_RHSI]] ], [ [[TMP19]], [[ABS_RHSR_LESS_THAN_ABS_RHSI]] ]
+// FRTRN-NEXT:    [[RETVAL_REALP:%.*]] = getelementptr inbounds { float, float }, ptr [[RETVAL]], i32 0, i32 0
+// FRTRN-NEXT:    [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { float, float }, ptr [[RETVAL]], i32 0, i32 1
+// FRTRN-NEXT:    store float [[TMP20]], ptr [[RETVAL_REALP]], align 4
+// FRTRN-NEXT:    store float [[TMP21]], ptr [[RETVAL_IMAGP]], align 4
+// FRTRN-NEXT:    [[TMP22:%.*]] = load <2 x float>, ptr [[RETVAL]], align 4
+// FRTRN-NEXT:    ret <2 x float> [[TMP22]]
+//
+_Complex float div(_Complex float a, _Complex float b) {
+  return a / b;
+}

diff  --git a/clang/test/Driver/range.c b/clang/test/Driver/range.c
index 8d456a997d6967..045d9c7d3d802a 100644
--- a/clang/test/Driver/range.c
+++ b/clang/test/Driver/range.c
@@ -6,6 +6,9 @@
 // RUN: %clang -### -target x86_64 -fno-cx-limited-range -c %s 2>&1 \
 // RUN:   | FileCheck %s
 
+// RUN: %clang -### -target x86_64 -fcx-limited-range -fno-cx-limited-range \
+// RUN: -c %s 2>&1 | FileCheck --check-prefix=FULL %s
+
 // RUN: %clang -### -target x86_64 -fcx-fortran-rules -c %s 2>&1 \
 // RUN:   | FileCheck --check-prefix=FRTRN %s
 
@@ -29,7 +32,11 @@
 // RUN: %clang -### -target x86_64 -fcx-limited-range -ffast-math -c %s 2>&1 \
 // RUN:   | FileCheck --check-prefix=LMTD %s
 
+// RUN: %clang -### -target x86_64 -ffast-math -fno-cx-limited-range -c %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=FULL %s
+
 // LMTD: -complex-range=limited
+// FULL: -complex-range=full
 // LMTD-NOT: -complex-range=fortran
 // CHECK-NOT: -complex-range=limited
 // FRTRN: -complex-range=fortran


        


More information about the cfe-commits mailing list