diff --git a/clang/include/clang/Driver/CommonArgs.h b/clang/include/clang/Driver/CommonArgs.h index 26aa3ccf84786..49c7149380fba 100644 --- a/clang/include/clang/Driver/CommonArgs.h +++ b/clang/include/clang/Driver/CommonArgs.h @@ -283,6 +283,12 @@ StringRef parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags, StringRef parseMRecipOption(clang::DiagnosticsEngine &Diags, const llvm::opt::ArgList &Args); +// Convert ComplexRangeKind to a string that can be passed as a frontend option. +std::string complexRangeKindToStr(LangOptions::ComplexRangeKind Range); + +// Render a frontend option corresponding to ComplexRangeKind. +std::string renderComplexRangeOption(LangOptions::ComplexRangeKind Range); + } // end namespace tools } // end namespace driver } // end namespace clang diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 9911d752966e3..a1350e69a202e 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1023,12 +1023,13 @@ defm offload_uniform_block : BoolFOption<"offload-uniform-block", BothFlags<[], [ClangOption], " that kernels are launched with uniform block sizes (default true for CUDA/HIP and false otherwise)">>; def fcomplex_arithmetic_EQ : Joined<["-"], "fcomplex-arithmetic=">, Group, - Visibility<[ClangOption, CC1Option]>, + Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>, Values<"full,improved,promoted,basic">, NormalizedValuesScope<"LangOptions">, - NormalizedValues<["CX_Full", "CX_Improved", "CX_Promoted", "CX_Basic"]>; + NormalizedValues<["CX_Full", "CX_Improved", "CX_Promoted", "CX_Basic"]>, + HelpText<"Controls the calculation methods of complex number multiplication and division.">; def complex_range_EQ : Joined<["-"], "complex-range=">, Group, - Visibility<[CC1Option]>, + Visibility<[CC1Option, FC1Option]>, Values<"full,improved,promoted,basic">, NormalizedValuesScope<"LangOptions">, NormalizedValues<["CX_Full", "CX_Improved", "CX_Promoted", "CX_Basic"]>, MarshallingInfoEnum, "CX_Full">; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index fea4ee909ff46..df80565867f48 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -2740,29 +2740,10 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, } } -static std::string ComplexRangeKindToStr(LangOptions::ComplexRangeKind Range) { - switch (Range) { - case LangOptions::ComplexRangeKind::CX_Full: - return "full"; - break; - case LangOptions::ComplexRangeKind::CX_Basic: - return "basic"; - break; - case LangOptions::ComplexRangeKind::CX_Improved: - return "improved"; - break; - case LangOptions::ComplexRangeKind::CX_Promoted: - return "promoted"; - break; - default: - return ""; - } -} - static std::string ComplexArithmeticStr(LangOptions::ComplexRangeKind Range) { return (Range == LangOptions::ComplexRangeKind::CX_None) ? "" - : "-fcomplex-arithmetic=" + ComplexRangeKindToStr(Range); + : "-fcomplex-arithmetic=" + complexRangeKindToStr(Range); } static void EmitComplexRangeDiag(const Driver &D, std::string str1, @@ -2772,14 +2753,6 @@ static void EmitComplexRangeDiag(const Driver &D, std::string str1, } } -static std::string -RenderComplexRangeOption(LangOptions::ComplexRangeKind Range) { - std::string ComplexRangeStr = ComplexRangeKindToStr(Range); - if (!ComplexRangeStr.empty()) - return "-complex-range=" + ComplexRangeStr; - return ComplexRangeStr; -} - static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, bool OFastEnabled, const ArgList &Args, ArgStringList &CmdArgs, @@ -2912,7 +2885,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, case options::OPT_fcx_limited_range: if (GccRangeComplexOption.empty()) { if (Range != LangOptions::ComplexRangeKind::CX_Basic) - EmitComplexRangeDiag(D, RenderComplexRangeOption(Range), + EmitComplexRangeDiag(D, renderComplexRangeOption(Range), "-fcx-limited-range"); } else { if (GccRangeComplexOption != "-fno-cx-limited-range") @@ -2924,7 +2897,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, break; case options::OPT_fno_cx_limited_range: if (GccRangeComplexOption.empty()) { - EmitComplexRangeDiag(D, RenderComplexRangeOption(Range), + EmitComplexRangeDiag(D, renderComplexRangeOption(Range), "-fno-cx-limited-range"); } else { if (GccRangeComplexOption != "-fcx-limited-range" && @@ -2938,7 +2911,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, break; case options::OPT_fcx_fortran_rules: if (GccRangeComplexOption.empty()) - EmitComplexRangeDiag(D, RenderComplexRangeOption(Range), + EmitComplexRangeDiag(D, renderComplexRangeOption(Range), "-fcx-fortran-rules"); else EmitComplexRangeDiag(D, GccRangeComplexOption, "-fcx-fortran-rules"); @@ -2948,7 +2921,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, break; case options::OPT_fno_cx_fortran_rules: if (GccRangeComplexOption.empty()) { - EmitComplexRangeDiag(D, RenderComplexRangeOption(Range), + EmitComplexRangeDiag(D, renderComplexRangeOption(Range), "-fno-cx-fortran-rules"); } else { if (GccRangeComplexOption != "-fno-cx-limited-range") @@ -3416,12 +3389,12 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, CmdArgs.push_back("-fno-strict-float-cast-overflow"); if (Range != LangOptions::ComplexRangeKind::CX_None) - ComplexRangeStr = RenderComplexRangeOption(Range); + ComplexRangeStr = renderComplexRangeOption(Range); if (!ComplexRangeStr.empty()) { CmdArgs.push_back(Args.MakeArgString(ComplexRangeStr)); if (Args.hasArg(options::OPT_fcomplex_arithmetic_EQ)) CmdArgs.push_back(Args.MakeArgString("-fcomplex-arithmetic=" + - ComplexRangeKindToStr(Range))); + complexRangeKindToStr(Range))); } if (Args.hasArg(options::OPT_fcx_limited_range)) CmdArgs.push_back("-fcx-limited-range"); diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 070901f037823..b5543a7eb738d 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -3409,3 +3409,30 @@ StringRef tools::parseMRecipOption(clang::DiagnosticsEngine &Diags, return Out; } + +std::string tools::complexRangeKindToStr(LangOptions::ComplexRangeKind Range) { + switch (Range) { + case LangOptions::ComplexRangeKind::CX_Full: + return "full"; + break; + case LangOptions::ComplexRangeKind::CX_Basic: + return "basic"; + break; + case LangOptions::ComplexRangeKind::CX_Improved: + return "improved"; + break; + case LangOptions::ComplexRangeKind::CX_Promoted: + return "promoted"; + break; + default: + return ""; + } +} + +std::string +tools::renderComplexRangeOption(LangOptionsBase::ComplexRangeKind Range) { + std::string ComplexRangeStr = complexRangeKindToStr(Range); + if (!ComplexRangeStr.empty()) + return "-complex-range=" + ComplexRangeStr; + return ComplexRangeStr; +} diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index e4e321ba1e195..3c73f73ac9acf 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -605,6 +605,8 @@ static void addFloatingPointOptions(const Driver &D, const ArgList &Args, bool AssociativeMath = false; bool ReciprocalMath = false; + LangOptions::ComplexRangeKind Range = LangOptions::ComplexRangeKind::CX_None; + if (const Arg *A = Args.getLastArg(options::OPT_ffp_contract)) { const StringRef Val = A->getValue(); if (Val == "fast" || Val == "off") { @@ -629,6 +631,20 @@ static void addFloatingPointOptions(const Driver &D, const ArgList &Args, default: continue; + case options::OPT_fcomplex_arithmetic_EQ: { + StringRef Val = A->getValue(); + if (Val == "full") + Range = LangOptions::ComplexRangeKind::CX_Full; + else if (Val == "improved") + Range = LangOptions::ComplexRangeKind::CX_Improved; + else if (Val == "basic") + Range = LangOptions::ComplexRangeKind::CX_Basic; + else { + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Val; + } + break; + } case options::OPT_fhonor_infinities: HonorINFs = true; break; @@ -699,6 +715,13 @@ static void addFloatingPointOptions(const Driver &D, const ArgList &Args, if (!Recip.empty()) CmdArgs.push_back(Args.MakeArgString("-mrecip=" + Recip)); + if (Range != LangOptions::ComplexRangeKind::CX_None) { + std::string ComplexRangeStr = renderComplexRangeOption(Range); + CmdArgs.push_back(Args.MakeArgString(ComplexRangeStr)); + CmdArgs.push_back(Args.MakeArgString("-fcomplex-arithmetic=" + + complexRangeKindToStr(Range))); + } + if (!HonorINFs && !HonorNaNs && AssociativeMath && ReciprocalMath && ApproxFunc && !SignedZeros && (FPContract == "fast" || FPContract.empty())) { diff --git a/flang/docs/ComplexOperations.md b/flang/docs/ComplexOperations.md index 03566035c28a3..3ebeea5e0a540 100644 --- a/flang/docs/ComplexOperations.md +++ b/flang/docs/ComplexOperations.md @@ -74,4 +74,26 @@ The ComplexToStandard dialect does still call into libm for some floating point math operations, however these don't have the same ABI issues as the complex libm functions. +The flang driver option `-fcomplex-arithmetic=` allows you to select whether +complex number division is lowered to function calls or to the `complex.div` +operation in the MLIR complex dialect. To avoid the ABI issues mentioned above, +the choice of function calls or the `complex.div` operation is made during the +lowering phase. The behavior of this option is as follows: + +- `basic`: Lowers to `complex.div` and is converted to algebraic formulas. No +special handling to avoid overflow. NaN and infinite values are not handled. +- `improved`: Lowers to `complex.div` and is converted to Smith's algorithm. See +SMITH, R. L. Algorithm 116: Complex division. Commun. ACM 5, 8 (1962). This +value offers improved handling for overflow in intermediate calculations, but +overflow may occur. NaN and infinite values are handled. +- `full`: Lowers to a call to runtime library functions. Overflow and non-finite +values are handled by the library implementation. This is the default value. + +While [the same option in clang][2] allows specifying `promoted`, this is not +implemented in Flang. Also, in the case of `improved`, clang does not handle NaN +and infinite values, but Flang does. These behavioral differences arise because +the transformation of complex division calculations depends on the implementation +of ComplexToStandard, which may change in the future. + [1]: https://discourse.llvm.org/t/rfc-change-lowering-of-fortran-math-intrinsics/63971 +[2]: https://clang.llvm.org/docs/UsersManual.html#cmdoption-fcomplex-arithmetic diff --git a/flang/include/flang/Frontend/CodeGenOptions.def b/flang/include/flang/Frontend/CodeGenOptions.def index ae12aec518108..cdeea93c9aecb 100644 --- a/flang/include/flang/Frontend/CodeGenOptions.def +++ b/flang/include/flang/Frontend/CodeGenOptions.def @@ -52,6 +52,7 @@ ENUM_CODEGENOPT(RelocationModel, llvm::Reloc::Model, 3, llvm::Reloc::PIC_) ///< ENUM_CODEGENOPT(DebugInfo, llvm::codegenoptions::DebugInfoKind, 4, llvm::codegenoptions::NoDebugInfo) ///< Level of debug info to generate ENUM_CODEGENOPT(VecLib, llvm::driver::VectorLibrary, 4, llvm::driver::VectorLibrary::NoLibrary) ///< Vector functions library to use ENUM_CODEGENOPT(FramePointer, llvm::FramePointerKind, 2, llvm::FramePointerKind::None) ///< Enable the usage of frame pointers +ENUM_CODEGENOPT(ComplexRange, ComplexRangeKind, 3, ComplexRangeKind::CX_Full) ///< Method for calculating complex number division ENUM_CODEGENOPT(DoConcurrentMapping, DoConcurrentMappingKind, 2, DoConcurrentMappingKind::DCMK_None) ///< Map `do concurrent` to OpenMP diff --git a/flang/include/flang/Frontend/CodeGenOptions.h b/flang/include/flang/Frontend/CodeGenOptions.h index bad17c8309eb8..df6063cc90340 100644 --- a/flang/include/flang/Frontend/CodeGenOptions.h +++ b/flang/include/flang/Frontend/CodeGenOptions.h @@ -192,6 +192,31 @@ class CodeGenOptions : public CodeGenOptionsBase { return getProfileUse() == llvm::driver::ProfileCSIRInstr; } + /// Controls the various implementations for complex division. + enum ComplexRangeKind { + /// Implementation of complex division using a call to runtime library + /// functions. Overflow and non-finite values are handled by the library + /// implementation. This is the default value. + CX_Full, + + /// Implementation of complex division offering an improved handling + /// for overflow in intermediate calculations. Overflow and non-finite + /// values are handled by MLIR's implementation of "complex.div", but this + /// may change in the future. + CX_Improved, + + /// Implementation of complex division using algebraic formulas at source + /// precision. No special handling to avoid overflow. NaN and infinite + /// values are not handled. + CX_Basic, + + /// No range rule is enabled. + CX_None + + /// TODO: Implemention of other values as needed. In Clang, "CX_Promoted" + /// is implemented. (See clang/Basic/LangOptions.h) + }; + // Define accessors/mutators for code generation options of enumeration type. #define CODEGENOPT(Name, Bits, Default) #define ENUM_CODEGENOPT(Name, Type, Bits, Default) \ diff --git a/flang/include/flang/Lower/LoweringOptions.def b/flang/include/flang/Lower/LoweringOptions.def index 3263ab129d076..8135704971aa4 100644 --- a/flang/include/flang/Lower/LoweringOptions.def +++ b/flang/include/flang/Lower/LoweringOptions.def @@ -70,5 +70,9 @@ ENUM_LOWERINGOPT(CUDARuntimeCheck, unsigned, 1, 0) /// derived types defined in other compilation units. ENUM_LOWERINGOPT(SkipExternalRttiDefinition, unsigned, 1, 0) +/// If true, convert complex number division to runtime on the frontend. +/// If false, lower to the complex dialect of MLIR. +/// On by default. +ENUM_LOWERINGOPT(ComplexDivisionToRuntime, unsigned, 1, 1) #undef LOWERINGOPT #undef ENUM_LOWERINGOPT diff --git a/flang/include/flang/Optimizer/Builder/FIRBuilder.h b/flang/include/flang/Optimizer/Builder/FIRBuilder.h index e1eaab3346901..004ad00b6f470 100644 --- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h +++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h @@ -609,6 +609,17 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener { return integerOverflowFlags; } + /// Set ComplexDivisionToRuntimeFlag value. If set to true, complex number + /// division is lowered to a runtime function by this builder. + void setComplexDivisionToRuntimeFlag(bool flag) { + complexDivisionToRuntimeFlag = flag; + } + + /// Get current ComplexDivisionToRuntimeFlag value. + bool getComplexDivisionToRuntimeFlag() const { + return complexDivisionToRuntimeFlag; + } + /// Dump the current function. (debug) LLVM_DUMP_METHOD void dumpFunc(); @@ -673,6 +684,10 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener { /// mlir::arith::IntegerOverflowFlagsAttr. mlir::arith::IntegerOverflowFlags integerOverflowFlags{}; + /// Flag to control whether complex number division is lowered to a runtime + /// function or to the MLIR complex dialect. + bool complexDivisionToRuntimeFlag = true; + /// fir::GlobalOp and func::FuncOp symbol table to speed-up /// lookups. mlir::SymbolTable *symbolTable = nullptr; diff --git a/flang/include/flang/Optimizer/CodeGen/CodeGen.h b/flang/include/flang/Optimizer/CodeGen/CodeGen.h index 93f07d8d5d4d9..e9a07a8dde5cd 100644 --- a/flang/include/flang/Optimizer/CodeGen/CodeGen.h +++ b/flang/include/flang/Optimizer/CodeGen/CodeGen.h @@ -9,6 +9,7 @@ #ifndef FORTRAN_OPTIMIZER_CODEGEN_CODEGEN_H #define FORTRAN_OPTIMIZER_CODEGEN_CODEGEN_H +#include "flang/Frontend/CodeGenOptions.h" #include "mlir/IR/BuiltinOps.h" #include "mlir/Pass/Pass.h" #include "mlir/Pass/PassRegistry.h" @@ -58,6 +59,11 @@ struct FIRToLLVMPassOptions { // the name of the global variable corresponding to a derived // type's descriptor. bool typeDescriptorsRenamedForAssembly = false; + + // Specify the calculation method for complex number division used by the + // Conversion pass of the MLIR complex dialect. + Fortran::frontend::CodeGenOptions::ComplexRangeKind ComplexRange = + Fortran::frontend::CodeGenOptions::ComplexRangeKind::CX_Full; }; /// Convert FIR to the LLVM IR dialect with default options. diff --git a/flang/include/flang/Tools/CrossToolHelpers.h b/flang/include/flang/Tools/CrossToolHelpers.h index 337685c82af5f..df1da27058552 100644 --- a/flang/include/flang/Tools/CrossToolHelpers.h +++ b/flang/include/flang/Tools/CrossToolHelpers.h @@ -140,6 +140,9 @@ struct MLIRToLLVMPassPipelineConfig : public FlangEPCallBacks { std::string InstrumentFunctionExit = ""; ///< Name of the instrument-function that is called on each ///< function-exit + Fortran::frontend::CodeGenOptions::ComplexRangeKind ComplexRange = + Fortran::frontend::CodeGenOptions::ComplexRangeKind:: + CX_Full; ///< Method for calculating complex number division }; struct OffloadModuleOpts { diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index 30d81f3daa969..910e0f5dcebd5 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -484,6 +484,21 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts, } parseDoConcurrentMapping(opts, args, diags); + + if (const llvm::opt::Arg *arg = + args.getLastArg(clang::driver::options::OPT_complex_range_EQ)) { + llvm::StringRef argValue = llvm::StringRef(arg->getValue()); + if (argValue == "full") { + opts.setComplexRange(CodeGenOptions::ComplexRangeKind::CX_Full); + } else if (argValue == "improved") { + opts.setComplexRange(CodeGenOptions::ComplexRangeKind::CX_Improved); + } else if (argValue == "basic") { + opts.setComplexRange(CodeGenOptions::ComplexRangeKind::CX_Basic); + } else { + diags.Report(clang::diag::err_drv_invalid_value) + << arg->getAsString(args) << arg->getValue(); + } + } } /// Parses all target input arguments and populates the target @@ -1811,4 +1826,10 @@ void CompilerInvocation::setLoweringOptions() { .setNoSignedZeros(langOptions.NoSignedZeros) .setAssociativeMath(langOptions.AssociativeMath) .setReciprocalMath(langOptions.ReciprocalMath); + + if (codegenOpts.getComplexRange() == + CodeGenOptions::ComplexRangeKind::CX_Improved || + codegenOpts.getComplexRange() == + CodeGenOptions::ComplexRangeKind::CX_Basic) + loweringOpts.setComplexDivisionToRuntime(false); } diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp index bf15def3f3b2e..b5f4f9421f633 100644 --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -750,6 +750,8 @@ void CodeGenAction::generateLLVMIR() { if (ci.getInvocation().getLoweringOpts().getIntegerWrapAround()) config.NSWOnLoopVarInc = false; + config.ComplexRange = opts.getComplexRange(); + // Create the pass pipeline fir::createMLIRToLLVMPassPipeline(pm, config, getCurrentFile()); (void)mlir::applyPassManagerCLOptions(pm); diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index ff35840a6668c..7e95c640e73b0 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -5746,6 +5746,8 @@ class FirConverter : public Fortran::lower::AbstractConverter { builder = new fir::FirOpBuilder(func, bridge.getKindMap(), &mlirSymbolTable); assert(builder && "FirOpBuilder did not instantiate"); + builder->setComplexDivisionToRuntimeFlag( + bridge.getLoweringOptions().getComplexDivisionToRuntime()); builder->setFastMathFlags(bridge.getLoweringOptions().getMathOptions()); builder->setInsertionPointToStart(&func.front()); if (funit.parent.isA()) { diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp index df8dfbc72c030..9689f920840fb 100644 --- a/flang/lib/Lower/ConvertExprToHLFIR.cpp +++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp @@ -1066,8 +1066,17 @@ struct BinaryOp(loc, lhs, rhs)}; + } } }; diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp index 2b018912b40e4..4cf533f195e69 100644 --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -4119,7 +4119,20 @@ class FIRToLLVMLowering mathToFuncsOptions.minWidthOfFPowIExponent = 33; mathConvertionPM.addPass( mlir::createConvertMathToFuncs(mathToFuncsOptions)); - mathConvertionPM.addPass(mlir::createConvertComplexToStandardPass()); + + mlir::ConvertComplexToStandardPassOptions complexToStandardOptions{}; + if (options.ComplexRange == + Fortran::frontend::CodeGenOptions::ComplexRangeKind::CX_Basic) { + complexToStandardOptions.complexRange = + mlir::complex::ComplexRangeFlags::basic; + } else if (options.ComplexRange == Fortran::frontend::CodeGenOptions:: + ComplexRangeKind::CX_Improved) { + complexToStandardOptions.complexRange = + mlir::complex::ComplexRangeFlags::improved; + } + mathConvertionPM.addPass( + mlir::createConvertComplexToStandardPass(complexToStandardOptions)); + // Convert Math dialect operations into LLVM dialect operations. // There is no way to prefer MathToLLVM patterns over MathToLibm // patterns (applied below), so we have to run MathToLLVM conversion here. diff --git a/flang/lib/Optimizer/Passes/Pipelines.cpp b/flang/lib/Optimizer/Passes/Pipelines.cpp index 42d9e7ba2418f..d940934f9f6ad 100644 --- a/flang/lib/Optimizer/Passes/Pipelines.cpp +++ b/flang/lib/Optimizer/Passes/Pipelines.cpp @@ -113,6 +113,7 @@ void addFIRToLLVMPass(mlir::PassManager &pm, options.forceUnifiedTBAATree = useOldAliasTags; options.typeDescriptorsRenamedForAssembly = !disableCompilerGeneratedNamesConversion; + options.ComplexRange = config.ComplexRange; addPassConditionally(pm, disableFirToLlvmIr, [&]() { return fir::createFIRToLLVMPass(options); }); // The dialect conversion framework may leave dead unrealized_conversion_cast diff --git a/flang/test/Driver/complex-range.f90 b/flang/test/Driver/complex-range.f90 new file mode 100644 index 0000000000000..e5a1ba9068ac9 --- /dev/null +++ b/flang/test/Driver/complex-range.f90 @@ -0,0 +1,23 @@ +! Test range options for complex multiplication and division. + +! RUN: %flang -### -c %s 2>&1 \ +! RUN: | FileCheck %s --check-prefix=RANGE + +! RUN: %flang -### -fcomplex-arithmetic=full -c %s 2>&1 \ +! RUN: | FileCheck %s --check-prefix=FULL + +! RUN: %flang -### -fcomplex-arithmetic=improved -c %s 2>&1 \ +! RUN: | FileCheck %s --check-prefix=IMPRVD + +! RUN: %flang -### -fcomplex-arithmetic=basic -c %s 2>&1 \ +! RUN: | FileCheck %s --check-prefix=BASIC + +! RUN: not %flang -### -fcomplex-arithmetic=foo -c %s 2>&1 \ +! RUN: | FileCheck %s --check-prefix=ERR + +! RANGE-NOT: -complex-range= +! FULL: -complex-range=full +! IMPRVD: -complex-range=improved +! BASIC: -complex-range=basic + +! ERR: error: unsupported argument 'foo' to option '-fcomplex-arithmetic=' diff --git a/flang/test/Integration/complex-div-to-llvm-kind10.f90 b/flang/test/Integration/complex-div-to-llvm-kind10.f90 new file mode 100644 index 0000000000000..04d1f7ed9b024 --- /dev/null +++ b/flang/test/Integration/complex-div-to-llvm-kind10.f90 @@ -0,0 +1,131 @@ +! Test lowering complex division to llvm ir according to options + +! REQUIRES: target=x86_64{{.*}} +! RUN: %flang -fcomplex-arithmetic=improved -S -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,IMPRVD +! RUN: %flang -fcomplex-arithmetic=basic -S -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,BASIC + + +! CHECK-LABEL: @div_test_extended +! CHECK-SAME: ptr %[[RET:.*]], ptr %[[LHS:.*]], ptr %[[RHS:.*]]) +! CHECK: %[[LOAD_LHS:.*]] = load { x86_fp80, x86_fp80 }, ptr %[[LHS]], align 16 +! CHECK: %[[LOAD_RHS:.*]] = load { x86_fp80, x86_fp80 }, ptr %[[RHS]], align 16 +! CHECK: %[[LHS_REAL:.*]] = extractvalue { x86_fp80, x86_fp80 } %[[LOAD_LHS]], 0 +! CHECK: %[[LHS_IMAG:.*]] = extractvalue { x86_fp80, x86_fp80 } %[[LOAD_LHS]], 1 +! CHECK: %[[RHS_REAL:.*]] = extractvalue { x86_fp80, x86_fp80 } %[[LOAD_RHS]], 0 +! CHECK: %[[RHS_IMAG:.*]] = extractvalue { x86_fp80, x86_fp80 } %[[LOAD_RHS]], 1 + +! IMPRVD: %[[RHS_REAL_IMAG_RATIO:.*]] = fdiv contract x86_fp80 %[[RHS_REAL]], %[[RHS_IMAG]] +! IMPRVD: %[[RHS_REAL_TIMES_RHS_REAL_IMAG_RATIO:.*]] = fmul contract x86_fp80 %[[RHS_REAL_IMAG_RATIO]], %[[RHS_REAL]] +! IMPRVD: %[[RHS_REAL_IMAG_DENOM:.*]] = fadd contract x86_fp80 %[[RHS_IMAG]], %[[RHS_REAL_TIMES_RHS_REAL_IMAG_RATIO]] +! IMPRVD: %[[LHS_REAL_TIMES_RHS_REAL_IMAG_RATIO:.*]] = fmul contract x86_fp80 %[[LHS_REAL]], %[[RHS_REAL_IMAG_RATIO]] +! IMPRVD: %[[REAL_NUMERATOR_1:.*]] = fadd contract x86_fp80 %[[LHS_REAL_TIMES_RHS_REAL_IMAG_RATIO]], %[[LHS_IMAG]] +! IMPRVD: %[[RESULT_REAL_1:.*]] = fdiv contract x86_fp80 %[[REAL_NUMERATOR_1]], %[[RHS_REAL_IMAG_DENOM]] +! IMPRVD: %[[LHS_IMAG_TIMES_RHS_REAL_IMAG_RATIO:.*]] = fmul contract x86_fp80 %[[LHS_IMAG]], %[[RHS_REAL_IMAG_RATIO]] +! IMPRVD: %[[IMAG_NUMERATOR_1:.*]] = fsub contract x86_fp80 %[[LHS_IMAG_TIMES_RHS_REAL_IMAG_RATIO]], %[[LHS_REAL]] +! IMPRVD: %[[RESULT_IMAG_1:.*]] = fdiv contract x86_fp80 %[[IMAG_NUMERATOR_1]], %[[RHS_REAL_IMAG_DENOM]] +! IMPRVD: %[[RHS_IMAG_REAL_RATIO:.*]] = fdiv contract x86_fp80 %[[RHS_IMAG]], %[[RHS_REAL]] +! IMPRVD: %[[RHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO:.*]] = fmul contract x86_fp80 %[[RHS_IMAG_REAL_RATIO]], %[[RHS_IMAG]] +! IMPRVD: %[[RHS_IMAG_REAL_DENOM:.*]] = fadd contract x86_fp80 %[[RHS_REAL]], %[[RHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[LHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO:.*]] = fmul contract x86_fp80 %[[LHS_IMAG]], %[[RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[REAL_NUMERATOR_2:.*]] = fadd contract x86_fp80 %[[LHS_REAL]], %[[LHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[RESULT_REAL_2:.*]] = fdiv contract x86_fp80 %[[REAL_NUMERATOR_2]], %[[RHS_IMAG_REAL_DENOM]] +! IMPRVD: %[[LHS_REAL_TIMES_RHS_IMAG_REAL_RATIO:.*]] = fmul contract x86_fp80 %[[LHS_REAL]], %[[RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[IMAG_NUMERATOR_2:.*]] = fsub contract x86_fp80 %[[LHS_IMAG]], %[[LHS_REAL_TIMES_RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[RESULT_IMAG_2:.*]] = fdiv contract x86_fp80 %[[IMAG_NUMERATOR_2]], %[[RHS_IMAG_REAL_DENOM]] + +! Case 1. Zero denominator, numerator contains at most one NaN value. +! IMPRVD: %[[RHS_REAL_ABS:.*]] = call contract x86_fp80 @llvm.fabs.f80(x86_fp80 %[[RHS_REAL]]) +! IMPRVD: %[[RHS_REAL_ABS_IS_ZERO:.*]] = fcmp oeq x86_fp80 %[[RHS_REAL_ABS]], 0xK00000000000000000000 +! IMPRVD: %[[RHS_IMAG_ABS:.*]] = call contract x86_fp80 @llvm.fabs.f80(x86_fp80 %[[RHS_IMAG]]) +! IMPRVD: %[[RHS_IMAG_ABS_IS_ZERO:.*]] = fcmp oeq x86_fp80 %[[RHS_IMAG_ABS]], 0xK00000000000000000000 +! IMPRVD: %[[LHS_REAL_IS_NOT_NAN:.*]] = fcmp ord x86_fp80 %[[LHS_REAL]], 0xK00000000000000000000 +! IMPRVD: %[[LHS_IMAG_IS_NOT_NAN:.*]] = fcmp ord x86_fp80 %[[LHS_IMAG]], 0xK00000000000000000000 +! IMPRVD: %[[LHS_CONTAINS_NOT_NAN_VALUE:.*]] = or i1 %[[LHS_REAL_IS_NOT_NAN]], %[[LHS_IMAG_IS_NOT_NAN]] +! IMPRVD: %[[RHS_IS_ZERO:.*]] = and i1 %[[RHS_REAL_ABS_IS_ZERO]], %[[RHS_IMAG_ABS_IS_ZERO]] +! IMPRVD: %[[RESULT_IS_INFINITY:.*]] = and i1 %[[LHS_CONTAINS_NOT_NAN_VALUE]], %[[RHS_IS_ZERO]] +! IMPRVD: %[[INF_WITH_SIGN_OF_RHS_REAL:.*]] = call x86_fp80 @llvm.copysign.f80(x86_fp80 0xK7FFF8000000000000000, x86_fp80 %[[RHS_REAL]]) +! IMPRVD: %[[INFINITY_RESULT_REAL:.*]] = fmul contract x86_fp80 %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_REAL]] +! IMPRVD: %[[INFINITY_RESULT_IMAG:.*]] = fmul contract x86_fp80 %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_IMAG]] + +! Case 2. Infinite numerator, finite denominator. +! IMPRVD: %[[RHS_REAL_FINITE:.*]] = fcmp one x86_fp80 %[[RHS_REAL_ABS]], 0xK7FFF8000000000000000 +! IMPRVD: %[[RHS_IMAG_FINITE:.*]] = fcmp one x86_fp80 %[[RHS_IMAG_ABS]], 0xK7FFF8000000000000000 +! IMPRVD: %[[RHS_IS_FINITE:.*]] = and i1 %[[RHS_REAL_FINITE]], %[[RHS_IMAG_FINITE]] +! IMPRVD: %[[LHS_REAL_ABS:.*]] = call contract x86_fp80 @llvm.fabs.f80(x86_fp80 %[[LHS_REAL]]) +! IMPRVD: %[[LHS_REAL_INFINITE:.*]] = fcmp oeq x86_fp80 %[[LHS_REAL_ABS]], 0xK7FFF8000000000000000 +! IMPRVD: %[[LHS_IMAG_ABS:.*]] = call contract x86_fp80 @llvm.fabs.f80(x86_fp80 %[[LHS_IMAG]]) +! IMPRVD: %[[LHS_IMAG_INFINITE:.*]] = fcmp oeq x86_fp80 %[[LHS_IMAG_ABS]], 0xK7FFF8000000000000000 +! IMPRVD: %[[LHS_IS_INFINITE:.*]] = or i1 %[[LHS_REAL_INFINITE]], %[[LHS_IMAG_INFINITE]] +! IMPRVD: %[[INF_NUM_FINITE_DENOM:.*]] = and i1 %[[LHS_IS_INFINITE]], %[[RHS_IS_FINITE]] +! IMPRVD: %[[LHS_REAL_IS_INF:.*]] = select i1 %[[LHS_REAL_INFINITE]], x86_fp80 0xK3FFF8000000000000000, x86_fp80 0xK00000000000000000000 +! IMPRVD: %[[LHS_REAL_IS_INF_WITH_SIGN:.*]] = call x86_fp80 @llvm.copysign.f80(x86_fp80 %[[LHS_REAL_IS_INF]], x86_fp80 %[[LHS_REAL]]) +! IMPRVD: %[[LHS_IMAG_IS_INF:.*]] = select i1 %[[LHS_IMAG_INFINITE]], x86_fp80 0xK3FFF8000000000000000, x86_fp80 0xK00000000000000000000 +! IMPRVD: %[[LHS_IMAG_IS_INF_WITH_SIGN:.*]] = call x86_fp80 @llvm.copysign.f80(x86_fp80 %[[LHS_IMAG_IS_INF]], x86_fp80 %[[LHS_IMAG]]) +! IMPRVD: %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_REAL:.*]] = fmul contract x86_fp80 %[[LHS_REAL_IS_INF_WITH_SIGN]], %[[RHS_REAL]] +! IMPRVD: %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_IMAG:.*]] = fmul contract x86_fp80 %[[LHS_IMAG_IS_INF_WITH_SIGN]], %[[RHS_IMAG]] +! IMPRVD: %[[INF_MULTIPLICATOR_1:.*]] = fadd contract x86_fp80 %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_REAL]], %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_IMAG]] +! IMPRVD: %[[RESULT_REAL_3:.*]] = fmul contract x86_fp80 %[[INF_MULTIPLICATOR_1]], 0xK7FFF8000000000000000 +! IMPRVD: %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_IMAG:.*]] = fmul contract x86_fp80 %[[LHS_REAL_IS_INF_WITH_SIGN]], %[[RHS_IMAG]] +! IMPRVD: %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_REAL:.*]] = fmul contract x86_fp80 %[[LHS_IMAG_IS_INF_WITH_SIGN]], %[[RHS_REAL]] +! IMPRVD: %[[INF_MULTIPLICATOR_2:.*]] = fsub contract x86_fp80 %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_REAL]], %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_IMAG]] +! IMPRVD: %[[RESULT_IMAG_3:.*]] = fmul contract x86_fp80 %[[INF_MULTIPLICATOR_2]], 0xK7FFF8000000000000000 + +! Case 3. Finite numerator, infinite denominator. +! IMPRVD: %[[LHS_REAL_FINITE:.*]] = fcmp one x86_fp80 %[[LHS_REAL_ABS]], 0xK7FFF8000000000000000 +! IMPRVD: %[[LHS_IMAG_FINITE:.*]] = fcmp one x86_fp80 %[[LHS_IMAG_ABS]], 0xK7FFF8000000000000000 +! IMPRVD: %[[LHS_IS_FINITE:.*]] = and i1 %[[LHS_REAL_FINITE]], %[[LHS_IMAG_FINITE]] +! IMPRVD: %[[RHS_REAL_INFINITE:.*]] = fcmp oeq x86_fp80 %[[RHS_REAL_ABS]], 0xK7FFF8000000000000000 +! IMPRVD: %[[RHS_IMAG_INFINITE:.*]] = fcmp oeq x86_fp80 %[[RHS_IMAG_ABS]], 0xK7FFF8000000000000000 +! IMPRVD: %[[RHS_IS_INFINITE:.*]] = or i1 %[[RHS_REAL_INFINITE]], %[[RHS_IMAG_INFINITE]] +! IMPRVD: %[[FINITE_NUM_INFINITE_DENOM:.*]] = and i1 %[[LHS_IS_FINITE]], %[[RHS_IS_INFINITE]] +! IMPRVD: %[[RHS_REAL_IS_INF:.*]] = select i1 %[[RHS_REAL_INFINITE]], x86_fp80 0xK3FFF8000000000000000, x86_fp80 0xK00000000000000000000 +! IMPRVD: %[[RHS_REAL_IS_INF_WITH_SIGN:.*]] = call x86_fp80 @llvm.copysign.f80(x86_fp80 %[[RHS_REAL_IS_INF]], x86_fp80 %[[RHS_REAL]]) +! IMPRVD: %[[RHS_IMAG_IS_INF:.*]] = select i1 %[[RHS_IMAG_INFINITE]], x86_fp80 0xK3FFF8000000000000000, x86_fp80 0xK00000000000000000000 +! IMPRVD: %[[RHS_IMAG_IS_INF_WITH_SIGN:.*]] = call x86_fp80 @llvm.copysign.f80(x86_fp80 %[[RHS_IMAG_IS_INF]], x86_fp80 %[[RHS_IMAG]]) +! IMPRVD: %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_REAL:.*]] = fmul contract x86_fp80 %[[LHS_REAL]], %[[RHS_REAL_IS_INF_WITH_SIGN]] +! IMPRVD: %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_IMAG:.*]] = fmul contract x86_fp80 %[[LHS_IMAG]], %[[RHS_IMAG_IS_INF_WITH_SIGN]] +! IMPRVD: %[[ZERO_MULTIPLICATOR_1:.*]] = fadd contract x86_fp80 %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_REAL]], %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_IMAG]] +! IMPRVD: %[[RESULT_REAL_4:.*]] = fmul contract x86_fp80 %[[ZERO_MULTIPLICATOR_1]], 0xK00000000000000000000 +! IMPRVD: %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_IMAG:.*]] = fmul contract x86_fp80 %[[LHS_IMAG]], %[[RHS_REAL_IS_INF_WITH_SIGN]] +! IMPRVD: %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_REAL:.*]] = fmul contract x86_fp80 %[[LHS_REAL]], %[[RHS_IMAG_IS_INF_WITH_SIGN]] +! IMPRVD: %[[ZERO_MULTIPLICATOR_2:.*]] = fsub contract x86_fp80 %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_IMAG]], %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_REAL]] +! IMPRVD: %[[RESULT_IMAG_4:.*]] = fmul contract x86_fp80 %[[ZERO_MULTIPLICATOR_2]], 0xK00000000000000000000 + +! IMPRVD: %[[REAL_ABS_SMALLER_THAN_IMAG_ABS:.*]] = fcmp olt x86_fp80 %[[RHS_REAL_ABS]], %[[RHS_IMAG_ABS]] +! IMPRVD: %[[RESULT_REAL:.*]] = select i1 %[[REAL_ABS_SMALLER_THAN_IMAG_ABS]], x86_fp80 %[[RESULT_REAL_1]], x86_fp80 %[[RESULT_REAL_2]] +! IMPRVD: %[[RESULT_IMAG:.*]] = select i1 %[[REAL_ABS_SMALLER_THAN_IMAG_ABS]], x86_fp80 %[[RESULT_IMAG_1]], x86_fp80 %[[RESULT_IMAG_2]] +! IMPRVD: %[[RESULT_REAL_SPECIAL_CASE_3:.*]] = select i1 %[[FINITE_NUM_INFINITE_DENOM]], x86_fp80 %[[RESULT_REAL_4]], x86_fp80 %[[RESULT_REAL]] +! IMPRVD: %[[RESULT_IMAG_SPECIAL_CASE_3:.*]] = select i1 %[[FINITE_NUM_INFINITE_DENOM]], x86_fp80 %[[RESULT_IMAG_4]], x86_fp80 %[[RESULT_IMAG]] +! IMPRVD: %[[RESULT_REAL_SPECIAL_CASE_2:.*]] = select i1 %[[INF_NUM_FINITE_DENOM]], x86_fp80 %[[RESULT_REAL_3]], x86_fp80 %[[RESULT_REAL_SPECIAL_CASE_3]] +! IMPRVD: %[[RESULT_IMAG_SPECIAL_CASE_2:.*]] = select i1 %[[INF_NUM_FINITE_DENOM]], x86_fp80 %[[RESULT_IMAG_3]], x86_fp80 %[[RESULT_IMAG_SPECIAL_CASE_3]] +! IMPRVD: %[[RESULT_REAL_SPECIAL_CASE_1:.*]] = select i1 %[[RESULT_IS_INFINITY]], x86_fp80 %[[INFINITY_RESULT_REAL]], x86_fp80 %[[RESULT_REAL_SPECIAL_CASE_2]] +! IMPRVD: %[[RESULT_IMAG_SPECIAL_CASE_1:.*]] = select i1 %[[RESULT_IS_INFINITY]], x86_fp80 %[[INFINITY_RESULT_IMAG]], x86_fp80 %[[RESULT_IMAG_SPECIAL_CASE_2]] +! IMPRVD: %[[RESULT_REAL_IS_NAN:.*]] = fcmp uno x86_fp80 %[[RESULT_REAL]], 0xK00000000000000000000 +! IMPRVD: %[[RESULT_IMAG_IS_NAN:.*]] = fcmp uno x86_fp80 %[[RESULT_IMAG]], 0xK00000000000000000000 +! IMPRVD: %[[RESULT_IS_NAN:.*]] = and i1 %[[RESULT_REAL_IS_NAN]], %[[RESULT_IMAG_IS_NAN]] +! IMPRVD: %[[RESULT_REAL_WITH_SPECIAL_CASES:.*]] = select i1 %[[RESULT_IS_NAN]], x86_fp80 %[[RESULT_REAL_SPECIAL_CASE_1]], x86_fp80 %[[RESULT_REAL]] +! IMPRVD: %[[RESULT_IMAG_WITH_SPECIAL_CASES:.*]] = select i1 %[[RESULT_IS_NAN]], x86_fp80 %[[RESULT_IMAG_SPECIAL_CASE_1]], x86_fp80 %[[RESULT_IMAG]] +! IMPRVD: %[[RESULT_1:.*]] = insertvalue { x86_fp80, x86_fp80 } poison, x86_fp80 %[[RESULT_REAL_WITH_SPECIAL_CASES]], 0 +! IMPRVD: %[[RESULT_2:.*]] = insertvalue { x86_fp80, x86_fp80 } %[[RESULT_1]], x86_fp80 %[[RESULT_IMAG_WITH_SPECIAL_CASES]], 1 +! IMPRVD: store { x86_fp80, x86_fp80 } %[[RESULT_2]], ptr %[[RET]], align 16 + +! BASIC-DAG: %[[RHS_REAL_SQ:.*]] = fmul contract x86_fp80 %[[RHS_REAL]], %[[RHS_REAL]] +! BASIC-DAG: %[[RHS_IMAG_SQ:.*]] = fmul contract x86_fp80 %[[RHS_IMAG]], %[[RHS_IMAG]] +! BASIC: %[[SQ_NORM:.*]] = fadd contract x86_fp80 %[[RHS_REAL_SQ]], %[[RHS_IMAG_SQ]] +! BASIC-DAG: %[[REAL_TMP_0:.*]] = fmul contract x86_fp80 %[[LHS_REAL]], %[[RHS_REAL]] +! BASIC-DAG: %[[REAL_TMP_1:.*]] = fmul contract x86_fp80 %[[LHS_IMAG]], %[[RHS_IMAG]] +! BASIC: %[[REAL_TMP_2:.*]] = fadd contract x86_fp80 %[[REAL_TMP_0]], %[[REAL_TMP_1]] +! BASIC-DAG: %[[IMAG_TMP_0:.*]] = fmul contract x86_fp80 %[[LHS_IMAG]], %[[RHS_REAL]] +! BASIC-DAG: %[[IMAG_TMP_1:.*]] = fmul contract x86_fp80 %[[LHS_REAL]], %[[RHS_IMAG]] +! BASIC: %[[IMAG_TMP_2:.*]] = fsub contract x86_fp80 %[[IMAG_TMP_0]], %[[IMAG_TMP_1]] +! BASIC: %[[REAL:.*]] = fdiv contract x86_fp80 %[[REAL_TMP_2]], %[[SQ_NORM]] +! BASIC: %[[IMAG:.*]] = fdiv contract x86_fp80 %[[IMAG_TMP_2]], %[[SQ_NORM]] +! BASIC: %[[RESULT_1:.*]] = insertvalue { x86_fp80, x86_fp80 } poison, x86_fp80 %[[REAL]], 0 +! BASIC: %[[RESULT_2:.*]] = insertvalue { x86_fp80, x86_fp80 } %[[RESULT_1]], x86_fp80 %[[IMAG]], 1 +! BASIC: store { x86_fp80, x86_fp80 } %[[RESULT_2]], ptr %[[RET]], align 16 + +! CHECK: ret void +subroutine div_test_extended(a,b,c) + complex(kind=10) :: a, b, c + a = b / c +end subroutine div_test_extended diff --git a/flang/test/Integration/complex-div-to-llvm-kind16.f90 b/flang/test/Integration/complex-div-to-llvm-kind16.f90 new file mode 100644 index 0000000000000..887a7972dc1be --- /dev/null +++ b/flang/test/Integration/complex-div-to-llvm-kind16.f90 @@ -0,0 +1,131 @@ +! Test lowering complex division to llvm ir according to options + +! REQUIRES: flang-supports-f128-math +! RUN: %flang -fcomplex-arithmetic=improved -S -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,IMPRVD +! RUN: %flang -fcomplex-arithmetic=basic -S -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,BASIC + + +! CHECK-LABEL: @div_test_quad +! CHECK-SAME: ptr %[[RET:.*]], ptr %[[LHS:.*]], ptr %[[RHS:.*]]) +! CHECK: %[[LOAD_LHS:.*]] = load { fp128, fp128 }, ptr %[[LHS]], align 16 +! CHECK: %[[LOAD_RHS:.*]] = load { fp128, fp128 }, ptr %[[RHS]], align 16 +! CHECK: %[[LHS_REAL:.*]] = extractvalue { fp128, fp128 } %[[LOAD_LHS]], 0 +! CHECK: %[[LHS_IMAG:.*]] = extractvalue { fp128, fp128 } %[[LOAD_LHS]], 1 +! CHECK: %[[RHS_REAL:.*]] = extractvalue { fp128, fp128 } %[[LOAD_RHS]], 0 +! CHECK: %[[RHS_IMAG:.*]] = extractvalue { fp128, fp128 } %[[LOAD_RHS]], 1 + +! IMPRVD: %[[RHS_REAL_IMAG_RATIO:.*]] = fdiv contract fp128 %[[RHS_REAL]], %[[RHS_IMAG]] +! IMPRVD: %[[RHS_REAL_TIMES_RHS_REAL_IMAG_RATIO:.*]] = fmul contract fp128 %[[RHS_REAL_IMAG_RATIO]], %[[RHS_REAL]] +! IMPRVD: %[[RHS_REAL_IMAG_DENOM:.*]] = fadd contract fp128 %[[RHS_IMAG]], %[[RHS_REAL_TIMES_RHS_REAL_IMAG_RATIO]] +! IMPRVD: %[[LHS_REAL_TIMES_RHS_REAL_IMAG_RATIO:.*]] = fmul contract fp128 %[[LHS_REAL]], %[[RHS_REAL_IMAG_RATIO]] +! IMPRVD: %[[REAL_NUMERATOR_1:.*]] = fadd contract fp128 %[[LHS_REAL_TIMES_RHS_REAL_IMAG_RATIO]], %[[LHS_IMAG]] +! IMPRVD: %[[RESULT_REAL_1:.*]] = fdiv contract fp128 %[[REAL_NUMERATOR_1]], %[[RHS_REAL_IMAG_DENOM]] +! IMPRVD: %[[LHS_IMAG_TIMES_RHS_REAL_IMAG_RATIO:.*]] = fmul contract fp128 %[[LHS_IMAG]], %[[RHS_REAL_IMAG_RATIO]] +! IMPRVD: %[[IMAG_NUMERATOR_1:.*]] = fsub contract fp128 %[[LHS_IMAG_TIMES_RHS_REAL_IMAG_RATIO]], %[[LHS_REAL]] +! IMPRVD: %[[RESULT_IMAG_1:.*]] = fdiv contract fp128 %[[IMAG_NUMERATOR_1]], %[[RHS_REAL_IMAG_DENOM]] +! IMPRVD: %[[RHS_IMAG_REAL_RATIO:.*]] = fdiv contract fp128 %[[RHS_IMAG]], %[[RHS_REAL]] +! IMPRVD: %[[RHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO:.*]] = fmul contract fp128 %[[RHS_IMAG_REAL_RATIO]], %[[RHS_IMAG]] +! IMPRVD: %[[RHS_IMAG_REAL_DENOM:.*]] = fadd contract fp128 %[[RHS_REAL]], %[[RHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[LHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO:.*]] = fmul contract fp128 %[[LHS_IMAG]], %[[RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[REAL_NUMERATOR_2:.*]] = fadd contract fp128 %[[LHS_REAL]], %[[LHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[RESULT_REAL_2:.*]] = fdiv contract fp128 %[[REAL_NUMERATOR_2]], %[[RHS_IMAG_REAL_DENOM]] +! IMPRVD: %[[LHS_REAL_TIMES_RHS_IMAG_REAL_RATIO:.*]] = fmul contract fp128 %[[LHS_REAL]], %[[RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[IMAG_NUMERATOR_2:.*]] = fsub contract fp128 %[[LHS_IMAG]], %[[LHS_REAL_TIMES_RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[RESULT_IMAG_2:.*]] = fdiv contract fp128 %[[IMAG_NUMERATOR_2]], %[[RHS_IMAG_REAL_DENOM]] + +! Case 1. Zero denominator, numerator contains at most one NaN value. +! IMPRVD: %[[RHS_REAL_ABS:.*]] = call contract fp128 @llvm.fabs.f128(fp128 %[[RHS_REAL]]) +! IMPRVD: %[[RHS_REAL_ABS_IS_ZERO:.*]] = fcmp oeq fp128 %[[RHS_REAL_ABS]], 0xL00000000000000000000000000000000 +! IMPRVD: %[[RHS_IMAG_ABS:.*]] = call contract fp128 @llvm.fabs.f128(fp128 %[[RHS_IMAG]]) +! IMPRVD: %[[RHS_IMAG_ABS_IS_ZERO:.*]] = fcmp oeq fp128 %[[RHS_IMAG_ABS]], 0xL00000000000000000000000000000000 +! IMPRVD: %[[LHS_REAL_IS_NOT_NAN:.*]] = fcmp ord fp128 %[[LHS_REAL]], 0xL00000000000000000000000000000000 +! IMPRVD: %[[LHS_IMAG_IS_NOT_NAN:.*]] = fcmp ord fp128 %[[LHS_IMAG]], 0xL00000000000000000000000000000000 +! IMPRVD: %[[LHS_CONTAINS_NOT_NAN_VALUE:.*]] = or i1 %[[LHS_REAL_IS_NOT_NAN]], %[[LHS_IMAG_IS_NOT_NAN]] +! IMPRVD: %[[RHS_IS_ZERO:.*]] = and i1 %[[RHS_REAL_ABS_IS_ZERO]], %[[RHS_IMAG_ABS_IS_ZERO]] +! IMPRVD: %[[RESULT_IS_INFINITY:.*]] = and i1 %[[LHS_CONTAINS_NOT_NAN_VALUE]], %[[RHS_IS_ZERO]] +! IMPRVD: %[[INF_WITH_SIGN_OF_RHS_REAL:.*]] = call fp128 @llvm.copysign.f128(fp128 0xL00000000000000007FFF000000000000, fp128 %[[RHS_REAL]]) +! IMPRVD: %[[INFINITY_RESULT_REAL:.*]] = fmul contract fp128 %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_REAL]] +! IMPRVD: %[[INFINITY_RESULT_IMAG:.*]] = fmul contract fp128 %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_IMAG]] + +! Case 2. Infinite numerator, finite denominator. +! IMPRVD: %[[RHS_REAL_FINITE:.*]] = fcmp one fp128 %[[RHS_REAL_ABS]], 0xL00000000000000007FFF000000000000 +! IMPRVD: %[[RHS_IMAG_FINITE:.*]] = fcmp one fp128 %[[RHS_IMAG_ABS]], 0xL00000000000000007FFF000000000000 +! IMPRVD: %[[RHS_IS_FINITE:.*]] = and i1 %[[RHS_REAL_FINITE]], %[[RHS_IMAG_FINITE]] +! IMPRVD: %[[LHS_REAL_ABS:.*]] = call contract fp128 @llvm.fabs.f128(fp128 %[[LHS_REAL]]) +! IMPRVD: %[[LHS_REAL_INFINITE:.*]] = fcmp oeq fp128 %[[LHS_REAL_ABS]], 0xL00000000000000007FFF000000000000 +! IMPRVD: %[[LHS_IMAG_ABS:.*]] = call contract fp128 @llvm.fabs.f128(fp128 %[[LHS_IMAG]]) +! IMPRVD: %[[LHS_IMAG_INFINITE:.*]] = fcmp oeq fp128 %[[LHS_IMAG_ABS]], 0xL00000000000000007FFF000000000000 +! IMPRVD: %[[LHS_IS_INFINITE:.*]] = or i1 %[[LHS_REAL_INFINITE]], %[[LHS_IMAG_INFINITE]] +! IMPRVD: %[[INF_NUM_FINITE_DENOM:.*]] = and i1 %[[LHS_IS_INFINITE]], %[[RHS_IS_FINITE]] +! IMPRVD: %[[LHS_REAL_IS_INF:.*]] = select i1 %[[LHS_REAL_INFINITE]], fp128 0xL00000000000000003FFF000000000000, fp128 0xL00000000000000000000000000000000 +! IMPRVD: %[[LHS_REAL_IS_INF_WITH_SIGN:.*]] = call fp128 @llvm.copysign.f128(fp128 %[[LHS_REAL_IS_INF]], fp128 %[[LHS_REAL]]) +! IMPRVD: %[[LHS_IMAG_IS_INF:.*]] = select i1 %[[LHS_IMAG_INFINITE]], fp128 0xL00000000000000003FFF000000000000, fp128 0xL00000000000000000000000000000000 +! IMPRVD: %[[LHS_IMAG_IS_INF_WITH_SIGN:.*]] = call fp128 @llvm.copysign.f128(fp128 %[[LHS_IMAG_IS_INF]], fp128 %[[LHS_IMAG]]) +! IMPRVD: %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_REAL:.*]] = fmul contract fp128 %[[LHS_REAL_IS_INF_WITH_SIGN]], %[[RHS_REAL]] +! IMPRVD: %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_IMAG:.*]] = fmul contract fp128 %[[LHS_IMAG_IS_INF_WITH_SIGN]], %[[RHS_IMAG]] +! IMPRVD: %[[INF_MULTIPLICATOR_1:.*]] = fadd contract fp128 %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_REAL]], %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_IMAG]] +! IMPRVD: %[[RESULT_REAL_3:.*]] = fmul contract fp128 %[[INF_MULTIPLICATOR_1]], 0xL00000000000000007FFF000000000000 +! IMPRVD: %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_IMAG:.*]] = fmul contract fp128 %[[LHS_REAL_IS_INF_WITH_SIGN]], %[[RHS_IMAG]] +! IMPRVD: %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_REAL:.*]] = fmul contract fp128 %[[LHS_IMAG_IS_INF_WITH_SIGN]], %[[RHS_REAL]] +! IMPRVD: %[[INF_MULTIPLICATOR_2:.*]] = fsub contract fp128 %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_REAL]], %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_IMAG]] +! IMPRVD: %[[RESULT_IMAG_3:.*]] = fmul contract fp128 %[[INF_MULTIPLICATOR_2]], 0xL00000000000000007FFF000000000000 + +! Case 3. Finite numerator, infinite denominator. +! IMPRVD: %[[LHS_REAL_FINITE:.*]] = fcmp one fp128 %[[LHS_REAL_ABS]], 0xL00000000000000007FFF000000000000 +! IMPRVD: %[[LHS_IMAG_FINITE:.*]] = fcmp one fp128 %[[LHS_IMAG_ABS]], 0xL00000000000000007FFF000000000000 +! IMPRVD: %[[LHS_IS_FINITE:.*]] = and i1 %[[LHS_REAL_FINITE]], %[[LHS_IMAG_FINITE]] +! IMPRVD: %[[RHS_REAL_INFINITE:.*]] = fcmp oeq fp128 %[[RHS_REAL_ABS]], 0xL00000000000000007FFF000000000000 +! IMPRVD: %[[RHS_IMAG_INFINITE:.*]] = fcmp oeq fp128 %[[RHS_IMAG_ABS]], 0xL00000000000000007FFF000000000000 +! IMPRVD: %[[RHS_IS_INFINITE:.*]] = or i1 %[[RHS_REAL_INFINITE]], %[[RHS_IMAG_INFINITE]] +! IMPRVD: %[[FINITE_NUM_INFINITE_DENOM:.*]] = and i1 %[[LHS_IS_FINITE]], %[[RHS_IS_INFINITE]] +! IMPRVD: %[[RHS_REAL_IS_INF:.*]] = select i1 %[[RHS_REAL_INFINITE]], fp128 0xL00000000000000003FFF000000000000, fp128 0xL00000000000000000000000000000000 +! IMPRVD: %[[RHS_REAL_IS_INF_WITH_SIGN:.*]] = call fp128 @llvm.copysign.f128(fp128 %[[RHS_REAL_IS_INF]], fp128 %[[RHS_REAL]]) +! IMPRVD: %[[RHS_IMAG_IS_INF:.*]] = select i1 %[[RHS_IMAG_INFINITE]], fp128 0xL00000000000000003FFF000000000000, fp128 0xL00000000000000000000000000000000 +! IMPRVD: %[[RHS_IMAG_IS_INF_WITH_SIGN:.*]] = call fp128 @llvm.copysign.f128(fp128 %[[RHS_IMAG_IS_INF]], fp128 %[[RHS_IMAG]]) +! IMPRVD: %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_REAL:.*]] = fmul contract fp128 %[[LHS_REAL]], %[[RHS_REAL_IS_INF_WITH_SIGN]] +! IMPRVD: %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_IMAG:.*]] = fmul contract fp128 %[[LHS_IMAG]], %[[RHS_IMAG_IS_INF_WITH_SIGN]] +! IMPRVD: %[[ZERO_MULTIPLICATOR_1:.*]] = fadd contract fp128 %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_REAL]], %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_IMAG]] +! IMPRVD: %[[RESULT_REAL_4:.*]] = fmul contract fp128 %[[ZERO_MULTIPLICATOR_1]], 0xL00000000000000000000000000000000 +! IMPRVD: %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_IMAG:.*]] = fmul contract fp128 %[[LHS_IMAG]], %[[RHS_REAL_IS_INF_WITH_SIGN]] +! IMPRVD: %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_REAL:.*]] = fmul contract fp128 %[[LHS_REAL]], %[[RHS_IMAG_IS_INF_WITH_SIGN]] +! IMPRVD: %[[ZERO_MULTIPLICATOR_2:.*]] = fsub contract fp128 %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_IMAG]], %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_REAL]] +! IMPRVD: %[[RESULT_IMAG_4:.*]] = fmul contract fp128 %[[ZERO_MULTIPLICATOR_2]], 0xL00000000000000000000000000000000 + +! IMPRVD: %[[REAL_ABS_SMALLER_THAN_IMAG_ABS:.*]] = fcmp olt fp128 %[[RHS_REAL_ABS]], %[[RHS_IMAG_ABS]] +! IMPRVD: %[[RESULT_REAL:.*]] = select i1 %[[REAL_ABS_SMALLER_THAN_IMAG_ABS]], fp128 %[[RESULT_REAL_1]], fp128 %[[RESULT_REAL_2]] +! IMPRVD: %[[RESULT_IMAG:.*]] = select i1 %[[REAL_ABS_SMALLER_THAN_IMAG_ABS]], fp128 %[[RESULT_IMAG_1]], fp128 %[[RESULT_IMAG_2]] +! IMPRVD: %[[RESULT_REAL_SPECIAL_CASE_3:.*]] = select i1 %[[FINITE_NUM_INFINITE_DENOM]], fp128 %[[RESULT_REAL_4]], fp128 %[[RESULT_REAL]] +! IMPRVD: %[[RESULT_IMAG_SPECIAL_CASE_3:.*]] = select i1 %[[FINITE_NUM_INFINITE_DENOM]], fp128 %[[RESULT_IMAG_4]], fp128 %[[RESULT_IMAG]] +! IMPRVD: %[[RESULT_REAL_SPECIAL_CASE_2:.*]] = select i1 %[[INF_NUM_FINITE_DENOM]], fp128 %[[RESULT_REAL_3]], fp128 %[[RESULT_REAL_SPECIAL_CASE_3]] +! IMPRVD: %[[RESULT_IMAG_SPECIAL_CASE_2:.*]] = select i1 %[[INF_NUM_FINITE_DENOM]], fp128 %[[RESULT_IMAG_3]], fp128 %[[RESULT_IMAG_SPECIAL_CASE_3]] +! IMPRVD: %[[RESULT_REAL_SPECIAL_CASE_1:.*]] = select i1 %[[RESULT_IS_INFINITY]], fp128 %[[INFINITY_RESULT_REAL]], fp128 %[[RESULT_REAL_SPECIAL_CASE_2]] +! IMPRVD: %[[RESULT_IMAG_SPECIAL_CASE_1:.*]] = select i1 %[[RESULT_IS_INFINITY]], fp128 %[[INFINITY_RESULT_IMAG]], fp128 %[[RESULT_IMAG_SPECIAL_CASE_2]] +! IMPRVD: %[[RESULT_REAL_IS_NAN:.*]] = fcmp uno fp128 %[[RESULT_REAL]], 0xL00000000000000000000000000000000 +! IMPRVD: %[[RESULT_IMAG_IS_NAN:.*]] = fcmp uno fp128 %[[RESULT_IMAG]], 0xL00000000000000000000000000000000 +! IMPRVD: %[[RESULT_IS_NAN:.*]] = and i1 %[[RESULT_REAL_IS_NAN]], %[[RESULT_IMAG_IS_NAN]] +! IMPRVD: %[[RESULT_REAL_WITH_SPECIAL_CASES:.*]] = select i1 %[[RESULT_IS_NAN]], fp128 %[[RESULT_REAL_SPECIAL_CASE_1]], fp128 %[[RESULT_REAL]] +! IMPRVD: %[[RESULT_IMAG_WITH_SPECIAL_CASES:.*]] = select i1 %[[RESULT_IS_NAN]], fp128 %[[RESULT_IMAG_SPECIAL_CASE_1]], fp128 %[[RESULT_IMAG]] +! IMPRVD: %[[RESULT_1:.*]] = insertvalue { fp128, fp128 } poison, fp128 %[[RESULT_REAL_WITH_SPECIAL_CASES]], 0 +! IMPRVD: %[[RESULT_2:.*]] = insertvalue { fp128, fp128 } %[[RESULT_1]], fp128 %[[RESULT_IMAG_WITH_SPECIAL_CASES]], 1 +! IMPRVD: store { fp128, fp128 } %[[RESULT_2]], ptr %[[RET]], align 16 + +! BASIC-DAG: %[[RHS_REAL_SQ:.*]] = fmul contract fp128 %[[RHS_REAL]], %[[RHS_REAL]] +! BASIC-DAG: %[[RHS_IMAG_SQ:.*]] = fmul contract fp128 %[[RHS_IMAG]], %[[RHS_IMAG]] +! BASIC: %[[SQ_NORM:.*]] = fadd contract fp128 %[[RHS_REAL_SQ]], %[[RHS_IMAG_SQ]] +! BASIC-DAG: %[[REAL_TMP_0:.*]] = fmul contract fp128 %[[LHS_REAL]], %[[RHS_REAL]] +! BASIC-DAG: %[[REAL_TMP_1:.*]] = fmul contract fp128 %[[LHS_IMAG]], %[[RHS_IMAG]] +! BASIC: %[[REAL_TMP_2:.*]] = fadd contract fp128 %[[REAL_TMP_0]], %[[REAL_TMP_1]] +! BASIC-DAG: %[[IMAG_TMP_0:.*]] = fmul contract fp128 %[[LHS_IMAG]], %[[RHS_REAL]] +! BASIC-DAG: %[[IMAG_TMP_1:.*]] = fmul contract fp128 %[[LHS_REAL]], %[[RHS_IMAG]] +! BASIC: %[[IMAG_TMP_2:.*]] = fsub contract fp128 %[[IMAG_TMP_0]], %[[IMAG_TMP_1]] +! BASIC: %[[REAL:.*]] = fdiv contract fp128 %[[REAL_TMP_2]], %[[SQ_NORM]] +! BASIC: %[[IMAG:.*]] = fdiv contract fp128 %[[IMAG_TMP_2]], %[[SQ_NORM]] +! BASIC: %[[RESULT_1:.*]] = insertvalue { fp128, fp128 } poison, fp128 %[[REAL]], 0 +! BASIC: %[[RESULT_2:.*]] = insertvalue { fp128, fp128 } %[[RESULT_1]], fp128 %[[IMAG]], 1 +! BASIC: store { fp128, fp128 } %[[RESULT_2]], ptr %[[RET]], align 16 + +! CHECK: ret void +subroutine div_test_quad(a,b,c) + complex(kind=16) :: a, b, c + a = b / c +end subroutine div_test_quad diff --git a/flang/test/Integration/complex-div-to-llvm.f90 b/flang/test/Integration/complex-div-to-llvm.f90 new file mode 100644 index 0000000000000..01782a565f24c --- /dev/null +++ b/flang/test/Integration/complex-div-to-llvm.f90 @@ -0,0 +1,508 @@ +! Test lowering complex division to llvm ir according to options + +! RUN: %flang -fcomplex-arithmetic=improved -S -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,IMPRVD +! RUN: %flang -fcomplex-arithmetic=basic -S -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,BASIC + + +! CHECK-LABEL: @div_test_half +! CHECK-SAME: ptr %[[RET:.*]], ptr %[[LHS:.*]], ptr %[[RHS:.*]]) +! CHECK: %[[LOAD_LHS:.*]] = load { half, half }, ptr %[[LHS]], align 2 +! CHECK: %[[LOAD_RHS:.*]] = load { half, half }, ptr %[[RHS]], align 2 +! CHECK: %[[LHS_REAL:.*]] = extractvalue { half, half } %[[LOAD_LHS]], 0 +! CHECK: %[[LHS_IMAG:.*]] = extractvalue { half, half } %[[LOAD_LHS]], 1 +! CHECK: %[[RHS_REAL:.*]] = extractvalue { half, half } %[[LOAD_RHS]], 0 +! CHECK: %[[RHS_IMAG:.*]] = extractvalue { half, half } %[[LOAD_RHS]], 1 + +! IMPRVD: %[[RHS_REAL_IMAG_RATIO:.*]] = fdiv contract half %[[RHS_REAL]], %[[RHS_IMAG]] +! IMPRVD: %[[RHS_REAL_TIMES_RHS_REAL_IMAG_RATIO:.*]] = fmul contract half %[[RHS_REAL_IMAG_RATIO]], %[[RHS_REAL]] +! IMPRVD: %[[RHS_REAL_IMAG_DENOM:.*]] = fadd contract half %[[RHS_IMAG]], %[[RHS_REAL_TIMES_RHS_REAL_IMAG_RATIO]] +! IMPRVD: %[[LHS_REAL_TIMES_RHS_REAL_IMAG_RATIO:.*]] = fmul contract half %[[LHS_REAL]], %[[RHS_REAL_IMAG_RATIO]] +! IMPRVD: %[[REAL_NUMERATOR_1:.*]] = fadd contract half %[[LHS_REAL_TIMES_RHS_REAL_IMAG_RATIO]], %[[LHS_IMAG]] +! IMPRVD: %[[RESULT_REAL_1:.*]] = fdiv contract half %[[REAL_NUMERATOR_1]], %[[RHS_REAL_IMAG_DENOM]] +! IMPRVD: %[[LHS_IMAG_TIMES_RHS_REAL_IMAG_RATIO:.*]] = fmul contract half %[[LHS_IMAG]], %[[RHS_REAL_IMAG_RATIO]] +! IMPRVD: %[[IMAG_NUMERATOR_1:.*]] = fsub contract half %[[LHS_IMAG_TIMES_RHS_REAL_IMAG_RATIO]], %[[LHS_REAL]] +! IMPRVD: %[[RESULT_IMAG_1:.*]] = fdiv contract half %[[IMAG_NUMERATOR_1]], %[[RHS_REAL_IMAG_DENOM]] +! IMPRVD: %[[RHS_IMAG_REAL_RATIO:.*]] = fdiv contract half %[[RHS_IMAG]], %[[RHS_REAL]] +! IMPRVD: %[[RHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO:.*]] = fmul contract half %[[RHS_IMAG_REAL_RATIO]], %[[RHS_IMAG]] +! IMPRVD: %[[RHS_IMAG_REAL_DENOM:.*]] = fadd contract half %[[RHS_REAL]], %[[RHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[LHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO:.*]] = fmul contract half %[[LHS_IMAG]], %[[RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[REAL_NUMERATOR_2:.*]] = fadd contract half %[[LHS_REAL]], %[[LHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[RESULT_REAL_2:.*]] = fdiv contract half %[[REAL_NUMERATOR_2]], %[[RHS_IMAG_REAL_DENOM]] +! IMPRVD: %[[LHS_REAL_TIMES_RHS_IMAG_REAL_RATIO:.*]] = fmul contract half %[[LHS_REAL]], %[[RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[IMAG_NUMERATOR_2:.*]] = fsub contract half %[[LHS_IMAG]], %[[LHS_REAL_TIMES_RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[RESULT_IMAG_2:.*]] = fdiv contract half %[[IMAG_NUMERATOR_2]], %[[RHS_IMAG_REAL_DENOM]] + +! Case 1. Zero denominator, numerator contains at most one NaN value. +! IMPRVD: %[[RHS_REAL_ABS:.*]] = call contract half @llvm.fabs.f16(half %[[RHS_REAL]]) +! IMPRVD: %[[RHS_REAL_ABS_IS_ZERO:.*]] = fcmp oeq half %[[RHS_REAL_ABS]], 0xH0000 +! IMPRVD: %[[RHS_IMAG_ABS:.*]] = call contract half @llvm.fabs.f16(half %[[RHS_IMAG]]) +! IMPRVD: %[[RHS_IMAG_ABS_IS_ZERO:.*]] = fcmp oeq half %[[RHS_IMAG_ABS]], 0xH0000 +! IMPRVD: %[[LHS_REAL_IS_NOT_NAN:.*]] = fcmp ord half %[[LHS_REAL]], 0xH0000 +! IMPRVD: %[[LHS_IMAG_IS_NOT_NAN:.*]] = fcmp ord half %[[LHS_IMAG]], 0xH0000 +! IMPRVD: %[[LHS_CONTAINS_NOT_NAN_VALUE:.*]] = or i1 %[[LHS_REAL_IS_NOT_NAN]], %[[LHS_IMAG_IS_NOT_NAN]] +! IMPRVD: %[[RHS_IS_ZERO:.*]] = and i1 %[[RHS_REAL_ABS_IS_ZERO]], %[[RHS_IMAG_ABS_IS_ZERO]] +! IMPRVD: %[[RESULT_IS_INFINITY:.*]] = and i1 %[[LHS_CONTAINS_NOT_NAN_VALUE]], %[[RHS_IS_ZERO]] +! IMPRVD: %[[INF_WITH_SIGN_OF_RHS_REAL:.*]] = call half @llvm.copysign.f16(half 0xH7C00, half %[[RHS_REAL]]) +! IMPRVD: %[[INFINITY_RESULT_REAL:.*]] = fmul contract half %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_REAL]] +! IMPRVD: %[[INFINITY_RESULT_IMAG:.*]] = fmul contract half %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_IMAG]] + +! Case 2. Infinite numerator, finite denominator. +! IMPRVD: %[[RHS_REAL_FINITE:.*]] = fcmp one half %[[RHS_REAL_ABS]], 0xH7C00 +! IMPRVD: %[[RHS_IMAG_FINITE:.*]] = fcmp one half %[[RHS_IMAG_ABS]], 0xH7C00 +! IMPRVD: %[[RHS_IS_FINITE:.*]] = and i1 %[[RHS_REAL_FINITE]], %[[RHS_IMAG_FINITE]] +! IMPRVD: %[[LHS_REAL_ABS:.*]] = call contract half @llvm.fabs.f16(half %[[LHS_REAL]]) +! IMPRVD: %[[LHS_REAL_INFINITE:.*]] = fcmp oeq half %[[LHS_REAL_ABS]], 0xH7C00 +! IMPRVD: %[[LHS_IMAG_ABS:.*]] = call contract half @llvm.fabs.f16(half %[[LHS_IMAG]]) +! IMPRVD: %[[LHS_IMAG_INFINITE:.*]] = fcmp oeq half %[[LHS_IMAG_ABS]], 0xH7C00 +! IMPRVD: %[[LHS_IS_INFINITE:.*]] = or i1 %[[LHS_REAL_INFINITE]], %[[LHS_IMAG_INFINITE]] +! IMPRVD: %[[INF_NUM_FINITE_DENOM:.*]] = and i1 %[[LHS_IS_INFINITE]], %[[RHS_IS_FINITE]] +! IMPRVD: %[[LHS_REAL_IS_INF:.*]] = select i1 %[[LHS_REAL_INFINITE]], half 0xH3C00, half 0xH0000 +! IMPRVD: %[[LHS_REAL_IS_INF_WITH_SIGN:.*]] = call half @llvm.copysign.f16(half %[[LHS_REAL_IS_INF]], half %[[LHS_REAL]]) +! IMPRVD: %[[LHS_IMAG_IS_INF:.*]] = select i1 %[[LHS_IMAG_INFINITE]], half 0xH3C00, half 0xH0000 +! IMPRVD: %[[LHS_IMAG_IS_INF_WITH_SIGN:.*]] = call half @llvm.copysign.f16(half %[[LHS_IMAG_IS_INF]], half %[[LHS_IMAG]]) +! IMPRVD: %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_REAL:.*]] = fmul contract half %[[LHS_REAL_IS_INF_WITH_SIGN]], %[[RHS_REAL]] +! IMPRVD: %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_IMAG:.*]] = fmul contract half %[[LHS_IMAG_IS_INF_WITH_SIGN]], %[[RHS_IMAG]] +! IMPRVD: %[[INF_MULTIPLICATOR_1:.*]] = fadd contract half %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_REAL]], %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_IMAG]] +! IMPRVD: %[[RESULT_REAL_3:.*]] = fmul contract half %[[INF_MULTIPLICATOR_1]], 0xH7C00 +! IMPRVD: %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_IMAG:.*]] = fmul contract half %[[LHS_REAL_IS_INF_WITH_SIGN]], %[[RHS_IMAG]] +! IMPRVD: %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_REAL:.*]] = fmul contract half %[[LHS_IMAG_IS_INF_WITH_SIGN]], %[[RHS_REAL]] +! IMPRVD: %[[INF_MULTIPLICATOR_2:.*]] = fsub contract half %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_REAL]], %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_IMAG]] +! IMPRVD: %[[RESULT_IMAG_3:.*]] = fmul contract half %[[INF_MULTIPLICATOR_2]], 0xH7C00 + +! Case 3. Finite numerator, infinite denominator. +! IMPRVD: %[[LHS_REAL_FINITE:.*]] = fcmp one half %[[LHS_REAL_ABS]], 0xH7C00 +! IMPRVD: %[[LHS_IMAG_FINITE:.*]] = fcmp one half %[[LHS_IMAG_ABS]], 0xH7C00 +! IMPRVD: %[[LHS_IS_FINITE:.*]] = and i1 %[[LHS_REAL_FINITE]], %[[LHS_IMAG_FINITE]] +! IMPRVD: %[[RHS_REAL_INFINITE:.*]] = fcmp oeq half %[[RHS_REAL_ABS]], 0xH7C00 +! IMPRVD: %[[RHS_IMAG_INFINITE:.*]] = fcmp oeq half %[[RHS_IMAG_ABS]], 0xH7C00 +! IMPRVD: %[[RHS_IS_INFINITE:.*]] = or i1 %[[RHS_REAL_INFINITE]], %[[RHS_IMAG_INFINITE]] +! IMPRVD: %[[FINITE_NUM_INFINITE_DENOM:.*]] = and i1 %[[LHS_IS_FINITE]], %[[RHS_IS_INFINITE]] +! IMPRVD: %[[RHS_REAL_IS_INF:.*]] = select i1 %[[RHS_REAL_INFINITE]], half 0xH3C00, half 0xH0000 +! IMPRVD: %[[RHS_REAL_IS_INF_WITH_SIGN:.*]] = call half @llvm.copysign.f16(half %[[RHS_REAL_IS_INF]], half %[[RHS_REAL]]) +! IMPRVD: %[[RHS_IMAG_IS_INF:.*]] = select i1 %[[RHS_IMAG_INFINITE]], half 0xH3C00, half 0xH0000 +! IMPRVD: %[[RHS_IMAG_IS_INF_WITH_SIGN:.*]] = call half @llvm.copysign.f16(half %[[RHS_IMAG_IS_INF]], half %[[RHS_IMAG]]) +! IMPRVD: %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_REAL:.*]] = fmul contract half %[[LHS_REAL]], %[[RHS_REAL_IS_INF_WITH_SIGN]] +! IMPRVD: %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_IMAG:.*]] = fmul contract half %[[LHS_IMAG]], %[[RHS_IMAG_IS_INF_WITH_SIGN]] +! IMPRVD: %[[ZERO_MULTIPLICATOR_1:.*]] = fadd contract half %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_REAL]], %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_IMAG]] +! IMPRVD: %[[RESULT_REAL_4:.*]] = fmul contract half %[[ZERO_MULTIPLICATOR_1]], 0xH0000 +! IMPRVD: %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_IMAG:.*]] = fmul contract half %[[LHS_IMAG]], %[[RHS_REAL_IS_INF_WITH_SIGN]] +! IMPRVD: %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_REAL:.*]] = fmul contract half %[[LHS_REAL]], %[[RHS_IMAG_IS_INF_WITH_SIGN]] +! IMPRVD: %[[ZERO_MULTIPLICATOR_2:.*]] = fsub contract half %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_IMAG]], %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_REAL]] +! IMPRVD: %[[RESULT_IMAG_4:.*]] = fmul contract half %[[ZERO_MULTIPLICATOR_2]], 0xH0000 + +! IMPRVD: %[[REAL_ABS_SMALLER_THAN_IMAG_ABS:.*]] = fcmp olt half %[[RHS_REAL_ABS]], %[[RHS_IMAG_ABS]] +! IMPRVD: %[[RESULT_REAL:.*]] = select i1 %[[REAL_ABS_SMALLER_THAN_IMAG_ABS]], half %[[RESULT_REAL_1]], half %[[RESULT_REAL_2]] +! IMPRVD: %[[RESULT_IMAG:.*]] = select i1 %[[REAL_ABS_SMALLER_THAN_IMAG_ABS]], half %[[RESULT_IMAG_1]], half %[[RESULT_IMAG_2]] +! IMPRVD: %[[RESULT_REAL_SPECIAL_CASE_3:.*]] = select i1 %[[FINITE_NUM_INFINITE_DENOM]], half %[[RESULT_REAL_4]], half %[[RESULT_REAL]] +! IMPRVD: %[[RESULT_IMAG_SPECIAL_CASE_3:.*]] = select i1 %[[FINITE_NUM_INFINITE_DENOM]], half %[[RESULT_IMAG_4]], half %[[RESULT_IMAG]] +! IMPRVD: %[[RESULT_REAL_SPECIAL_CASE_2:.*]] = select i1 %[[INF_NUM_FINITE_DENOM]], half %[[RESULT_REAL_3]], half %[[RESULT_REAL_SPECIAL_CASE_3]] +! IMPRVD: %[[RESULT_IMAG_SPECIAL_CASE_2:.*]] = select i1 %[[INF_NUM_FINITE_DENOM]], half %[[RESULT_IMAG_3]], half %[[RESULT_IMAG_SPECIAL_CASE_3]] +! IMPRVD: %[[RESULT_REAL_SPECIAL_CASE_1:.*]] = select i1 %[[RESULT_IS_INFINITY]], half %[[INFINITY_RESULT_REAL]], half %[[RESULT_REAL_SPECIAL_CASE_2]] +! IMPRVD: %[[RESULT_IMAG_SPECIAL_CASE_1:.*]] = select i1 %[[RESULT_IS_INFINITY]], half %[[INFINITY_RESULT_IMAG]], half %[[RESULT_IMAG_SPECIAL_CASE_2]] +! IMPRVD: %[[RESULT_REAL_IS_NAN:.*]] = fcmp uno half %[[RESULT_REAL]], 0xH0000 +! IMPRVD: %[[RESULT_IMAG_IS_NAN:.*]] = fcmp uno half %[[RESULT_IMAG]], 0xH0000 +! IMPRVD: %[[RESULT_IS_NAN:.*]] = and i1 %[[RESULT_REAL_IS_NAN]], %[[RESULT_IMAG_IS_NAN]] +! IMPRVD: %[[RESULT_REAL_WITH_SPECIAL_CASES:.*]] = select i1 %[[RESULT_IS_NAN]], half %[[RESULT_REAL_SPECIAL_CASE_1]], half %[[RESULT_REAL]] +! IMPRVD: %[[RESULT_IMAG_WITH_SPECIAL_CASES:.*]] = select i1 %[[RESULT_IS_NAN]], half %[[RESULT_IMAG_SPECIAL_CASE_1]], half %[[RESULT_IMAG]] +! IMPRVD: %[[RESULT_1:.*]] = insertvalue { half, half } poison, half %[[RESULT_REAL_WITH_SPECIAL_CASES]], 0 +! IMPRVD: %[[RESULT_2:.*]] = insertvalue { half, half } %[[RESULT_1]], half %[[RESULT_IMAG_WITH_SPECIAL_CASES]], 1 +! IMPRVD: store { half, half } %[[RESULT_2]], ptr %[[RET]], align 2 + +! BASIC-DAG: %[[RHS_REAL_SQ:.*]] = fmul contract half %[[RHS_REAL]], %[[RHS_REAL]] +! BASIC-DAG: %[[RHS_IMAG_SQ:.*]] = fmul contract half %[[RHS_IMAG]], %[[RHS_IMAG]] +! BASIC: %[[SQ_NORM:.*]] = fadd contract half %[[RHS_REAL_SQ]], %[[RHS_IMAG_SQ]] +! BASIC-DAG: %[[REAL_TMP_0:.*]] = fmul contract half %[[LHS_REAL]], %[[RHS_REAL]] +! BASIC-DAG: %[[REAL_TMP_1:.*]] = fmul contract half %[[LHS_IMAG]], %[[RHS_IMAG]] +! BASIC: %[[REAL_TMP_2:.*]] = fadd contract half %[[REAL_TMP_0]], %[[REAL_TMP_1]] +! BASIC-DAG: %[[IMAG_TMP_0:.*]] = fmul contract half %[[LHS_IMAG]], %[[RHS_REAL]] +! BASIC-DAG: %[[IMAG_TMP_1:.*]] = fmul contract half %[[LHS_REAL]], %[[RHS_IMAG]] +! BASIC: %[[IMAG_TMP_2:.*]] = fsub contract half %[[IMAG_TMP_0]], %[[IMAG_TMP_1]] +! BASIC: %[[REAL:.*]] = fdiv contract half %[[REAL_TMP_2]], %[[SQ_NORM]] +! BASIC: %[[IMAG:.*]] = fdiv contract half %[[IMAG_TMP_2]], %[[SQ_NORM]] +! BASIC: %[[RESULT_1:.*]] = insertvalue { half, half } poison, half %[[REAL]], 0 +! BASIC: %[[RESULT_2:.*]] = insertvalue { half, half } %[[RESULT_1]], half %[[IMAG]], 1 +! BASIC: store { half, half } %[[RESULT_2]], ptr %[[RET]], align 2 + +! CHECK: ret void +subroutine div_test_half(a,b,c) + complex(kind=2) :: a, b, c + a = b / c +end subroutine div_test_half + + +! CHECK-LABEL: @div_test_bfloat +! CHECK-SAME: ptr %[[RET:.*]], ptr %[[LHS:.*]], ptr %[[RHS:.*]]) +! CHECK: %[[LOAD_LHS:.*]] = load { bfloat, bfloat }, ptr %[[LHS]], align 2 +! CHECK: %[[LOAD_RHS:.*]] = load { bfloat, bfloat }, ptr %[[RHS]], align 2 +! CHECK: %[[LHS_REAL:.*]] = extractvalue { bfloat, bfloat } %[[LOAD_LHS]], 0 +! CHECK: %[[LHS_IMAG:.*]] = extractvalue { bfloat, bfloat } %[[LOAD_LHS]], 1 +! CHECK: %[[RHS_REAL:.*]] = extractvalue { bfloat, bfloat } %[[LOAD_RHS]], 0 +! CHECK: %[[RHS_IMAG:.*]] = extractvalue { bfloat, bfloat } %[[LOAD_RHS]], 1 + +! IMPRVD: %[[RHS_REAL_IMAG_RATIO:.*]] = fdiv contract bfloat %[[RHS_REAL]], %[[RHS_IMAG]] +! IMPRVD: %[[RHS_REAL_TIMES_RHS_REAL_IMAG_RATIO:.*]] = fmul contract bfloat %[[RHS_REAL_IMAG_RATIO]], %[[RHS_REAL]] +! IMPRVD: %[[RHS_REAL_IMAG_DENOM:.*]] = fadd contract bfloat %[[RHS_IMAG]], %[[RHS_REAL_TIMES_RHS_REAL_IMAG_RATIO]] +! IMPRVD: %[[LHS_REAL_TIMES_RHS_REAL_IMAG_RATIO:.*]] = fmul contract bfloat %[[LHS_REAL]], %[[RHS_REAL_IMAG_RATIO]] +! IMPRVD: %[[REAL_NUMERATOR_1:.*]] = fadd contract bfloat %[[LHS_REAL_TIMES_RHS_REAL_IMAG_RATIO]], %[[LHS_IMAG]] +! IMPRVD: %[[RESULT_REAL_1:.*]] = fdiv contract bfloat %[[REAL_NUMERATOR_1]], %[[RHS_REAL_IMAG_DENOM]] +! IMPRVD: %[[LHS_IMAG_TIMES_RHS_REAL_IMAG_RATIO:.*]] = fmul contract bfloat %[[LHS_IMAG]], %[[RHS_REAL_IMAG_RATIO]] +! IMPRVD: %[[IMAG_NUMERATOR_1:.*]] = fsub contract bfloat %[[LHS_IMAG_TIMES_RHS_REAL_IMAG_RATIO]], %[[LHS_REAL]] +! IMPRVD: %[[RESULT_IMAG_1:.*]] = fdiv contract bfloat %[[IMAG_NUMERATOR_1]], %[[RHS_REAL_IMAG_DENOM]] +! IMPRVD: %[[RHS_IMAG_REAL_RATIO:.*]] = fdiv contract bfloat %[[RHS_IMAG]], %[[RHS_REAL]] +! IMPRVD: %[[RHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO:.*]] = fmul contract bfloat %[[RHS_IMAG_REAL_RATIO]], %[[RHS_IMAG]] +! IMPRVD: %[[RHS_IMAG_REAL_DENOM:.*]] = fadd contract bfloat %[[RHS_REAL]], %[[RHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[LHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO:.*]] = fmul contract bfloat %[[LHS_IMAG]], %[[RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[REAL_NUMERATOR_2:.*]] = fadd contract bfloat %[[LHS_REAL]], %[[LHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[RESULT_REAL_2:.*]] = fdiv contract bfloat %[[REAL_NUMERATOR_2]], %[[RHS_IMAG_REAL_DENOM]] +! IMPRVD: %[[LHS_REAL_TIMES_RHS_IMAG_REAL_RATIO:.*]] = fmul contract bfloat %[[LHS_REAL]], %[[RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[IMAG_NUMERATOR_2:.*]] = fsub contract bfloat %[[LHS_IMAG]], %[[LHS_REAL_TIMES_RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[RESULT_IMAG_2:.*]] = fdiv contract bfloat %[[IMAG_NUMERATOR_2]], %[[RHS_IMAG_REAL_DENOM]] + +! Case 1. Zero denominator, numerator contains at most one NaN value. +! IMPRVD: %[[RHS_REAL_ABS:.*]] = call contract bfloat @llvm.fabs.bf16(bfloat %[[RHS_REAL]]) +! IMPRVD: %[[RHS_REAL_ABS_IS_ZERO:.*]] = fcmp oeq bfloat %[[RHS_REAL_ABS]], 0xR0000 +! IMPRVD: %[[RHS_IMAG_ABS:.*]] = call contract bfloat @llvm.fabs.bf16(bfloat %[[RHS_IMAG]]) +! IMPRVD: %[[RHS_IMAG_ABS_IS_ZERO:.*]] = fcmp oeq bfloat %[[RHS_IMAG_ABS]], 0xR0000 +! IMPRVD: %[[LHS_REAL_IS_NOT_NAN:.*]] = fcmp ord bfloat %[[LHS_REAL]], 0xR0000 +! IMPRVD: %[[LHS_IMAG_IS_NOT_NAN:.*]] = fcmp ord bfloat %[[LHS_IMAG]], 0xR0000 +! IMPRVD: %[[LHS_CONTAINS_NOT_NAN_VALUE:.*]] = or i1 %[[LHS_REAL_IS_NOT_NAN]], %[[LHS_IMAG_IS_NOT_NAN]] +! IMPRVD: %[[RHS_IS_ZERO:.*]] = and i1 %[[RHS_REAL_ABS_IS_ZERO]], %[[RHS_IMAG_ABS_IS_ZERO]] +! IMPRVD: %[[RESULT_IS_INFINITY:.*]] = and i1 %[[LHS_CONTAINS_NOT_NAN_VALUE]], %[[RHS_IS_ZERO]] +! IMPRVD: %[[INF_WITH_SIGN_OF_RHS_REAL:.*]] = call bfloat @llvm.copysign.bf16(bfloat 0xR7F80, bfloat %[[RHS_REAL]]) +! IMPRVD: %[[INFINITY_RESULT_REAL:.*]] = fmul contract bfloat %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_REAL]] +! IMPRVD: %[[INFINITY_RESULT_IMAG:.*]] = fmul contract bfloat %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_IMAG]] + +! Case 2. Infinite numerator, finite denominator. +! IMPRVD: %[[RHS_REAL_FINITE:.*]] = fcmp one bfloat %[[RHS_REAL_ABS]], 0xR7F80 +! IMPRVD: %[[RHS_IMAG_FINITE:.*]] = fcmp one bfloat %[[RHS_IMAG_ABS]], 0xR7F80 +! IMPRVD: %[[RHS_IS_FINITE:.*]] = and i1 %[[RHS_REAL_FINITE]], %[[RHS_IMAG_FINITE]] +! IMPRVD: %[[LHS_REAL_ABS:.*]] = call contract bfloat @llvm.fabs.bf16(bfloat %[[LHS_REAL]]) +! IMPRVD: %[[LHS_REAL_INFINITE:.*]] = fcmp oeq bfloat %[[LHS_REAL_ABS]], 0xR7F80 +! IMPRVD: %[[LHS_IMAG_ABS:.*]] = call contract bfloat @llvm.fabs.bf16(bfloat %[[LHS_IMAG]]) +! IMPRVD: %[[LHS_IMAG_INFINITE:.*]] = fcmp oeq bfloat %[[LHS_IMAG_ABS]], 0xR7F80 +! IMPRVD: %[[LHS_IS_INFINITE:.*]] = or i1 %[[LHS_REAL_INFINITE]], %[[LHS_IMAG_INFINITE]] +! IMPRVD: %[[INF_NUM_FINITE_DENOM:.*]] = and i1 %[[LHS_IS_INFINITE]], %[[RHS_IS_FINITE]] +! IMPRVD: %[[LHS_REAL_IS_INF:.*]] = select i1 %[[LHS_REAL_INFINITE]], bfloat 0xR3F80, bfloat 0xR0000 +! IMPRVD: %[[LHS_REAL_IS_INF_WITH_SIGN:.*]] = call bfloat @llvm.copysign.bf16(bfloat %[[LHS_REAL_IS_INF]], bfloat %[[LHS_REAL]]) +! IMPRVD: %[[LHS_IMAG_IS_INF:.*]] = select i1 %[[LHS_IMAG_INFINITE]], bfloat 0xR3F80, bfloat 0xR0000 +! IMPRVD: %[[LHS_IMAG_IS_INF_WITH_SIGN:.*]] = call bfloat @llvm.copysign.bf16(bfloat %[[LHS_IMAG_IS_INF]], bfloat %[[LHS_IMAG]]) +! IMPRVD: %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_REAL:.*]] = fmul contract bfloat %[[LHS_REAL_IS_INF_WITH_SIGN]], %[[RHS_REAL]] +! IMPRVD: %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_IMAG:.*]] = fmul contract bfloat %[[LHS_IMAG_IS_INF_WITH_SIGN]], %[[RHS_IMAG]] +! IMPRVD: %[[INF_MULTIPLICATOR_1:.*]] = fadd contract bfloat %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_REAL]], %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_IMAG]] +! IMPRVD: %[[RESULT_REAL_3:.*]] = fmul contract bfloat %[[INF_MULTIPLICATOR_1]], 0xR7F80 +! IMPRVD: %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_IMAG:.*]] = fmul contract bfloat %[[LHS_REAL_IS_INF_WITH_SIGN]], %[[RHS_IMAG]] +! IMPRVD: %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_REAL:.*]] = fmul contract bfloat %[[LHS_IMAG_IS_INF_WITH_SIGN]], %[[RHS_REAL]] +! IMPRVD: %[[INF_MULTIPLICATOR_2:.*]] = fsub contract bfloat %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_REAL]], %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_IMAG]] +! IMPRVD: %[[RESULT_IMAG_3:.*]] = fmul contract bfloat %[[INF_MULTIPLICATOR_2]], 0xR7F80 + +! Case 3. Finite numerator, infinite denominator. +! IMPRVD: %[[LHS_REAL_FINITE:.*]] = fcmp one bfloat %[[LHS_REAL_ABS]], 0xR7F80 +! IMPRVD: %[[LHS_IMAG_FINITE:.*]] = fcmp one bfloat %[[LHS_IMAG_ABS]], 0xR7F80 +! IMPRVD: %[[LHS_IS_FINITE:.*]] = and i1 %[[LHS_REAL_FINITE]], %[[LHS_IMAG_FINITE]] +! IMPRVD: %[[RHS_REAL_INFINITE:.*]] = fcmp oeq bfloat %[[RHS_REAL_ABS]], 0xR7F80 +! IMPRVD: %[[RHS_IMAG_INFINITE:.*]] = fcmp oeq bfloat %[[RHS_IMAG_ABS]], 0xR7F80 +! IMPRVD: %[[RHS_IS_INFINITE:.*]] = or i1 %[[RHS_REAL_INFINITE]], %[[RHS_IMAG_INFINITE]] +! IMPRVD: %[[FINITE_NUM_INFINITE_DENOM:.*]] = and i1 %[[LHS_IS_FINITE]], %[[RHS_IS_INFINITE]] +! IMPRVD: %[[RHS_REAL_IS_INF:.*]] = select i1 %[[RHS_REAL_INFINITE]], bfloat 0xR3F80, bfloat 0xR0000 +! IMPRVD: %[[RHS_REAL_IS_INF_WITH_SIGN:.*]] = call bfloat @llvm.copysign.bf16(bfloat %[[RHS_REAL_IS_INF]], bfloat %[[RHS_REAL]]) +! IMPRVD: %[[RHS_IMAG_IS_INF:.*]] = select i1 %[[RHS_IMAG_INFINITE]], bfloat 0xR3F80, bfloat 0xR0000 +! IMPRVD: %[[RHS_IMAG_IS_INF_WITH_SIGN:.*]] = call bfloat @llvm.copysign.bf16(bfloat %[[RHS_IMAG_IS_INF]], bfloat %[[RHS_IMAG]]) +! IMPRVD: %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_REAL:.*]] = fmul contract bfloat %[[LHS_REAL]], %[[RHS_REAL_IS_INF_WITH_SIGN]] +! IMPRVD: %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_IMAG:.*]] = fmul contract bfloat %[[LHS_IMAG]], %[[RHS_IMAG_IS_INF_WITH_SIGN]] +! IMPRVD: %[[ZERO_MULTIPLICATOR_1:.*]] = fadd contract bfloat %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_REAL]], %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_IMAG]] +! IMPRVD: %[[RESULT_REAL_4:.*]] = fmul contract bfloat %[[ZERO_MULTIPLICATOR_1]], 0xR0000 +! IMPRVD: %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_IMAG:.*]] = fmul contract bfloat %[[LHS_IMAG]], %[[RHS_REAL_IS_INF_WITH_SIGN]] +! IMPRVD: %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_REAL:.*]] = fmul contract bfloat %[[LHS_REAL]], %[[RHS_IMAG_IS_INF_WITH_SIGN]] +! IMPRVD: %[[ZERO_MULTIPLICATOR_2:.*]] = fsub contract bfloat %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_IMAG]], %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_REAL]] +! IMPRVD: %[[RESULT_IMAG_4:.*]] = fmul contract bfloat %[[ZERO_MULTIPLICATOR_2]], 0xR0000 + +! IMPRVD: %[[REAL_ABS_SMALLER_THAN_IMAG_ABS:.*]] = fcmp olt bfloat %[[RHS_REAL_ABS]], %[[RHS_IMAG_ABS]] +! IMPRVD: %[[RESULT_REAL:.*]] = select i1 %[[REAL_ABS_SMALLER_THAN_IMAG_ABS]], bfloat %[[RESULT_REAL_1]], bfloat %[[RESULT_REAL_2]] +! IMPRVD: %[[RESULT_IMAG:.*]] = select i1 %[[REAL_ABS_SMALLER_THAN_IMAG_ABS]], bfloat %[[RESULT_IMAG_1]], bfloat %[[RESULT_IMAG_2]] +! IMPRVD: %[[RESULT_REAL_SPECIAL_CASE_3:.*]] = select i1 %[[FINITE_NUM_INFINITE_DENOM]], bfloat %[[RESULT_REAL_4]], bfloat %[[RESULT_REAL]] +! IMPRVD: %[[RESULT_IMAG_SPECIAL_CASE_3:.*]] = select i1 %[[FINITE_NUM_INFINITE_DENOM]], bfloat %[[RESULT_IMAG_4]], bfloat %[[RESULT_IMAG]] +! IMPRVD: %[[RESULT_REAL_SPECIAL_CASE_2:.*]] = select i1 %[[INF_NUM_FINITE_DENOM]], bfloat %[[RESULT_REAL_3]], bfloat %[[RESULT_REAL_SPECIAL_CASE_3]] +! IMPRVD: %[[RESULT_IMAG_SPECIAL_CASE_2:.*]] = select i1 %[[INF_NUM_FINITE_DENOM]], bfloat %[[RESULT_IMAG_3]], bfloat %[[RESULT_IMAG_SPECIAL_CASE_3]] +! IMPRVD: %[[RESULT_REAL_SPECIAL_CASE_1:.*]] = select i1 %[[RESULT_IS_INFINITY]], bfloat %[[INFINITY_RESULT_REAL]], bfloat %[[RESULT_REAL_SPECIAL_CASE_2]] +! IMPRVD: %[[RESULT_IMAG_SPECIAL_CASE_1:.*]] = select i1 %[[RESULT_IS_INFINITY]], bfloat %[[INFINITY_RESULT_IMAG]], bfloat %[[RESULT_IMAG_SPECIAL_CASE_2]] +! IMPRVD: %[[RESULT_REAL_IS_NAN:.*]] = fcmp uno bfloat %[[RESULT_REAL]], 0xR0000 +! IMPRVD: %[[RESULT_IMAG_IS_NAN:.*]] = fcmp uno bfloat %[[RESULT_IMAG]], 0xR0000 +! IMPRVD: %[[RESULT_IS_NAN:.*]] = and i1 %[[RESULT_REAL_IS_NAN]], %[[RESULT_IMAG_IS_NAN]] +! IMPRVD: %[[RESULT_REAL_WITH_SPECIAL_CASES:.*]] = select i1 %[[RESULT_IS_NAN]], bfloat %[[RESULT_REAL_SPECIAL_CASE_1]], bfloat %[[RESULT_REAL]] +! IMPRVD: %[[RESULT_IMAG_WITH_SPECIAL_CASES:.*]] = select i1 %[[RESULT_IS_NAN]], bfloat %[[RESULT_IMAG_SPECIAL_CASE_1]], bfloat %[[RESULT_IMAG]] +! IMPRVD: %[[RESULT_1:.*]] = insertvalue { bfloat, bfloat } poison, bfloat %[[RESULT_REAL_WITH_SPECIAL_CASES]], 0 +! IMPRVD: %[[RESULT_2:.*]] = insertvalue { bfloat, bfloat } %[[RESULT_1]], bfloat %[[RESULT_IMAG_WITH_SPECIAL_CASES]], 1 +! IMPRVD: store { bfloat, bfloat } %[[RESULT_2]], ptr %[[RET]], align 2 + +! BASIC-DAG: %[[RHS_REAL_SQ:.*]] = fmul contract bfloat %[[RHS_REAL]], %[[RHS_REAL]] +! BASIC-DAG: %[[RHS_IMAG_SQ:.*]] = fmul contract bfloat %[[RHS_IMAG]], %[[RHS_IMAG]] +! BASIC: %[[SQ_NORM:.*]] = fadd contract bfloat %[[RHS_REAL_SQ]], %[[RHS_IMAG_SQ]] +! BASIC-DAG: %[[REAL_TMP_0:.*]] = fmul contract bfloat %[[LHS_REAL]], %[[RHS_REAL]] +! BASIC-DAG: %[[REAL_TMP_1:.*]] = fmul contract bfloat %[[LHS_IMAG]], %[[RHS_IMAG]] +! BASIC: %[[REAL_TMP_2:.*]] = fadd contract bfloat %[[REAL_TMP_0]], %[[REAL_TMP_1]] +! BASIC-DAG: %[[IMAG_TMP_0:.*]] = fmul contract bfloat %[[LHS_IMAG]], %[[RHS_REAL]] +! BASIC-DAG: %[[IMAG_TMP_1:.*]] = fmul contract bfloat %[[LHS_REAL]], %[[RHS_IMAG]] +! BASIC: %[[IMAG_TMP_2:.*]] = fsub contract bfloat %[[IMAG_TMP_0]], %[[IMAG_TMP_1]] +! BASIC: %[[REAL:.*]] = fdiv contract bfloat %[[REAL_TMP_2]], %[[SQ_NORM]] +! BASIC: %[[IMAG:.*]] = fdiv contract bfloat %[[IMAG_TMP_2]], %[[SQ_NORM]] +! BASIC: %[[RESULT_1:.*]] = insertvalue { bfloat, bfloat } poison, bfloat %[[REAL]], 0 +! BASIC: %[[RESULT_2:.*]] = insertvalue { bfloat, bfloat } %[[RESULT_1]], bfloat %[[IMAG]], 1 +! BASIC: store { bfloat, bfloat } %[[RESULT_2]], ptr %[[RET]], align 2 + +! CHECK: ret void +subroutine div_test_bfloat(a,b,c) + complex(kind=3) :: a, b, c + a = b / c +end subroutine div_test_bfloat + + +! CHECK-LABEL: @div_test_single +! CHECK-SAME: ptr %[[RET:.*]], ptr %[[LHS:.*]], ptr %[[RHS:.*]]) +! CHECK: %[[LOAD_LHS:.*]] = load { float, float }, ptr %[[LHS]], align 4 +! CHECK: %[[LOAD_RHS:.*]] = load { float, float }, ptr %[[RHS]], align 4 +! CHECK: %[[LHS_REAL:.*]] = extractvalue { float, float } %[[LOAD_LHS]], 0 +! CHECK: %[[LHS_IMAG:.*]] = extractvalue { float, float } %[[LOAD_LHS]], 1 +! CHECK: %[[RHS_REAL:.*]] = extractvalue { float, float } %[[LOAD_RHS]], 0 +! CHECK: %[[RHS_IMAG:.*]] = extractvalue { float, float } %[[LOAD_RHS]], 1 + +! IMPRVD: %[[RHS_REAL_IMAG_RATIO:.*]] = fdiv contract float %[[RHS_REAL]], %[[RHS_IMAG]] +! IMPRVD: %[[RHS_REAL_TIMES_RHS_REAL_IMAG_RATIO:.*]] = fmul contract float %[[RHS_REAL_IMAG_RATIO]], %[[RHS_REAL]] +! IMPRVD: %[[RHS_REAL_IMAG_DENOM:.*]] = fadd contract float %[[RHS_IMAG]], %[[RHS_REAL_TIMES_RHS_REAL_IMAG_RATIO]] +! IMPRVD: %[[LHS_REAL_TIMES_RHS_REAL_IMAG_RATIO:.*]] = fmul contract float %[[LHS_REAL]], %[[RHS_REAL_IMAG_RATIO]] +! IMPRVD: %[[REAL_NUMERATOR_1:.*]] = fadd contract float %[[LHS_REAL_TIMES_RHS_REAL_IMAG_RATIO]], %[[LHS_IMAG]] +! IMPRVD: %[[RESULT_REAL_1:.*]] = fdiv contract float %[[REAL_NUMERATOR_1]], %[[RHS_REAL_IMAG_DENOM]] +! IMPRVD: %[[LHS_IMAG_TIMES_RHS_REAL_IMAG_RATIO:.*]] = fmul contract float %[[LHS_IMAG]], %[[RHS_REAL_IMAG_RATIO]] +! IMPRVD: %[[IMAG_NUMERATOR_1:.*]] = fsub contract float %[[LHS_IMAG_TIMES_RHS_REAL_IMAG_RATIO]], %[[LHS_REAL]] +! IMPRVD: %[[RESULT_IMAG_1:.*]] = fdiv contract float %[[IMAG_NUMERATOR_1]], %[[RHS_REAL_IMAG_DENOM]] +! IMPRVD: %[[RHS_IMAG_REAL_RATIO:.*]] = fdiv contract float %[[RHS_IMAG]], %[[RHS_REAL]] +! IMPRVD: %[[RHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO:.*]] = fmul contract float %[[RHS_IMAG_REAL_RATIO]], %[[RHS_IMAG]] +! IMPRVD: %[[RHS_IMAG_REAL_DENOM:.*]] = fadd contract float %[[RHS_REAL]], %[[RHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[LHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO:.*]] = fmul contract float %[[LHS_IMAG]], %[[RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[REAL_NUMERATOR_2:.*]] = fadd contract float %[[LHS_REAL]], %[[LHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[RESULT_REAL_2:.*]] = fdiv contract float %[[REAL_NUMERATOR_2]], %[[RHS_IMAG_REAL_DENOM]] +! IMPRVD: %[[LHS_REAL_TIMES_RHS_IMAG_REAL_RATIO:.*]] = fmul contract float %[[LHS_REAL]], %[[RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[IMAG_NUMERATOR_2:.*]] = fsub contract float %[[LHS_IMAG]], %[[LHS_REAL_TIMES_RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[RESULT_IMAG_2:.*]] = fdiv contract float %[[IMAG_NUMERATOR_2]], %[[RHS_IMAG_REAL_DENOM]] + +! Case 1. Zero denominator, numerator contains at most one NaN value. +! IMPRVD: %[[RHS_REAL_ABS:.*]] = call contract float @llvm.fabs.f32(float %[[RHS_REAL]]) +! IMPRVD: %[[RHS_REAL_ABS_IS_ZERO:.*]] = fcmp oeq float %[[RHS_REAL_ABS]], 0.000000e+00 +! IMPRVD: %[[RHS_IMAG_ABS:.*]] = call contract float @llvm.fabs.f32(float %[[RHS_IMAG]]) +! IMPRVD: %[[RHS_IMAG_ABS_IS_ZERO:.*]] = fcmp oeq float %[[RHS_IMAG_ABS]], 0.000000e+00 +! IMPRVD: %[[LHS_REAL_IS_NOT_NAN:.*]] = fcmp ord float %[[LHS_REAL]], 0.000000e+00 +! IMPRVD: %[[LHS_IMAG_IS_NOT_NAN:.*]] = fcmp ord float %[[LHS_IMAG]], 0.000000e+00 +! IMPRVD: %[[LHS_CONTAINS_NOT_NAN_VALUE:.*]] = or i1 %[[LHS_REAL_IS_NOT_NAN]], %[[LHS_IMAG_IS_NOT_NAN]] +! IMPRVD: %[[RHS_IS_ZERO:.*]] = and i1 %[[RHS_REAL_ABS_IS_ZERO]], %[[RHS_IMAG_ABS_IS_ZERO]] +! IMPRVD: %[[RESULT_IS_INFINITY:.*]] = and i1 %[[LHS_CONTAINS_NOT_NAN_VALUE]], %[[RHS_IS_ZERO]] +! IMPRVD: %[[INF_WITH_SIGN_OF_RHS_REAL:.*]] = call float @llvm.copysign.f32(float 0x7FF0000000000000, float %[[RHS_REAL]]) +! IMPRVD: %[[INFINITY_RESULT_REAL:.*]] = fmul contract float %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_REAL]] +! IMPRVD: %[[INFINITY_RESULT_IMAG:.*]] = fmul contract float %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_IMAG]] + +! Case 2. Infinite numerator, finite denominator. +! IMPRVD: %[[RHS_REAL_FINITE:.*]] = fcmp one float %[[RHS_REAL_ABS]], 0x7FF0000000000000 +! IMPRVD: %[[RHS_IMAG_FINITE:.*]] = fcmp one float %[[RHS_IMAG_ABS]], 0x7FF0000000000000 +! IMPRVD: %[[RHS_IS_FINITE:.*]] = and i1 %[[RHS_REAL_FINITE]], %[[RHS_IMAG_FINITE]] +! IMPRVD: %[[LHS_REAL_ABS:.*]] = call contract float @llvm.fabs.f32(float %[[LHS_REAL]]) +! IMPRVD: %[[LHS_REAL_INFINITE:.*]] = fcmp oeq float %[[LHS_REAL_ABS]], 0x7FF0000000000000 +! IMPRVD: %[[LHS_IMAG_ABS:.*]] = call contract float @llvm.fabs.f32(float %[[LHS_IMAG]]) +! IMPRVD: %[[LHS_IMAG_INFINITE:.*]] = fcmp oeq float %[[LHS_IMAG_ABS]], 0x7FF0000000000000 +! IMPRVD: %[[LHS_IS_INFINITE:.*]] = or i1 %[[LHS_REAL_INFINITE]], %[[LHS_IMAG_INFINITE]] +! IMPRVD: %[[INF_NUM_FINITE_DENOM:.*]] = and i1 %[[LHS_IS_INFINITE]], %[[RHS_IS_FINITE]] +! IMPRVD: %[[LHS_REAL_IS_INF:.*]] = select i1 %[[LHS_REAL_INFINITE]], float 1.000000e+00, float 0.000000e+00 +! IMPRVD: %[[LHS_REAL_IS_INF_WITH_SIGN:.*]] = call float @llvm.copysign.f32(float %[[LHS_REAL_IS_INF]], float %[[LHS_REAL]]) +! IMPRVD: %[[LHS_IMAG_IS_INF:.*]] = select i1 %[[LHS_IMAG_INFINITE]], float 1.000000e+00, float 0.000000e+00 +! IMPRVD: %[[LHS_IMAG_IS_INF_WITH_SIGN:.*]] = call float @llvm.copysign.f32(float %[[LHS_IMAG_IS_INF]], float %[[LHS_IMAG]]) +! IMPRVD: %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_REAL:.*]] = fmul contract float %[[LHS_REAL_IS_INF_WITH_SIGN]], %[[RHS_REAL]] +! IMPRVD: %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_IMAG:.*]] = fmul contract float %[[LHS_IMAG_IS_INF_WITH_SIGN]], %[[RHS_IMAG]] +! IMPRVD: %[[INF_MULTIPLICATOR_1:.*]] = fadd contract float %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_REAL]], %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_IMAG]] +! IMPRVD: %[[RESULT_REAL_3:.*]] = fmul contract float %[[INF_MULTIPLICATOR_1]], 0x7FF0000000000000 +! IMPRVD: %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_IMAG:.*]] = fmul contract float %[[LHS_REAL_IS_INF_WITH_SIGN]], %[[RHS_IMAG]] +! IMPRVD: %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_REAL:.*]] = fmul contract float %[[LHS_IMAG_IS_INF_WITH_SIGN]], %[[RHS_REAL]] +! IMPRVD: %[[INF_MULTIPLICATOR_2:.*]] = fsub contract float %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_REAL]], %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_IMAG]] +! IMPRVD: %[[RESULT_IMAG_3:.*]] = fmul contract float %[[INF_MULTIPLICATOR_2]], 0x7FF0000000000000 + +! Case 3. Finite numerator, infinite denominator. +! IMPRVD: %[[LHS_REAL_FINITE:.*]] = fcmp one float %[[LHS_REAL_ABS]], 0x7FF0000000000000 +! IMPRVD: %[[LHS_IMAG_FINITE:.*]] = fcmp one float %[[LHS_IMAG_ABS]], 0x7FF0000000000000 +! IMPRVD: %[[LHS_IS_FINITE:.*]] = and i1 %[[LHS_REAL_FINITE]], %[[LHS_IMAG_FINITE]] +! IMPRVD: %[[RHS_REAL_INFINITE:.*]] = fcmp oeq float %[[RHS_REAL_ABS]], 0x7FF0000000000000 +! IMPRVD: %[[RHS_IMAG_INFINITE:.*]] = fcmp oeq float %[[RHS_IMAG_ABS]], 0x7FF0000000000000 +! IMPRVD: %[[RHS_IS_INFINITE:.*]] = or i1 %[[RHS_REAL_INFINITE]], %[[RHS_IMAG_INFINITE]] +! IMPRVD: %[[FINITE_NUM_INFINITE_DENOM:.*]] = and i1 %[[LHS_IS_FINITE]], %[[RHS_IS_INFINITE]] +! IMPRVD: %[[RHS_REAL_IS_INF:.*]] = select i1 %[[RHS_REAL_INFINITE]], float 1.000000e+00, float 0.000000e+00 +! IMPRVD: %[[RHS_REAL_IS_INF_WITH_SIGN:.*]] = call float @llvm.copysign.f32(float %[[RHS_REAL_IS_INF]], float %[[RHS_REAL]]) +! IMPRVD: %[[RHS_IMAG_IS_INF:.*]] = select i1 %[[RHS_IMAG_INFINITE]], float 1.000000e+00, float 0.000000e+00 +! IMPRVD: %[[RHS_IMAG_IS_INF_WITH_SIGN:.*]] = call float @llvm.copysign.f32(float %[[RHS_IMAG_IS_INF]], float %[[RHS_IMAG]]) +! IMPRVD: %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_REAL:.*]] = fmul contract float %[[LHS_REAL]], %[[RHS_REAL_IS_INF_WITH_SIGN]] +! IMPRVD: %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_IMAG:.*]] = fmul contract float %[[LHS_IMAG]], %[[RHS_IMAG_IS_INF_WITH_SIGN]] +! IMPRVD: %[[ZERO_MULTIPLICATOR_1:.*]] = fadd contract float %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_REAL]], %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_IMAG]] +! IMPRVD: %[[RESULT_REAL_4:.*]] = fmul contract float %[[ZERO_MULTIPLICATOR_1]], 0.000000e+00 +! IMPRVD: %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_IMAG:.*]] = fmul contract float %[[LHS_IMAG]], %[[RHS_REAL_IS_INF_WITH_SIGN]] +! IMPRVD: %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_REAL:.*]] = fmul contract float %[[LHS_REAL]], %[[RHS_IMAG_IS_INF_WITH_SIGN]] +! IMPRVD: %[[ZERO_MULTIPLICATOR_2:.*]] = fsub contract float %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_IMAG]], %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_REAL]] +! IMPRVD: %[[RESULT_IMAG_4:.*]] = fmul contract float %[[ZERO_MULTIPLICATOR_2]], 0.000000e+00 + +! IMPRVD: %[[REAL_ABS_SMALLER_THAN_IMAG_ABS:.*]] = fcmp olt float %[[RHS_REAL_ABS]], %[[RHS_IMAG_ABS]] +! IMPRVD: %[[RESULT_REAL:.*]] = select i1 %[[REAL_ABS_SMALLER_THAN_IMAG_ABS]], float %[[RESULT_REAL_1]], float %[[RESULT_REAL_2]] +! IMPRVD: %[[RESULT_IMAG:.*]] = select i1 %[[REAL_ABS_SMALLER_THAN_IMAG_ABS]], float %[[RESULT_IMAG_1]], float %[[RESULT_IMAG_2]] +! IMPRVD: %[[RESULT_REAL_SPECIAL_CASE_3:.*]] = select i1 %[[FINITE_NUM_INFINITE_DENOM]], float %[[RESULT_REAL_4]], float %[[RESULT_REAL]] +! IMPRVD: %[[RESULT_IMAG_SPECIAL_CASE_3:.*]] = select i1 %[[FINITE_NUM_INFINITE_DENOM]], float %[[RESULT_IMAG_4]], float %[[RESULT_IMAG]] +! IMPRVD: %[[RESULT_REAL_SPECIAL_CASE_2:.*]] = select i1 %[[INF_NUM_FINITE_DENOM]], float %[[RESULT_REAL_3]], float %[[RESULT_REAL_SPECIAL_CASE_3]] +! IMPRVD: %[[RESULT_IMAG_SPECIAL_CASE_2:.*]] = select i1 %[[INF_NUM_FINITE_DENOM]], float %[[RESULT_IMAG_3]], float %[[RESULT_IMAG_SPECIAL_CASE_3]] +! IMPRVD: %[[RESULT_REAL_SPECIAL_CASE_1:.*]] = select i1 %[[RESULT_IS_INFINITY]], float %[[INFINITY_RESULT_REAL]], float %[[RESULT_REAL_SPECIAL_CASE_2]] +! IMPRVD: %[[RESULT_IMAG_SPECIAL_CASE_1:.*]] = select i1 %[[RESULT_IS_INFINITY]], float %[[INFINITY_RESULT_IMAG]], float %[[RESULT_IMAG_SPECIAL_CASE_2]] +! IMPRVD: %[[RESULT_REAL_IS_NAN:.*]] = fcmp uno float %[[RESULT_REAL]], 0.000000e+00 +! IMPRVD: %[[RESULT_IMAG_IS_NAN:.*]] = fcmp uno float %[[RESULT_IMAG]], 0.000000e+00 +! IMPRVD: %[[RESULT_IS_NAN:.*]] = and i1 %[[RESULT_REAL_IS_NAN]], %[[RESULT_IMAG_IS_NAN]] +! IMPRVD: %[[RESULT_REAL_WITH_SPECIAL_CASES:.*]] = select i1 %[[RESULT_IS_NAN]], float %[[RESULT_REAL_SPECIAL_CASE_1]], float %[[RESULT_REAL]] +! IMPRVD: %[[RESULT_IMAG_WITH_SPECIAL_CASES:.*]] = select i1 %[[RESULT_IS_NAN]], float %[[RESULT_IMAG_SPECIAL_CASE_1]], float %[[RESULT_IMAG]] +! IMPRVD: %[[RESULT_1:.*]] = insertvalue { float, float } poison, float %[[RESULT_REAL_WITH_SPECIAL_CASES]], 0 +! IMPRVD: %[[RESULT_2:.*]] = insertvalue { float, float } %[[RESULT_1]], float %[[RESULT_IMAG_WITH_SPECIAL_CASES]], 1 +! IMPRVD: store { float, float } %[[RESULT_2]], ptr %[[RET]], align 4 + +! BASIC-DAG: %[[RHS_REAL_SQ:.*]] = fmul contract float %[[RHS_REAL]], %[[RHS_REAL]] +! BASIC-DAG: %[[RHS_IMAG_SQ:.*]] = fmul contract float %[[RHS_IMAG]], %[[RHS_IMAG]] +! BASIC: %[[SQ_NORM:.*]] = fadd contract float %[[RHS_REAL_SQ]], %[[RHS_IMAG_SQ]] +! BASIC-DAG: %[[REAL_TMP_0:.*]] = fmul contract float %[[LHS_REAL]], %[[RHS_REAL]] +! BASIC-DAG: %[[REAL_TMP_1:.*]] = fmul contract float %[[LHS_IMAG]], %[[RHS_IMAG]] +! BASIC: %[[REAL_TMP_2:.*]] = fadd contract float %[[REAL_TMP_0]], %[[REAL_TMP_1]] +! BASIC-DAG: %[[IMAG_TMP_0:.*]] = fmul contract float %[[LHS_IMAG]], %[[RHS_REAL]] +! BASIC-DAG: %[[IMAG_TMP_1:.*]] = fmul contract float %[[LHS_REAL]], %[[RHS_IMAG]] +! BASIC: %[[IMAG_TMP_2:.*]] = fsub contract float %[[IMAG_TMP_0]], %[[IMAG_TMP_1]] +! BASIC: %[[REAL:.*]] = fdiv contract float %[[REAL_TMP_2]], %[[SQ_NORM]] +! BASIC: %[[IMAG:.*]] = fdiv contract float %[[IMAG_TMP_2]], %[[SQ_NORM]] +! BASIC: %[[RESULT_1:.*]] = insertvalue { float, float } poison, float %[[REAL]], 0 +! BASIC: %[[RESULT_2:.*]] = insertvalue { float, float } %[[RESULT_1]], float %[[IMAG]], 1 +! BASIC: store { float, float } %[[RESULT_2]], ptr %[[RET]], align 4 + +! CHECK: ret void +subroutine div_test_single(a,b,c) + complex(kind=4) :: a, b, c + a = b / c +end subroutine div_test_single + + +! CHECK-LABEL: @div_test_double +! CHECK-SAME: ptr %[[RET:.*]], ptr %[[LHS:.*]], ptr %[[RHS:.*]]) +! CHECK: %[[LOAD_LHS:.*]] = load { double, double }, ptr %[[LHS]], align 8 +! CHECK: %[[LOAD_RHS:.*]] = load { double, double }, ptr %[[RHS]], align 8 +! CHECK: %[[LHS_REAL:.*]] = extractvalue { double, double } %[[LOAD_LHS]], 0 +! CHECK: %[[LHS_IMAG:.*]] = extractvalue { double, double } %[[LOAD_LHS]], 1 +! CHECK: %[[RHS_REAL:.*]] = extractvalue { double, double } %[[LOAD_RHS]], 0 +! CHECK: %[[RHS_IMAG:.*]] = extractvalue { double, double } %[[LOAD_RHS]], 1 + +! IMPRVD: %[[RHS_REAL_IMAG_RATIO:.*]] = fdiv contract double %[[RHS_REAL]], %[[RHS_IMAG]] +! IMPRVD: %[[RHS_REAL_TIMES_RHS_REAL_IMAG_RATIO:.*]] = fmul contract double %[[RHS_REAL_IMAG_RATIO]], %[[RHS_REAL]] +! IMPRVD: %[[RHS_REAL_IMAG_DENOM:.*]] = fadd contract double %[[RHS_IMAG]], %[[RHS_REAL_TIMES_RHS_REAL_IMAG_RATIO]] +! IMPRVD: %[[LHS_REAL_TIMES_RHS_REAL_IMAG_RATIO:.*]] = fmul contract double %[[LHS_REAL]], %[[RHS_REAL_IMAG_RATIO]] +! IMPRVD: %[[REAL_NUMERATOR_1:.*]] = fadd contract double %[[LHS_REAL_TIMES_RHS_REAL_IMAG_RATIO]], %[[LHS_IMAG]] +! IMPRVD: %[[RESULT_REAL_1:.*]] = fdiv contract double %[[REAL_NUMERATOR_1]], %[[RHS_REAL_IMAG_DENOM]] +! IMPRVD: %[[LHS_IMAG_TIMES_RHS_REAL_IMAG_RATIO:.*]] = fmul contract double %[[LHS_IMAG]], %[[RHS_REAL_IMAG_RATIO]] +! IMPRVD: %[[IMAG_NUMERATOR_1:.*]] = fsub contract double %[[LHS_IMAG_TIMES_RHS_REAL_IMAG_RATIO]], %[[LHS_REAL]] +! IMPRVD: %[[RESULT_IMAG_1:.*]] = fdiv contract double %[[IMAG_NUMERATOR_1]], %[[RHS_REAL_IMAG_DENOM]] +! IMPRVD: %[[RHS_IMAG_REAL_RATIO:.*]] = fdiv contract double %[[RHS_IMAG]], %[[RHS_REAL]] +! IMPRVD: %[[RHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO:.*]] = fmul contract double %[[RHS_IMAG_REAL_RATIO]], %[[RHS_IMAG]] +! IMPRVD: %[[RHS_IMAG_REAL_DENOM:.*]] = fadd contract double %[[RHS_REAL]], %[[RHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[LHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO:.*]] = fmul contract double %[[LHS_IMAG]], %[[RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[REAL_NUMERATOR_2:.*]] = fadd contract double %[[LHS_REAL]], %[[LHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[RESULT_REAL_2:.*]] = fdiv contract double %[[REAL_NUMERATOR_2]], %[[RHS_IMAG_REAL_DENOM]] +! IMPRVD: %[[LHS_REAL_TIMES_RHS_IMAG_REAL_RATIO:.*]] = fmul contract double %[[LHS_REAL]], %[[RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[IMAG_NUMERATOR_2:.*]] = fsub contract double %[[LHS_IMAG]], %[[LHS_REAL_TIMES_RHS_IMAG_REAL_RATIO]] +! IMPRVD: %[[RESULT_IMAG_2:.*]] = fdiv contract double %[[IMAG_NUMERATOR_2]], %[[RHS_IMAG_REAL_DENOM]] + +! Case 1. Zero denominator, numerator contains at most one NaN value. +! IMPRVD: %[[RHS_REAL_ABS:.*]] = call contract double @llvm.fabs.f64(double %[[RHS_REAL]]) +! IMPRVD: %[[RHS_REAL_ABS_IS_ZERO:.*]] = fcmp oeq double %[[RHS_REAL_ABS]], 0.000000e+00 +! IMPRVD: %[[RHS_IMAG_ABS:.*]] = call contract double @llvm.fabs.f64(double %[[RHS_IMAG]]) +! IMPRVD: %[[RHS_IMAG_ABS_IS_ZERO:.*]] = fcmp oeq double %[[RHS_IMAG_ABS]], 0.000000e+00 +! IMPRVD: %[[LHS_REAL_IS_NOT_NAN:.*]] = fcmp ord double %[[LHS_REAL]], 0.000000e+00 +! IMPRVD: %[[LHS_IMAG_IS_NOT_NAN:.*]] = fcmp ord double %[[LHS_IMAG]], 0.000000e+00 +! IMPRVD: %[[LHS_CONTAINS_NOT_NAN_VALUE:.*]] = or i1 %[[LHS_REAL_IS_NOT_NAN]], %[[LHS_IMAG_IS_NOT_NAN]] +! IMPRVD: %[[RHS_IS_ZERO:.*]] = and i1 %[[RHS_REAL_ABS_IS_ZERO]], %[[RHS_IMAG_ABS_IS_ZERO]] +! IMPRVD: %[[RESULT_IS_INFINITY:.*]] = and i1 %[[LHS_CONTAINS_NOT_NAN_VALUE]], %[[RHS_IS_ZERO]] +! IMPRVD: %[[INF_WITH_SIGN_OF_RHS_REAL:.*]] = call double @llvm.copysign.f64(double 0x7FF0000000000000, double %[[RHS_REAL]]) +! IMPRVD: %[[INFINITY_RESULT_REAL:.*]] = fmul contract double %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_REAL]] +! IMPRVD: %[[INFINITY_RESULT_IMAG:.*]] = fmul contract double %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_IMAG]] + +! Case 2. Infinite numerator, finite denominator. +! IMPRVD: %[[RHS_REAL_FINITE:.*]] = fcmp one double %[[RHS_REAL_ABS]], 0x7FF0000000000000 +! IMPRVD: %[[RHS_IMAG_FINITE:.*]] = fcmp one double %[[RHS_IMAG_ABS]], 0x7FF0000000000000 +! IMPRVD: %[[RHS_IS_FINITE:.*]] = and i1 %[[RHS_REAL_FINITE]], %[[RHS_IMAG_FINITE]] +! IMPRVD: %[[LHS_REAL_ABS:.*]] = call contract double @llvm.fabs.f64(double %[[LHS_REAL]]) +! IMPRVD: %[[LHS_REAL_INFINITE:.*]] = fcmp oeq double %[[LHS_REAL_ABS]], 0x7FF0000000000000 +! IMPRVD: %[[LHS_IMAG_ABS:.*]] = call contract double @llvm.fabs.f64(double %[[LHS_IMAG]]) +! IMPRVD: %[[LHS_IMAG_INFINITE:.*]] = fcmp oeq double %[[LHS_IMAG_ABS]], 0x7FF0000000000000 +! IMPRVD: %[[LHS_IS_INFINITE:.*]] = or i1 %[[LHS_REAL_INFINITE]], %[[LHS_IMAG_INFINITE]] +! IMPRVD: %[[INF_NUM_FINITE_DENOM:.*]] = and i1 %[[LHS_IS_INFINITE]], %[[RHS_IS_FINITE]] +! IMPRVD: %[[LHS_REAL_IS_INF:.*]] = select i1 %[[LHS_REAL_INFINITE]], double 1.000000e+00, double 0.000000e+00 +! IMPRVD: %[[LHS_REAL_IS_INF_WITH_SIGN:.*]] = call double @llvm.copysign.f64(double %[[LHS_REAL_IS_INF]], double %[[LHS_REAL]]) +! IMPRVD: %[[LHS_IMAG_IS_INF:.*]] = select i1 %[[LHS_IMAG_INFINITE]], double 1.000000e+00, double 0.000000e+00 +! IMPRVD: %[[LHS_IMAG_IS_INF_WITH_SIGN:.*]] = call double @llvm.copysign.f64(double %[[LHS_IMAG_IS_INF]], double %[[LHS_IMAG]]) +! IMPRVD: %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_REAL:.*]] = fmul contract double %[[LHS_REAL_IS_INF_WITH_SIGN]], %[[RHS_REAL]] +! IMPRVD: %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_IMAG:.*]] = fmul contract double %[[LHS_IMAG_IS_INF_WITH_SIGN]], %[[RHS_IMAG]] +! IMPRVD: %[[INF_MULTIPLICATOR_1:.*]] = fadd contract double %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_REAL]], %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_IMAG]] +! IMPRVD: %[[RESULT_REAL_3:.*]] = fmul contract double %[[INF_MULTIPLICATOR_1]], 0x7FF0000000000000 +! IMPRVD: %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_IMAG:.*]] = fmul contract double %[[LHS_REAL_IS_INF_WITH_SIGN]], %[[RHS_IMAG]] +! IMPRVD: %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_REAL:.*]] = fmul contract double %[[LHS_IMAG_IS_INF_WITH_SIGN]], %[[RHS_REAL]] +! IMPRVD: %[[INF_MULTIPLICATOR_2:.*]] = fsub contract double %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_REAL]], %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_IMAG]] +! IMPRVD: %[[RESULT_IMAG_3:.*]] = fmul contract double %[[INF_MULTIPLICATOR_2]], 0x7FF0000000000000 + +! Case 3. Finite numerator, infinite denominator. +! IMPRVD: %[[LHS_REAL_FINITE:.*]] = fcmp one double %[[LHS_REAL_ABS]], 0x7FF0000000000000 +! IMPRVD: %[[LHS_IMAG_FINITE:.*]] = fcmp one double %[[LHS_IMAG_ABS]], 0x7FF0000000000000 +! IMPRVD: %[[LHS_IS_FINITE:.*]] = and i1 %[[LHS_REAL_FINITE]], %[[LHS_IMAG_FINITE]] +! IMPRVD: %[[RHS_REAL_INFINITE:.*]] = fcmp oeq double %[[RHS_REAL_ABS]], 0x7FF0000000000000 +! IMPRVD: %[[RHS_IMAG_INFINITE:.*]] = fcmp oeq double %[[RHS_IMAG_ABS]], 0x7FF0000000000000 +! IMPRVD: %[[RHS_IS_INFINITE:.*]] = or i1 %[[RHS_REAL_INFINITE]], %[[RHS_IMAG_INFINITE]] +! IMPRVD: %[[FINITE_NUM_INFINITE_DENOM:.*]] = and i1 %[[LHS_IS_FINITE]], %[[RHS_IS_INFINITE]] +! IMPRVD: %[[RHS_REAL_IS_INF:.*]] = select i1 %[[RHS_REAL_INFINITE]], double 1.000000e+00, double 0.000000e+00 +! IMPRVD: %[[RHS_REAL_IS_INF_WITH_SIGN:.*]] = call double @llvm.copysign.f64(double %[[RHS_REAL_IS_INF]], double %[[RHS_REAL]]) +! IMPRVD: %[[RHS_IMAG_IS_INF:.*]] = select i1 %[[RHS_IMAG_INFINITE]], double 1.000000e+00, double 0.000000e+00 +! IMPRVD: %[[RHS_IMAG_IS_INF_WITH_SIGN:.*]] = call double @llvm.copysign.f64(double %[[RHS_IMAG_IS_INF]], double %[[RHS_IMAG]]) +! IMPRVD: %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_REAL:.*]] = fmul contract double %[[LHS_REAL]], %[[RHS_REAL_IS_INF_WITH_SIGN]] +! IMPRVD: %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_IMAG:.*]] = fmul contract double %[[LHS_IMAG]], %[[RHS_IMAG_IS_INF_WITH_SIGN]] +! IMPRVD: %[[ZERO_MULTIPLICATOR_1:.*]] = fadd contract double %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_REAL]], %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_IMAG]] +! IMPRVD: %[[RESULT_REAL_4:.*]] = fmul contract double %[[ZERO_MULTIPLICATOR_1]], 0.000000e+00 +! IMPRVD: %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_IMAG:.*]] = fmul contract double %[[LHS_IMAG]], %[[RHS_REAL_IS_INF_WITH_SIGN]] +! IMPRVD: %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_REAL:.*]] = fmul contract double %[[LHS_REAL]], %[[RHS_IMAG_IS_INF_WITH_SIGN]] +! IMPRVD: %[[ZERO_MULTIPLICATOR_2:.*]] = fsub contract double %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_IMAG]], %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_REAL]] +! IMPRVD: %[[RESULT_IMAG_4:.*]] = fmul contract double %[[ZERO_MULTIPLICATOR_2]], 0.000000e+00 + +! IMPRVD: %[[REAL_ABS_SMALLER_THAN_IMAG_ABS:.*]] = fcmp olt double %[[RHS_REAL_ABS]], %[[RHS_IMAG_ABS]] +! IMPRVD: %[[RESULT_REAL:.*]] = select i1 %[[REAL_ABS_SMALLER_THAN_IMAG_ABS]], double %[[RESULT_REAL_1]], double %[[RESULT_REAL_2]] +! IMPRVD: %[[RESULT_IMAG:.*]] = select i1 %[[REAL_ABS_SMALLER_THAN_IMAG_ABS]], double %[[RESULT_IMAG_1]], double %[[RESULT_IMAG_2]] +! IMPRVD: %[[RESULT_REAL_SPECIAL_CASE_3:.*]] = select i1 %[[FINITE_NUM_INFINITE_DENOM]], double %[[RESULT_REAL_4]], double %[[RESULT_REAL]] +! IMPRVD: %[[RESULT_IMAG_SPECIAL_CASE_3:.*]] = select i1 %[[FINITE_NUM_INFINITE_DENOM]], double %[[RESULT_IMAG_4]], double %[[RESULT_IMAG]] +! IMPRVD: %[[RESULT_REAL_SPECIAL_CASE_2:.*]] = select i1 %[[INF_NUM_FINITE_DENOM]], double %[[RESULT_REAL_3]], double %[[RESULT_REAL_SPECIAL_CASE_3]] +! IMPRVD: %[[RESULT_IMAG_SPECIAL_CASE_2:.*]] = select i1 %[[INF_NUM_FINITE_DENOM]], double %[[RESULT_IMAG_3]], double %[[RESULT_IMAG_SPECIAL_CASE_3]] +! IMPRVD: %[[RESULT_REAL_SPECIAL_CASE_1:.*]] = select i1 %[[RESULT_IS_INFINITY]], double %[[INFINITY_RESULT_REAL]], double %[[RESULT_REAL_SPECIAL_CASE_2]] +! IMPRVD: %[[RESULT_IMAG_SPECIAL_CASE_1:.*]] = select i1 %[[RESULT_IS_INFINITY]], double %[[INFINITY_RESULT_IMAG]], double %[[RESULT_IMAG_SPECIAL_CASE_2]] +! IMPRVD: %[[RESULT_REAL_IS_NAN:.*]] = fcmp uno double %[[RESULT_REAL]], 0.000000e+00 +! IMPRVD: %[[RESULT_IMAG_IS_NAN:.*]] = fcmp uno double %[[RESULT_IMAG]], 0.000000e+00 +! IMPRVD: %[[RESULT_IS_NAN:.*]] = and i1 %[[RESULT_REAL_IS_NAN]], %[[RESULT_IMAG_IS_NAN]] +! IMPRVD: %[[RESULT_REAL_WITH_SPECIAL_CASES:.*]] = select i1 %[[RESULT_IS_NAN]], double %[[RESULT_REAL_SPECIAL_CASE_1]], double %[[RESULT_REAL]] +! IMPRVD: %[[RESULT_IMAG_WITH_SPECIAL_CASES:.*]] = select i1 %[[RESULT_IS_NAN]], double %[[RESULT_IMAG_SPECIAL_CASE_1]], double %[[RESULT_IMAG]] +! IMPRVD: %[[RESULT_1:.*]] = insertvalue { double, double } poison, double %[[RESULT_REAL_WITH_SPECIAL_CASES]], 0 +! IMPRVD: %[[RESULT_2:.*]] = insertvalue { double, double } %[[RESULT_1]], double %[[RESULT_IMAG_WITH_SPECIAL_CASES]], 1 +! IMPRVD: store { double, double } %[[RESULT_2]], ptr %[[RET]], align 8 + +! BASIC-DAG: %[[RHS_REAL_SQ:.*]] = fmul contract double %[[RHS_REAL]], %[[RHS_REAL]] +! BASIC-DAG: %[[RHS_IMAG_SQ:.*]] = fmul contract double %[[RHS_IMAG]], %[[RHS_IMAG]] +! BASIC: %[[SQ_NORM:.*]] = fadd contract double %[[RHS_REAL_SQ]], %[[RHS_IMAG_SQ]] +! BASIC-DAG: %[[REAL_TMP_0:.*]] = fmul contract double %[[LHS_REAL]], %[[RHS_REAL]] +! BASIC-DAG: %[[REAL_TMP_1:.*]] = fmul contract double %[[LHS_IMAG]], %[[RHS_IMAG]] +! BASIC: %[[REAL_TMP_2:.*]] = fadd contract double %[[REAL_TMP_0]], %[[REAL_TMP_1]] +! BASIC-DAG: %[[IMAG_TMP_0:.*]] = fmul contract double %[[LHS_IMAG]], %[[RHS_REAL]] +! BASIC-DAG: %[[IMAG_TMP_1:.*]] = fmul contract double %[[LHS_REAL]], %[[RHS_IMAG]] +! BASIC: %[[IMAG_TMP_2:.*]] = fsub contract double %[[IMAG_TMP_0]], %[[IMAG_TMP_1]] +! BASIC: %[[REAL:.*]] = fdiv contract double %[[REAL_TMP_2]], %[[SQ_NORM]] +! BASIC: %[[IMAG:.*]] = fdiv contract double %[[IMAG_TMP_2]], %[[SQ_NORM]] +! BASIC: %[[RESULT_1:.*]] = insertvalue { double, double } poison, double %[[REAL]], 0 +! BASIC: %[[RESULT_2:.*]] = insertvalue { double, double } %[[RESULT_1]], double %[[IMAG]], 1 +! BASIC: store { double, double } %[[RESULT_2]], ptr %[[RET]], align 8 + +! CHECK: ret void +subroutine div_test_double(a,b,c) + complex(kind=8) :: a, b, c + a = b / c +end subroutine div_test_double diff --git a/flang/test/Lower/HLFIR/complex-div-to-hlfir-kind10.f90 b/flang/test/Lower/HLFIR/complex-div-to-hlfir-kind10.f90 new file mode 100644 index 0000000000000..0e219e30ec94b --- /dev/null +++ b/flang/test/Lower/HLFIR/complex-div-to-hlfir-kind10.f90 @@ -0,0 +1,34 @@ +! Test lowering of complex division according to options + +! REQUIRES: target=x86_64{{.*}} +! RUN: bbc -complex-range=full -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,FULL +! RUN: bbc -complex-range=improved -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,IMPRVD +! RUN: bbc -complex-range=basic -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,BASIC +! RUN: %flang_fc1 -complex-range=full -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,FULL +! RUN: %flang_fc1 -complex-range=improved -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,IMPRVD +! RUN: %flang_fc1 -complex-range=basic -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,BASIC + +! CHECK-LABEL: @_QPdiv_test_extended +! CHECK-SAME: %[[REF_0:.*]]: !fir.ref> {{.*}}, %[[REF_1:.*]]: !fir.ref> {{.*}}, %[[REF_2:.*]]: !fir.ref> {{.*}}) +! CHECK: %[[VAL_3:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[REF_0]] dummy_scope %[[VAL_3]] {uniq_name = "_QFdiv_test_extendedEa"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[REF_1]] dummy_scope %[[VAL_3]] {uniq_name = "_QFdiv_test_extendedEb"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[REF_2]] dummy_scope %[[VAL_3]] {uniq_name = "_QFdiv_test_extendedEc"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref> +! CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref> + +! FULL: %[[VAL_9:.*]] = fir.extract_value %[[VAL_7]], [0 : index] : (complex) -> f80 +! FULL: %[[VAL_10:.*]] = fir.extract_value %[[VAL_7]], [1 : index] : (complex) -> f80 +! FULL: %[[VAL_11:.*]] = fir.extract_value %[[VAL_8]], [0 : index] : (complex) -> f80 +! FULL: %[[VAL_12:.*]] = fir.extract_value %[[VAL_8]], [1 : index] : (complex) -> f80 +! FULL: %[[VAL_RET:.*]] = fir.call @__divxc3(%[[VAL_9]], %[[VAL_10]], %[[VAL_11]], %[[VAL_12]]) fastmath : (f80, f80, f80, f80) -> complex + +! IMPRVD: %[[VAL_RET:.*]] = complex.div %[[VAL_7]], %[[VAL_8]] fastmath : complex +! BASIC: %[[VAL_RET:.*]] = complex.div %[[VAL_7]], %[[VAL_8]] fastmath : complex + +! CHECK: hlfir.assign %[[VAL_RET]] to %[[VAL_4]]#0 : complex, !fir.ref> +! CHECK: return +subroutine div_test_extended(a,b,c) + complex(kind=10) :: a, b, c + a = b / c +end subroutine div_test_extended diff --git a/flang/test/Lower/HLFIR/complex-div-to-hlfir-kind16.f90 b/flang/test/Lower/HLFIR/complex-div-to-hlfir-kind16.f90 new file mode 100644 index 0000000000000..fe4a7256a4a16 --- /dev/null +++ b/flang/test/Lower/HLFIR/complex-div-to-hlfir-kind16.f90 @@ -0,0 +1,35 @@ +! Test lowering of complex division according to options + +! REQUIRES: flang-supports-f128-math +! RUN: bbc -complex-range=full -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,FULL +! RUN: bbc -complex-range=improved -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,IMPRVD +! RUN: bbc -complex-range=basic -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,BASIC +! RUN: %flang_fc1 -complex-range=full -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,FULL +! RUN: %flang_fc1 -complex-range=improved -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,IMPRVD +! RUN: %flang_fc1 -complex-range=basic -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,BASIC + + +! CHECK-LABEL: @_QPdiv_test_quad +! CHECK-SAME: %[[REF_0:.*]]: !fir.ref> {{.*}}, %[[REF_1:.*]]: !fir.ref> {{.*}}, %[[REF_2:.*]]: !fir.ref> {{.*}}) +! CHECK: %[[VAL_3:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[REF_0]] dummy_scope %[[VAL_3]] {uniq_name = "_QFdiv_test_quadEa"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[REF_1]] dummy_scope %[[VAL_3]] {uniq_name = "_QFdiv_test_quadEb"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[REF_2]] dummy_scope %[[VAL_3]] {uniq_name = "_QFdiv_test_quadEc"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref> +! CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref> + +! FULL: %[[VAL_9:.*]] = fir.extract_value %[[VAL_7]], [0 : index] : (complex) -> f128 +! FULL: %[[VAL_10:.*]] = fir.extract_value %[[VAL_7]], [1 : index] : (complex) -> f128 +! FULL: %[[VAL_11:.*]] = fir.extract_value %[[VAL_8]], [0 : index] : (complex) -> f128 +! FULL: %[[VAL_12:.*]] = fir.extract_value %[[VAL_8]], [1 : index] : (complex) -> f128 +! FULL: %[[VAL_RET:.*]] = fir.call @__divtc3(%[[VAL_9]], %[[VAL_10]], %[[VAL_11]], %[[VAL_12]]) fastmath : (f128, f128, f128, f128) -> complex + +! IMPRVD: %[[VAL_RET:.*]] = complex.div %[[VAL_7]], %[[VAL_8]] fastmath : complex +! BASIC: %[[VAL_RET:.*]] = complex.div %[[VAL_7]], %[[VAL_8]] fastmath : complex + +! CHECK: hlfir.assign %[[VAL_RET]] to %[[VAL_4]]#0 : complex, !fir.ref> +! CHECK: return +subroutine div_test_quad(a,b,c) + complex(kind=16) :: a, b, c + a = b / c +end subroutine div_test_quad diff --git a/flang/test/Lower/HLFIR/complex-div-to-hlfir.f90 b/flang/test/Lower/HLFIR/complex-div-to-hlfir.f90 new file mode 100644 index 0000000000000..b488bfde4ee85 --- /dev/null +++ b/flang/test/Lower/HLFIR/complex-div-to-hlfir.f90 @@ -0,0 +1,94 @@ +! Test lowering of complex division according to options + +! RUN: bbc -complex-range=full -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,FULL +! RUN: bbc -complex-range=improved -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,IMPRVD +! RUN: bbc -complex-range=basic -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,BASIC +! RUN: %flang_fc1 -complex-range=full -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,FULL +! RUN: %flang_fc1 -complex-range=improved -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,IMPRVD +! RUN: %flang_fc1 -complex-range=basic -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,BASIC + + +! CHECK-LABEL: @_QPdiv_test_half +! CHECK-SAME: %[[REF_0:.*]]: !fir.ref> {{.*}}, %[[REF_1:.*]]: !fir.ref> {{.*}}, %[[REF_2:.*]]: !fir.ref> {{.*}}) +! CHECK: %[[VAL_3:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[REF_0]] dummy_scope %[[VAL_3]] {uniq_name = "_QFdiv_test_halfEa"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[REF_1]] dummy_scope %[[VAL_3]] {uniq_name = "_QFdiv_test_halfEb"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[REF_2]] dummy_scope %[[VAL_3]] {uniq_name = "_QFdiv_test_halfEc"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref> +! CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref> +! CHECK: %[[VAL_9:.*]] = complex.div %[[VAL_7]], %[[VAL_8]] fastmath : complex +! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_4]]#0 : complex, !fir.ref> +! CHECK: return +subroutine div_test_half(a,b,c) + complex(kind=2) :: a, b, c + a = b / c +end subroutine div_test_half + + +! CHECK-LABEL: @_QPdiv_test_bfloat +! CHECK-SAME: %[[REF_0:.*]]: !fir.ref> {{.*}}, %[[REF_1:.*]]: !fir.ref> {{.*}}, %[[REF_2:.*]]: !fir.ref> {{.*}}) +! CHECK: %[[VAL_3:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[REF_0]] dummy_scope %[[VAL_3]] {uniq_name = "_QFdiv_test_bfloatEa"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[REF_1]] dummy_scope %[[VAL_3]] {uniq_name = "_QFdiv_test_bfloatEb"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[REF_2]] dummy_scope %[[VAL_3]] {uniq_name = "_QFdiv_test_bfloatEc"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref> +! CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref> +! CHECK: %[[VAL_9:.*]] = complex.div %[[VAL_7]], %[[VAL_8]] fastmath : complex +! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_4]]#0 : complex, !fir.ref> +! CHECK: return +subroutine div_test_bfloat(a,b,c) + complex(kind=3) :: a, b, c + a = b / c +end subroutine div_test_bfloat + + +! CHECK-LABEL: @_QPdiv_test_single +! CHECK-SAME: %[[REF_0:.*]]: !fir.ref> {{.*}}, %[[REF_1:.*]]: !fir.ref> {{.*}}, %[[REF_2:.*]]: !fir.ref> {{.*}}) +! CHECK: %[[VAL_3:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[REF_0]] dummy_scope %[[VAL_3]] {uniq_name = "_QFdiv_test_singleEa"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[REF_1]] dummy_scope %[[VAL_3]] {uniq_name = "_QFdiv_test_singleEb"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[REF_2]] dummy_scope %[[VAL_3]] {uniq_name = "_QFdiv_test_singleEc"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref> +! CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref> + +! FULL: %[[VAL_9:.*]] = fir.extract_value %[[VAL_7]], [0 : index] : (complex) -> f32 +! FULL: %[[VAL_10:.*]] = fir.extract_value %[[VAL_7]], [1 : index] : (complex) -> f32 +! FULL: %[[VAL_11:.*]] = fir.extract_value %[[VAL_8]], [0 : index] : (complex) -> f32 +! FULL: %[[VAL_12:.*]] = fir.extract_value %[[VAL_8]], [1 : index] : (complex) -> f32 +! FULL: %[[VAL_RET:.*]] = fir.call @__divsc3(%[[VAL_9]], %[[VAL_10]], %[[VAL_11]], %[[VAL_12]]) fastmath : (f32, f32, f32, f32) -> complex + +! IMPRVD: %[[VAL_RET:.*]] = complex.div %[[VAL_7]], %[[VAL_8]] fastmath : complex +! BASIC: %[[VAL_RET:.*]] = complex.div %[[VAL_7]], %[[VAL_8]] fastmath : complex + +! CHECK: hlfir.assign %[[VAL_RET]] to %[[VAL_4]]#0 : complex, !fir.ref> +! CHECK: return +subroutine div_test_single(a,b,c) + complex(kind=4) :: a, b, c + a = b / c +end subroutine div_test_single + + +! CHECK-LABEL: @_QPdiv_test_double +! CHECK-SAME: %[[REF_0:.*]]: !fir.ref> {{.*}}, %[[REF_1:.*]]: !fir.ref> {{.*}}, %[[REF_2:.*]]: !fir.ref> {{.*}}) +! CHECK: %[[VAL_3:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[REF_0]] dummy_scope %[[VAL_3]] {uniq_name = "_QFdiv_test_doubleEa"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[REF_1]] dummy_scope %[[VAL_3]] {uniq_name = "_QFdiv_test_doubleEb"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[REF_2]] dummy_scope %[[VAL_3]] {uniq_name = "_QFdiv_test_doubleEc"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref> +! CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref> + +! FULL: %[[VAL_9:.*]] = fir.extract_value %[[VAL_7]], [0 : index] : (complex) -> f64 +! FULL: %[[VAL_10:.*]] = fir.extract_value %[[VAL_7]], [1 : index] : (complex) -> f64 +! FULL: %[[VAL_11:.*]] = fir.extract_value %[[VAL_8]], [0 : index] : (complex) -> f64 +! FULL: %[[VAL_12:.*]] = fir.extract_value %[[VAL_8]], [1 : index] : (complex) -> f64 +! FULL: %[[VAL_RET:.*]] = fir.call @__divdc3(%[[VAL_9]], %[[VAL_10]], %[[VAL_11]], %[[VAL_12]]) fastmath : (f64, f64, f64, f64) -> complex + +! IMPRVD: %[[VAL_RET:.*]] = complex.div %[[VAL_7]], %[[VAL_8]] fastmath : complex +! BASIC: %[[VAL_RET:.*]] = complex.div %[[VAL_7]], %[[VAL_8]] fastmath : complex + +! CHECK: hlfir.assign %[[VAL_RET]] to %[[VAL_4]]#0 : complex, !fir.ref> +! CHECK: return +subroutine div_test_double(a,b,c) + complex(kind=8) :: a, b, c + a = b / c +end subroutine div_test_double diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp index 59372a8eb58ed..2ccbe8b96d805 100644 --- a/flang/tools/bbc/bbc.cpp +++ b/flang/tools/bbc/bbc.cpp @@ -276,6 +276,12 @@ static llvm::cl::opt "leading dimension will be repacked"), llvm::cl::init(true)); +static llvm::cl::opt complexRange( + "complex-range", + llvm::cl::desc("Controls the various implementations for complex " + "multiplication and division [full|improved|basic]"), + llvm::cl::init("")); + #define FLANG_EXCLUDE_CODEGEN #include "flang/Optimizer/Passes/CommandLineOpts.h" #include "flang/Optimizer/Passes/Pipelines.h" @@ -437,6 +443,8 @@ static llvm::LogicalResult convertFortranSourceToMLIR( loweringOptions.setSkipExternalRttiDefinition(skipExternalRttiDefinition); if (enableCUDA) loweringOptions.setCUDARuntimeCheck(true); + if (complexRange == "improved" || complexRange == "basic") + loweringOptions.setComplexDivisionToRuntime(false); std::vector envDefaults = {}; Fortran::frontend::TargetOptions targetOpts; Fortran::frontend::CodeGenOptions cgOpts;