[Mlir-commits] [mlir] [mlir][complex] Add complex-range option and select complex division … (PR #127010)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed Feb 12 20:27:19 PST 2025
https://github.com/s-watanabe314 created https://github.com/llvm/llvm-project/pull/127010
…algorithm
This patch adds the `complex-range` option and two calculation methods for complex number division (algebraic method and Smith's algorithm) to both the `ComplexToLLVM` and `ComplexToStandard` passes, allowing the calculation method to be controlled by the option.
See also the discussion in the following discourse post.
https://discourse.llvm.org/t/question-and-proposal-regarding-complex-number-division-algorithm-in-the-complex-dialect/83772
>From eaeaf2f4e96136367cb15ba18fd93ae493eff40f Mon Sep 17 00:00:00 2001
From: s-watanabe314 <watanabe.shu-06 at fujitsu.com>
Date: Tue, 28 Jan 2025 13:59:17 +0900
Subject: [PATCH] [mlir][complex] Add complex-range option and select complex
division algorithm
This patch adds the `complex-range` option and two calculation methods
for complex number division (algebraic method and Smith's algorithm)
to both the `ComplexToLLVM` and `ComplexToStandard` passes, allowing
the calculation method to be controlled by the option.
See also the discussion in the following discourse post.
https://discourse.llvm.org/t/question-and-proposal-regarding-complex-number-division-algorithm-in-the-complex-dialect/83772
---
.../ComplexCommon/DivisionConverter.h | 48 ++
.../Conversion/ComplexToLLVM/ComplexToLLVM.h | 8 +-
.../ComplexToStandard/ComplexToStandard.h | 9 +-
mlir/include/mlir/Conversion/Passes.td | 22 +
.../mlir/Dialect/Complex/IR/CMakeLists.txt | 2 +
.../include/mlir/Dialect/Complex/IR/Complex.h | 6 +
.../mlir/Dialect/Complex/IR/ComplexBase.td | 16 +
mlir/lib/Conversion/CMakeLists.txt | 1 +
.../Conversion/ComplexCommon/CMakeLists.txt | 12 +
.../ComplexCommon/DivisionConverter.cpp | 456 ++++++++++++++++++
.../Conversion/ComplexToLLVM/CMakeLists.txt | 1 +
.../ComplexToLLVM/ComplexToLLVM.cpp | 44 +-
.../ComplexToStandard/CMakeLists.txt | 1 +
.../ComplexToStandard/ComplexToStandard.cpp | 243 ++--------
.../ComplexToLLVM/complex-range-option.mlir | 303 ++++++++++++
.../ComplexToLLVM/convert-to-llvm.mlir | 4 +-
.../ComplexToLLVM/full-conversion.mlir | 2 +-
.../complex-range-option.mlir | 277 +++++++++++
18 files changed, 1223 insertions(+), 232 deletions(-)
create mode 100644 mlir/include/mlir/Conversion/ComplexCommon/DivisionConverter.h
create mode 100644 mlir/lib/Conversion/ComplexCommon/CMakeLists.txt
create mode 100644 mlir/lib/Conversion/ComplexCommon/DivisionConverter.cpp
create mode 100644 mlir/test/Conversion/ComplexToLLVM/complex-range-option.mlir
create mode 100644 mlir/test/Conversion/ComplexToStandard/complex-range-option.mlir
diff --git a/mlir/include/mlir/Conversion/ComplexCommon/DivisionConverter.h b/mlir/include/mlir/Conversion/ComplexCommon/DivisionConverter.h
new file mode 100644
index 0000000000000..df97dc2c4eb7d
--- /dev/null
+++ b/mlir/include/mlir/Conversion/ComplexCommon/DivisionConverter.h
@@ -0,0 +1,48 @@
+//===- DivisionConverter.h - Complex division conversion ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_CONVERSION_COMPLEXCOMMON_DIVISIONCONVERTER_H
+#define MLIR_CONVERSION_COMPLEXCOMMON_DIVISIONCONVERTER_H
+
+#include "mlir/Conversion/LLVMCommon/ConversionTarget.h"
+#include "mlir/Dialect/Arith/IR/Arith.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+
+namespace mlir {
+namespace complex {
+/// convert a complex division to the LLVM dialect using algebraic method
+void convertDivToLLVMUsingAlgebraic(ConversionPatternRewriter &rewriter,
+ Location loc, Value lhsRe, Value lhsIm,
+ Value rhsRe, Value rhsIm,
+ LLVM::FastmathFlagsAttr fmf,
+ Value *resultRe, Value *resultIm);
+
+/// convert a complex division to the arith/math dialects using algebraic method
+void convertDivToStandardUsingAlgebraic(ConversionPatternRewriter &rewriter,
+ Location loc, Value lhsRe, Value lhsIm,
+ Value rhsRe, Value rhsIm,
+ arith::FastMathFlagsAttr fmf,
+ Value *resultRe, Value *resultIm);
+
+/// convert a complex division to the LLVM dialect using Smith's method
+void convertDivToLLVMUsingRangeReduction(ConversionPatternRewriter &rewriter,
+ Location loc, Value lhsRe, Value lhsIm,
+ Value rhsRe, Value rhsIm,
+ LLVM::FastmathFlagsAttr fmf,
+ Value *resultRe, Value *resultIm);
+
+/// convert a complex division to the arith/math dialects using Smith's method
+void convertDivToStandardUsingRangeReduction(
+ ConversionPatternRewriter &rewriter, Location loc, Value lhsRe, Value lhsIm,
+ Value rhsRe, Value rhsIm, arith::FastMathFlagsAttr fmf, Value *resultRe,
+ Value *resultIm);
+
+} // namespace complex
+} // namespace mlir
+
+#endif // MLIR_CONVERSION_COMPLEXCOMMON_DIVISIONCONVERTER_H
diff --git a/mlir/include/mlir/Conversion/ComplexToLLVM/ComplexToLLVM.h b/mlir/include/mlir/Conversion/ComplexToLLVM/ComplexToLLVM.h
index 8266442cf5db8..1db75563fe304 100644
--- a/mlir/include/mlir/Conversion/ComplexToLLVM/ComplexToLLVM.h
+++ b/mlir/include/mlir/Conversion/ComplexToLLVM/ComplexToLLVM.h
@@ -9,6 +9,8 @@
#define MLIR_CONVERSION_COMPLEXTOLLVM_COMPLEXTOLLVM_H_
#include "mlir/Conversion/LLVMCommon/StructBuilder.h"
+#include "mlir/Dialect/Complex/IR/Complex.h"
+#include "mlir/Pass/Pass.h"
namespace mlir {
class DialectRegistry;
@@ -39,8 +41,10 @@ class ComplexStructBuilder : public StructBuilder {
};
/// Populate the given list with patterns that convert from Complex to LLVM.
-void populateComplexToLLVMConversionPatterns(const LLVMTypeConverter &converter,
- RewritePatternSet &patterns);
+void populateComplexToLLVMConversionPatterns(
+ const LLVMTypeConverter &converter, RewritePatternSet &patterns,
+ mlir::complex::ComplexRangeFlags complexRange =
+ mlir::complex::ComplexRangeFlags::basic);
void registerConvertComplexToLLVMInterface(DialectRegistry ®istry);
diff --git a/mlir/include/mlir/Conversion/ComplexToStandard/ComplexToStandard.h b/mlir/include/mlir/Conversion/ComplexToStandard/ComplexToStandard.h
index 39c4a1ae54617..30b86cac9cd4e 100644
--- a/mlir/include/mlir/Conversion/ComplexToStandard/ComplexToStandard.h
+++ b/mlir/include/mlir/Conversion/ComplexToStandard/ComplexToStandard.h
@@ -8,6 +8,8 @@
#ifndef MLIR_CONVERSION_COMPLEXTOSTANDARD_COMPLEXTOSTANDARD_H_
#define MLIR_CONVERSION_COMPLEXTOSTANDARD_COMPLEXTOSTANDARD_H_
+#include "mlir/Dialect/Complex/IR/Complex.h"
+#include "mlir/Pass/Pass.h"
#include <memory>
namespace mlir {
@@ -18,10 +20,15 @@ class Pass;
#include "mlir/Conversion/Passes.h.inc"
/// Populate the given list with patterns that convert from Complex to Standard.
-void populateComplexToStandardConversionPatterns(RewritePatternSet &patterns);
+void populateComplexToStandardConversionPatterns(
+ RewritePatternSet &patterns,
+ mlir::complex::ComplexRangeFlags complexRange =
+ mlir::complex::ComplexRangeFlags::improved);
/// Create a pass to convert Complex operations to the Standard dialect.
std::unique_ptr<Pass> createConvertComplexToStandardPass();
+std::unique_ptr<Pass>
+createConvertComplexToStandardPass(ConvertComplexToStandardOptions options);
} // namespace mlir
diff --git a/mlir/include/mlir/Conversion/Passes.td b/mlir/include/mlir/Conversion/Passes.td
index ff79a1226c047..5203838a6eb35 100644
--- a/mlir/include/mlir/Conversion/Passes.td
+++ b/mlir/include/mlir/Conversion/Passes.td
@@ -274,6 +274,17 @@ def ConvertBufferizationToMemRef : Pass<"convert-bufferization-to-memref"> {
def ConvertComplexToLLVMPass : Pass<"convert-complex-to-llvm"> {
let summary = "Convert Complex dialect to LLVM dialect";
let dependentDialects = ["LLVM::LLVMDialect"];
+
+ let options = [
+ Option<"complexRange", "complex-range", "::mlir::complex::ComplexRangeFlags",
+ /*default=*/"::mlir::complex::ComplexRangeFlags::basic",
+ "Control the intermediate calculation of complex number division",
+ [{::llvm::cl::values(
+ clEnumValN(::mlir::complex::ComplexRangeFlags::improved, "improved", "improved"),
+ clEnumValN(::mlir::complex::ComplexRangeFlags::basic, "basic", "basic (default)"),
+ clEnumValN(::mlir::complex::ComplexRangeFlags::none, "none", "none")
+ )}]>,
+ ];
}
//===----------------------------------------------------------------------===//
@@ -308,6 +319,17 @@ def ConvertComplexToStandard : Pass<"convert-complex-to-standard"> {
let summary = "Convert Complex dialect to standard dialect";
let constructor = "mlir::createConvertComplexToStandardPass()";
let dependentDialects = ["math::MathDialect"];
+
+ let options = [
+ Option<"complexRange", "complex-range", "::mlir::complex::ComplexRangeFlags",
+ /*default=*/"::mlir::complex::ComplexRangeFlags::improved",
+ "Control the intermediate calculation of complex number division",
+ [{::llvm::cl::values(
+ clEnumValN(::mlir::complex::ComplexRangeFlags::improved, "improved", "improved (default)"),
+ clEnumValN(::mlir::complex::ComplexRangeFlags::basic, "basic", "basic"),
+ clEnumValN(::mlir::complex::ComplexRangeFlags::none, "none", "none")
+ )}]>,
+ ];
}
//===----------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/Dialect/Complex/IR/CMakeLists.txt b/mlir/include/mlir/Dialect/Complex/IR/CMakeLists.txt
index f41888d01a2fd..837664e25b3c2 100644
--- a/mlir/include/mlir/Dialect/Complex/IR/CMakeLists.txt
+++ b/mlir/include/mlir/Dialect/Complex/IR/CMakeLists.txt
@@ -2,6 +2,8 @@ add_mlir_dialect(ComplexOps complex)
add_mlir_doc(ComplexOps ComplexOps Dialects/ -gen-dialect-doc -dialect=complex)
set(LLVM_TARGET_DEFINITIONS ComplexAttributes.td)
+mlir_tablegen(ComplexEnums.h.inc -gen-enum-decls)
+mlir_tablegen(ComplexEnums.cpp.inc -gen-enum-defs)
mlir_tablegen(ComplexAttributes.h.inc -gen-attrdef-decls)
mlir_tablegen(ComplexAttributes.cpp.inc -gen-attrdef-defs)
add_public_tablegen_target(MLIRComplexAttributesIncGen)
diff --git a/mlir/include/mlir/Dialect/Complex/IR/Complex.h b/mlir/include/mlir/Dialect/Complex/IR/Complex.h
index fb024fa2e951e..be7e50d656385 100644
--- a/mlir/include/mlir/Dialect/Complex/IR/Complex.h
+++ b/mlir/include/mlir/Dialect/Complex/IR/Complex.h
@@ -22,6 +22,12 @@
#include "mlir/Dialect/Complex/IR/ComplexOpsDialect.h.inc"
+//===----------------------------------------------------------------------===//
+// Complex Dialect Enums
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/Complex/IR/ComplexEnums.h.inc"
+
//===----------------------------------------------------------------------===//
// Complex Dialect Operations
//===----------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/Dialect/Complex/IR/ComplexBase.td b/mlir/include/mlir/Dialect/Complex/IR/ComplexBase.td
index 31135fc8c8ce7..c8af498f44829 100644
--- a/mlir/include/mlir/Dialect/Complex/IR/ComplexBase.td
+++ b/mlir/include/mlir/Dialect/Complex/IR/ComplexBase.td
@@ -9,6 +9,7 @@
#ifndef COMPLEX_BASE
#define COMPLEX_BASE
+include "mlir/IR/EnumAttr.td"
include "mlir/IR/OpBase.td"
def Complex_Dialect : Dialect {
@@ -24,4 +25,19 @@ def Complex_Dialect : Dialect {
let useDefaultAttributePrinterParser = 1;
}
+//===----------------------------------------------------------------------===//
+// Complex_ComplexRangeFlags
+//===----------------------------------------------------------------------===//
+
+def Complex_CRF_improved : I32BitEnumAttrCaseBit<"improved", 0>;
+def Complex_CRF_basic : I32BitEnumAttrCaseBit<"basic", 1>;
+def Complex_CRF_none : I32BitEnumAttrCaseBit<"none", 2>;
+
+def Complex_ComplexRangeFlags : I32BitEnumAttr<
+ "ComplexRangeFlags",
+ "Complex range flags",
+ [Complex_CRF_improved, Complex_CRF_basic, Complex_CRF_none]> {
+ let cppNamespace = "::mlir::complex";
+}
+
#endif // COMPLEX_BASE
diff --git a/mlir/lib/Conversion/CMakeLists.txt b/mlir/lib/Conversion/CMakeLists.txt
index 0bd08ec6333e6..fa904a33ebf96 100644
--- a/mlir/lib/Conversion/CMakeLists.txt
+++ b/mlir/lib/Conversion/CMakeLists.txt
@@ -11,6 +11,7 @@ add_subdirectory(ArmSMEToSCF)
add_subdirectory(ArmSMEToLLVM)
add_subdirectory(AsyncToLLVM)
add_subdirectory(BufferizationToMemRef)
+add_subdirectory(ComplexCommon)
add_subdirectory(ComplexToLibm)
add_subdirectory(ComplexToLLVM)
add_subdirectory(ComplexToSPIRV)
diff --git a/mlir/lib/Conversion/ComplexCommon/CMakeLists.txt b/mlir/lib/Conversion/ComplexCommon/CMakeLists.txt
new file mode 100644
index 0000000000000..2560a4a5631f4
--- /dev/null
+++ b/mlir/lib/Conversion/ComplexCommon/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_mlir_conversion_library(MLIRComplexDivisionConversion
+ DivisionConverter.cpp
+
+ LINK_COMPONENTS
+ Core
+
+ LINK_LIBS PUBLIC
+ MLIRArithDialect
+ MLIRComplexDialect
+ MLIRLLVMDialect
+ MLIRMathDialect
+ )
diff --git a/mlir/lib/Conversion/ComplexCommon/DivisionConverter.cpp b/mlir/lib/Conversion/ComplexCommon/DivisionConverter.cpp
new file mode 100644
index 0000000000000..cce9cc77c3a4c
--- /dev/null
+++ b/mlir/lib/Conversion/ComplexCommon/DivisionConverter.cpp
@@ -0,0 +1,456 @@
+//===- DivisionConverter.cpp - Complex division conversion ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements functions for two different complex number division
+// algorithms, the `algebraic formula` and `Smith's range reduction method`.
+// These are used in two conversions: `ComplexToLLVM` and `ComplexToStandard`.
+// When modifying the algorithms, both `ToLLVM` and `ToStandard` must be
+// changed.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Conversion/ComplexCommon/DivisionConverter.h"
+#include "mlir/Dialect/Math/IR/Math.h"
+
+using namespace mlir;
+
+void mlir::complex::convertDivToLLVMUsingAlgebraic(
+ ConversionPatternRewriter &rewriter, Location loc, Value lhsRe, Value lhsIm,
+ Value rhsRe, Value rhsIm, LLVM::FastmathFlagsAttr fmf, Value *resultRe,
+ Value *resultIm) {
+ Value rhsSqNorm = rewriter.create<LLVM::FAddOp>(
+ loc, rewriter.create<LLVM::FMulOp>(loc, rhsRe, rhsRe, fmf),
+ rewriter.create<LLVM::FMulOp>(loc, rhsIm, rhsIm, fmf), fmf);
+
+ Value realNumerator = rewriter.create<LLVM::FAddOp>(
+ loc, rewriter.create<LLVM::FMulOp>(loc, lhsRe, rhsRe, fmf),
+ rewriter.create<LLVM::FMulOp>(loc, lhsIm, rhsIm, fmf), fmf);
+
+ Value imagNumerator = rewriter.create<LLVM::FSubOp>(
+ loc, rewriter.create<LLVM::FMulOp>(loc, lhsIm, rhsRe, fmf),
+ rewriter.create<LLVM::FMulOp>(loc, lhsRe, rhsIm, fmf), fmf);
+
+ *resultRe = rewriter.create<LLVM::FDivOp>(loc, realNumerator, rhsSqNorm, fmf);
+ *resultIm = rewriter.create<LLVM::FDivOp>(loc, imagNumerator, rhsSqNorm, fmf);
+}
+
+void mlir::complex::convertDivToStandardUsingAlgebraic(
+ ConversionPatternRewriter &rewriter, Location loc, Value lhsRe, Value lhsIm,
+ Value rhsRe, Value rhsIm, arith::FastMathFlagsAttr fmf, Value *resultRe,
+ Value *resultIm) {
+ Value rhsSqNorm = rewriter.create<arith::AddFOp>(
+ loc, rewriter.create<arith::MulFOp>(loc, rhsRe, rhsRe, fmf),
+ rewriter.create<arith::MulFOp>(loc, rhsIm, rhsIm, fmf), fmf);
+
+ Value realNumerator = rewriter.create<arith::AddFOp>(
+ loc, rewriter.create<arith::MulFOp>(loc, lhsRe, rhsRe, fmf),
+ rewriter.create<arith::MulFOp>(loc, lhsIm, rhsIm, fmf), fmf);
+ Value imagNumerator = rewriter.create<arith::SubFOp>(
+ loc, rewriter.create<arith::MulFOp>(loc, lhsIm, rhsRe, fmf),
+ rewriter.create<arith::MulFOp>(loc, lhsRe, rhsIm, fmf), fmf);
+
+ *resultRe =
+ rewriter.create<arith::DivFOp>(loc, realNumerator, rhsSqNorm, fmf);
+ *resultIm =
+ rewriter.create<arith::DivFOp>(loc, imagNumerator, rhsSqNorm, fmf);
+};
+
+// Smith's algorithm to divide complex numbers. It is just a bit smarter
+// way to compute the following algebraic formula:
+// (lhsRe + lhsIm * i) / (rhsRe + rhsIm * i)
+// = (lhsRe + lhsIm * i) (rhsRe - rhsIm * i) /
+// ((rhsRe + rhsIm * i)(rhsRe - rhsIm * i))
+// = ((lhsRe * rhsRe + lhsIm * rhsIm) +
+// (lhsIm * rhsRe - lhsRe * rhsIm) * i) / ||rhs||^2
+//
+// Depending on whether |rhsRe| < |rhsIm| we compute either
+// rhsRealImagRatio = rhsRe / rhsIm
+// rhsRealImagDenom = rhsIm + rhsRe * rhsRealImagRatio
+// resultRe = (lhsRe * rhsRealImagRatio + lhsIm) /
+// rhsRealImagDenom
+// resultIm = (lhsIm * rhsRealImagRatio - lhsRe) /
+// rhsRealImagDenom
+//
+// or
+//
+// rhsImagRealRatio = rhsIm / rhsRe
+// rhsImagRealDenom = rhsRe + rhsIm * rhsImagRealRatio
+// resultRe = (lhsRe + lhsIm * rhsImagRealRatio) /
+// rhsImagRealDenom
+// resultIm = (lhsIm - lhsRe * rhsImagRealRatio) /
+// rhsImagRealDenom
+//
+// See https://dl.acm.org/citation.cfm?id=368661 for more details.
+
+void mlir::complex::convertDivToLLVMUsingRangeReduction(
+ ConversionPatternRewriter &rewriter, Location loc, Value lhsRe, Value lhsIm,
+ Value rhsRe, Value rhsIm, LLVM::FastmathFlagsAttr fmf, Value *resultRe,
+ Value *resultIm) {
+ auto elementType = cast<FloatType>(rhsRe.getType());
+
+ Value rhsRealImagRatio =
+ rewriter.create<LLVM::FDivOp>(loc, rhsRe, rhsIm, fmf);
+ Value rhsRealImagDenom = rewriter.create<LLVM::FAddOp>(
+ loc, rhsIm,
+ rewriter.create<LLVM::FMulOp>(loc, rhsRealImagRatio, rhsRe, fmf), fmf);
+ Value realNumerator1 = rewriter.create<LLVM::FAddOp>(
+ loc, rewriter.create<LLVM::FMulOp>(loc, lhsRe, rhsRealImagRatio, fmf),
+ lhsIm, fmf);
+ Value resultReal1 =
+ rewriter.create<LLVM::FDivOp>(loc, realNumerator1, rhsRealImagDenom, fmf);
+ Value imagNumerator1 = rewriter.create<LLVM::FSubOp>(
+ loc, rewriter.create<LLVM::FMulOp>(loc, lhsIm, rhsRealImagRatio, fmf),
+ lhsRe, fmf);
+ Value resultImag1 =
+ rewriter.create<LLVM::FDivOp>(loc, imagNumerator1, rhsRealImagDenom, fmf);
+
+ Value rhsImagRealRatio =
+ rewriter.create<LLVM::FDivOp>(loc, rhsIm, rhsRe, fmf);
+ Value rhsImagRealDenom = rewriter.create<LLVM::FAddOp>(
+ loc, rhsRe,
+ rewriter.create<LLVM::FMulOp>(loc, rhsImagRealRatio, rhsIm, fmf), fmf);
+ Value realNumerator2 = rewriter.create<LLVM::FAddOp>(
+ loc, lhsRe,
+ rewriter.create<LLVM::FMulOp>(loc, lhsIm, rhsImagRealRatio, fmf), fmf);
+ Value resultReal2 =
+ rewriter.create<LLVM::FDivOp>(loc, realNumerator2, rhsImagRealDenom, fmf);
+ Value imagNumerator2 = rewriter.create<LLVM::FSubOp>(
+ loc, lhsIm,
+ rewriter.create<LLVM::FMulOp>(loc, lhsRe, rhsImagRealRatio, fmf), fmf);
+ Value resultImag2 =
+ rewriter.create<LLVM::FDivOp>(loc, imagNumerator2, rhsImagRealDenom, fmf);
+
+ // Consider corner cases.
+ // Case 1. Zero denominator, numerator contains at most one NaN value.
+ Value zero = rewriter.create<LLVM::ConstantOp>(
+ loc, elementType, rewriter.getZeroAttr(elementType));
+ Value rhsRealAbs = rewriter.create<LLVM::FAbsOp>(loc, rhsRe, fmf);
+ Value rhsRealIsZero = rewriter.create<LLVM::FCmpOp>(
+ loc, LLVM::FCmpPredicate::oeq, rhsRealAbs, zero);
+ Value rhsImagAbs = rewriter.create<LLVM::FAbsOp>(loc, rhsIm, fmf);
+ Value rhsImagIsZero = rewriter.create<LLVM::FCmpOp>(
+ loc, LLVM::FCmpPredicate::oeq, rhsImagAbs, zero);
+ Value lhsRealIsNotNaN =
+ rewriter.create<LLVM::FCmpOp>(loc, LLVM::FCmpPredicate::ord, lhsRe, zero);
+ Value lhsImagIsNotNaN =
+ rewriter.create<LLVM::FCmpOp>(loc, LLVM::FCmpPredicate::ord, lhsIm, zero);
+ Value lhsContainsNotNaNValue =
+ rewriter.create<LLVM::OrOp>(loc, lhsRealIsNotNaN, lhsImagIsNotNaN);
+ Value resultIsInfinity = rewriter.create<LLVM::AndOp>(
+ loc, lhsContainsNotNaNValue,
+ rewriter.create<LLVM::AndOp>(loc, rhsRealIsZero, rhsImagIsZero));
+ Value inf = rewriter.create<LLVM::ConstantOp>(
+ loc, elementType,
+ rewriter.getFloatAttr(elementType,
+ APFloat::getInf(elementType.getFloatSemantics())));
+ Value infWithSignOfrhsReal =
+ rewriter.create<LLVM::CopySignOp>(loc, inf, rhsRe);
+ Value infinityResultReal =
+ rewriter.create<LLVM::FMulOp>(loc, infWithSignOfrhsReal, lhsRe, fmf);
+ Value infinityResultImag =
+ rewriter.create<LLVM::FMulOp>(loc, infWithSignOfrhsReal, lhsIm, fmf);
+
+ // Case 2. Infinite numerator, finite denominator.
+ Value rhsRealFinite = rewriter.create<LLVM::FCmpOp>(
+ loc, LLVM::FCmpPredicate::one, rhsRealAbs, inf);
+ Value rhsImagFinite = rewriter.create<LLVM::FCmpOp>(
+ loc, LLVM::FCmpPredicate::one, rhsImagAbs, inf);
+ Value rhsFinite =
+ rewriter.create<LLVM::AndOp>(loc, rhsRealFinite, rhsImagFinite);
+ Value lhsRealAbs = rewriter.create<LLVM::FAbsOp>(loc, lhsRe, fmf);
+ Value lhsRealInfinite = rewriter.create<LLVM::FCmpOp>(
+ loc, LLVM::FCmpPredicate::oeq, lhsRealAbs, inf);
+ Value lhsImagAbs = rewriter.create<LLVM::FAbsOp>(loc, lhsIm, fmf);
+ Value lhsImagInfinite = rewriter.create<LLVM::FCmpOp>(
+ loc, LLVM::FCmpPredicate::oeq, lhsImagAbs, inf);
+ Value lhsInfinite =
+ rewriter.create<LLVM::OrOp>(loc, lhsRealInfinite, lhsImagInfinite);
+ Value infNumFiniteDenom =
+ rewriter.create<LLVM::AndOp>(loc, lhsInfinite, rhsFinite);
+ Value one = rewriter.create<LLVM::ConstantOp>(
+ loc, elementType, rewriter.getFloatAttr(elementType, 1));
+ Value lhsRealIsInfWithSign = rewriter.create<LLVM::CopySignOp>(
+ loc, rewriter.create<LLVM::SelectOp>(loc, lhsRealInfinite, one, zero),
+ lhsRe);
+ Value lhsImagIsInfWithSign = rewriter.create<LLVM::CopySignOp>(
+ loc, rewriter.create<LLVM::SelectOp>(loc, lhsImagInfinite, one, zero),
+ lhsIm);
+ Value lhsRealIsInfWithSignTimesrhsReal =
+ rewriter.create<LLVM::FMulOp>(loc, lhsRealIsInfWithSign, rhsRe, fmf);
+ Value lhsImagIsInfWithSignTimesrhsImag =
+ rewriter.create<LLVM::FMulOp>(loc, lhsImagIsInfWithSign, rhsIm, fmf);
+ Value resultReal3 = rewriter.create<LLVM::FMulOp>(
+ loc, inf,
+ rewriter.create<LLVM::FAddOp>(loc, lhsRealIsInfWithSignTimesrhsReal,
+ lhsImagIsInfWithSignTimesrhsImag, fmf),
+ fmf);
+ Value lhsRealIsInfWithSignTimesrhsImag =
+ rewriter.create<LLVM::FMulOp>(loc, lhsRealIsInfWithSign, rhsIm, fmf);
+ Value lhsImagIsInfWithSignTimesrhsReal =
+ rewriter.create<LLVM::FMulOp>(loc, lhsImagIsInfWithSign, rhsRe, fmf);
+ Value resultImag3 = rewriter.create<LLVM::FMulOp>(
+ loc, inf,
+ rewriter.create<LLVM::FSubOp>(loc, lhsImagIsInfWithSignTimesrhsReal,
+ lhsRealIsInfWithSignTimesrhsImag, fmf),
+ fmf);
+
+ // Case 3: Finite numerator, infinite denominator.
+ Value lhsRealFinite = rewriter.create<LLVM::FCmpOp>(
+ loc, LLVM::FCmpPredicate::one, lhsRealAbs, inf);
+ Value lhsImagFinite = rewriter.create<LLVM::FCmpOp>(
+ loc, LLVM::FCmpPredicate::one, lhsImagAbs, inf);
+ Value lhsFinite =
+ rewriter.create<LLVM::AndOp>(loc, lhsRealFinite, lhsImagFinite);
+ Value rhsRealInfinite = rewriter.create<LLVM::FCmpOp>(
+ loc, LLVM::FCmpPredicate::oeq, rhsRealAbs, inf);
+ Value rhsImagInfinite = rewriter.create<LLVM::FCmpOp>(
+ loc, LLVM::FCmpPredicate::oeq, rhsImagAbs, inf);
+ Value rhsInfinite =
+ rewriter.create<LLVM::OrOp>(loc, rhsRealInfinite, rhsImagInfinite);
+ Value finiteNumInfiniteDenom =
+ rewriter.create<LLVM::AndOp>(loc, lhsFinite, rhsInfinite);
+ Value rhsRealIsInfWithSign = rewriter.create<LLVM::CopySignOp>(
+ loc, rewriter.create<LLVM::SelectOp>(loc, rhsRealInfinite, one, zero),
+ rhsRe);
+ Value rhsImagIsInfWithSign = rewriter.create<LLVM::CopySignOp>(
+ loc, rewriter.create<LLVM::SelectOp>(loc, rhsImagInfinite, one, zero),
+ rhsIm);
+ Value rhsRealIsInfWithSignTimeslhsReal =
+ rewriter.create<LLVM::FMulOp>(loc, lhsRe, rhsRealIsInfWithSign, fmf);
+ Value rhsImagIsInfWithSignTimeslhsImag =
+ rewriter.create<LLVM::FMulOp>(loc, lhsIm, rhsImagIsInfWithSign, fmf);
+ Value resultReal4 = rewriter.create<LLVM::FMulOp>(
+ loc, zero,
+ rewriter.create<LLVM::FAddOp>(loc, rhsRealIsInfWithSignTimeslhsReal,
+ rhsImagIsInfWithSignTimeslhsImag, fmf),
+ fmf);
+ Value rhsRealIsInfWithSignTimeslhsImag =
+ rewriter.create<LLVM::FMulOp>(loc, lhsIm, rhsRealIsInfWithSign, fmf);
+ Value rhsImagIsInfWithSignTimeslhsReal =
+ rewriter.create<LLVM::FMulOp>(loc, lhsRe, rhsImagIsInfWithSign, fmf);
+ Value resultImag4 = rewriter.create<LLVM::FMulOp>(
+ loc, zero,
+ rewriter.create<LLVM::FSubOp>(loc, rhsRealIsInfWithSignTimeslhsImag,
+ rhsImagIsInfWithSignTimeslhsReal, fmf),
+ fmf);
+
+ Value realAbsSmallerThanImagAbs = rewriter.create<LLVM::FCmpOp>(
+ loc, LLVM::FCmpPredicate::olt, rhsRealAbs, rhsImagAbs);
+ Value resultReal5 = rewriter.create<LLVM::SelectOp>(
+ loc, realAbsSmallerThanImagAbs, resultReal1, resultReal2);
+ Value resultImag5 = rewriter.create<LLVM::SelectOp>(
+ loc, realAbsSmallerThanImagAbs, resultImag1, resultImag2);
+ Value resultRealSpecialCase3 = rewriter.create<LLVM::SelectOp>(
+ loc, finiteNumInfiniteDenom, resultReal4, resultReal5);
+ Value resultImagSpecialCase3 = rewriter.create<LLVM::SelectOp>(
+ loc, finiteNumInfiniteDenom, resultImag4, resultImag5);
+ Value resultRealSpecialCase2 = rewriter.create<LLVM::SelectOp>(
+ loc, infNumFiniteDenom, resultReal3, resultRealSpecialCase3);
+ Value resultImagSpecialCase2 = rewriter.create<LLVM::SelectOp>(
+ loc, infNumFiniteDenom, resultImag3, resultImagSpecialCase3);
+ Value resultRealSpecialCase1 = rewriter.create<LLVM::SelectOp>(
+ loc, resultIsInfinity, infinityResultReal, resultRealSpecialCase2);
+ Value resultImagSpecialCase1 = rewriter.create<LLVM::SelectOp>(
+ loc, resultIsInfinity, infinityResultImag, resultImagSpecialCase2);
+
+ Value resultRealIsNaN = rewriter.create<LLVM::FCmpOp>(
+ loc, LLVM::FCmpPredicate::uno, resultReal5, zero);
+ Value resultImagIsNaN = rewriter.create<LLVM::FCmpOp>(
+ loc, LLVM::FCmpPredicate::uno, resultImag5, zero);
+ Value resultIsNaN =
+ rewriter.create<LLVM::AndOp>(loc, resultRealIsNaN, resultImagIsNaN);
+
+ *resultRe = rewriter.create<LLVM::SelectOp>(
+ loc, resultIsNaN, resultRealSpecialCase1, resultReal5);
+ *resultIm = rewriter.create<LLVM::SelectOp>(
+ loc, resultIsNaN, resultImagSpecialCase1, resultImag5);
+}
+
+void mlir::complex::convertDivToStandardUsingRangeReduction(
+ ConversionPatternRewriter &rewriter, Location loc, Value lhsRe, Value lhsIm,
+ Value rhsRe, Value rhsIm, arith::FastMathFlagsAttr fmf, Value *resultRe,
+ Value *resultIm) {
+ auto elementType = cast<FloatType>(rhsRe.getType());
+
+ Value rhsRealImagRatio =
+ rewriter.create<arith::DivFOp>(loc, rhsRe, rhsIm, fmf);
+ Value rhsRealImagDenom = rewriter.create<arith::AddFOp>(
+ loc, rhsIm,
+ rewriter.create<arith::MulFOp>(loc, rhsRealImagRatio, rhsRe, fmf), fmf);
+ Value realNumerator1 = rewriter.create<arith::AddFOp>(
+ loc, rewriter.create<arith::MulFOp>(loc, lhsRe, rhsRealImagRatio, fmf),
+ lhsIm, fmf);
+ Value resultReal1 = rewriter.create<arith::DivFOp>(loc, realNumerator1,
+ rhsRealImagDenom, fmf);
+ Value imagNumerator1 = rewriter.create<arith::SubFOp>(
+ loc, rewriter.create<arith::MulFOp>(loc, lhsIm, rhsRealImagRatio, fmf),
+ lhsRe, fmf);
+ Value resultImag1 = rewriter.create<arith::DivFOp>(loc, imagNumerator1,
+ rhsRealImagDenom, fmf);
+
+ Value rhsImagRealRatio =
+ rewriter.create<arith::DivFOp>(loc, rhsIm, rhsRe, fmf);
+ Value rhsImagRealDenom = rewriter.create<arith::AddFOp>(
+ loc, rhsRe,
+ rewriter.create<arith::MulFOp>(loc, rhsImagRealRatio, rhsIm, fmf), fmf);
+ Value realNumerator2 = rewriter.create<arith::AddFOp>(
+ loc, lhsRe,
+ rewriter.create<arith::MulFOp>(loc, lhsIm, rhsImagRealRatio, fmf), fmf);
+ Value resultReal2 = rewriter.create<arith::DivFOp>(loc, realNumerator2,
+ rhsImagRealDenom, fmf);
+ Value imagNumerator2 = rewriter.create<arith::SubFOp>(
+ loc, lhsIm,
+ rewriter.create<arith::MulFOp>(loc, lhsRe, rhsImagRealRatio, fmf), fmf);
+ Value resultImag2 = rewriter.create<arith::DivFOp>(loc, imagNumerator2,
+ rhsImagRealDenom, fmf);
+
+ // Consider corner cases.
+ // Case 1. Zero denominator, numerator contains at most one NaN value.
+ Value zero = rewriter.create<arith::ConstantOp>(
+ loc, elementType, rewriter.getZeroAttr(elementType));
+ Value rhsRealAbs = rewriter.create<math::AbsFOp>(loc, rhsRe, fmf);
+ Value rhsRealIsZero = rewriter.create<arith::CmpFOp>(
+ loc, arith::CmpFPredicate::OEQ, rhsRealAbs, zero);
+ Value rhsImagAbs = rewriter.create<math::AbsFOp>(loc, rhsIm, fmf);
+ Value rhsImagIsZero = rewriter.create<arith::CmpFOp>(
+ loc, arith::CmpFPredicate::OEQ, rhsImagAbs, zero);
+ Value lhsRealIsNotNaN = rewriter.create<arith::CmpFOp>(
+ loc, arith::CmpFPredicate::ORD, lhsRe, zero);
+ Value lhsImagIsNotNaN = rewriter.create<arith::CmpFOp>(
+ loc, arith::CmpFPredicate::ORD, lhsIm, zero);
+ Value lhsContainsNotNaNValue =
+ rewriter.create<arith::OrIOp>(loc, lhsRealIsNotNaN, lhsImagIsNotNaN);
+ Value resultIsInfinity = rewriter.create<arith::AndIOp>(
+ loc, lhsContainsNotNaNValue,
+ rewriter.create<arith::AndIOp>(loc, rhsRealIsZero, rhsImagIsZero));
+ Value inf = rewriter.create<arith::ConstantOp>(
+ loc, elementType,
+ rewriter.getFloatAttr(elementType,
+ APFloat::getInf(elementType.getFloatSemantics())));
+ Value infWithSignOfRhsReal =
+ rewriter.create<math::CopySignOp>(loc, inf, rhsRe);
+ Value infinityResultReal =
+ rewriter.create<arith::MulFOp>(loc, infWithSignOfRhsReal, lhsRe, fmf);
+ Value infinityResultImag =
+ rewriter.create<arith::MulFOp>(loc, infWithSignOfRhsReal, lhsIm, fmf);
+
+ // Case 2. Infinite numerator, finite denominator.
+ Value rhsRealFinite = rewriter.create<arith::CmpFOp>(
+ loc, arith::CmpFPredicate::ONE, rhsRealAbs, inf);
+ Value rhsImagFinite = rewriter.create<arith::CmpFOp>(
+ loc, arith::CmpFPredicate::ONE, rhsImagAbs, inf);
+ Value rhsFinite =
+ rewriter.create<arith::AndIOp>(loc, rhsRealFinite, rhsImagFinite);
+ Value lhsRealAbs = rewriter.create<math::AbsFOp>(loc, lhsRe, fmf);
+ Value lhsRealInfinite = rewriter.create<arith::CmpFOp>(
+ loc, arith::CmpFPredicate::OEQ, lhsRealAbs, inf);
+ Value lhsImagAbs = rewriter.create<math::AbsFOp>(loc, lhsIm, fmf);
+ Value lhsImagInfinite = rewriter.create<arith::CmpFOp>(
+ loc, arith::CmpFPredicate::OEQ, lhsImagAbs, inf);
+ Value lhsInfinite =
+ rewriter.create<arith::OrIOp>(loc, lhsRealInfinite, lhsImagInfinite);
+ Value infNumFiniteDenom =
+ rewriter.create<arith::AndIOp>(loc, lhsInfinite, rhsFinite);
+ Value one = rewriter.create<arith::ConstantOp>(
+ loc, elementType, rewriter.getFloatAttr(elementType, 1));
+ Value lhsRealIsInfWithSign = rewriter.create<math::CopySignOp>(
+ loc, rewriter.create<arith::SelectOp>(loc, lhsRealInfinite, one, zero),
+ lhsRe);
+ Value lhsImagIsInfWithSign = rewriter.create<math::CopySignOp>(
+ loc, rewriter.create<arith::SelectOp>(loc, lhsImagInfinite, one, zero),
+ lhsIm);
+ Value lhsRealIsInfWithSignTimesRhsReal =
+ rewriter.create<arith::MulFOp>(loc, lhsRealIsInfWithSign, rhsRe, fmf);
+ Value lhsImagIsInfWithSignTimesRhsImag =
+ rewriter.create<arith::MulFOp>(loc, lhsImagIsInfWithSign, rhsIm, fmf);
+ Value resultReal3 = rewriter.create<arith::MulFOp>(
+ loc, inf,
+ rewriter.create<arith::AddFOp>(loc, lhsRealIsInfWithSignTimesRhsReal,
+ lhsImagIsInfWithSignTimesRhsImag, fmf),
+ fmf);
+ Value lhsRealIsInfWithSignTimesRhsImag =
+ rewriter.create<arith::MulFOp>(loc, lhsRealIsInfWithSign, rhsIm, fmf);
+ Value lhsImagIsInfWithSignTimesRhsReal =
+ rewriter.create<arith::MulFOp>(loc, lhsImagIsInfWithSign, rhsRe, fmf);
+ Value resultImag3 = rewriter.create<arith::MulFOp>(
+ loc, inf,
+ rewriter.create<arith::SubFOp>(loc, lhsImagIsInfWithSignTimesRhsReal,
+ lhsRealIsInfWithSignTimesRhsImag, fmf),
+ fmf);
+
+ // Case 3: Finite numerator, infinite denominator.
+ Value lhsRealFinite = rewriter.create<arith::CmpFOp>(
+ loc, arith::CmpFPredicate::ONE, lhsRealAbs, inf);
+ Value lhsImagFinite = rewriter.create<arith::CmpFOp>(
+ loc, arith::CmpFPredicate::ONE, lhsImagAbs, inf);
+ Value lhsFinite =
+ rewriter.create<arith::AndIOp>(loc, lhsRealFinite, lhsImagFinite);
+ Value rhsRealInfinite = rewriter.create<arith::CmpFOp>(
+ loc, arith::CmpFPredicate::OEQ, rhsRealAbs, inf);
+ Value rhsImagInfinite = rewriter.create<arith::CmpFOp>(
+ loc, arith::CmpFPredicate::OEQ, rhsImagAbs, inf);
+ Value rhsInfinite =
+ rewriter.create<arith::OrIOp>(loc, rhsRealInfinite, rhsImagInfinite);
+ Value finiteNumInfiniteDenom =
+ rewriter.create<arith::AndIOp>(loc, lhsFinite, rhsInfinite);
+ Value rhsRealIsInfWithSign = rewriter.create<math::CopySignOp>(
+ loc, rewriter.create<arith::SelectOp>(loc, rhsRealInfinite, one, zero),
+ rhsRe);
+ Value rhsImagIsInfWithSign = rewriter.create<math::CopySignOp>(
+ loc, rewriter.create<arith::SelectOp>(loc, rhsImagInfinite, one, zero),
+ rhsIm);
+ Value rhsRealIsInfWithSignTimesLhsReal =
+ rewriter.create<arith::MulFOp>(loc, lhsRe, rhsRealIsInfWithSign, fmf);
+ Value rhsImagIsInfWithSignTimesLhsImag =
+ rewriter.create<arith::MulFOp>(loc, lhsIm, rhsImagIsInfWithSign, fmf);
+ Value resultReal4 = rewriter.create<arith::MulFOp>(
+ loc, zero,
+ rewriter.create<arith::AddFOp>(loc, rhsRealIsInfWithSignTimesLhsReal,
+ rhsImagIsInfWithSignTimesLhsImag, fmf),
+ fmf);
+ Value rhsRealIsInfWithSignTimesLhsImag =
+ rewriter.create<arith::MulFOp>(loc, lhsIm, rhsRealIsInfWithSign, fmf);
+ Value rhsImagIsInfWithSignTimesLhsReal =
+ rewriter.create<arith::MulFOp>(loc, lhsRe, rhsImagIsInfWithSign, fmf);
+ Value resultImag4 = rewriter.create<arith::MulFOp>(
+ loc, zero,
+ rewriter.create<arith::SubFOp>(loc, rhsRealIsInfWithSignTimesLhsImag,
+ rhsImagIsInfWithSignTimesLhsReal, fmf),
+ fmf);
+
+ Value realAbsSmallerThanImagAbs = rewriter.create<arith::CmpFOp>(
+ loc, arith::CmpFPredicate::OLT, rhsRealAbs, rhsImagAbs);
+ Value resultReal5 = rewriter.create<arith::SelectOp>(
+ loc, realAbsSmallerThanImagAbs, resultReal1, resultReal2);
+ Value resultImag5 = rewriter.create<arith::SelectOp>(
+ loc, realAbsSmallerThanImagAbs, resultImag1, resultImag2);
+ Value resultRealSpecialCase3 = rewriter.create<arith::SelectOp>(
+ loc, finiteNumInfiniteDenom, resultReal4, resultReal5);
+ Value resultImagSpecialCase3 = rewriter.create<arith::SelectOp>(
+ loc, finiteNumInfiniteDenom, resultImag4, resultImag5);
+ Value resultRealSpecialCase2 = rewriter.create<arith::SelectOp>(
+ loc, infNumFiniteDenom, resultReal3, resultRealSpecialCase3);
+ Value resultImagSpecialCase2 = rewriter.create<arith::SelectOp>(
+ loc, infNumFiniteDenom, resultImag3, resultImagSpecialCase3);
+ Value resultRealSpecialCase1 = rewriter.create<arith::SelectOp>(
+ loc, resultIsInfinity, infinityResultReal, resultRealSpecialCase2);
+ Value resultImagSpecialCase1 = rewriter.create<arith::SelectOp>(
+ loc, resultIsInfinity, infinityResultImag, resultImagSpecialCase2);
+
+ Value resultRealIsNaN = rewriter.create<arith::CmpFOp>(
+ loc, arith::CmpFPredicate::UNO, resultReal5, zero);
+ Value resultImagIsNaN = rewriter.create<arith::CmpFOp>(
+ loc, arith::CmpFPredicate::UNO, resultImag5, zero);
+ Value resultIsNaN =
+ rewriter.create<arith::AndIOp>(loc, resultRealIsNaN, resultImagIsNaN);
+
+ *resultRe = rewriter.create<arith::SelectOp>(
+ loc, resultIsNaN, resultRealSpecialCase1, resultReal5);
+ *resultIm = rewriter.create<arith::SelectOp>(
+ loc, resultIsNaN, resultImagSpecialCase1, resultImag5);
+}
diff --git a/mlir/lib/Conversion/ComplexToLLVM/CMakeLists.txt b/mlir/lib/Conversion/ComplexToLLVM/CMakeLists.txt
index d3a5bf2aa2f05..074bc4bc3f0d7 100644
--- a/mlir/lib/Conversion/ComplexToLLVM/CMakeLists.txt
+++ b/mlir/lib/Conversion/ComplexToLLVM/CMakeLists.txt
@@ -12,6 +12,7 @@ add_mlir_conversion_library(MLIRComplexToLLVM
LINK_LIBS PUBLIC
MLIRArithAttrToLLVMConversion
+ MLIRComplexDivisionConversion
MLIRComplexDialect
MLIRLLVMCommonConversion
MLIRLLVMDialect
diff --git a/mlir/lib/Conversion/ComplexToLLVM/ComplexToLLVM.cpp b/mlir/lib/Conversion/ComplexToLLVM/ComplexToLLVM.cpp
index ad86fe362076b..6956c81f2a2d3 100644
--- a/mlir/lib/Conversion/ComplexToLLVM/ComplexToLLVM.cpp
+++ b/mlir/lib/Conversion/ComplexToLLVM/ComplexToLLVM.cpp
@@ -9,6 +9,7 @@
#include "mlir/Conversion/ComplexToLLVM/ComplexToLLVM.h"
#include "mlir/Conversion/ArithCommon/AttrToLLVMConverter.h"
+#include "mlir/Conversion/ComplexCommon/DivisionConverter.h"
#include "mlir/Conversion/ConvertToLLVM/ToLLVMInterface.h"
#include "mlir/Conversion/LLVMCommon/ConversionTarget.h"
#include "mlir/Conversion/LLVMCommon/Pattern.h"
@@ -204,6 +205,11 @@ struct AddOpConversion : public ConvertOpToLLVMPattern<complex::AddOp> {
};
struct DivOpConversion : public ConvertOpToLLVMPattern<complex::DivOp> {
+ DivOpConversion(const LLVMTypeConverter &converter,
+ complex::ComplexRangeFlags target)
+ : ConvertOpToLLVMPattern<complex::DivOp>(converter),
+ complexRange(target) {}
+
using ConvertOpToLLVMPattern<complex::DivOp>::ConvertOpToLLVMPattern;
LogicalResult
@@ -227,28 +233,26 @@ struct DivOpConversion : public ConvertOpToLLVMPattern<complex::DivOp> {
Value lhsRe = arg.lhs.real();
Value lhsIm = arg.lhs.imag();
- Value rhsSqNorm = rewriter.create<LLVM::FAddOp>(
- loc, rewriter.create<LLVM::FMulOp>(loc, rhsRe, rhsRe, fmf),
- rewriter.create<LLVM::FMulOp>(loc, rhsIm, rhsIm, fmf), fmf);
-
- Value resultReal = rewriter.create<LLVM::FAddOp>(
- loc, rewriter.create<LLVM::FMulOp>(loc, lhsRe, rhsRe, fmf),
- rewriter.create<LLVM::FMulOp>(loc, lhsIm, rhsIm, fmf), fmf);
+ Value resultRe, resultIm;
- Value resultImag = rewriter.create<LLVM::FSubOp>(
- loc, rewriter.create<LLVM::FMulOp>(loc, lhsIm, rhsRe, fmf),
- rewriter.create<LLVM::FMulOp>(loc, lhsRe, rhsIm, fmf), fmf);
+ if (complexRange == complex::ComplexRangeFlags::basic ||
+ complexRange == complex::ComplexRangeFlags::none) {
+ mlir::complex::convertDivToLLVMUsingAlgebraic(
+ rewriter, loc, lhsRe, lhsIm, rhsRe, rhsIm, fmf, &resultRe, &resultIm);
+ } else if (complexRange == complex::ComplexRangeFlags::improved) {
+ mlir::complex::convertDivToLLVMUsingRangeReduction(
+ rewriter, loc, lhsRe, lhsIm, rhsRe, rhsIm, fmf, &resultRe, &resultIm);
+ }
- result.setReal(
- rewriter, loc,
- rewriter.create<LLVM::FDivOp>(loc, resultReal, rhsSqNorm, fmf));
- result.setImaginary(
- rewriter, loc,
- rewriter.create<LLVM::FDivOp>(loc, resultImag, rhsSqNorm, fmf));
+ result.setReal(rewriter, loc, resultRe);
+ result.setImaginary(rewriter, loc, resultIm);
rewriter.replaceOp(op, {result});
return success();
}
+
+private:
+ complex::ComplexRangeFlags complexRange;
};
struct MulOpConversion : public ConvertOpToLLVMPattern<complex::MulOp> {
@@ -324,19 +328,21 @@ struct SubOpConversion : public ConvertOpToLLVMPattern<complex::SubOp> {
} // namespace
void mlir::populateComplexToLLVMConversionPatterns(
- const LLVMTypeConverter &converter, RewritePatternSet &patterns) {
+ const LLVMTypeConverter &converter, RewritePatternSet &patterns,
+ complex::ComplexRangeFlags complexRange) {
// clang-format off
patterns.add<
AbsOpConversion,
AddOpConversion,
ConstantOpLowering,
CreateOpConversion,
- DivOpConversion,
ImOpConversion,
MulOpConversion,
ReOpConversion,
SubOpConversion
>(converter);
+
+ patterns.add<DivOpConversion>(converter, complexRange);
// clang-format on
}
@@ -353,7 +359,7 @@ void ConvertComplexToLLVMPass::runOnOperation() {
// Convert to the LLVM IR dialect using the converter defined above.
RewritePatternSet patterns(&getContext());
LLVMTypeConverter converter(&getContext());
- populateComplexToLLVMConversionPatterns(converter, patterns);
+ populateComplexToLLVMConversionPatterns(converter, patterns, complexRange);
LLVMConversionTarget target(getContext());
target.addIllegalDialect<complex::ComplexDialect>();
diff --git a/mlir/lib/Conversion/ComplexToStandard/CMakeLists.txt b/mlir/lib/Conversion/ComplexToStandard/CMakeLists.txt
index e74c212b9a4f1..c3cf92f57b48d 100644
--- a/mlir/lib/Conversion/ComplexToStandard/CMakeLists.txt
+++ b/mlir/lib/Conversion/ComplexToStandard/CMakeLists.txt
@@ -9,6 +9,7 @@ add_mlir_conversion_library(MLIRComplexToStandard
LINK_LIBS PUBLIC
MLIRArithDialect
+ MLIRComplexDivisionConversion
MLIRComplexDialect
MLIRIR
MLIRMathDialect
diff --git a/mlir/lib/Conversion/ComplexToStandard/ComplexToStandard.cpp b/mlir/lib/Conversion/ComplexToStandard/ComplexToStandard.cpp
index 473b1da4f701c..3df8ad47e4d33 100644
--- a/mlir/lib/Conversion/ComplexToStandard/ComplexToStandard.cpp
+++ b/mlir/lib/Conversion/ComplexToStandard/ComplexToStandard.cpp
@@ -8,6 +8,7 @@
#include "mlir/Conversion/ComplexToStandard/ComplexToStandard.h"
+#include "mlir/Conversion/ComplexCommon/DivisionConverter.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/Complex/IR/Complex.h"
#include "mlir/Dialect/Math/IR/Math.h"
@@ -262,6 +263,9 @@ struct CosOpConversion : public TrigonometricOpConversion<complex::CosOp> {
};
struct DivOpConversion : public OpConversionPattern<complex::DivOp> {
+ DivOpConversion(MLIRContext *context, complex::ComplexRangeFlags target)
+ : OpConversionPattern<complex::DivOp>(context), complexRange(target) {}
+
using OpConversionPattern<complex::DivOp>::OpConversionPattern;
LogicalResult
@@ -281,214 +285,27 @@ struct DivOpConversion : public OpConversionPattern<complex::DivOp> {
Value rhsImag =
rewriter.create<complex::ImOp>(loc, elementType, adaptor.getRhs());
- // Smith's algorithm to divide complex numbers. It is just a bit smarter
- // way to compute the following formula:
- // (lhsReal + lhsImag * i) / (rhsReal + rhsImag * i)
- // = (lhsReal + lhsImag * i) (rhsReal - rhsImag * i) /
- // ((rhsReal + rhsImag * i)(rhsReal - rhsImag * i))
- // = ((lhsReal * rhsReal + lhsImag * rhsImag) +
- // (lhsImag * rhsReal - lhsReal * rhsImag) * i) / ||rhs||^2
- //
- // Depending on whether |rhsReal| < |rhsImag| we compute either
- // rhsRealImagRatio = rhsReal / rhsImag
- // rhsRealImagDenom = rhsImag + rhsReal * rhsRealImagRatio
- // resultReal = (lhsReal * rhsRealImagRatio + lhsImag) / rhsRealImagDenom
- // resultImag = (lhsImag * rhsRealImagRatio - lhsReal) / rhsRealImagDenom
- //
- // or
- //
- // rhsImagRealRatio = rhsImag / rhsReal
- // rhsImagRealDenom = rhsReal + rhsImag * rhsImagRealRatio
- // resultReal = (lhsReal + lhsImag * rhsImagRealRatio) / rhsImagRealDenom
- // resultImag = (lhsImag - lhsReal * rhsImagRealRatio) / rhsImagRealDenom
- //
- // See https://dl.acm.org/citation.cfm?id=368661 for more details.
- Value rhsRealImagRatio =
- rewriter.create<arith::DivFOp>(loc, rhsReal, rhsImag, fmf);
- Value rhsRealImagDenom = rewriter.create<arith::AddFOp>(
- loc, rhsImag,
- rewriter.create<arith::MulFOp>(loc, rhsRealImagRatio, rhsReal, fmf),
- fmf);
- Value realNumerator1 = rewriter.create<arith::AddFOp>(
- loc,
- rewriter.create<arith::MulFOp>(loc, lhsReal, rhsRealImagRatio, fmf),
- lhsImag, fmf);
- Value resultReal1 = rewriter.create<arith::DivFOp>(loc, realNumerator1,
- rhsRealImagDenom, fmf);
- Value imagNumerator1 = rewriter.create<arith::SubFOp>(
- loc,
- rewriter.create<arith::MulFOp>(loc, lhsImag, rhsRealImagRatio, fmf),
- lhsReal, fmf);
- Value resultImag1 = rewriter.create<arith::DivFOp>(loc, imagNumerator1,
- rhsRealImagDenom, fmf);
-
- Value rhsImagRealRatio =
- rewriter.create<arith::DivFOp>(loc, rhsImag, rhsReal, fmf);
- Value rhsImagRealDenom = rewriter.create<arith::AddFOp>(
- loc, rhsReal,
- rewriter.create<arith::MulFOp>(loc, rhsImagRealRatio, rhsImag, fmf),
- fmf);
- Value realNumerator2 = rewriter.create<arith::AddFOp>(
- loc, lhsReal,
- rewriter.create<arith::MulFOp>(loc, lhsImag, rhsImagRealRatio, fmf),
- fmf);
- Value resultReal2 = rewriter.create<arith::DivFOp>(loc, realNumerator2,
- rhsImagRealDenom, fmf);
- Value imagNumerator2 = rewriter.create<arith::SubFOp>(
- loc, lhsImag,
- rewriter.create<arith::MulFOp>(loc, lhsReal, rhsImagRealRatio, fmf),
- fmf);
- Value resultImag2 = rewriter.create<arith::DivFOp>(loc, imagNumerator2,
- rhsImagRealDenom, fmf);
-
- // Consider corner cases.
- // Case 1. Zero denominator, numerator contains at most one NaN value.
- Value zero = rewriter.create<arith::ConstantOp>(
- loc, elementType, rewriter.getZeroAttr(elementType));
- Value rhsRealAbs = rewriter.create<math::AbsFOp>(loc, rhsReal, fmf);
- Value rhsRealIsZero = rewriter.create<arith::CmpFOp>(
- loc, arith::CmpFPredicate::OEQ, rhsRealAbs, zero);
- Value rhsImagAbs = rewriter.create<math::AbsFOp>(loc, rhsImag, fmf);
- Value rhsImagIsZero = rewriter.create<arith::CmpFOp>(
- loc, arith::CmpFPredicate::OEQ, rhsImagAbs, zero);
- Value lhsRealIsNotNaN = rewriter.create<arith::CmpFOp>(
- loc, arith::CmpFPredicate::ORD, lhsReal, zero);
- Value lhsImagIsNotNaN = rewriter.create<arith::CmpFOp>(
- loc, arith::CmpFPredicate::ORD, lhsImag, zero);
- Value lhsContainsNotNaNValue =
- rewriter.create<arith::OrIOp>(loc, lhsRealIsNotNaN, lhsImagIsNotNaN);
- Value resultIsInfinity = rewriter.create<arith::AndIOp>(
- loc, lhsContainsNotNaNValue,
- rewriter.create<arith::AndIOp>(loc, rhsRealIsZero, rhsImagIsZero));
- Value inf = rewriter.create<arith::ConstantOp>(
- loc, elementType,
- rewriter.getFloatAttr(
- elementType, APFloat::getInf(elementType.getFloatSemantics())));
- Value infWithSignOfRhsReal =
- rewriter.create<math::CopySignOp>(loc, inf, rhsReal);
- Value infinityResultReal =
- rewriter.create<arith::MulFOp>(loc, infWithSignOfRhsReal, lhsReal, fmf);
- Value infinityResultImag =
- rewriter.create<arith::MulFOp>(loc, infWithSignOfRhsReal, lhsImag, fmf);
-
- // Case 2. Infinite numerator, finite denominator.
- Value rhsRealFinite = rewriter.create<arith::CmpFOp>(
- loc, arith::CmpFPredicate::ONE, rhsRealAbs, inf);
- Value rhsImagFinite = rewriter.create<arith::CmpFOp>(
- loc, arith::CmpFPredicate::ONE, rhsImagAbs, inf);
- Value rhsFinite =
- rewriter.create<arith::AndIOp>(loc, rhsRealFinite, rhsImagFinite);
- Value lhsRealAbs = rewriter.create<math::AbsFOp>(loc, lhsReal, fmf);
- Value lhsRealInfinite = rewriter.create<arith::CmpFOp>(
- loc, arith::CmpFPredicate::OEQ, lhsRealAbs, inf);
- Value lhsImagAbs = rewriter.create<math::AbsFOp>(loc, lhsImag, fmf);
- Value lhsImagInfinite = rewriter.create<arith::CmpFOp>(
- loc, arith::CmpFPredicate::OEQ, lhsImagAbs, inf);
- Value lhsInfinite =
- rewriter.create<arith::OrIOp>(loc, lhsRealInfinite, lhsImagInfinite);
- Value infNumFiniteDenom =
- rewriter.create<arith::AndIOp>(loc, lhsInfinite, rhsFinite);
- Value one = rewriter.create<arith::ConstantOp>(
- loc, elementType, rewriter.getFloatAttr(elementType, 1));
- Value lhsRealIsInfWithSign = rewriter.create<math::CopySignOp>(
- loc, rewriter.create<arith::SelectOp>(loc, lhsRealInfinite, one, zero),
- lhsReal);
- Value lhsImagIsInfWithSign = rewriter.create<math::CopySignOp>(
- loc, rewriter.create<arith::SelectOp>(loc, lhsImagInfinite, one, zero),
- lhsImag);
- Value lhsRealIsInfWithSignTimesRhsReal =
- rewriter.create<arith::MulFOp>(loc, lhsRealIsInfWithSign, rhsReal, fmf);
- Value lhsImagIsInfWithSignTimesRhsImag =
- rewriter.create<arith::MulFOp>(loc, lhsImagIsInfWithSign, rhsImag, fmf);
- Value resultReal3 = rewriter.create<arith::MulFOp>(
- loc, inf,
- rewriter.create<arith::AddFOp>(loc, lhsRealIsInfWithSignTimesRhsReal,
- lhsImagIsInfWithSignTimesRhsImag, fmf),
- fmf);
- Value lhsRealIsInfWithSignTimesRhsImag =
- rewriter.create<arith::MulFOp>(loc, lhsRealIsInfWithSign, rhsImag, fmf);
- Value lhsImagIsInfWithSignTimesRhsReal =
- rewriter.create<arith::MulFOp>(loc, lhsImagIsInfWithSign, rhsReal, fmf);
- Value resultImag3 = rewriter.create<arith::MulFOp>(
- loc, inf,
- rewriter.create<arith::SubFOp>(loc, lhsImagIsInfWithSignTimesRhsReal,
- lhsRealIsInfWithSignTimesRhsImag, fmf),
- fmf);
+ Value resultReal, resultImag;
+
+ if (complexRange == complex::ComplexRangeFlags::basic ||
+ complexRange == complex::ComplexRangeFlags::none) {
+ mlir::complex::convertDivToStandardUsingAlgebraic(
+ rewriter, loc, lhsReal, lhsImag, rhsReal, rhsImag, fmf, &resultReal,
+ &resultImag);
+ } else if (complexRange == complex::ComplexRangeFlags::improved) {
+ mlir::complex::convertDivToStandardUsingRangeReduction(
+ rewriter, loc, lhsReal, lhsImag, rhsReal, rhsImag, fmf, &resultReal,
+ &resultImag);
+ }
- // Case 3: Finite numerator, infinite denominator.
- Value lhsRealFinite = rewriter.create<arith::CmpFOp>(
- loc, arith::CmpFPredicate::ONE, lhsRealAbs, inf);
- Value lhsImagFinite = rewriter.create<arith::CmpFOp>(
- loc, arith::CmpFPredicate::ONE, lhsImagAbs, inf);
- Value lhsFinite =
- rewriter.create<arith::AndIOp>(loc, lhsRealFinite, lhsImagFinite);
- Value rhsRealInfinite = rewriter.create<arith::CmpFOp>(
- loc, arith::CmpFPredicate::OEQ, rhsRealAbs, inf);
- Value rhsImagInfinite = rewriter.create<arith::CmpFOp>(
- loc, arith::CmpFPredicate::OEQ, rhsImagAbs, inf);
- Value rhsInfinite =
- rewriter.create<arith::OrIOp>(loc, rhsRealInfinite, rhsImagInfinite);
- Value finiteNumInfiniteDenom =
- rewriter.create<arith::AndIOp>(loc, lhsFinite, rhsInfinite);
- Value rhsRealIsInfWithSign = rewriter.create<math::CopySignOp>(
- loc, rewriter.create<arith::SelectOp>(loc, rhsRealInfinite, one, zero),
- rhsReal);
- Value rhsImagIsInfWithSign = rewriter.create<math::CopySignOp>(
- loc, rewriter.create<arith::SelectOp>(loc, rhsImagInfinite, one, zero),
- rhsImag);
- Value rhsRealIsInfWithSignTimesLhsReal =
- rewriter.create<arith::MulFOp>(loc, lhsReal, rhsRealIsInfWithSign, fmf);
- Value rhsImagIsInfWithSignTimesLhsImag =
- rewriter.create<arith::MulFOp>(loc, lhsImag, rhsImagIsInfWithSign, fmf);
- Value resultReal4 = rewriter.create<arith::MulFOp>(
- loc, zero,
- rewriter.create<arith::AddFOp>(loc, rhsRealIsInfWithSignTimesLhsReal,
- rhsImagIsInfWithSignTimesLhsImag, fmf),
- fmf);
- Value rhsRealIsInfWithSignTimesLhsImag =
- rewriter.create<arith::MulFOp>(loc, lhsImag, rhsRealIsInfWithSign, fmf);
- Value rhsImagIsInfWithSignTimesLhsReal =
- rewriter.create<arith::MulFOp>(loc, lhsReal, rhsImagIsInfWithSign, fmf);
- Value resultImag4 = rewriter.create<arith::MulFOp>(
- loc, zero,
- rewriter.create<arith::SubFOp>(loc, rhsRealIsInfWithSignTimesLhsImag,
- rhsImagIsInfWithSignTimesLhsReal, fmf),
- fmf);
+ rewriter.replaceOpWithNewOp<complex::CreateOp>(op, type, resultReal,
+ resultImag);
- Value realAbsSmallerThanImagAbs = rewriter.create<arith::CmpFOp>(
- loc, arith::CmpFPredicate::OLT, rhsRealAbs, rhsImagAbs);
- Value resultReal = rewriter.create<arith::SelectOp>(
- loc, realAbsSmallerThanImagAbs, resultReal1, resultReal2);
- Value resultImag = rewriter.create<arith::SelectOp>(
- loc, realAbsSmallerThanImagAbs, resultImag1, resultImag2);
- Value resultRealSpecialCase3 = rewriter.create<arith::SelectOp>(
- loc, finiteNumInfiniteDenom, resultReal4, resultReal);
- Value resultImagSpecialCase3 = rewriter.create<arith::SelectOp>(
- loc, finiteNumInfiniteDenom, resultImag4, resultImag);
- Value resultRealSpecialCase2 = rewriter.create<arith::SelectOp>(
- loc, infNumFiniteDenom, resultReal3, resultRealSpecialCase3);
- Value resultImagSpecialCase2 = rewriter.create<arith::SelectOp>(
- loc, infNumFiniteDenom, resultImag3, resultImagSpecialCase3);
- Value resultRealSpecialCase1 = rewriter.create<arith::SelectOp>(
- loc, resultIsInfinity, infinityResultReal, resultRealSpecialCase2);
- Value resultImagSpecialCase1 = rewriter.create<arith::SelectOp>(
- loc, resultIsInfinity, infinityResultImag, resultImagSpecialCase2);
-
- Value resultRealIsNaN = rewriter.create<arith::CmpFOp>(
- loc, arith::CmpFPredicate::UNO, resultReal, zero);
- Value resultImagIsNaN = rewriter.create<arith::CmpFOp>(
- loc, arith::CmpFPredicate::UNO, resultImag, zero);
- Value resultIsNaN =
- rewriter.create<arith::AndIOp>(loc, resultRealIsNaN, resultImagIsNaN);
- Value resultRealWithSpecialCases = rewriter.create<arith::SelectOp>(
- loc, resultIsNaN, resultRealSpecialCase1, resultReal);
- Value resultImagWithSpecialCases = rewriter.create<arith::SelectOp>(
- loc, resultIsNaN, resultImagSpecialCase1, resultImag);
-
- rewriter.replaceOpWithNewOp<complex::CreateOp>(
- op, type, resultRealWithSpecialCases, resultImagWithSpecialCases);
return success();
}
+
+private:
+ complex::ComplexRangeFlags complexRange;
};
struct ExpOpConversion : public OpConversionPattern<complex::ExpOp> {
@@ -1219,7 +1036,7 @@ struct AngleOpConversion : public OpConversionPattern<complex::AngleOp> {
} // namespace
void mlir::populateComplexToStandardConversionPatterns(
- RewritePatternSet &patterns) {
+ RewritePatternSet &patterns, complex::ComplexRangeFlags complexRange) {
// clang-format off
patterns.add<
AbsOpConversion,
@@ -1231,7 +1048,6 @@ void mlir::populateComplexToStandardConversionPatterns(
ComparisonOpConversion<complex::NotEqualOp, arith::CmpFPredicate::UNE>,
ConjOpConversion,
CosOpConversion,
- DivOpConversion,
ExpOpConversion,
Expm1OpConversion,
Log1pOpConversion,
@@ -1246,19 +1062,27 @@ void mlir::populateComplexToStandardConversionPatterns(
PowOpConversion,
RsqrtOpConversion
>(patterns.getContext());
+
+ patterns.add<DivOpConversion>(patterns.getContext(), complexRange);
+
// clang-format on
}
namespace {
struct ConvertComplexToStandardPass
: public impl::ConvertComplexToStandardBase<ConvertComplexToStandardPass> {
+ ConvertComplexToStandardPass() = default;
+ ConvertComplexToStandardPass(const ConvertComplexToStandardOptions &options)
+ : impl::ConvertComplexToStandardBase<ConvertComplexToStandardPass>(
+ options) {}
+
void runOnOperation() override;
};
void ConvertComplexToStandardPass::runOnOperation() {
// Convert to the Standard dialect using the converter defined above.
RewritePatternSet patterns(&getContext());
- populateComplexToStandardConversionPatterns(patterns);
+ populateComplexToStandardConversionPatterns(patterns, complexRange);
ConversionTarget target(getContext());
target.addLegalDialect<arith::ArithDialect, math::MathDialect>();
@@ -1272,3 +1096,8 @@ void ConvertComplexToStandardPass::runOnOperation() {
std::unique_ptr<Pass> mlir::createConvertComplexToStandardPass() {
return std::make_unique<ConvertComplexToStandardPass>();
}
+
+std::unique_ptr<Pass> mlir::createConvertComplexToStandardPass(
+ ConvertComplexToStandardOptions options) {
+ return std::make_unique<ConvertComplexToStandardPass>(std::move(options));
+}
diff --git a/mlir/test/Conversion/ComplexToLLVM/complex-range-option.mlir b/mlir/test/Conversion/ComplexToLLVM/complex-range-option.mlir
new file mode 100644
index 0000000000000..78e8db795788a
--- /dev/null
+++ b/mlir/test/Conversion/ComplexToLLVM/complex-range-option.mlir
@@ -0,0 +1,303 @@
+// RUN: mlir-opt %s -convert-complex-to-llvm=complex-range=improved | FileCheck %s --check-prefix=DIV-SMITH
+// RUN: mlir-opt %s -convert-complex-to-llvm=complex-range=basic | FileCheck %s --check-prefix=DIV-ALGEBRAIC
+// RUN: mlir-opt %s -convert-complex-to-llvm=complex-range=none | FileCheck %s --check-prefix=DIV-ALGEBRAIC
+
+
+func.func @complex_div(%lhs: complex<f32>, %rhs: complex<f32>) -> complex<f32> {
+ %div = complex.div %lhs, %rhs : complex<f32>
+ return %div : complex<f32>
+}
+// DIV-SMITH-LABEL: func @complex_div
+// DIV-SMITH-SAME: %[[LHS:.*]]: complex<f32>, %[[RHS:.*]]: complex<f32>
+// DIV-SMITH-DAG: %[[CASTED_LHS:.*]] = builtin.unrealized_conversion_cast %[[LHS]] : complex<f32> to ![[C_TY:.*>]]
+// DIV-SMITH-DAG: %[[CASTED_RHS:.*]] = builtin.unrealized_conversion_cast %[[RHS]] : complex<f32> to ![[C_TY]]
+
+// DIV-SMITH: %[[LHS_REAL:.*]] = llvm.extractvalue %[[CASTED_LHS]][0] : ![[C_TY]]
+// DIV-SMITH: %[[LHS_IMAG:.*]] = llvm.extractvalue %[[CASTED_LHS]][1] : ![[C_TY]]
+// DIV-SMITH: %[[RHS_REAL:.*]] = llvm.extractvalue %[[CASTED_RHS]][0] : ![[C_TY]]
+// DIV-SMITH: %[[RHS_IMAG:.*]] = llvm.extractvalue %[[CASTED_RHS]][1] : ![[C_TY]]
+
+// DIV-SMITH: %[[RESULT_0:.*]] = llvm.mlir.poison : ![[C_TY]]
+
+// DIV-SMITH: %[[RHS_REAL_IMAG_RATIO:.*]] = llvm.fdiv %[[RHS_REAL]], %[[RHS_IMAG]] : f32
+// DIV-SMITH: %[[RHS_REAL_TIMES_RHS_REAL_IMAG_RATIO:.*]] = llvm.fmul %[[RHS_REAL_IMAG_RATIO]], %[[RHS_REAL]] : f32
+// DIV-SMITH: %[[RHS_REAL_IMAG_DENOM:.*]] = llvm.fadd %[[RHS_IMAG]], %[[RHS_REAL_TIMES_RHS_REAL_IMAG_RATIO]] : f32
+// DIV-SMITH: %[[LHS_REAL_TIMES_RHS_REAL_IMAG_RATIO:.*]] = llvm.fmul %[[LHS_REAL]], %[[RHS_REAL_IMAG_RATIO]] : f32
+// DIV-SMITH: %[[REAL_NUMERATOR_1:.*]] = llvm.fadd %[[LHS_REAL_TIMES_RHS_REAL_IMAG_RATIO]], %[[LHS_IMAG]] : f32
+// DIV-SMITH: %[[RESULT_REAL_1:.*]] = llvm.fdiv %[[REAL_NUMERATOR_1]], %[[RHS_REAL_IMAG_DENOM]] : f32
+// DIV-SMITH: %[[LHS_IMAG_TIMES_RHS_REAL_IMAG_RATIO:.*]] = llvm.fmul %[[LHS_IMAG]], %[[RHS_REAL_IMAG_RATIO]] : f32
+// DIV-SMITH: %[[IMAG_NUMERATOR_1:.*]] = llvm.fsub %[[LHS_IMAG_TIMES_RHS_REAL_IMAG_RATIO]], %[[LHS_REAL]] : f32
+// DIV-SMITH: %[[RESULT_IMAG_1:.*]] = llvm.fdiv %[[IMAG_NUMERATOR_1]], %[[RHS_REAL_IMAG_DENOM]] : f32
+
+// DIV-SMITH: %[[RHS_IMAG_REAL_RATIO:.*]] = llvm.fdiv %[[RHS_IMAG]], %[[RHS_REAL]] : f32
+// DIV-SMITH: %[[RHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO:.*]] = llvm.fmul %[[RHS_IMAG_REAL_RATIO]], %[[RHS_IMAG]] : f32
+// DIV-SMITH: %[[RHS_IMAG_REAL_DENOM:.*]] = llvm.fadd %[[RHS_REAL]], %[[RHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO]] : f32
+// DIV-SMITH: %[[LHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO:.*]] = llvm.fmul %[[LHS_IMAG]], %[[RHS_IMAG_REAL_RATIO]] : f32
+// DIV-SMITH: %[[REAL_NUMERATOR_2:.*]] = llvm.fadd %[[LHS_REAL]], %[[LHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO]] : f32
+// DIV-SMITH: %[[RESULT_REAL_2:.*]] = llvm.fdiv %[[REAL_NUMERATOR_2]], %[[RHS_IMAG_REAL_DENOM]] : f32
+// DIV-SMITH: %[[LHS_REAL_TIMES_RHS_IMAG_REAL_RATIO:.*]] = llvm.fmul %[[LHS_REAL]], %[[RHS_IMAG_REAL_RATIO]] : f32
+// DIV-SMITH: %[[IMAG_NUMERATOR_2:.*]] = llvm.fsub %[[LHS_IMAG]], %[[LHS_REAL_TIMES_RHS_IMAG_REAL_RATIO]] : f32
+// DIV-SMITH: %[[RESULT_IMAG_2:.*]] = llvm.fdiv %[[IMAG_NUMERATOR_2]], %[[RHS_IMAG_REAL_DENOM]] : f32
+
+// Case 1. Zero denominator, numerator contains at most one NaN value.
+// DIV-SMITH: %[[ZERO:.*]] = llvm.mlir.constant(0.000000e+00 : f32) : f32
+// DIV-SMITH: %[[RHS_REAL_ABS:.*]] = llvm.intr.fabs(%[[RHS_REAL]]) : (f32) -> f32
+// DIV-SMITH: %[[RHS_REAL_ABS_IS_ZERO:.*]] = llvm.fcmp "oeq" %[[RHS_REAL_ABS]], %[[ZERO]] : f32
+// DIV-SMITH: %[[RHS_IMAG_ABS:.*]] = llvm.intr.fabs(%[[RHS_IMAG]]) : (f32) -> f32
+// DIV-SMITH: %[[RHS_IMAG_ABS_IS_ZERO:.*]] = llvm.fcmp "oeq" %[[RHS_IMAG_ABS]], %[[ZERO]] : f32
+// DIV-SMITH: %[[LHS_REAL_IS_NOT_NAN:.*]] = llvm.fcmp "ord" %[[LHS_REAL]], %[[ZERO]] : f32
+// DIV-SMITH: %[[LHS_IMAG_IS_NOT_NAN:.*]] = llvm.fcmp "ord" %[[LHS_IMAG]], %[[ZERO]] : f32
+// DIV-SMITH: %[[LHS_CONTAINS_NOT_NAN_VALUE:.*]] = llvm.or %[[LHS_REAL_IS_NOT_NAN]], %[[LHS_IMAG_IS_NOT_NAN]] : i1
+// DIV-SMITH: %[[RHS_IS_ZERO:.*]] = llvm.and %[[RHS_REAL_ABS_IS_ZERO]], %[[RHS_IMAG_ABS_IS_ZERO]] : i1
+// DIV-SMITH: %[[RESULT_IS_INFINITY:.*]] = llvm.and %[[LHS_CONTAINS_NOT_NAN_VALUE]], %[[RHS_IS_ZERO]] : i1
+// DIV-SMITH: %[[INF:.*]] = llvm.mlir.constant(0x7F800000 : f32) : f32
+// DIV-SMITH: %[[INF_WITH_SIGN_OF_RHS_REAL:.*]] = llvm.intr.copysign(%[[INF]], %[[RHS_REAL]]) : (f32, f32) -> f32
+// DIV-SMITH: %[[INFINITY_RESULT_REAL:.*]] = llvm.fmul %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_REAL]] : f32
+// DIV-SMITH: %[[INFINITY_RESULT_IMAG:.*]] = llvm.fmul %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_IMAG]] : f32
+
+// Case 2. Infinite numerator, finite denominator.
+// DIV-SMITH: %[[RHS_REAL_FINITE:.*]] = llvm.fcmp "one" %[[RHS_REAL_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[RHS_IMAG_FINITE:.*]] = llvm.fcmp "one" %[[RHS_IMAG_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[RHS_IS_FINITE:.*]] = llvm.and %[[RHS_REAL_FINITE]], %[[RHS_IMAG_FINITE]] : i1
+// DIV-SMITH: %[[LHS_REAL_ABS:.*]] = llvm.intr.fabs(%[[LHS_REAL]]) : (f32) -> f32
+// DIV-SMITH: %[[LHS_REAL_INFINITE:.*]] = llvm.fcmp "oeq" %[[LHS_REAL_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[LHS_IMAG_ABS:.*]] = llvm.intr.fabs(%[[LHS_IMAG]]) : (f32) -> f32
+// DIV-SMITH: %[[LHS_IMAG_INFINITE:.*]] = llvm.fcmp "oeq" %[[LHS_IMAG_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[LHS_IS_INFINITE:.*]] = llvm.or %[[LHS_REAL_INFINITE]], %[[LHS_IMAG_INFINITE]] : i1
+// DIV-SMITH: %[[INF_NUM_FINITE_DENOM:.*]] = llvm.and %[[LHS_IS_INFINITE]], %[[RHS_IS_FINITE]] : i1
+// DIV-SMITH: %[[ONE:.*]] = llvm.mlir.constant(1.000000e+00 : f32) : f32
+// DIV-SMITH: %[[LHS_REAL_IS_INF:.*]] = llvm.select %[[LHS_REAL_INFINITE]], %[[ONE]], %[[ZERO]] : i1, f32
+// DIV-SMITH: %[[LHS_REAL_IS_INF_WITH_SIGN:.*]] = llvm.intr.copysign(%[[LHS_REAL_IS_INF]], %[[LHS_REAL]]) : (f32, f32) -> f32
+// DIV-SMITH: %[[LHS_IMAG_IS_INF:.*]] = llvm.select %[[LHS_IMAG_INFINITE]], %[[ONE]], %[[ZERO]] : i1, f32
+// DIV-SMITH: %[[LHS_IMAG_IS_INF_WITH_SIGN:.*]] = llvm.intr.copysign(%[[LHS_IMAG_IS_INF]], %[[LHS_IMAG]]) : (f32, f32) -> f32
+// DIV-SMITH: %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_REAL:.*]] = llvm.fmul %[[LHS_REAL_IS_INF_WITH_SIGN]], %[[RHS_REAL]] : f32
+// DIV-SMITH: %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_IMAG:.*]] = llvm.fmul %[[LHS_IMAG_IS_INF_WITH_SIGN]], %[[RHS_IMAG]] : f32
+// DIV-SMITH: %[[INF_MULTIPLICATOR_1:.*]] = llvm.fadd %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_REAL]], %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_IMAG]] : f32
+// DIV-SMITH: %[[RESULT_REAL_3:.*]] = llvm.fmul %[[INF]], %[[INF_MULTIPLICATOR_1]] : f32
+// DIV-SMITH: %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_IMAG:.*]] = llvm.fmul %[[LHS_REAL_IS_INF_WITH_SIGN]], %[[RHS_IMAG]] : f32
+// DIV-SMITH: %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_REAL:.*]] = llvm.fmul %[[LHS_IMAG_IS_INF_WITH_SIGN]], %[[RHS_REAL]] : f32
+// DIV-SMITH: %[[INF_MULTIPLICATOR_2:.*]] = llvm.fsub %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_REAL]], %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_IMAG]] : f32
+// DIV-SMITH: %[[RESULT_IMAG_3:.*]] = llvm.fmul %[[INF]], %[[INF_MULTIPLICATOR_2]] : f32
+
+// Case 3. Finite numerator, infinite denominator.
+// DIV-SMITH: %[[LHS_REAL_FINITE:.*]] = llvm.fcmp "one" %[[LHS_REAL_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[LHS_IMAG_FINITE:.*]] = llvm.fcmp "one" %[[LHS_IMAG_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[LHS_IS_FINITE:.*]] = llvm.and %[[LHS_REAL_FINITE]], %[[LHS_IMAG_FINITE]] : i1
+// DIV-SMITH: %[[RHS_REAL_INFINITE:.*]] = llvm.fcmp "oeq" %[[RHS_REAL_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[RHS_IMAG_INFINITE:.*]] = llvm.fcmp "oeq" %[[RHS_IMAG_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[RHS_IS_INFINITE:.*]] = llvm.or %[[RHS_REAL_INFINITE]], %[[RHS_IMAG_INFINITE]] : i1
+// DIV-SMITH: %[[FINITE_NUM_INFINITE_DENOM:.*]] = llvm.and %[[LHS_IS_FINITE]], %[[RHS_IS_INFINITE]] : i1
+// DIV-SMITH: %[[RHS_REAL_IS_INF:.*]] = llvm.select %[[RHS_REAL_INFINITE]], %[[ONE]], %[[ZERO]] : i1, f32
+// DIV-SMITH: %[[RHS_REAL_IS_INF_WITH_SIGN:.*]] = llvm.intr.copysign(%[[RHS_REAL_IS_INF]], %[[RHS_REAL]]) : (f32, f32) -> f32
+// DIV-SMITH: %[[RHS_IMAG_IS_INF:.*]] = llvm.select %[[RHS_IMAG_INFINITE]], %[[ONE]], %[[ZERO]] : i1, f32
+// DIV-SMITH: %[[RHS_IMAG_IS_INF_WITH_SIGN:.*]] = llvm.intr.copysign(%[[RHS_IMAG_IS_INF]], %[[RHS_IMAG]]) : (f32, f32) -> f32
+// DIV-SMITH: %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_REAL:.*]] = llvm.fmul %[[LHS_REAL]], %[[RHS_REAL_IS_INF_WITH_SIGN]] : f32
+// DIV-SMITH: %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_IMAG:.*]] = llvm.fmul %[[LHS_IMAG]], %[[RHS_IMAG_IS_INF_WITH_SIGN]] : f32
+// DIV-SMITH: %[[ZERO_MULTIPLICATOR_1:.*]] = llvm.fadd %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_REAL]], %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_IMAG]] : f32
+// DIV-SMITH: %[[RESULT_REAL_4:.*]] = llvm.fmul %[[ZERO]], %[[ZERO_MULTIPLICATOR_1]] : f32
+// DIV-SMITH: %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_IMAG:.*]] = llvm.fmul %[[LHS_IMAG]], %[[RHS_REAL_IS_INF_WITH_SIGN]] : f32
+// DIV-SMITH: %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_REAL:.*]] = llvm.fmul %[[LHS_REAL]], %[[RHS_IMAG_IS_INF_WITH_SIGN]] : f32
+// DIV-SMITH: %[[ZERO_MULTIPLICATOR_2:.*]] = llvm.fsub %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_IMAG]], %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_REAL]] : f32
+// DIV-SMITH: %[[RESULT_IMAG_4:.*]] = llvm.fmul %[[ZERO]], %[[ZERO_MULTIPLICATOR_2]] : f32
+
+// DIV-SMITH: %[[REAL_ABS_SMALLER_THAN_IMAG_ABS:.*]] = llvm.fcmp "olt" %[[RHS_REAL_ABS]], %[[RHS_IMAG_ABS]] : f32
+// DIV-SMITH: %[[RESULT_REAL:.*]] = llvm.select %[[REAL_ABS_SMALLER_THAN_IMAG_ABS]], %[[RESULT_REAL_1]], %[[RESULT_REAL_2]] : i1, f32
+// DIV-SMITH: %[[RESULT_IMAG:.*]] = llvm.select %[[REAL_ABS_SMALLER_THAN_IMAG_ABS]], %[[RESULT_IMAG_1]], %[[RESULT_IMAG_2]] : i1, f32
+// DIV-SMITH: %[[RESULT_REAL_SPECIAL_CASE_3:.*]] = llvm.select %[[FINITE_NUM_INFINITE_DENOM]], %[[RESULT_REAL_4]], %[[RESULT_REAL]] : i1, f32
+// DIV-SMITH: %[[RESULT_IMAG_SPECIAL_CASE_3:.*]] = llvm.select %[[FINITE_NUM_INFINITE_DENOM]], %[[RESULT_IMAG_4]], %[[RESULT_IMAG]] : i1, f32
+// DIV-SMITH: %[[RESULT_REAL_SPECIAL_CASE_2:.*]] = llvm.select %[[INF_NUM_FINITE_DENOM]], %[[RESULT_REAL_3]], %[[RESULT_REAL_SPECIAL_CASE_3]] : i1, f32
+// DIV-SMITH: %[[RESULT_IMAG_SPECIAL_CASE_2:.*]] = llvm.select %[[INF_NUM_FINITE_DENOM]], %[[RESULT_IMAG_3]], %[[RESULT_IMAG_SPECIAL_CASE_3]] : i1, f32
+// DIV-SMITH: %[[RESULT_REAL_SPECIAL_CASE_1:.*]] = llvm.select %[[RESULT_IS_INFINITY]], %[[INFINITY_RESULT_REAL]], %[[RESULT_REAL_SPECIAL_CASE_2]] : i1, f32
+// DIV-SMITH: %[[RESULT_IMAG_SPECIAL_CASE_1:.*]] = llvm.select %[[RESULT_IS_INFINITY]], %[[INFINITY_RESULT_IMAG]], %[[RESULT_IMAG_SPECIAL_CASE_2]] : i1, f32
+// DIV-SMITH: %[[RESULT_REAL_IS_NAN:.*]] = llvm.fcmp "uno" %[[RESULT_REAL]], %[[ZERO]] : f32
+// DIV-SMITH: %[[RESULT_IMAG_IS_NAN:.*]] = llvm.fcmp "uno" %[[RESULT_IMAG]], %[[ZERO]] : f32
+// DIV-SMITH: %[[RESULT_IS_NAN:.*]] = llvm.and %[[RESULT_REAL_IS_NAN]], %[[RESULT_IMAG_IS_NAN]] : i1
+// DIV-SMITH: %[[RESULT_REAL_WITH_SPECIAL_CASES:.*]] = llvm.select %[[RESULT_IS_NAN]], %[[RESULT_REAL_SPECIAL_CASE_1]], %[[RESULT_REAL]] : i1, f32
+// DIV-SMITH: %[[RESULT_IMAG_WITH_SPECIAL_CASES:.*]] = llvm.select %[[RESULT_IS_NAN]], %[[RESULT_IMAG_SPECIAL_CASE_1]], %[[RESULT_IMAG]] : i1, f32
+// DIV-SMITH: %[[RESULT_1:.*]] = llvm.insertvalue %[[RESULT_REAL_WITH_SPECIAL_CASES]], %[[RESULT_0]][0] : ![[C_TY]]
+// DIV-SMITH: %[[RESULT_2:.*]] = llvm.insertvalue %[[RESULT_IMAG_WITH_SPECIAL_CASES]], %[[RESULT_1]][1] : ![[C_TY]]
+// DIV-SMITH: %[[CASTED_RESULT:.*]] = builtin.unrealized_conversion_cast %[[RESULT_2]] : ![[C_TY]] to complex<f32>
+// DIV-SMITH: return %[[CASTED_RESULT]] : complex<f32>
+
+
+// DIV-ALGEBRAIC-LABEL: func @complex_div
+// DIV-ALGEBRAIC-SAME: %[[LHS:.*]]: complex<f32>, %[[RHS:.*]]: complex<f32>
+// DIV-ALGEBRAIC-DAG: %[[CASTED_LHS:.*]] = builtin.unrealized_conversion_cast %[[LHS]] : complex<f32> to ![[C_TY:.*>]]
+// DIV-ALGEBRAIC-DAG: %[[CASTED_RHS:.*]] = builtin.unrealized_conversion_cast %[[RHS]] : complex<f32> to ![[C_TY]]
+
+// DIV-ALGEBRAIC: %[[LHS_RE:.*]] = llvm.extractvalue %[[CASTED_LHS]][0] : ![[C_TY]]
+// DIV-ALGEBRAIC: %[[LHS_IM:.*]] = llvm.extractvalue %[[CASTED_LHS]][1] : ![[C_TY]]
+// DIV-ALGEBRAIC: %[[RHS_RE:.*]] = llvm.extractvalue %[[CASTED_RHS]][0] : ![[C_TY]]
+// DIV-ALGEBRAIC: %[[RHS_IM:.*]] = llvm.extractvalue %[[CASTED_RHS]][1] : ![[C_TY]]
+
+// DIV-ALGEBRAIC: %[[RESULT_0:.*]] = llvm.mlir.poison : ![[C_TY]]
+
+// DIV-ALGEBRAIC-DAG: %[[RHS_RE_SQ:.*]] = llvm.fmul %[[RHS_RE]], %[[RHS_RE]] : f32
+// DIV-ALGEBRAIC-DAG: %[[RHS_IM_SQ:.*]] = llvm.fmul %[[RHS_IM]], %[[RHS_IM]] : f32
+// DIV-ALGEBRAIC: %[[SQ_NORM:.*]] = llvm.fadd %[[RHS_RE_SQ]], %[[RHS_IM_SQ]] : f32
+
+// DIV-ALGEBRAIC-DAG: %[[REAL_TMP_0:.*]] = llvm.fmul %[[LHS_RE]], %[[RHS_RE]] : f32
+// DIV-ALGEBRAIC-DAG: %[[REAL_TMP_1:.*]] = llvm.fmul %[[LHS_IM]], %[[RHS_IM]] : f32
+// DIV-ALGEBRAIC: %[[REAL_TMP_2:.*]] = llvm.fadd %[[REAL_TMP_0]], %[[REAL_TMP_1]] : f32
+
+// DIV-ALGEBRAIC-DAG: %[[IMAG_TMP_0:.*]] = llvm.fmul %[[LHS_IM]], %[[RHS_RE]] : f32
+// DIV-ALGEBRAIC-DAG: %[[IMAG_TMP_1:.*]] = llvm.fmul %[[LHS_RE]], %[[RHS_IM]] : f32
+// DIV-ALGEBRAIC: %[[IMAG_TMP_2:.*]] = llvm.fsub %[[IMAG_TMP_0]], %[[IMAG_TMP_1]] : f32
+
+// DIV-ALGEBRAIC: %[[REAL:.*]] = llvm.fdiv %[[REAL_TMP_2]], %[[SQ_NORM]] : f32
+// DIV-ALGEBRAIC: %[[IMAG:.*]] = llvm.fdiv %[[IMAG_TMP_2]], %[[SQ_NORM]] : f32
+// DIV-ALGEBRAIC: %[[RESULT_1:.*]] = llvm.insertvalue %[[REAL]], %[[RESULT_0]][0] : ![[C_TY]]
+// DIV-ALGEBRAIC: %[[RESULT_2:.*]] = llvm.insertvalue %[[IMAG]], %[[RESULT_1]][1] : ![[C_TY]]
+//
+// DIV-ALGEBRAIC: %[[CASTED_RESULT:.*]] = builtin.unrealized_conversion_cast %[[RESULT_2]] : ![[C_TY]] to complex<f32>
+// DIV-ALGEBRAIC: return %[[CASTED_RESULT]] : complex<f32>
+
+
+func.func @complex_div_with_fmf(%lhs: complex<f32>, %rhs: complex<f32>) -> complex<f32> {
+ %div = complex.div %lhs, %rhs fastmath<nsz,arcp> : complex<f32>
+ return %div : complex<f32>
+}
+// DIV-SMITH-LABEL: func @complex_div_with_fmf
+// DIV-SMITH-SAME: %[[LHS:.*]]: complex<f32>, %[[RHS:.*]]: complex<f32>
+// DIV-SMITH-DAG: %[[CASTED_LHS:.*]] = builtin.unrealized_conversion_cast %[[LHS]] : complex<f32> to ![[C_TY:.*>]]
+// DIV-SMITH-DAG: %[[CASTED_RHS:.*]] = builtin.unrealized_conversion_cast %[[RHS]] : complex<f32> to ![[C_TY]]
+
+// DIV-SMITH: %[[LHS_REAL:.*]] = llvm.extractvalue %[[CASTED_LHS]][0] : ![[C_TY]]
+// DIV-SMITH: %[[LHS_IMAG:.*]] = llvm.extractvalue %[[CASTED_LHS]][1] : ![[C_TY]]
+// DIV-SMITH: %[[RHS_REAL:.*]] = llvm.extractvalue %[[CASTED_RHS]][0] : ![[C_TY]]
+// DIV-SMITH: %[[RHS_IMAG:.*]] = llvm.extractvalue %[[CASTED_RHS]][1] : ![[C_TY]]
+
+// DIV-SMITH: %[[RESULT_0:.*]] = llvm.mlir.poison : ![[C_TY]]
+
+// DIV-SMITH: %[[RHS_REAL_IMAG_RATIO:.*]] = llvm.fdiv %[[RHS_REAL]], %[[RHS_IMAG]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[RHS_REAL_TIMES_RHS_REAL_IMAG_RATIO:.*]] = llvm.fmul %[[RHS_REAL_IMAG_RATIO]], %[[RHS_REAL]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[RHS_REAL_IMAG_DENOM:.*]] = llvm.fadd %[[RHS_IMAG]], %[[RHS_REAL_TIMES_RHS_REAL_IMAG_RATIO]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[LHS_REAL_TIMES_RHS_REAL_IMAG_RATIO:.*]] = llvm.fmul %[[LHS_REAL]], %[[RHS_REAL_IMAG_RATIO]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[REAL_NUMERATOR_1:.*]] = llvm.fadd %[[LHS_REAL_TIMES_RHS_REAL_IMAG_RATIO]], %[[LHS_IMAG]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[RESULT_REAL_1:.*]] = llvm.fdiv %[[REAL_NUMERATOR_1]], %[[RHS_REAL_IMAG_DENOM]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[LHS_IMAG_TIMES_RHS_REAL_IMAG_RATIO:.*]] = llvm.fmul %[[LHS_IMAG]], %[[RHS_REAL_IMAG_RATIO]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[IMAG_NUMERATOR_1:.*]] = llvm.fsub %[[LHS_IMAG_TIMES_RHS_REAL_IMAG_RATIO]], %[[LHS_REAL]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[RESULT_IMAG_1:.*]] = llvm.fdiv %[[IMAG_NUMERATOR_1]], %[[RHS_REAL_IMAG_DENOM]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+
+// DIV-SMITH: %[[RHS_IMAG_REAL_RATIO:.*]] = llvm.fdiv %[[RHS_IMAG]], %[[RHS_REAL]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[RHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO:.*]] = llvm.fmul %[[RHS_IMAG_REAL_RATIO]], %[[RHS_IMAG]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[RHS_IMAG_REAL_DENOM:.*]] = llvm.fadd %[[RHS_REAL]], %[[RHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[LHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO:.*]] = llvm.fmul %[[LHS_IMAG]], %[[RHS_IMAG_REAL_RATIO]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[REAL_NUMERATOR_2:.*]] = llvm.fadd %[[LHS_REAL]], %[[LHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[RESULT_REAL_2:.*]] = llvm.fdiv %[[REAL_NUMERATOR_2]], %[[RHS_IMAG_REAL_DENOM]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[LHS_REAL_TIMES_RHS_IMAG_REAL_RATIO:.*]] = llvm.fmul %[[LHS_REAL]], %[[RHS_IMAG_REAL_RATIO]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[IMAG_NUMERATOR_2:.*]] = llvm.fsub %[[LHS_IMAG]], %[[LHS_REAL_TIMES_RHS_IMAG_REAL_RATIO]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[RESULT_IMAG_2:.*]] = llvm.fdiv %[[IMAG_NUMERATOR_2]], %[[RHS_IMAG_REAL_DENOM]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+
+// Case 1. Zero denominator, numerator contains at most one NaN value.
+// DIV-SMITH: %[[ZERO:.*]] = llvm.mlir.constant(0.000000e+00 : f32) : f32
+// DIV-SMITH: %[[RHS_REAL_ABS:.*]] = llvm.intr.fabs(%[[RHS_REAL]]) {fastmathFlags = #llvm.fastmath<nsz, arcp>} : (f32) -> f32
+// DIV-SMITH: %[[RHS_REAL_ABS_IS_ZERO:.*]] = llvm.fcmp "oeq" %[[RHS_REAL_ABS]], %[[ZERO]] : f32
+// DIV-SMITH: %[[RHS_IMAG_ABS:.*]] = llvm.intr.fabs(%[[RHS_IMAG]]) {fastmathFlags = #llvm.fastmath<nsz, arcp>} : (f32) -> f32
+// DIV-SMITH: %[[RHS_IMAG_ABS_IS_ZERO:.*]] = llvm.fcmp "oeq" %[[RHS_IMAG_ABS]], %[[ZERO]] : f32
+// DIV-SMITH: %[[LHS_REAL_IS_NOT_NAN:.*]] = llvm.fcmp "ord" %[[LHS_REAL]], %[[ZERO]] : f32
+// DIV-SMITH: %[[LHS_IMAG_IS_NOT_NAN:.*]] = llvm.fcmp "ord" %[[LHS_IMAG]], %[[ZERO]] : f32
+// DIV-SMITH: %[[LHS_CONTAINS_NOT_NAN_VALUE:.*]] = llvm.or %[[LHS_REAL_IS_NOT_NAN]], %[[LHS_IMAG_IS_NOT_NAN]] : i1
+// DIV-SMITH: %[[RHS_IS_ZERO:.*]] = llvm.and %[[RHS_REAL_ABS_IS_ZERO]], %[[RHS_IMAG_ABS_IS_ZERO]] : i1
+// DIV-SMITH: %[[RESULT_IS_INFINITY:.*]] = llvm.and %[[LHS_CONTAINS_NOT_NAN_VALUE]], %[[RHS_IS_ZERO]] : i1
+// DIV-SMITH: %[[INF:.*]] = llvm.mlir.constant(0x7F800000 : f32) : f32
+// DIV-SMITH: %[[INF_WITH_SIGN_OF_RHS_REAL:.*]] = llvm.intr.copysign(%[[INF]], %[[RHS_REAL]]) : (f32, f32) -> f32
+// DIV-SMITH: %[[INFINITY_RESULT_REAL:.*]] = llvm.fmul %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_REAL]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[INFINITY_RESULT_IMAG:.*]] = llvm.fmul %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_IMAG]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+
+// Case 2. Infinite numerator, finite denominator.
+// DIV-SMITH: %[[RHS_REAL_FINITE:.*]] = llvm.fcmp "one" %[[RHS_REAL_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[RHS_IMAG_FINITE:.*]] = llvm.fcmp "one" %[[RHS_IMAG_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[RHS_IS_FINITE:.*]] = llvm.and %[[RHS_REAL_FINITE]], %[[RHS_IMAG_FINITE]] : i1
+// DIV-SMITH: %[[LHS_REAL_ABS:.*]] = llvm.intr.fabs(%[[LHS_REAL]]) {fastmathFlags = #llvm.fastmath<nsz, arcp>} : (f32) -> f32
+// DIV-SMITH: %[[LHS_REAL_INFINITE:.*]] = llvm.fcmp "oeq" %[[LHS_REAL_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[LHS_IMAG_ABS:.*]] = llvm.intr.fabs(%[[LHS_IMAG]]) {fastmathFlags = #llvm.fastmath<nsz, arcp>} : (f32) -> f32
+// DIV-SMITH: %[[LHS_IMAG_INFINITE:.*]] = llvm.fcmp "oeq" %[[LHS_IMAG_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[LHS_IS_INFINITE:.*]] = llvm.or %[[LHS_REAL_INFINITE]], %[[LHS_IMAG_INFINITE]] : i1
+// DIV-SMITH: %[[INF_NUM_FINITE_DENOM:.*]] = llvm.and %[[LHS_IS_INFINITE]], %[[RHS_IS_FINITE]] : i1
+// DIV-SMITH: %[[ONE:.*]] = llvm.mlir.constant(1.000000e+00 : f32) : f32
+// DIV-SMITH: %[[LHS_REAL_IS_INF:.*]] = llvm.select %[[LHS_REAL_INFINITE]], %[[ONE]], %[[ZERO]] : i1, f32
+// DIV-SMITH: %[[LHS_REAL_IS_INF_WITH_SIGN:.*]] = llvm.intr.copysign(%[[LHS_REAL_IS_INF]], %[[LHS_REAL]]) : (f32, f32) -> f32
+// DIV-SMITH: %[[LHS_IMAG_IS_INF:.*]] = llvm.select %[[LHS_IMAG_INFINITE]], %[[ONE]], %[[ZERO]] : i1, f32
+// DIV-SMITH: %[[LHS_IMAG_IS_INF_WITH_SIGN:.*]] = llvm.intr.copysign(%[[LHS_IMAG_IS_INF]], %[[LHS_IMAG]]) : (f32, f32) -> f32
+// DIV-SMITH: %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_REAL:.*]] = llvm.fmul %[[LHS_REAL_IS_INF_WITH_SIGN]], %[[RHS_REAL]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_IMAG:.*]] = llvm.fmul %[[LHS_IMAG_IS_INF_WITH_SIGN]], %[[RHS_IMAG]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[INF_MULTIPLICATOR_1:.*]] = llvm.fadd %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_REAL]], %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_IMAG]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[RESULT_REAL_3:.*]] = llvm.fmul %[[INF]], %[[INF_MULTIPLICATOR_1]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_IMAG:.*]] = llvm.fmul %[[LHS_REAL_IS_INF_WITH_SIGN]], %[[RHS_IMAG]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_REAL:.*]] = llvm.fmul %[[LHS_IMAG_IS_INF_WITH_SIGN]], %[[RHS_REAL]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[INF_MULTIPLICATOR_2:.*]] = llvm.fsub %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_REAL]], %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_IMAG]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[RESULT_IMAG_3:.*]] = llvm.fmul %[[INF]], %[[INF_MULTIPLICATOR_2]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+
+// Case 3. Finite numerator, infinite denominator.
+// DIV-SMITH: %[[LHS_REAL_FINITE:.*]] = llvm.fcmp "one" %[[LHS_REAL_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[LHS_IMAG_FINITE:.*]] = llvm.fcmp "one" %[[LHS_IMAG_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[LHS_IS_FINITE:.*]] = llvm.and %[[LHS_REAL_FINITE]], %[[LHS_IMAG_FINITE]] : i1
+// DIV-SMITH: %[[RHS_REAL_INFINITE:.*]] = llvm.fcmp "oeq" %[[RHS_REAL_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[RHS_IMAG_INFINITE:.*]] = llvm.fcmp "oeq" %[[RHS_IMAG_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[RHS_IS_INFINITE:.*]] = llvm.or %[[RHS_REAL_INFINITE]], %[[RHS_IMAG_INFINITE]] : i1
+// DIV-SMITH: %[[FINITE_NUM_INFINITE_DENOM:.*]] = llvm.and %[[LHS_IS_FINITE]], %[[RHS_IS_INFINITE]] : i1
+// DIV-SMITH: %[[RHS_REAL_IS_INF:.*]] = llvm.select %[[RHS_REAL_INFINITE]], %[[ONE]], %[[ZERO]] : i1, f32
+// DIV-SMITH: %[[RHS_REAL_IS_INF_WITH_SIGN:.*]] = llvm.intr.copysign(%[[RHS_REAL_IS_INF]], %[[RHS_REAL]]) : (f32, f32) -> f32
+// DIV-SMITH: %[[RHS_IMAG_IS_INF:.*]] = llvm.select %[[RHS_IMAG_INFINITE]], %[[ONE]], %[[ZERO]] : i1, f32
+// DIV-SMITH: %[[RHS_IMAG_IS_INF_WITH_SIGN:.*]] = llvm.intr.copysign(%[[RHS_IMAG_IS_INF]], %[[RHS_IMAG]]) : (f32, f32) -> f32
+// DIV-SMITH: %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_REAL:.*]] = llvm.fmul %[[LHS_REAL]], %[[RHS_REAL_IS_INF_WITH_SIGN]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_IMAG:.*]] = llvm.fmul %[[LHS_IMAG]], %[[RHS_IMAG_IS_INF_WITH_SIGN]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[ZERO_MULTIPLICATOR_1:.*]] = llvm.fadd %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_REAL]], %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_IMAG]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[RESULT_REAL_4:.*]] = llvm.fmul %[[ZERO]], %[[ZERO_MULTIPLICATOR_1]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_IMAG:.*]] = llvm.fmul %[[LHS_IMAG]], %[[RHS_REAL_IS_INF_WITH_SIGN]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_REAL:.*]] = llvm.fmul %[[LHS_REAL]], %[[RHS_IMAG_IS_INF_WITH_SIGN]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[ZERO_MULTIPLICATOR_2:.*]] = llvm.fsub %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_IMAG]], %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_REAL]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-SMITH: %[[RESULT_IMAG_4:.*]] = llvm.fmul %[[ZERO]], %[[ZERO_MULTIPLICATOR_2]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+
+// DIV-SMITH: %[[REAL_ABS_SMALLER_THAN_IMAG_ABS:.*]] = llvm.fcmp "olt" %[[RHS_REAL_ABS]], %[[RHS_IMAG_ABS]] : f32
+// DIV-SMITH: %[[RESULT_REAL:.*]] = llvm.select %[[REAL_ABS_SMALLER_THAN_IMAG_ABS]], %[[RESULT_REAL_1]], %[[RESULT_REAL_2]] : i1, f32
+// DIV-SMITH: %[[RESULT_IMAG:.*]] = llvm.select %[[REAL_ABS_SMALLER_THAN_IMAG_ABS]], %[[RESULT_IMAG_1]], %[[RESULT_IMAG_2]] : i1, f32
+// DIV-SMITH: %[[RESULT_REAL_SPECIAL_CASE_3:.*]] = llvm.select %[[FINITE_NUM_INFINITE_DENOM]], %[[RESULT_REAL_4]], %[[RESULT_REAL]] : i1, f32
+// DIV-SMITH: %[[RESULT_IMAG_SPECIAL_CASE_3:.*]] = llvm.select %[[FINITE_NUM_INFINITE_DENOM]], %[[RESULT_IMAG_4]], %[[RESULT_IMAG]] : i1, f32
+// DIV-SMITH: %[[RESULT_REAL_SPECIAL_CASE_2:.*]] = llvm.select %[[INF_NUM_FINITE_DENOM]], %[[RESULT_REAL_3]], %[[RESULT_REAL_SPECIAL_CASE_3]] : i1, f32
+// DIV-SMITH: %[[RESULT_IMAG_SPECIAL_CASE_2:.*]] = llvm.select %[[INF_NUM_FINITE_DENOM]], %[[RESULT_IMAG_3]], %[[RESULT_IMAG_SPECIAL_CASE_3]] : i1, f32
+// DIV-SMITH: %[[RESULT_REAL_SPECIAL_CASE_1:.*]] = llvm.select %[[RESULT_IS_INFINITY]], %[[INFINITY_RESULT_REAL]], %[[RESULT_REAL_SPECIAL_CASE_2]] : i1, f32
+// DIV-SMITH: %[[RESULT_IMAG_SPECIAL_CASE_1:.*]] = llvm.select %[[RESULT_IS_INFINITY]], %[[INFINITY_RESULT_IMAG]], %[[RESULT_IMAG_SPECIAL_CASE_2]] : i1, f32
+// DIV-SMITH: %[[RESULT_REAL_IS_NAN:.*]] = llvm.fcmp "uno" %[[RESULT_REAL]], %[[ZERO]] : f32
+// DIV-SMITH: %[[RESULT_IMAG_IS_NAN:.*]] = llvm.fcmp "uno" %[[RESULT_IMAG]], %[[ZERO]] : f32
+// DIV-SMITH: %[[RESULT_IS_NAN:.*]] = llvm.and %[[RESULT_REAL_IS_NAN]], %[[RESULT_IMAG_IS_NAN]] : i1
+// DIV-SMITH: %[[RESULT_REAL_WITH_SPECIAL_CASES:.*]] = llvm.select %[[RESULT_IS_NAN]], %[[RESULT_REAL_SPECIAL_CASE_1]], %[[RESULT_REAL]] : i1, f32
+// DIV-SMITH: %[[RESULT_IMAG_WITH_SPECIAL_CASES:.*]] = llvm.select %[[RESULT_IS_NAN]], %[[RESULT_IMAG_SPECIAL_CASE_1]], %[[RESULT_IMAG]] : i1, f32
+// DIV-SMITH: %[[RESULT_1:.*]] = llvm.insertvalue %[[RESULT_REAL_WITH_SPECIAL_CASES]], %[[RESULT_0]][0] : ![[C_TY]]
+// DIV-SMITH: %[[RESULT_2:.*]] = llvm.insertvalue %[[RESULT_IMAG_WITH_SPECIAL_CASES]], %[[RESULT_1]][1] : ![[C_TY]]
+// DIV-SMITH: %[[CASTED_RESULT:.*]] = builtin.unrealized_conversion_cast %[[RESULT_2]] : ![[C_TY]] to complex<f32>
+// DIV-SMITH: return %[[CASTED_RESULT]] : complex<f32>
+
+
+// DIV-ALGEBRAIC-LABEL: func @complex_div_with_fmf
+// DIV-ALGEBRAIC-SAME: %[[LHS:.*]]: complex<f32>, %[[RHS:.*]]: complex<f32>
+// DIV-ALGEBRAIC-DAG: %[[CASTED_LHS:.*]] = builtin.unrealized_conversion_cast %[[LHS]] : complex<f32> to ![[C_TY:.*>]]
+// DIV-ALGEBRAIC-DAG: %[[CASTED_RHS:.*]] = builtin.unrealized_conversion_cast %[[RHS]] : complex<f32> to ![[C_TY]]
+
+// DIV-ALGEBRAIC: %[[LHS_RE:.*]] = llvm.extractvalue %[[CASTED_LHS]][0] : ![[C_TY]]
+// DIV-ALGEBRAIC: %[[LHS_IM:.*]] = llvm.extractvalue %[[CASTED_LHS]][1] : ![[C_TY]]
+// DIV-ALGEBRAIC: %[[RHS_RE:.*]] = llvm.extractvalue %[[CASTED_RHS]][0] : ![[C_TY]]
+// DIV-ALGEBRAIC: %[[RHS_IM:.*]] = llvm.extractvalue %[[CASTED_RHS]][1] : ![[C_TY]]
+
+// DIV-ALGEBRAIC: %[[RESULT_0:.*]] = llvm.mlir.poison : ![[C_TY]]
+
+// DIV-ALGEBRAIC-DAG: %[[RHS_RE_SQ:.*]] = llvm.fmul %[[RHS_RE]], %[[RHS_RE]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-ALGEBRAIC-DAG: %[[RHS_IM_SQ:.*]] = llvm.fmul %[[RHS_IM]], %[[RHS_IM]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-ALGEBRAIC: %[[SQ_NORM:.*]] = llvm.fadd %[[RHS_RE_SQ]], %[[RHS_IM_SQ]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+
+// DIV-ALGEBRAIC-DAG: %[[REAL_TMP_0:.*]] = llvm.fmul %[[LHS_RE]], %[[RHS_RE]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-ALGEBRAIC-DAG: %[[REAL_TMP_1:.*]] = llvm.fmul %[[LHS_IM]], %[[RHS_IM]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-ALGEBRAIC: %[[REAL_TMP_2:.*]] = llvm.fadd %[[REAL_TMP_0]], %[[REAL_TMP_1]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+
+// DIV-ALGEBRAIC-DAG: %[[IMAG_TMP_0:.*]] = llvm.fmul %[[LHS_IM]], %[[RHS_RE]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-ALGEBRAIC-DAG: %[[IMAG_TMP_1:.*]] = llvm.fmul %[[LHS_RE]], %[[RHS_IM]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-ALGEBRAIC: %[[IMAG_TMP_2:.*]] = llvm.fsub %[[IMAG_TMP_0]], %[[IMAG_TMP_1]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+
+// DIV-ALGEBRAIC: %[[REAL:.*]] = llvm.fdiv %[[REAL_TMP_2]], %[[SQ_NORM]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-ALGEBRAIC: %[[IMAG:.*]] = llvm.fdiv %[[IMAG_TMP_2]], %[[SQ_NORM]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// DIV-ALGEBRAIC: %[[RESULT_1:.*]] = llvm.insertvalue %[[REAL]], %[[RESULT_0]][0] : ![[C_TY]]
+// DIV-ALGEBRAIC: %[[RESULT_2:.*]] = llvm.insertvalue %[[IMAG]], %[[RESULT_1]][1] : ![[C_TY]]
+//
+// DIV-ALGEBRAIC: %[[CASTED_RESULT:.*]] = builtin.unrealized_conversion_cast %[[RESULT_2]] : ![[C_TY]] to complex<f32>
+// DIV-ALGEBRAIC: return %[[CASTED_RESULT]] : complex<f32>
diff --git a/mlir/test/Conversion/ComplexToLLVM/convert-to-llvm.mlir b/mlir/test/Conversion/ComplexToLLVM/convert-to-llvm.mlir
index 40f8af7de44aa..ad1b6658fbe78 100644
--- a/mlir/test/Conversion/ComplexToLLVM/convert-to-llvm.mlir
+++ b/mlir/test/Conversion/ComplexToLLVM/convert-to-llvm.mlir
@@ -103,8 +103,8 @@ func.func @complex_div(%lhs: complex<f32>, %rhs: complex<f32>) -> complex<f32> {
// CHECK: %[[IMAG_TMP_2:.*]] = llvm.fsub %[[IMAG_TMP_0]], %[[IMAG_TMP_1]] : f32
// CHECK: %[[REAL:.*]] = llvm.fdiv %[[REAL_TMP_2]], %[[SQ_NORM]] : f32
-// CHECK: %[[RESULT_1:.*]] = llvm.insertvalue %[[REAL]], %[[RESULT_0]][0] : ![[C_TY]]
// CHECK: %[[IMAG:.*]] = llvm.fdiv %[[IMAG_TMP_2]], %[[SQ_NORM]] : f32
+// CHECK: %[[RESULT_1:.*]] = llvm.insertvalue %[[REAL]], %[[RESULT_0]][0] : ![[C_TY]]
// CHECK: %[[RESULT_2:.*]] = llvm.insertvalue %[[IMAG]], %[[RESULT_1]][1] : ![[C_TY]]
//
// CHECK: %[[CASTED_RESULT:.*]] = builtin.unrealized_conversion_cast %[[RESULT_2]] : ![[C_TY]] to complex<f32>
@@ -221,8 +221,8 @@ func.func @complex_substraction_with_fmf() {
// CHECK: %[[IMAG_TMP_2:.*]] = llvm.fsub %[[IMAG_TMP_0]], %[[IMAG_TMP_1]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
// CHECK: %[[REAL:.*]] = llvm.fdiv %[[REAL_TMP_2]], %[[SQ_NORM]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
-// CHECK: %[[RESULT_1:.*]] = llvm.insertvalue %[[REAL]], %[[RESULT_0]][0] : ![[C_TY]]
// CHECK: %[[IMAG:.*]] = llvm.fdiv %[[IMAG_TMP_2]], %[[SQ_NORM]] {fastmathFlags = #llvm.fastmath<nsz, arcp>} : f32
+// CHECK: %[[RESULT_1:.*]] = llvm.insertvalue %[[REAL]], %[[RESULT_0]][0] : ![[C_TY]]
// CHECK: %[[RESULT_2:.*]] = llvm.insertvalue %[[IMAG]], %[[RESULT_1]][1] : ![[C_TY]]
//
// CHECK: %[[CASTED_RESULT:.*]] = builtin.unrealized_conversion_cast %[[RESULT_2]] : ![[C_TY]] to complex<f32>
diff --git a/mlir/test/Conversion/ComplexToLLVM/full-conversion.mlir b/mlir/test/Conversion/ComplexToLLVM/full-conversion.mlir
index deae4f618f789..2e27d694d1e71 100644
--- a/mlir/test/Conversion/ComplexToLLVM/full-conversion.mlir
+++ b/mlir/test/Conversion/ComplexToLLVM/full-conversion.mlir
@@ -26,8 +26,8 @@ func.func @complex_div(%lhs: complex<f32>, %rhs: complex<f32>) -> complex<f32> {
// CHECK: %[[IMAG_TMP_2:.*]] = llvm.fsub %[[IMAG_TMP_0]], %[[IMAG_TMP_1]] : f32
// CHECK: %[[REAL:.*]] = llvm.fdiv %[[REAL_TMP_2]], %[[SQ_NORM]] : f32
-// CHECK: %[[RESULT_1:.*]] = llvm.insertvalue %[[REAL]], %[[RESULT_0]][0] : ![[C_TY]]
// CHECK: %[[IMAG:.*]] = llvm.fdiv %[[IMAG_TMP_2]], %[[SQ_NORM]] : f32
+// CHECK: %[[RESULT_1:.*]] = llvm.insertvalue %[[REAL]], %[[RESULT_0]][0] : ![[C_TY]]
// CHECK: %[[RESULT_2:.*]] = llvm.insertvalue %[[IMAG]], %[[RESULT_1]][1] : ![[C_TY]]
// CHECK: llvm.return %[[RESULT_2]] : ![[C_TY]]
diff --git a/mlir/test/Conversion/ComplexToStandard/complex-range-option.mlir b/mlir/test/Conversion/ComplexToStandard/complex-range-option.mlir
new file mode 100644
index 0000000000000..97f37d8ebe77e
--- /dev/null
+++ b/mlir/test/Conversion/ComplexToStandard/complex-range-option.mlir
@@ -0,0 +1,277 @@
+// RUN: mlir-opt %s -convert-complex-to-standard=complex-range=improved | FileCheck %s --check-prefix=DIV-SMITH
+// RUN: mlir-opt %s -convert-complex-to-standard=complex-range=basic | FileCheck %s --check-prefix=DIV-ALGEBRAIC
+// RUN: mlir-opt %s -convert-complex-to-standard=complex-range=none | FileCheck %s --check-prefix=DIV-ALGEBRAIC
+
+
+func.func @complex_div(%lhs: complex<f32>, %rhs: complex<f32>) -> complex<f32> {
+ %div = complex.div %lhs, %rhs : complex<f32>
+ return %div : complex<f32>
+}
+// DIV-SMITH-LABEL: func @complex_div
+// DIV-SMITH-SAME: %[[LHS:.*]]: complex<f32>, %[[RHS:.*]]: complex<f32>
+
+// DIV-SMITH: %[[LHS_REAL:.*]] = complex.re %[[LHS]] : complex<f32>
+// DIV-SMITH: %[[LHS_IMAG:.*]] = complex.im %[[LHS]] : complex<f32>
+// DIV-SMITH: %[[RHS_REAL:.*]] = complex.re %[[RHS]] : complex<f32>
+// DIV-SMITH: %[[RHS_IMAG:.*]] = complex.im %[[RHS]] : complex<f32>
+
+// DIV-SMITH: %[[RHS_REAL_IMAG_RATIO:.*]] = arith.divf %[[RHS_REAL]], %[[RHS_IMAG]] : f32
+// DIV-SMITH: %[[RHS_REAL_TIMES_RHS_REAL_IMAG_RATIO:.*]] = arith.mulf %[[RHS_REAL_IMAG_RATIO]], %[[RHS_REAL]] : f32
+// DIV-SMITH: %[[RHS_REAL_IMAG_DENOM:.*]] = arith.addf %[[RHS_IMAG]], %[[RHS_REAL_TIMES_RHS_REAL_IMAG_RATIO]] : f32
+// DIV-SMITH: %[[LHS_REAL_TIMES_RHS_REAL_IMAG_RATIO:.*]] = arith.mulf %[[LHS_REAL]], %[[RHS_REAL_IMAG_RATIO]] : f32
+// DIV-SMITH: %[[REAL_NUMERATOR_1:.*]] = arith.addf %[[LHS_REAL_TIMES_RHS_REAL_IMAG_RATIO]], %[[LHS_IMAG]] : f32
+// DIV-SMITH: %[[RESULT_REAL_1:.*]] = arith.divf %[[REAL_NUMERATOR_1]], %[[RHS_REAL_IMAG_DENOM]] : f32
+// DIV-SMITH: %[[LHS_IMAG_TIMES_RHS_REAL_IMAG_RATIO:.*]] = arith.mulf %[[LHS_IMAG]], %[[RHS_REAL_IMAG_RATIO]] : f32
+// DIV-SMITH: %[[IMAG_NUMERATOR_1:.*]] = arith.subf %[[LHS_IMAG_TIMES_RHS_REAL_IMAG_RATIO]], %[[LHS_REAL]] : f32
+// DIV-SMITH: %[[RESULT_IMAG_1:.*]] = arith.divf %[[IMAG_NUMERATOR_1]], %[[RHS_REAL_IMAG_DENOM]] : f32
+
+// DIV-SMITH: %[[RHS_IMAG_REAL_RATIO:.*]] = arith.divf %[[RHS_IMAG]], %[[RHS_REAL]] : f32
+// DIV-SMITH: %[[RHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO:.*]] = arith.mulf %[[RHS_IMAG_REAL_RATIO]], %[[RHS_IMAG]] : f32
+// DIV-SMITH: %[[RHS_IMAG_REAL_DENOM:.*]] = arith.addf %[[RHS_REAL]], %[[RHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO]] : f32
+// DIV-SMITH: %[[LHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO:.*]] = arith.mulf %[[LHS_IMAG]], %[[RHS_IMAG_REAL_RATIO]] : f32
+// DIV-SMITH: %[[REAL_NUMERATOR_2:.*]] = arith.addf %[[LHS_REAL]], %[[LHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO]] : f32
+// DIV-SMITH: %[[RESULT_REAL_2:.*]] = arith.divf %[[REAL_NUMERATOR_2]], %[[RHS_IMAG_REAL_DENOM]] : f32
+// DIV-SMITH: %[[LHS_REAL_TIMES_RHS_IMAG_REAL_RATIO:.*]] = arith.mulf %[[LHS_REAL]], %[[RHS_IMAG_REAL_RATIO]] : f32
+// DIV-SMITH: %[[IMAG_NUMERATOR_2:.*]] = arith.subf %[[LHS_IMAG]], %[[LHS_REAL_TIMES_RHS_IMAG_REAL_RATIO]] : f32
+// DIV-SMITH: %[[RESULT_IMAG_2:.*]] = arith.divf %[[IMAG_NUMERATOR_2]], %[[RHS_IMAG_REAL_DENOM]] : f32
+
+// Case 1. Zero denominator, numerator contains at most one NaN value.
+// DIV-SMITH: %[[ZERO:.*]] = arith.constant 0.000000e+00 : f32
+// DIV-SMITH: %[[RHS_REAL_ABS:.*]] = math.absf %[[RHS_REAL]] : f32
+// DIV-SMITH: %[[RHS_REAL_ABS_IS_ZERO:.*]] = arith.cmpf oeq, %[[RHS_REAL_ABS]], %[[ZERO]] : f32
+// DIV-SMITH: %[[RHS_IMAG_ABS:.*]] = math.absf %[[RHS_IMAG]] : f32
+// DIV-SMITH: %[[RHS_IMAG_ABS_IS_ZERO:.*]] = arith.cmpf oeq, %[[RHS_IMAG_ABS]], %[[ZERO]] : f32
+// DIV-SMITH: %[[LHS_REAL_IS_NOT_NAN:.*]] = arith.cmpf ord, %[[LHS_REAL]], %[[ZERO]] : f32
+// DIV-SMITH: %[[LHS_IMAG_IS_NOT_NAN:.*]] = arith.cmpf ord, %[[LHS_IMAG]], %[[ZERO]] : f32
+// DIV-SMITH: %[[LHS_CONTAINS_NOT_NAN_VALUE:.*]] = arith.ori %[[LHS_REAL_IS_NOT_NAN]], %[[LHS_IMAG_IS_NOT_NAN]] : i1
+// DIV-SMITH: %[[RHS_IS_ZERO:.*]] = arith.andi %[[RHS_REAL_ABS_IS_ZERO]], %[[RHS_IMAG_ABS_IS_ZERO]] : i1
+// DIV-SMITH: %[[RESULT_IS_INFINITY:.*]] = arith.andi %[[LHS_CONTAINS_NOT_NAN_VALUE]], %[[RHS_IS_ZERO]] : i1
+// DIV-SMITH: %[[INF:.*]] = arith.constant 0x7F800000 : f32
+// DIV-SMITH: %[[INF_WITH_SIGN_OF_RHS_REAL:.*]] = math.copysign %[[INF]], %[[RHS_REAL]] : f32
+// DIV-SMITH: %[[INFINITY_RESULT_REAL:.*]] = arith.mulf %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_REAL]] : f32
+// DIV-SMITH: %[[INFINITY_RESULT_IMAG:.*]] = arith.mulf %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_IMAG]] : f32
+
+// Case 2. Infinite numerator, finite denominator.
+// DIV-SMITH: %[[RHS_REAL_FINITE:.*]] = arith.cmpf one, %[[RHS_REAL_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[RHS_IMAG_FINITE:.*]] = arith.cmpf one, %[[RHS_IMAG_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[RHS_IS_FINITE:.*]] = arith.andi %[[RHS_REAL_FINITE]], %[[RHS_IMAG_FINITE]] : i1
+// DIV-SMITH: %[[LHS_REAL_ABS:.*]] = math.absf %[[LHS_REAL]] : f32
+// DIV-SMITH: %[[LHS_REAL_INFINITE:.*]] = arith.cmpf oeq, %[[LHS_REAL_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[LHS_IMAG_ABS:.*]] = math.absf %[[LHS_IMAG]] : f32
+// DIV-SMITH: %[[LHS_IMAG_INFINITE:.*]] = arith.cmpf oeq, %[[LHS_IMAG_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[LHS_IS_INFINITE:.*]] = arith.ori %[[LHS_REAL_INFINITE]], %[[LHS_IMAG_INFINITE]] : i1
+// DIV-SMITH: %[[INF_NUM_FINITE_DENOM:.*]] = arith.andi %[[LHS_IS_INFINITE]], %[[RHS_IS_FINITE]] : i1
+// DIV-SMITH: %[[ONE:.*]] = arith.constant 1.000000e+00 : f32
+// DIV-SMITH: %[[LHS_REAL_IS_INF:.*]] = arith.select %[[LHS_REAL_INFINITE]], %[[ONE]], %[[ZERO]] : f32
+// DIV-SMITH: %[[LHS_REAL_IS_INF_WITH_SIGN:.*]] = math.copysign %[[LHS_REAL_IS_INF]], %[[LHS_REAL]] : f32
+// DIV-SMITH: %[[LHS_IMAG_IS_INF:.*]] = arith.select %[[LHS_IMAG_INFINITE]], %[[ONE]], %[[ZERO]] : f32
+// DIV-SMITH: %[[LHS_IMAG_IS_INF_WITH_SIGN:.*]] = math.copysign %[[LHS_IMAG_IS_INF]], %[[LHS_IMAG]] : f32
+// DIV-SMITH: %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_REAL:.*]] = arith.mulf %[[LHS_REAL_IS_INF_WITH_SIGN]], %[[RHS_REAL]] : f32
+// DIV-SMITH: %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_IMAG:.*]] = arith.mulf %[[LHS_IMAG_IS_INF_WITH_SIGN]], %[[RHS_IMAG]] : f32
+// DIV-SMITH: %[[INF_MULTIPLICATOR_1:.*]] = arith.addf %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_REAL]], %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_IMAG]] : f32
+// DIV-SMITH: %[[RESULT_REAL_3:.*]] = arith.mulf %[[INF]], %[[INF_MULTIPLICATOR_1]] : f32
+// DIV-SMITH: %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_IMAG:.*]] = arith.mulf %[[LHS_REAL_IS_INF_WITH_SIGN]], %[[RHS_IMAG]] : f32
+// DIV-SMITH: %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_REAL:.*]] = arith.mulf %[[LHS_IMAG_IS_INF_WITH_SIGN]], %[[RHS_REAL]] : f32
+// DIV-SMITH: %[[INF_MULTIPLICATOR_2:.*]] = arith.subf %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_REAL]], %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_IMAG]] : f32
+// DIV-SMITH: %[[RESULT_IMAG_3:.*]] = arith.mulf %[[INF]], %[[INF_MULTIPLICATOR_2]] : f32
+
+// Case 3. Finite numerator, infinite denominator.
+// DIV-SMITH: %[[LHS_REAL_FINITE:.*]] = arith.cmpf one, %[[LHS_REAL_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[LHS_IMAG_FINITE:.*]] = arith.cmpf one, %[[LHS_IMAG_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[LHS_IS_FINITE:.*]] = arith.andi %[[LHS_REAL_FINITE]], %[[LHS_IMAG_FINITE]] : i1
+// DIV-SMITH: %[[RHS_REAL_INFINITE:.*]] = arith.cmpf oeq, %[[RHS_REAL_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[RHS_IMAG_INFINITE:.*]] = arith.cmpf oeq, %[[RHS_IMAG_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[RHS_IS_INFINITE:.*]] = arith.ori %[[RHS_REAL_INFINITE]], %[[RHS_IMAG_INFINITE]] : i1
+// DIV-SMITH: %[[FINITE_NUM_INFINITE_DENOM:.*]] = arith.andi %[[LHS_IS_FINITE]], %[[RHS_IS_INFINITE]] : i1
+// DIV-SMITH: %[[RHS_REAL_IS_INF:.*]] = arith.select %[[RHS_REAL_INFINITE]], %[[ONE]], %[[ZERO]] : f32
+// DIV-SMITH: %[[RHS_REAL_IS_INF_WITH_SIGN:.*]] = math.copysign %[[RHS_REAL_IS_INF]], %[[RHS_REAL]] : f32
+// DIV-SMITH: %[[RHS_IMAG_IS_INF:.*]] = arith.select %[[RHS_IMAG_INFINITE]], %[[ONE]], %[[ZERO]] : f32
+// DIV-SMITH: %[[RHS_IMAG_IS_INF_WITH_SIGN:.*]] = math.copysign %[[RHS_IMAG_IS_INF]], %[[RHS_IMAG]] : f32
+// DIV-SMITH: %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_REAL:.*]] = arith.mulf %[[LHS_REAL]], %[[RHS_REAL_IS_INF_WITH_SIGN]] : f32
+// DIV-SMITH: %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_IMAG:.*]] = arith.mulf %[[LHS_IMAG]], %[[RHS_IMAG_IS_INF_WITH_SIGN]] : f32
+// DIV-SMITH: %[[ZERO_MULTIPLICATOR_1:.*]] = arith.addf %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_REAL]], %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_IMAG]] : f32
+// DIV-SMITH: %[[RESULT_REAL_4:.*]] = arith.mulf %[[ZERO]], %[[ZERO_MULTIPLICATOR_1]] : f32
+// DIV-SMITH: %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_IMAG:.*]] = arith.mulf %[[LHS_IMAG]], %[[RHS_REAL_IS_INF_WITH_SIGN]] : f32
+// DIV-SMITH: %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_REAL:.*]] = arith.mulf %[[LHS_REAL]], %[[RHS_IMAG_IS_INF_WITH_SIGN]] : f32
+// DIV-SMITH: %[[ZERO_MULTIPLICATOR_2:.*]] = arith.subf %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_IMAG]], %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_REAL]] : f32
+// DIV-SMITH: %[[RESULT_IMAG_4:.*]] = arith.mulf %[[ZERO]], %[[ZERO_MULTIPLICATOR_2]] : f32
+
+// DIV-SMITH: %[[REAL_ABS_SMALLER_THAN_IMAG_ABS:.*]] = arith.cmpf olt, %[[RHS_REAL_ABS]], %[[RHS_IMAG_ABS]] : f32
+// DIV-SMITH: %[[RESULT_REAL:.*]] = arith.select %[[REAL_ABS_SMALLER_THAN_IMAG_ABS]], %[[RESULT_REAL_1]], %[[RESULT_REAL_2]] : f32
+// DIV-SMITH: %[[RESULT_IMAG:.*]] = arith.select %[[REAL_ABS_SMALLER_THAN_IMAG_ABS]], %[[RESULT_IMAG_1]], %[[RESULT_IMAG_2]] : f32
+// DIV-SMITH: %[[RESULT_REAL_SPECIAL_CASE_3:.*]] = arith.select %[[FINITE_NUM_INFINITE_DENOM]], %[[RESULT_REAL_4]], %[[RESULT_REAL]] : f32
+// DIV-SMITH: %[[RESULT_IMAG_SPECIAL_CASE_3:.*]] = arith.select %[[FINITE_NUM_INFINITE_DENOM]], %[[RESULT_IMAG_4]], %[[RESULT_IMAG]] : f32
+// DIV-SMITH: %[[RESULT_REAL_SPECIAL_CASE_2:.*]] = arith.select %[[INF_NUM_FINITE_DENOM]], %[[RESULT_REAL_3]], %[[RESULT_REAL_SPECIAL_CASE_3]] : f32
+// DIV-SMITH: %[[RESULT_IMAG_SPECIAL_CASE_2:.*]] = arith.select %[[INF_NUM_FINITE_DENOM]], %[[RESULT_IMAG_3]], %[[RESULT_IMAG_SPECIAL_CASE_3]] : f32
+// DIV-SMITH: %[[RESULT_REAL_SPECIAL_CASE_1:.*]] = arith.select %[[RESULT_IS_INFINITY]], %[[INFINITY_RESULT_REAL]], %[[RESULT_REAL_SPECIAL_CASE_2]] : f32
+// DIV-SMITH: %[[RESULT_IMAG_SPECIAL_CASE_1:.*]] = arith.select %[[RESULT_IS_INFINITY]], %[[INFINITY_RESULT_IMAG]], %[[RESULT_IMAG_SPECIAL_CASE_2]] : f32
+// DIV-SMITH: %[[RESULT_REAL_IS_NAN:.*]] = arith.cmpf uno, %[[RESULT_REAL]], %[[ZERO]] : f32
+// DIV-SMITH: %[[RESULT_IMAG_IS_NAN:.*]] = arith.cmpf uno, %[[RESULT_IMAG]], %[[ZERO]] : f32
+// DIV-SMITH: %[[RESULT_IS_NAN:.*]] = arith.andi %[[RESULT_REAL_IS_NAN]], %[[RESULT_IMAG_IS_NAN]] : i1
+// DIV-SMITH: %[[RESULT_REAL_WITH_SPECIAL_CASES:.*]] = arith.select %[[RESULT_IS_NAN]], %[[RESULT_REAL_SPECIAL_CASE_1]], %[[RESULT_REAL]] : f32
+// DIV-SMITH: %[[RESULT_IMAG_WITH_SPECIAL_CASES:.*]] = arith.select %[[RESULT_IS_NAN]], %[[RESULT_IMAG_SPECIAL_CASE_1]], %[[RESULT_IMAG]] : f32
+// DIV-SMITH: %[[RESULT:.*]] = complex.create %[[RESULT_REAL_WITH_SPECIAL_CASES]], %[[RESULT_IMAG_WITH_SPECIAL_CASES]] : complex<f32>
+// DIV-SMITH: return %[[RESULT]] : complex<f32>
+
+
+// DIV-ALGEBRAIC-LABEL: func @complex_div
+// DIV-ALGEBRAIC-SAME: %[[LHS:.*]]: complex<f32>, %[[RHS:.*]]: complex<f32>
+
+// DIV-ALGEBRAIC: %[[LHS_RE:.*]] = complex.re %[[LHS]] : complex<f32>
+// DIV-ALGEBRAIC: %[[LHS_IM:.*]] = complex.im %[[LHS]] : complex<f32>
+// DIV-ALGEBRAIC: %[[RHS_RE:.*]] = complex.re %[[RHS]] : complex<f32>
+// DIV-ALGEBRAIC: %[[RHS_IM:.*]] = complex.im %[[RHS]] : complex<f32>
+
+// DIV-ALGEBRAIC-DAG: %[[RHS_RE_SQ:.*]] = arith.mulf %[[RHS_RE]], %[[RHS_RE]] : f32
+// DIV-ALGEBRAIC-DAG: %[[RHS_IM_SQ:.*]] = arith.mulf %[[RHS_IM]], %[[RHS_IM]] : f32
+// DIV-ALGEBRAIC: %[[SQ_NORM:.*]] = arith.addf %[[RHS_RE_SQ]], %[[RHS_IM_SQ]] : f32
+
+// DIV-ALGEBRAIC-DAG: %[[REAL_TMP_0:.*]] = arith.mulf %[[LHS_RE]], %[[RHS_RE]] : f32
+// DIV-ALGEBRAIC-DAG: %[[REAL_TMP_1:.*]] = arith.mulf %[[LHS_IM]], %[[RHS_IM]] : f32
+// DIV-ALGEBRAIC: %[[REAL_TMP_2:.*]] = arith.addf %[[REAL_TMP_0]], %[[REAL_TMP_1]] : f32
+
+// DIV-ALGEBRAIC-DAG: %[[IMAG_TMP_0:.*]] = arith.mulf %[[LHS_IM]], %[[RHS_RE]] : f32
+// DIV-ALGEBRAIC-DAG: %[[IMAG_TMP_1:.*]] = arith.mulf %[[LHS_RE]], %[[RHS_IM]] : f32
+// DIV-ALGEBRAIC: %[[IMAG_TMP_2:.*]] = arith.subf %[[IMAG_TMP_0]], %[[IMAG_TMP_1]] : f32
+
+// DIV-ALGEBRAIC: %[[REAL:.*]] = arith.divf %[[REAL_TMP_2]], %[[SQ_NORM]] : f32
+// DIV-ALGEBRAIC: %[[IMAG:.*]] = arith.divf %[[IMAG_TMP_2]], %[[SQ_NORM]] : f32
+// DIV-ALGEBRAIC: %[[RESULT:.*]] = complex.create %[[REAL]], %[[IMAG]] : complex<f32>
+// DIV-ALGEBRAIC: return %[[RESULT]] : complex<f32>
+
+
+func.func @complex_div_with_fmf(%lhs: complex<f32>, %rhs: complex<f32>) -> complex<f32> {
+ %div = complex.div %lhs, %rhs fastmath<nsz,arcp> : complex<f32>
+ return %div : complex<f32>
+}
+// DIV-SMITH-LABEL: func @complex_div_with_fmf
+// DIV-SMITH-SAME: %[[LHS:.*]]: complex<f32>, %[[RHS:.*]]: complex<f32>
+
+// DIV-SMITH: %[[LHS_REAL:.*]] = complex.re %[[LHS]] : complex<f32>
+// DIV-SMITH: %[[LHS_IMAG:.*]] = complex.im %[[LHS]] : complex<f32>
+// DIV-SMITH: %[[RHS_REAL:.*]] = complex.re %[[RHS]] : complex<f32>
+// DIV-SMITH: %[[RHS_IMAG:.*]] = complex.im %[[RHS]] : complex<f32>
+
+// DIV-SMITH: %[[RHS_REAL_IMAG_RATIO:.*]] = arith.divf %[[RHS_REAL]], %[[RHS_IMAG]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[RHS_REAL_TIMES_RHS_REAL_IMAG_RATIO:.*]] = arith.mulf %[[RHS_REAL_IMAG_RATIO]], %[[RHS_REAL]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[RHS_REAL_IMAG_DENOM:.*]] = arith.addf %[[RHS_IMAG]], %[[RHS_REAL_TIMES_RHS_REAL_IMAG_RATIO]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[LHS_REAL_TIMES_RHS_REAL_IMAG_RATIO:.*]] = arith.mulf %[[LHS_REAL]], %[[RHS_REAL_IMAG_RATIO]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[REAL_NUMERATOR_1:.*]] = arith.addf %[[LHS_REAL_TIMES_RHS_REAL_IMAG_RATIO]], %[[LHS_IMAG]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[RESULT_REAL_1:.*]] = arith.divf %[[REAL_NUMERATOR_1]], %[[RHS_REAL_IMAG_DENOM]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[LHS_IMAG_TIMES_RHS_REAL_IMAG_RATIO:.*]] = arith.mulf %[[LHS_IMAG]], %[[RHS_REAL_IMAG_RATIO]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[IMAG_NUMERATOR_1:.*]] = arith.subf %[[LHS_IMAG_TIMES_RHS_REAL_IMAG_RATIO]], %[[LHS_REAL]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[RESULT_IMAG_1:.*]] = arith.divf %[[IMAG_NUMERATOR_1]], %[[RHS_REAL_IMAG_DENOM]] fastmath<nsz,arcp> : f32
+
+// DIV-SMITH: %[[RHS_IMAG_REAL_RATIO:.*]] = arith.divf %[[RHS_IMAG]], %[[RHS_REAL]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[RHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO:.*]] = arith.mulf %[[RHS_IMAG_REAL_RATIO]], %[[RHS_IMAG]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[RHS_IMAG_REAL_DENOM:.*]] = arith.addf %[[RHS_REAL]], %[[RHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[LHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO:.*]] = arith.mulf %[[LHS_IMAG]], %[[RHS_IMAG_REAL_RATIO]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[REAL_NUMERATOR_2:.*]] = arith.addf %[[LHS_REAL]], %[[LHS_IMAG_TIMES_RHS_IMAG_REAL_RATIO]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[RESULT_REAL_2:.*]] = arith.divf %[[REAL_NUMERATOR_2]], %[[RHS_IMAG_REAL_DENOM]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[LHS_REAL_TIMES_RHS_IMAG_REAL_RATIO:.*]] = arith.mulf %[[LHS_REAL]], %[[RHS_IMAG_REAL_RATIO]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[IMAG_NUMERATOR_2:.*]] = arith.subf %[[LHS_IMAG]], %[[LHS_REAL_TIMES_RHS_IMAG_REAL_RATIO]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[RESULT_IMAG_2:.*]] = arith.divf %[[IMAG_NUMERATOR_2]], %[[RHS_IMAG_REAL_DENOM]] fastmath<nsz,arcp> : f32
+
+// Case 1. Zero denominator, numerator contains at most one NaN value.
+// DIV-SMITH: %[[ZERO:.*]] = arith.constant 0.000000e+00 : f32
+// DIV-SMITH: %[[RHS_REAL_ABS:.*]] = math.absf %[[RHS_REAL]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[RHS_REAL_ABS_IS_ZERO:.*]] = arith.cmpf oeq, %[[RHS_REAL_ABS]], %[[ZERO]] : f32
+// DIV-SMITH: %[[RHS_IMAG_ABS:.*]] = math.absf %[[RHS_IMAG]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[RHS_IMAG_ABS_IS_ZERO:.*]] = arith.cmpf oeq, %[[RHS_IMAG_ABS]], %[[ZERO]] : f32
+// DIV-SMITH: %[[LHS_REAL_IS_NOT_NAN:.*]] = arith.cmpf ord, %[[LHS_REAL]], %[[ZERO]] : f32
+// DIV-SMITH: %[[LHS_IMAG_IS_NOT_NAN:.*]] = arith.cmpf ord, %[[LHS_IMAG]], %[[ZERO]] : f32
+// DIV-SMITH: %[[LHS_CONTAINS_NOT_NAN_VALUE:.*]] = arith.ori %[[LHS_REAL_IS_NOT_NAN]], %[[LHS_IMAG_IS_NOT_NAN]] : i1
+// DIV-SMITH: %[[RHS_IS_ZERO:.*]] = arith.andi %[[RHS_REAL_ABS_IS_ZERO]], %[[RHS_IMAG_ABS_IS_ZERO]] : i1
+// DIV-SMITH: %[[RESULT_IS_INFINITY:.*]] = arith.andi %[[LHS_CONTAINS_NOT_NAN_VALUE]], %[[RHS_IS_ZERO]] : i1
+// DIV-SMITH: %[[INF:.*]] = arith.constant 0x7F800000 : f32
+// DIV-SMITH: %[[INF_WITH_SIGN_OF_RHS_REAL:.*]] = math.copysign %[[INF]], %[[RHS_REAL]] : f32
+// DIV-SMITH: %[[INFINITY_RESULT_REAL:.*]] = arith.mulf %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_REAL]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[INFINITY_RESULT_IMAG:.*]] = arith.mulf %[[INF_WITH_SIGN_OF_RHS_REAL]], %[[LHS_IMAG]] fastmath<nsz,arcp> : f32
+
+// Case 2. Infinite numerator, finite denominator.
+// DIV-SMITH: %[[RHS_REAL_FINITE:.*]] = arith.cmpf one, %[[RHS_REAL_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[RHS_IMAG_FINITE:.*]] = arith.cmpf one, %[[RHS_IMAG_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[RHS_IS_FINITE:.*]] = arith.andi %[[RHS_REAL_FINITE]], %[[RHS_IMAG_FINITE]] : i1
+// DIV-SMITH: %[[LHS_REAL_ABS:.*]] = math.absf %[[LHS_REAL]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[LHS_REAL_INFINITE:.*]] = arith.cmpf oeq, %[[LHS_REAL_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[LHS_IMAG_ABS:.*]] = math.absf %[[LHS_IMAG]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[LHS_IMAG_INFINITE:.*]] = arith.cmpf oeq, %[[LHS_IMAG_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[LHS_IS_INFINITE:.*]] = arith.ori %[[LHS_REAL_INFINITE]], %[[LHS_IMAG_INFINITE]] : i1
+// DIV-SMITH: %[[INF_NUM_FINITE_DENOM:.*]] = arith.andi %[[LHS_IS_INFINITE]], %[[RHS_IS_FINITE]] : i1
+// DIV-SMITH: %[[ONE:.*]] = arith.constant 1.000000e+00 : f32
+// DIV-SMITH: %[[LHS_REAL_IS_INF:.*]] = arith.select %[[LHS_REAL_INFINITE]], %[[ONE]], %[[ZERO]] : f32
+// DIV-SMITH: %[[LHS_REAL_IS_INF_WITH_SIGN:.*]] = math.copysign %[[LHS_REAL_IS_INF]], %[[LHS_REAL]] : f32
+// DIV-SMITH: %[[LHS_IMAG_IS_INF:.*]] = arith.select %[[LHS_IMAG_INFINITE]], %[[ONE]], %[[ZERO]] : f32
+// DIV-SMITH: %[[LHS_IMAG_IS_INF_WITH_SIGN:.*]] = math.copysign %[[LHS_IMAG_IS_INF]], %[[LHS_IMAG]] : f32
+// DIV-SMITH: %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_REAL:.*]] = arith.mulf %[[LHS_REAL_IS_INF_WITH_SIGN]], %[[RHS_REAL]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_IMAG:.*]] = arith.mulf %[[LHS_IMAG_IS_INF_WITH_SIGN]], %[[RHS_IMAG]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[INF_MULTIPLICATOR_1:.*]] = arith.addf %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_REAL]], %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_IMAG]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[RESULT_REAL_3:.*]] = arith.mulf %[[INF]], %[[INF_MULTIPLICATOR_1]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_IMAG:.*]] = arith.mulf %[[LHS_REAL_IS_INF_WITH_SIGN]], %[[RHS_IMAG]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_REAL:.*]] = arith.mulf %[[LHS_IMAG_IS_INF_WITH_SIGN]], %[[RHS_REAL]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[INF_MULTIPLICATOR_2:.*]] = arith.subf %[[LHS_IMAG_IS_INF_WITH_SIGN_TIMES_RHS_REAL]], %[[LHS_REAL_IS_INF_WITH_SIGN_TIMES_RHS_IMAG]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[RESULT_IMAG_3:.*]] = arith.mulf %[[INF]], %[[INF_MULTIPLICATOR_2]] fastmath<nsz,arcp> : f32
+
+// Case 3. Finite numerator, infinite denominator.
+// DIV-SMITH: %[[LHS_REAL_FINITE:.*]] = arith.cmpf one, %[[LHS_REAL_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[LHS_IMAG_FINITE:.*]] = arith.cmpf one, %[[LHS_IMAG_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[LHS_IS_FINITE:.*]] = arith.andi %[[LHS_REAL_FINITE]], %[[LHS_IMAG_FINITE]] : i1
+// DIV-SMITH: %[[RHS_REAL_INFINITE:.*]] = arith.cmpf oeq, %[[RHS_REAL_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[RHS_IMAG_INFINITE:.*]] = arith.cmpf oeq, %[[RHS_IMAG_ABS]], %[[INF]] : f32
+// DIV-SMITH: %[[RHS_IS_INFINITE:.*]] = arith.ori %[[RHS_REAL_INFINITE]], %[[RHS_IMAG_INFINITE]] : i1
+// DIV-SMITH: %[[FINITE_NUM_INFINITE_DENOM:.*]] = arith.andi %[[LHS_IS_FINITE]], %[[RHS_IS_INFINITE]] : i1
+// DIV-SMITH: %[[RHS_REAL_IS_INF:.*]] = arith.select %[[RHS_REAL_INFINITE]], %[[ONE]], %[[ZERO]] : f32
+// DIV-SMITH: %[[RHS_REAL_IS_INF_WITH_SIGN:.*]] = math.copysign %[[RHS_REAL_IS_INF]], %[[RHS_REAL]] : f32
+// DIV-SMITH: %[[RHS_IMAG_IS_INF:.*]] = arith.select %[[RHS_IMAG_INFINITE]], %[[ONE]], %[[ZERO]] : f32
+// DIV-SMITH: %[[RHS_IMAG_IS_INF_WITH_SIGN:.*]] = math.copysign %[[RHS_IMAG_IS_INF]], %[[RHS_IMAG]] : f32
+// DIV-SMITH: %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_REAL:.*]] = arith.mulf %[[LHS_REAL]], %[[RHS_REAL_IS_INF_WITH_SIGN]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_IMAG:.*]] = arith.mulf %[[LHS_IMAG]], %[[RHS_IMAG_IS_INF_WITH_SIGN]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[ZERO_MULTIPLICATOR_1:.*]] = arith.addf %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_REAL]], %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_IMAG]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[RESULT_REAL_4:.*]] = arith.mulf %[[ZERO]], %[[ZERO_MULTIPLICATOR_1]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_IMAG:.*]] = arith.mulf %[[LHS_IMAG]], %[[RHS_REAL_IS_INF_WITH_SIGN]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_REAL:.*]] = arith.mulf %[[LHS_REAL]], %[[RHS_IMAG_IS_INF_WITH_SIGN]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[ZERO_MULTIPLICATOR_2:.*]] = arith.subf %[[RHS_REAL_IS_INF_WITH_SIGN_TIMES_LHS_IMAG]], %[[RHS_IMAG_IS_INF_WITH_SIGN_TIMES_LHS_REAL]] fastmath<nsz,arcp> : f32
+// DIV-SMITH: %[[RESULT_IMAG_4:.*]] = arith.mulf %[[ZERO]], %[[ZERO_MULTIPLICATOR_2]] fastmath<nsz,arcp> : f32
+
+// DIV-SMITH: %[[REAL_ABS_SMALLER_THAN_IMAG_ABS:.*]] = arith.cmpf olt, %[[RHS_REAL_ABS]], %[[RHS_IMAG_ABS]] : f32
+// DIV-SMITH: %[[RESULT_REAL:.*]] = arith.select %[[REAL_ABS_SMALLER_THAN_IMAG_ABS]], %[[RESULT_REAL_1]], %[[RESULT_REAL_2]] : f32
+// DIV-SMITH: %[[RESULT_IMAG:.*]] = arith.select %[[REAL_ABS_SMALLER_THAN_IMAG_ABS]], %[[RESULT_IMAG_1]], %[[RESULT_IMAG_2]] : f32
+// DIV-SMITH: %[[RESULT_REAL_SPECIAL_CASE_3:.*]] = arith.select %[[FINITE_NUM_INFINITE_DENOM]], %[[RESULT_REAL_4]], %[[RESULT_REAL]] : f32
+// DIV-SMITH: %[[RESULT_IMAG_SPECIAL_CASE_3:.*]] = arith.select %[[FINITE_NUM_INFINITE_DENOM]], %[[RESULT_IMAG_4]], %[[RESULT_IMAG]] : f32
+// DIV-SMITH: %[[RESULT_REAL_SPECIAL_CASE_2:.*]] = arith.select %[[INF_NUM_FINITE_DENOM]], %[[RESULT_REAL_3]], %[[RESULT_REAL_SPECIAL_CASE_3]] : f32
+// DIV-SMITH: %[[RESULT_IMAG_SPECIAL_CASE_2:.*]] = arith.select %[[INF_NUM_FINITE_DENOM]], %[[RESULT_IMAG_3]], %[[RESULT_IMAG_SPECIAL_CASE_3]] : f32
+// DIV-SMITH: %[[RESULT_REAL_SPECIAL_CASE_1:.*]] = arith.select %[[RESULT_IS_INFINITY]], %[[INFINITY_RESULT_REAL]], %[[RESULT_REAL_SPECIAL_CASE_2]] : f32
+// DIV-SMITH: %[[RESULT_IMAG_SPECIAL_CASE_1:.*]] = arith.select %[[RESULT_IS_INFINITY]], %[[INFINITY_RESULT_IMAG]], %[[RESULT_IMAG_SPECIAL_CASE_2]] : f32
+// DIV-SMITH: %[[RESULT_REAL_IS_NAN:.*]] = arith.cmpf uno, %[[RESULT_REAL]], %[[ZERO]] : f32
+// DIV-SMITH: %[[RESULT_IMAG_IS_NAN:.*]] = arith.cmpf uno, %[[RESULT_IMAG]], %[[ZERO]] : f32
+// DIV-SMITH: %[[RESULT_IS_NAN:.*]] = arith.andi %[[RESULT_REAL_IS_NAN]], %[[RESULT_IMAG_IS_NAN]] : i1
+// DIV-SMITH: %[[RESULT_REAL_WITH_SPECIAL_CASES:.*]] = arith.select %[[RESULT_IS_NAN]], %[[RESULT_REAL_SPECIAL_CASE_1]], %[[RESULT_REAL]] : f32
+// DIV-SMITH: %[[RESULT_IMAG_WITH_SPECIAL_CASES:.*]] = arith.select %[[RESULT_IS_NAN]], %[[RESULT_IMAG_SPECIAL_CASE_1]], %[[RESULT_IMAG]] : f32
+// DIV-SMITH: %[[RESULT:.*]] = complex.create %[[RESULT_REAL_WITH_SPECIAL_CASES]], %[[RESULT_IMAG_WITH_SPECIAL_CASES]] : complex<f32>
+// DIV-SMITH: return %[[RESULT]] : complex<f32>
+
+
+// DIV-ALGEBRAIC-LABEL: func @complex_div_with_fmf
+// DIV-ALGEBRAIC-SAME: %[[LHS:.*]]: complex<f32>, %[[RHS:.*]]: complex<f32>
+
+// DIV-ALGEBRAIC: %[[LHS_RE:.*]] = complex.re %[[LHS]] : complex<f32>
+// DIV-ALGEBRAIC: %[[LHS_IM:.*]] = complex.im %[[LHS]] : complex<f32>
+// DIV-ALGEBRAIC: %[[RHS_RE:.*]] = complex.re %[[RHS]] : complex<f32>
+// DIV-ALGEBRAIC: %[[RHS_IM:.*]] = complex.im %[[RHS]] : complex<f32>
+
+// DIV-ALGEBRAIC-DAG: %[[RHS_RE_SQ:.*]] = arith.mulf %[[RHS_RE]], %[[RHS_RE]] fastmath<nsz,arcp> : f32
+// DIV-ALGEBRAIC-DAG: %[[RHS_IM_SQ:.*]] = arith.mulf %[[RHS_IM]], %[[RHS_IM]] fastmath<nsz,arcp> : f32
+// DIV-ALGEBRAIC: %[[SQ_NORM:.*]] = arith.addf %[[RHS_RE_SQ]], %[[RHS_IM_SQ]] fastmath<nsz,arcp> : f32
+
+// DIV-ALGEBRAIC-DAG: %[[REAL_TMP_0:.*]] = arith.mulf %[[LHS_RE]], %[[RHS_RE]] fastmath<nsz,arcp> : f32
+// DIV-ALGEBRAIC-DAG: %[[REAL_TMP_1:.*]] = arith.mulf %[[LHS_IM]], %[[RHS_IM]] fastmath<nsz,arcp> : f32
+// DIV-ALGEBRAIC: %[[REAL_TMP_2:.*]] = arith.addf %[[REAL_TMP_0]], %[[REAL_TMP_1]] fastmath<nsz,arcp> : f32
+
+// DIV-ALGEBRAIC-DAG: %[[IMAG_TMP_0:.*]] = arith.mulf %[[LHS_IM]], %[[RHS_RE]] fastmath<nsz,arcp> : f32
+// DIV-ALGEBRAIC-DAG: %[[IMAG_TMP_1:.*]] = arith.mulf %[[LHS_RE]], %[[RHS_IM]] fastmath<nsz,arcp> : f32
+// DIV-ALGEBRAIC: %[[IMAG_TMP_2:.*]] = arith.subf %[[IMAG_TMP_0]], %[[IMAG_TMP_1]] fastmath<nsz,arcp> : f32
+
+// DIV-ALGEBRAIC: %[[REAL:.*]] = arith.divf %[[REAL_TMP_2]], %[[SQ_NORM]] fastmath<nsz,arcp> : f32
+// DIV-ALGEBRAIC: %[[IMAG:.*]] = arith.divf %[[IMAG_TMP_2]], %[[SQ_NORM]] fastmath<nsz,arcp> : f32
+// DIV-ALGEBRAIC: %[[RESULT:.*]] = complex.create %[[REAL]], %[[IMAG]] : complex<f32>
+// DIV-ALGEBRAIC: return %[[RESULT]] : complex<f32>
More information about the Mlir-commits
mailing list