| //===- 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 = LLVM::FAddOp::create( | |
| rewriter, loc, LLVM::FMulOp::create(rewriter, loc, rhsRe, rhsRe, fmf), | |
| LLVM::FMulOp::create(rewriter, loc, rhsIm, rhsIm, fmf), fmf); | |
| Value realNumerator = LLVM::FAddOp::create( | |
| rewriter, loc, LLVM::FMulOp::create(rewriter, loc, lhsRe, rhsRe, fmf), | |
| LLVM::FMulOp::create(rewriter, loc, lhsIm, rhsIm, fmf), fmf); | |
| Value imagNumerator = LLVM::FSubOp::create( | |
| rewriter, loc, LLVM::FMulOp::create(rewriter, loc, lhsIm, rhsRe, fmf), | |
| LLVM::FMulOp::create(rewriter, loc, lhsRe, rhsIm, fmf), fmf); | |
| *resultRe = | |
| LLVM::FDivOp::create(rewriter, loc, realNumerator, rhsSqNorm, fmf); | |
| *resultIm = | |
| LLVM::FDivOp::create(rewriter, 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 = arith::AddFOp::create( | |
| rewriter, loc, arith::MulFOp::create(rewriter, loc, rhsRe, rhsRe, fmf), | |
| arith::MulFOp::create(rewriter, loc, rhsIm, rhsIm, fmf), fmf); | |
| Value realNumerator = arith::AddFOp::create( | |
| rewriter, loc, arith::MulFOp::create(rewriter, loc, lhsRe, rhsRe, fmf), | |
| arith::MulFOp::create(rewriter, loc, lhsIm, rhsIm, fmf), fmf); | |
| Value imagNumerator = arith::SubFOp::create( | |
| rewriter, loc, arith::MulFOp::create(rewriter, loc, lhsIm, rhsRe, fmf), | |
| arith::MulFOp::create(rewriter, loc, lhsRe, rhsIm, fmf), fmf); | |
| *resultRe = | |
| arith::DivFOp::create(rewriter, loc, realNumerator, rhsSqNorm, fmf); | |
| *resultIm = | |
| arith::DivFOp::create(rewriter, 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 = | |
| LLVM::FDivOp::create(rewriter, loc, rhsRe, rhsIm, fmf); | |
| Value rhsRealImagDenom = LLVM::FAddOp::create( | |
| rewriter, loc, rhsIm, | |
| LLVM::FMulOp::create(rewriter, loc, rhsRealImagRatio, rhsRe, fmf), fmf); | |
| Value realNumerator1 = LLVM::FAddOp::create( | |
| rewriter, loc, | |
| LLVM::FMulOp::create(rewriter, loc, lhsRe, rhsRealImagRatio, fmf), lhsIm, | |
| fmf); | |
| Value resultReal1 = LLVM::FDivOp::create(rewriter, loc, realNumerator1, | |
| rhsRealImagDenom, fmf); | |
| Value imagNumerator1 = LLVM::FSubOp::create( | |
| rewriter, loc, | |
| LLVM::FMulOp::create(rewriter, loc, lhsIm, rhsRealImagRatio, fmf), lhsRe, | |
| fmf); | |
| Value resultImag1 = LLVM::FDivOp::create(rewriter, loc, imagNumerator1, | |
| rhsRealImagDenom, fmf); | |
| Value rhsImagRealRatio = | |
| LLVM::FDivOp::create(rewriter, loc, rhsIm, rhsRe, fmf); | |
| Value rhsImagRealDenom = LLVM::FAddOp::create( | |
| rewriter, loc, rhsRe, | |
| LLVM::FMulOp::create(rewriter, loc, rhsImagRealRatio, rhsIm, fmf), fmf); | |
| Value realNumerator2 = LLVM::FAddOp::create( | |
| rewriter, loc, lhsRe, | |
| LLVM::FMulOp::create(rewriter, loc, lhsIm, rhsImagRealRatio, fmf), fmf); | |
| Value resultReal2 = LLVM::FDivOp::create(rewriter, loc, realNumerator2, | |
| rhsImagRealDenom, fmf); | |
| Value imagNumerator2 = LLVM::FSubOp::create( | |
| rewriter, loc, lhsIm, | |
| LLVM::FMulOp::create(rewriter, loc, lhsRe, rhsImagRealRatio, fmf), fmf); | |
| Value resultImag2 = LLVM::FDivOp::create(rewriter, loc, imagNumerator2, | |
| rhsImagRealDenom, fmf); | |
| // Consider corner cases. | |
| // Case 1. Zero denominator, numerator contains at most one NaN value. | |
| Value zero = LLVM::ConstantOp::create(rewriter, loc, elementType, | |
| rewriter.getZeroAttr(elementType)); | |
| Value rhsRealAbs = LLVM::FAbsOp::create(rewriter, loc, rhsRe, fmf); | |
| Value rhsRealIsZero = LLVM::FCmpOp::create( | |
| rewriter, loc, LLVM::FCmpPredicate::oeq, rhsRealAbs, zero); | |
| Value rhsImagAbs = LLVM::FAbsOp::create(rewriter, loc, rhsIm, fmf); | |
| Value rhsImagIsZero = LLVM::FCmpOp::create( | |
| rewriter, loc, LLVM::FCmpPredicate::oeq, rhsImagAbs, zero); | |
| Value lhsRealIsNotNaN = LLVM::FCmpOp::create( | |
| rewriter, loc, LLVM::FCmpPredicate::ord, lhsRe, zero); | |
| Value lhsImagIsNotNaN = LLVM::FCmpOp::create( | |
| rewriter, loc, LLVM::FCmpPredicate::ord, lhsIm, zero); | |
| Value lhsContainsNotNaNValue = | |
| LLVM::OrOp::create(rewriter, loc, lhsRealIsNotNaN, lhsImagIsNotNaN); | |
| Value resultIsInfinity = LLVM::AndOp::create( | |
| rewriter, loc, lhsContainsNotNaNValue, | |
| LLVM::AndOp::create(rewriter, loc, rhsRealIsZero, rhsImagIsZero)); | |
| Value inf = LLVM::ConstantOp::create( | |
| rewriter, loc, elementType, | |
| rewriter.getFloatAttr(elementType, | |
| APFloat::getInf(elementType.getFloatSemantics()))); | |
| Value infWithSignOfrhsReal = | |
| LLVM::CopySignOp::create(rewriter, loc, inf, rhsRe); | |
| Value infinityResultReal = | |
| LLVM::FMulOp::create(rewriter, loc, infWithSignOfrhsReal, lhsRe, fmf); | |
| Value infinityResultImag = | |
| LLVM::FMulOp::create(rewriter, loc, infWithSignOfrhsReal, lhsIm, fmf); | |
| // Case 2. Infinite numerator, finite denominator. | |
| Value rhsRealFinite = LLVM::FCmpOp::create( | |
| rewriter, loc, LLVM::FCmpPredicate::one, rhsRealAbs, inf); | |
| Value rhsImagFinite = LLVM::FCmpOp::create( | |
| rewriter, loc, LLVM::FCmpPredicate::one, rhsImagAbs, inf); | |
| Value rhsFinite = | |
| LLVM::AndOp::create(rewriter, loc, rhsRealFinite, rhsImagFinite); | |
| Value lhsRealAbs = LLVM::FAbsOp::create(rewriter, loc, lhsRe, fmf); | |
| Value lhsRealInfinite = LLVM::FCmpOp::create( | |
| rewriter, loc, LLVM::FCmpPredicate::oeq, lhsRealAbs, inf); | |
| Value lhsImagAbs = LLVM::FAbsOp::create(rewriter, loc, lhsIm, fmf); | |
| Value lhsImagInfinite = LLVM::FCmpOp::create( | |
| rewriter, loc, LLVM::FCmpPredicate::oeq, lhsImagAbs, inf); | |
| Value lhsInfinite = | |
| LLVM::OrOp::create(rewriter, loc, lhsRealInfinite, lhsImagInfinite); | |
| Value infNumFiniteDenom = | |
| LLVM::AndOp::create(rewriter, loc, lhsInfinite, rhsFinite); | |
| Value one = LLVM::ConstantOp::create(rewriter, loc, elementType, | |
| rewriter.getFloatAttr(elementType, 1)); | |
| Value lhsRealIsInfWithSign = LLVM::CopySignOp::create( | |
| rewriter, loc, | |
| LLVM::SelectOp::create(rewriter, loc, lhsRealInfinite, one, zero), lhsRe); | |
| Value lhsImagIsInfWithSign = LLVM::CopySignOp::create( | |
| rewriter, loc, | |
| LLVM::SelectOp::create(rewriter, loc, lhsImagInfinite, one, zero), lhsIm); | |
| Value lhsRealIsInfWithSignTimesrhsReal = | |
| LLVM::FMulOp::create(rewriter, loc, lhsRealIsInfWithSign, rhsRe, fmf); | |
| Value lhsImagIsInfWithSignTimesrhsImag = | |
| LLVM::FMulOp::create(rewriter, loc, lhsImagIsInfWithSign, rhsIm, fmf); | |
| Value resultReal3 = LLVM::FMulOp::create( | |
| rewriter, loc, inf, | |
| LLVM::FAddOp::create(rewriter, loc, lhsRealIsInfWithSignTimesrhsReal, | |
| lhsImagIsInfWithSignTimesrhsImag, fmf), | |
| fmf); | |
| Value lhsRealIsInfWithSignTimesrhsImag = | |
| LLVM::FMulOp::create(rewriter, loc, lhsRealIsInfWithSign, rhsIm, fmf); | |
| Value lhsImagIsInfWithSignTimesrhsReal = | |
| LLVM::FMulOp::create(rewriter, loc, lhsImagIsInfWithSign, rhsRe, fmf); | |
| Value resultImag3 = LLVM::FMulOp::create( | |
| rewriter, loc, inf, | |
| LLVM::FSubOp::create(rewriter, loc, lhsImagIsInfWithSignTimesrhsReal, | |
| lhsRealIsInfWithSignTimesrhsImag, fmf), | |
| fmf); | |
| // Case 3: Finite numerator, infinite denominator. | |
| Value lhsRealFinite = LLVM::FCmpOp::create( | |
| rewriter, loc, LLVM::FCmpPredicate::one, lhsRealAbs, inf); | |
| Value lhsImagFinite = LLVM::FCmpOp::create( | |
| rewriter, loc, LLVM::FCmpPredicate::one, lhsImagAbs, inf); | |
| Value lhsFinite = | |
| LLVM::AndOp::create(rewriter, loc, lhsRealFinite, lhsImagFinite); | |
| Value rhsRealInfinite = LLVM::FCmpOp::create( | |
| rewriter, loc, LLVM::FCmpPredicate::oeq, rhsRealAbs, inf); | |
| Value rhsImagInfinite = LLVM::FCmpOp::create( | |
| rewriter, loc, LLVM::FCmpPredicate::oeq, rhsImagAbs, inf); | |
| Value rhsInfinite = | |
| LLVM::OrOp::create(rewriter, loc, rhsRealInfinite, rhsImagInfinite); | |
| Value finiteNumInfiniteDenom = | |
| LLVM::AndOp::create(rewriter, loc, lhsFinite, rhsInfinite); | |
| Value rhsRealIsInfWithSign = LLVM::CopySignOp::create( | |
| rewriter, loc, | |
| LLVM::SelectOp::create(rewriter, loc, rhsRealInfinite, one, zero), rhsRe); | |
| Value rhsImagIsInfWithSign = LLVM::CopySignOp::create( | |
| rewriter, loc, | |
| LLVM::SelectOp::create(rewriter, loc, rhsImagInfinite, one, zero), rhsIm); | |
| Value rhsRealIsInfWithSignTimeslhsReal = | |
| LLVM::FMulOp::create(rewriter, loc, lhsRe, rhsRealIsInfWithSign, fmf); | |
| Value rhsImagIsInfWithSignTimeslhsImag = | |
| LLVM::FMulOp::create(rewriter, loc, lhsIm, rhsImagIsInfWithSign, fmf); | |
| Value resultReal4 = LLVM::FMulOp::create( | |
| rewriter, loc, zero, | |
| LLVM::FAddOp::create(rewriter, loc, rhsRealIsInfWithSignTimeslhsReal, | |
| rhsImagIsInfWithSignTimeslhsImag, fmf), | |
| fmf); | |
| Value rhsRealIsInfWithSignTimeslhsImag = | |
| LLVM::FMulOp::create(rewriter, loc, lhsIm, rhsRealIsInfWithSign, fmf); | |
| Value rhsImagIsInfWithSignTimeslhsReal = | |
| LLVM::FMulOp::create(rewriter, loc, lhsRe, rhsImagIsInfWithSign, fmf); | |
| Value resultImag4 = LLVM::FMulOp::create( | |
| rewriter, loc, zero, | |
| LLVM::FSubOp::create(rewriter, loc, rhsRealIsInfWithSignTimeslhsImag, | |
| rhsImagIsInfWithSignTimeslhsReal, fmf), | |
| fmf); | |
| Value realAbsSmallerThanImagAbs = LLVM::FCmpOp::create( | |
| rewriter, loc, LLVM::FCmpPredicate::olt, rhsRealAbs, rhsImagAbs); | |
| Value resultReal5 = LLVM::SelectOp::create( | |
| rewriter, loc, realAbsSmallerThanImagAbs, resultReal1, resultReal2); | |
| Value resultImag5 = LLVM::SelectOp::create( | |
| rewriter, loc, realAbsSmallerThanImagAbs, resultImag1, resultImag2); | |
| Value resultRealSpecialCase3 = LLVM::SelectOp::create( | |
| rewriter, loc, finiteNumInfiniteDenom, resultReal4, resultReal5); | |
| Value resultImagSpecialCase3 = LLVM::SelectOp::create( | |
| rewriter, loc, finiteNumInfiniteDenom, resultImag4, resultImag5); | |
| Value resultRealSpecialCase2 = LLVM::SelectOp::create( | |
| rewriter, loc, infNumFiniteDenom, resultReal3, resultRealSpecialCase3); | |
| Value resultImagSpecialCase2 = LLVM::SelectOp::create( | |
| rewriter, loc, infNumFiniteDenom, resultImag3, resultImagSpecialCase3); | |
| Value resultRealSpecialCase1 = | |
| LLVM::SelectOp::create(rewriter, loc, resultIsInfinity, | |
| infinityResultReal, resultRealSpecialCase2); | |
| Value resultImagSpecialCase1 = | |
| LLVM::SelectOp::create(rewriter, loc, resultIsInfinity, | |
| infinityResultImag, resultImagSpecialCase2); | |
| Value resultRealIsNaN = LLVM::FCmpOp::create( | |
| rewriter, loc, LLVM::FCmpPredicate::uno, resultReal5, zero); | |
| Value resultImagIsNaN = LLVM::FCmpOp::create( | |
| rewriter, loc, LLVM::FCmpPredicate::uno, resultImag5, zero); | |
| Value resultIsNaN = | |
| LLVM::AndOp::create(rewriter, loc, resultRealIsNaN, resultImagIsNaN); | |
| *resultRe = LLVM::SelectOp::create(rewriter, loc, resultIsNaN, | |
| resultRealSpecialCase1, resultReal5); | |
| *resultIm = LLVM::SelectOp::create(rewriter, 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 = | |
| arith::DivFOp::create(rewriter, loc, rhsRe, rhsIm, fmf); | |
| Value rhsRealImagDenom = arith::AddFOp::create( | |
| rewriter, loc, rhsIm, | |
| arith::MulFOp::create(rewriter, loc, rhsRealImagRatio, rhsRe, fmf), fmf); | |
| Value realNumerator1 = arith::AddFOp::create( | |
| rewriter, loc, | |
| arith::MulFOp::create(rewriter, loc, lhsRe, rhsRealImagRatio, fmf), lhsIm, | |
| fmf); | |
| Value resultReal1 = arith::DivFOp::create(rewriter, loc, realNumerator1, | |
| rhsRealImagDenom, fmf); | |
| Value imagNumerator1 = arith::SubFOp::create( | |
| rewriter, loc, | |
| arith::MulFOp::create(rewriter, loc, lhsIm, rhsRealImagRatio, fmf), lhsRe, | |
| fmf); | |
| Value resultImag1 = arith::DivFOp::create(rewriter, loc, imagNumerator1, | |
| rhsRealImagDenom, fmf); | |
| Value rhsImagRealRatio = | |
| arith::DivFOp::create(rewriter, loc, rhsIm, rhsRe, fmf); | |
| Value rhsImagRealDenom = arith::AddFOp::create( | |
| rewriter, loc, rhsRe, | |
| arith::MulFOp::create(rewriter, loc, rhsImagRealRatio, rhsIm, fmf), fmf); | |
| Value realNumerator2 = arith::AddFOp::create( | |
| rewriter, loc, lhsRe, | |
| arith::MulFOp::create(rewriter, loc, lhsIm, rhsImagRealRatio, fmf), fmf); | |
| Value resultReal2 = arith::DivFOp::create(rewriter, loc, realNumerator2, | |
| rhsImagRealDenom, fmf); | |
| Value imagNumerator2 = arith::SubFOp::create( | |
| rewriter, loc, lhsIm, | |
| arith::MulFOp::create(rewriter, loc, lhsRe, rhsImagRealRatio, fmf), fmf); | |
| Value resultImag2 = arith::DivFOp::create(rewriter, loc, imagNumerator2, | |
| rhsImagRealDenom, fmf); | |
| // Consider corner cases. | |
| // Case 1. Zero denominator, numerator contains at most one NaN value. | |
| Value zero = arith::ConstantOp::create(rewriter, loc, elementType, | |
| rewriter.getZeroAttr(elementType)); | |
| Value rhsRealAbs = math::AbsFOp::create(rewriter, loc, rhsRe, fmf); | |
| Value rhsRealIsZero = arith::CmpFOp::create( | |
| rewriter, loc, arith::CmpFPredicate::OEQ, rhsRealAbs, zero); | |
| Value rhsImagAbs = math::AbsFOp::create(rewriter, loc, rhsIm, fmf); | |
| Value rhsImagIsZero = arith::CmpFOp::create( | |
| rewriter, loc, arith::CmpFPredicate::OEQ, rhsImagAbs, zero); | |
| Value lhsRealIsNotNaN = arith::CmpFOp::create( | |
| rewriter, loc, arith::CmpFPredicate::ORD, lhsRe, zero); | |
| Value lhsImagIsNotNaN = arith::CmpFOp::create( | |
| rewriter, loc, arith::CmpFPredicate::ORD, lhsIm, zero); | |
| Value lhsContainsNotNaNValue = | |
| arith::OrIOp::create(rewriter, loc, lhsRealIsNotNaN, lhsImagIsNotNaN); | |
| Value resultIsInfinity = arith::AndIOp::create( | |
| rewriter, loc, lhsContainsNotNaNValue, | |
| arith::AndIOp::create(rewriter, loc, rhsRealIsZero, rhsImagIsZero)); | |
| Value inf = arith::ConstantOp::create( | |
| rewriter, loc, elementType, | |
| rewriter.getFloatAttr(elementType, | |
| APFloat::getInf(elementType.getFloatSemantics()))); | |
| Value infWithSignOfRhsReal = | |
| math::CopySignOp::create(rewriter, loc, inf, rhsRe); | |
| Value infinityResultReal = | |
| arith::MulFOp::create(rewriter, loc, infWithSignOfRhsReal, lhsRe, fmf); | |
| Value infinityResultImag = | |
| arith::MulFOp::create(rewriter, loc, infWithSignOfRhsReal, lhsIm, fmf); | |
| // Case 2. Infinite numerator, finite denominator. | |
| Value rhsRealFinite = arith::CmpFOp::create( | |
| rewriter, loc, arith::CmpFPredicate::ONE, rhsRealAbs, inf); | |
| Value rhsImagFinite = arith::CmpFOp::create( | |
| rewriter, loc, arith::CmpFPredicate::ONE, rhsImagAbs, inf); | |
| Value rhsFinite = | |
| arith::AndIOp::create(rewriter, loc, rhsRealFinite, rhsImagFinite); | |
| Value lhsRealAbs = math::AbsFOp::create(rewriter, loc, lhsRe, fmf); | |
| Value lhsRealInfinite = arith::CmpFOp::create( | |
| rewriter, loc, arith::CmpFPredicate::OEQ, lhsRealAbs, inf); | |
| Value lhsImagAbs = math::AbsFOp::create(rewriter, loc, lhsIm, fmf); | |
| Value lhsImagInfinite = arith::CmpFOp::create( | |
| rewriter, loc, arith::CmpFPredicate::OEQ, lhsImagAbs, inf); | |
| Value lhsInfinite = | |
| arith::OrIOp::create(rewriter, loc, lhsRealInfinite, lhsImagInfinite); | |
| Value infNumFiniteDenom = | |
| arith::AndIOp::create(rewriter, loc, lhsInfinite, rhsFinite); | |
| Value one = arith::ConstantOp::create(rewriter, loc, elementType, | |
| rewriter.getFloatAttr(elementType, 1)); | |
| Value lhsRealIsInfWithSign = math::CopySignOp::create( | |
| rewriter, loc, | |
| arith::SelectOp::create(rewriter, loc, lhsRealInfinite, one, zero), | |
| lhsRe); | |
| Value lhsImagIsInfWithSign = math::CopySignOp::create( | |
| rewriter, loc, | |
| arith::SelectOp::create(rewriter, loc, lhsImagInfinite, one, zero), | |
| lhsIm); | |
| Value lhsRealIsInfWithSignTimesRhsReal = | |
| arith::MulFOp::create(rewriter, loc, lhsRealIsInfWithSign, rhsRe, fmf); | |
| Value lhsImagIsInfWithSignTimesRhsImag = | |
| arith::MulFOp::create(rewriter, loc, lhsImagIsInfWithSign, rhsIm, fmf); | |
| Value resultReal3 = arith::MulFOp::create( | |
| rewriter, loc, inf, | |
| arith::AddFOp::create(rewriter, loc, lhsRealIsInfWithSignTimesRhsReal, | |
| lhsImagIsInfWithSignTimesRhsImag, fmf), | |
| fmf); | |
| Value lhsRealIsInfWithSignTimesRhsImag = | |
| arith::MulFOp::create(rewriter, loc, lhsRealIsInfWithSign, rhsIm, fmf); | |
| Value lhsImagIsInfWithSignTimesRhsReal = | |
| arith::MulFOp::create(rewriter, loc, lhsImagIsInfWithSign, rhsRe, fmf); | |
| Value resultImag3 = arith::MulFOp::create( | |
| rewriter, loc, inf, | |
| arith::SubFOp::create(rewriter, loc, lhsImagIsInfWithSignTimesRhsReal, | |
| lhsRealIsInfWithSignTimesRhsImag, fmf), | |
| fmf); | |
| // Case 3: Finite numerator, infinite denominator. | |
| Value lhsRealFinite = arith::CmpFOp::create( | |
| rewriter, loc, arith::CmpFPredicate::ONE, lhsRealAbs, inf); | |
| Value lhsImagFinite = arith::CmpFOp::create( | |
| rewriter, loc, arith::CmpFPredicate::ONE, lhsImagAbs, inf); | |
| Value lhsFinite = | |
| arith::AndIOp::create(rewriter, loc, lhsRealFinite, lhsImagFinite); | |
| Value rhsRealInfinite = arith::CmpFOp::create( | |
| rewriter, loc, arith::CmpFPredicate::OEQ, rhsRealAbs, inf); | |
| Value rhsImagInfinite = arith::CmpFOp::create( | |
| rewriter, loc, arith::CmpFPredicate::OEQ, rhsImagAbs, inf); | |
| Value rhsInfinite = | |
| arith::OrIOp::create(rewriter, loc, rhsRealInfinite, rhsImagInfinite); | |
| Value finiteNumInfiniteDenom = | |
| arith::AndIOp::create(rewriter, loc, lhsFinite, rhsInfinite); | |
| Value rhsRealIsInfWithSign = math::CopySignOp::create( | |
| rewriter, loc, | |
| arith::SelectOp::create(rewriter, loc, rhsRealInfinite, one, zero), | |
| rhsRe); | |
| Value rhsImagIsInfWithSign = math::CopySignOp::create( | |
| rewriter, loc, | |
| arith::SelectOp::create(rewriter, loc, rhsImagInfinite, one, zero), | |
| rhsIm); | |
| Value rhsRealIsInfWithSignTimesLhsReal = | |
| arith::MulFOp::create(rewriter, loc, lhsRe, rhsRealIsInfWithSign, fmf); | |
| Value rhsImagIsInfWithSignTimesLhsImag = | |
| arith::MulFOp::create(rewriter, loc, lhsIm, rhsImagIsInfWithSign, fmf); | |
| Value resultReal4 = arith::MulFOp::create( | |
| rewriter, loc, zero, | |
| arith::AddFOp::create(rewriter, loc, rhsRealIsInfWithSignTimesLhsReal, | |
| rhsImagIsInfWithSignTimesLhsImag, fmf), | |
| fmf); | |
| Value rhsRealIsInfWithSignTimesLhsImag = | |
| arith::MulFOp::create(rewriter, loc, lhsIm, rhsRealIsInfWithSign, fmf); | |
| Value rhsImagIsInfWithSignTimesLhsReal = | |
| arith::MulFOp::create(rewriter, loc, lhsRe, rhsImagIsInfWithSign, fmf); | |
| Value resultImag4 = arith::MulFOp::create( | |
| rewriter, loc, zero, | |
| arith::SubFOp::create(rewriter, loc, rhsRealIsInfWithSignTimesLhsImag, | |
| rhsImagIsInfWithSignTimesLhsReal, fmf), | |
| fmf); | |
| Value realAbsSmallerThanImagAbs = arith::CmpFOp::create( | |
| rewriter, loc, arith::CmpFPredicate::OLT, rhsRealAbs, rhsImagAbs); | |
| Value resultReal5 = arith::SelectOp::create( | |
| rewriter, loc, realAbsSmallerThanImagAbs, resultReal1, resultReal2); | |
| Value resultImag5 = arith::SelectOp::create( | |
| rewriter, loc, realAbsSmallerThanImagAbs, resultImag1, resultImag2); | |
| Value resultRealSpecialCase3 = arith::SelectOp::create( | |
| rewriter, loc, finiteNumInfiniteDenom, resultReal4, resultReal5); | |
| Value resultImagSpecialCase3 = arith::SelectOp::create( | |
| rewriter, loc, finiteNumInfiniteDenom, resultImag4, resultImag5); | |
| Value resultRealSpecialCase2 = arith::SelectOp::create( | |
| rewriter, loc, infNumFiniteDenom, resultReal3, resultRealSpecialCase3); | |
| Value resultImagSpecialCase2 = arith::SelectOp::create( | |
| rewriter, loc, infNumFiniteDenom, resultImag3, resultImagSpecialCase3); | |
| Value resultRealSpecialCase1 = | |
| arith::SelectOp::create(rewriter, loc, resultIsInfinity, | |
| infinityResultReal, resultRealSpecialCase2); | |
| Value resultImagSpecialCase1 = | |
| arith::SelectOp::create(rewriter, loc, resultIsInfinity, | |
| infinityResultImag, resultImagSpecialCase2); | |
| Value resultRealIsNaN = arith::CmpFOp::create( | |
| rewriter, loc, arith::CmpFPredicate::UNO, resultReal5, zero); | |
| Value resultImagIsNaN = arith::CmpFOp::create( | |
| rewriter, loc, arith::CmpFPredicate::UNO, resultImag5, zero); | |
| Value resultIsNaN = | |
| arith::AndIOp::create(rewriter, loc, resultRealIsNaN, resultImagIsNaN); | |
| *resultRe = arith::SelectOp::create(rewriter, loc, resultIsNaN, | |
| resultRealSpecialCase1, resultReal5); | |
| *resultIm = arith::SelectOp::create(rewriter, loc, resultIsNaN, | |
| resultImagSpecialCase1, resultImag5); | |
| } |