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.ammarguel...@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.ammarguel...@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.ammarguel...@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.ammarguel...@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.ammarguel...@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; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits