[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 25 10:51:54 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/5] 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/5] 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 04f29a432564f4a111856e482c4a4b72ae0e46b4 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 3/5] 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 a871bea6cf14cd4..8001b6aac931ecf 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1003,9 +1003,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 40d66713d34040e..196c8f7ce8d0730 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -2814,6 +2814,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 82d5ec4efb0e4c9bfc92402ba9ccc34c2b18d8f8 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 4/5] 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 8001b6aac931ecf..5efce223d4b8ea7 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1010,6 +1010,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 196c8f7ce8d0730..495ccc82e8c45c5 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -2807,15 +2807,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();
@@ -2823,6 +2822,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;
@@ -3244,6 +3265,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 fb289055f31918e4e83152888846db2bcdbb3e0b 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 5/5] 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;
}
More information about the cfe-commits
mailing list