diff --git a/mlir/lib/Conversion/ComplexToStandard/ComplexToStandard.cpp b/mlir/lib/Conversion/ComplexToStandard/ComplexToStandard.cpp --- a/mlir/lib/Conversion/ComplexToStandard/ComplexToStandard.cpp +++ b/mlir/lib/Conversion/ComplexToStandard/ComplexToStandard.cpp @@ -337,6 +337,144 @@ } }; +struct MulOpConversion : public OpConversionPattern { + using OpConversionPattern::OpConversionPattern; + + LogicalResult + matchAndRewrite(complex::MulOp op, ArrayRef operands, + ConversionPatternRewriter &rewriter) const override { + complex::MulOp::Adaptor transformed(operands); + mlir::ImplicitLocOpBuilder b(op.getLoc(), rewriter); + auto type = transformed.lhs().getType().cast(); + auto elementType = type.getElementType().cast(); + + Value lhsReal = b.create(elementType, transformed.lhs()); + Value lhsRealAbs = b.create(lhsReal); + Value lhsImag = b.create(elementType, transformed.lhs()); + Value lhsImagAbs = b.create(lhsImag); + Value rhsReal = b.create(elementType, transformed.rhs()); + Value rhsRealAbs = b.create(rhsReal); + Value rhsImag = b.create(elementType, transformed.rhs()); + Value rhsImagAbs = b.create(rhsImag); + + Value lhsRealTimesRhsReal = b.create(lhsReal, rhsReal); + Value lhsRealTimesRhsRealAbs = b.create(lhsRealTimesRhsReal); + Value lhsImagTimesRhsImag = b.create(lhsImag, rhsImag); + Value lhsImagTimesRhsImagAbs = b.create(lhsImagTimesRhsImag); + Value real = b.create(lhsRealTimesRhsReal, lhsImagTimesRhsImag); + + Value lhsImagTimesRhsReal = b.create(lhsImag, rhsReal); + Value lhsImagTimesRhsRealAbs = b.create(lhsImagTimesRhsReal); + Value lhsRealTimesRhsImag = b.create(lhsReal, rhsImag); + Value lhsRealTimesRhsImagAbs = b.create(lhsRealTimesRhsImag); + Value imag = b.create(lhsImagTimesRhsReal, lhsRealTimesRhsImag); + + // Handle cases where the "naive" calculation results in NaN values. + Value realIsNan = b.create(CmpFPredicate::UNO, real, real); + Value imagIsNan = b.create(CmpFPredicate::UNO, imag, imag); + Value isNan = b.create(realIsNan, imagIsNan); + + Value inf = b.create( + elementType, + b.getFloatAttr(elementType, + APFloat::getInf(elementType.getFloatSemantics()))); + + // Case 1. `lhsReal` or `lhsImag` are infinite. + Value lhsRealIsInf = b.create(CmpFPredicate::OEQ, lhsRealAbs, inf); + Value lhsImagIsInf = b.create(CmpFPredicate::OEQ, lhsImagAbs, inf); + Value lhsIsInf = b.create(lhsRealIsInf, lhsImagIsInf); + Value rhsRealIsNan = b.create(CmpFPredicate::UNO, rhsReal, rhsReal); + Value rhsImagIsNan = b.create(CmpFPredicate::UNO, rhsImag, rhsImag); + Value zero = b.create(elementType, b.getZeroAttr(elementType)); + Value one = + b.create(elementType, b.getFloatAttr(elementType, 1)); + Value lhsRealIsInfFloat = b.create(lhsRealIsInf, one, zero); + lhsReal = b.create( + lhsIsInf, b.create(lhsRealIsInfFloat, lhsReal), lhsReal); + Value lhsImagIsInfFloat = b.create(lhsImagIsInf, one, zero); + lhsImag = b.create( + lhsIsInf, b.create(lhsImagIsInfFloat, lhsImag), lhsImag); + Value lhsIsInfAndRhsRealIsNan = b.create(lhsIsInf, rhsRealIsNan); + rhsReal = b.create(lhsIsInfAndRhsRealIsNan, + b.create(zero, rhsReal), rhsReal); + Value lhsIsInfAndRhsImagIsNan = b.create(lhsIsInf, rhsImagIsNan); + rhsImag = b.create(lhsIsInfAndRhsImagIsNan, + b.create(zero, rhsImag), rhsImag); + + // Case 2. `rhsReal` or `rhsImag` are infinite. + Value rhsRealIsInf = b.create(CmpFPredicate::OEQ, rhsRealAbs, inf); + Value rhsImagIsInf = b.create(CmpFPredicate::OEQ, rhsImagAbs, inf); + Value rhsIsInf = b.create(rhsRealIsInf, rhsImagIsInf); + Value lhsRealIsNan = b.create(CmpFPredicate::UNO, lhsReal, lhsReal); + Value lhsImagIsNan = b.create(CmpFPredicate::UNO, lhsImag, lhsImag); + Value rhsRealIsInfFloat = b.create(rhsRealIsInf, one, zero); + rhsReal = b.create( + rhsIsInf, b.create(rhsRealIsInfFloat, rhsReal), rhsReal); + Value rhsImagIsInfFloat = b.create(rhsImagIsInf, one, zero); + rhsImag = b.create( + rhsIsInf, b.create(rhsImagIsInfFloat, rhsImag), rhsImag); + Value rhsIsInfAndLhsRealIsNan = b.create(rhsIsInf, lhsRealIsNan); + lhsReal = b.create(rhsIsInfAndLhsRealIsNan, + b.create(zero, lhsReal), lhsReal); + Value rhsIsInfAndLhsImagIsNan = b.create(rhsIsInf, lhsImagIsNan); + lhsImag = b.create(rhsIsInfAndLhsImagIsNan, + b.create(zero, lhsImag), lhsImag); + Value recalc = b.create(lhsIsInf, rhsIsInf); + + // Case 3. One of the pairwise products of left hand side with right hand + // side is infinite. + Value lhsRealTimesRhsRealIsInf = + b.create(CmpFPredicate::OEQ, lhsRealTimesRhsRealAbs, inf); + Value lhsImagTimesRhsImagIsInf = + b.create(CmpFPredicate::OEQ, lhsImagTimesRhsImagAbs, inf); + Value isSpecialCase = + b.create(lhsRealTimesRhsRealIsInf, lhsImagTimesRhsImagIsInf); + Value lhsRealTimesRhsImagIsInf = + b.create(CmpFPredicate::OEQ, lhsRealTimesRhsImagAbs, inf); + isSpecialCase = b.create(isSpecialCase, lhsRealTimesRhsImagIsInf); + Value lhsImagTimesRhsRealIsInf = + b.create(CmpFPredicate::OEQ, lhsImagTimesRhsRealAbs, inf); + isSpecialCase = b.create(isSpecialCase, lhsImagTimesRhsRealIsInf); + Type i1Type = b.getI1Type(); + Value notRecalc = b.create( + recalc, b.create(i1Type, b.getIntegerAttr(i1Type, 1))); + isSpecialCase = b.create(isSpecialCase, notRecalc); + Value isSpecialCaseAndLhsRealIsNan = + b.create(isSpecialCase, lhsRealIsNan); + lhsReal = b.create(isSpecialCaseAndLhsRealIsNan, + b.create(zero, lhsReal), lhsReal); + Value isSpecialCaseAndLhsImagIsNan = + b.create(isSpecialCase, lhsImagIsNan); + lhsImag = b.create(isSpecialCaseAndLhsImagIsNan, + b.create(zero, lhsImag), lhsImag); + Value isSpecialCaseAndRhsRealIsNan = + b.create(isSpecialCase, rhsRealIsNan); + rhsReal = b.create(isSpecialCaseAndRhsRealIsNan, + b.create(zero, rhsReal), rhsReal); + Value isSpecialCaseAndRhsImagIsNan = + b.create(isSpecialCase, rhsImagIsNan); + rhsImag = b.create(isSpecialCaseAndRhsImagIsNan, + b.create(zero, rhsImag), rhsImag); + recalc = b.create(recalc, isSpecialCase); + recalc = b.create(isNan, recalc); + + // Recalculate real part. + lhsRealTimesRhsReal = b.create(lhsReal, rhsReal); + lhsImagTimesRhsImag = b.create(lhsImag, rhsImag); + Value newReal = b.create(lhsRealTimesRhsReal, lhsImagTimesRhsImag); + real = b.create(recalc, b.create(inf, newReal), real); + + // Recalculate imag part. + lhsImagTimesRhsReal = b.create(lhsImag, rhsReal); + lhsRealTimesRhsImag = b.create(lhsReal, rhsImag); + Value newImag = b.create(lhsImagTimesRhsReal, lhsRealTimesRhsImag); + imag = b.create(recalc, b.create(inf, newImag), imag); + + rewriter.replaceOpWithNewOp(op, type, real, imag); + return success(); + } +}; + struct NegOpConversion : public OpConversionPattern { using OpConversionPattern::OpConversionPattern; @@ -397,6 +535,7 @@ DivOpConversion, ExpOpConversion, LogOpConversion, + MulOpConversion, NegOpConversion, SignOpConversion>(patterns.getContext()); // clang-format on @@ -419,8 +558,8 @@ target.addLegalDialect(); target.addIllegalOp(); + complex::ExpOp, complex::LogOp, complex::MulOp, + complex::NegOp, complex::NotEqualOp, complex::SignOp>(); if (failed(applyPartialConversion(function, target, std::move(patterns)))) signalPassFailure(); } diff --git a/mlir/test/Conversion/ComplexToStandard/convert-to-standard.mlir b/mlir/test/Conversion/ComplexToStandard/convert-to-standard.mlir --- a/mlir/test/Conversion/ComplexToStandard/convert-to-standard.mlir +++ b/mlir/test/Conversion/ComplexToStandard/convert-to-standard.mlir @@ -173,6 +173,124 @@ // CHECK: %[[RESULT:.*]] = complex.create %[[RESULT_REAL]], %[[RESULT_IMAG]] : complex // CHECK: return %[[RESULT]] : complex +// CHECK-LABEL: func @complex_mul +// CHECK-SAME: (%[[LHS:.*]]: complex, %[[RHS:.*]]: complex) +func @complex_mul(%lhs: complex, %rhs: complex) -> complex { + %mul = complex.mul %lhs, %rhs : complex + return %mul : complex +} +// CHECK: %[[LHS_REAL:.*]] = complex.re %[[LHS]] : complex +// CHECK: %[[LHS_REAL_ABS:.*]] = absf %[[LHS_REAL]] : f32 +// CHECK: %[[LHS_IMAG:.*]] = complex.im %[[LHS]] : complex +// CHECK: %[[LHS_IMAG_ABS:.*]] = absf %[[LHS_IMAG]] : f32 +// CHECK: %[[RHS_REAL:.*]] = complex.re %[[RHS]] : complex +// CHECK: %[[RHS_REAL_ABS:.*]] = absf %[[RHS_REAL]] : f32 +// CHECK: %[[RHS_IMAG:.*]] = complex.im %[[RHS]] : complex +// CHECK: %[[RHS_IMAG_ABS:.*]] = absf %[[RHS_IMAG]] : f32 + +// CHECK: %[[LHS_REAL_TIMES_RHS_REAL:.*]] = mulf %[[LHS_REAL]], %[[RHS_REAL]] : f32 +// CHECK: %[[LHS_REAL_TIMES_RHS_REAL_ABS:.*]] = absf %[[LHS_REAL_TIMES_RHS_REAL]] : f32 +// CHECK: %[[LHS_IMAG_TIMES_RHS_IMAG:.*]] = mulf %[[LHS_IMAG]], %[[RHS_IMAG]] : f32 +// CHECK: %[[LHS_IMAG_TIMES_RHS_IMAG_ABS:.*]] = absf %[[LHS_IMAG_TIMES_RHS_IMAG]] : f32 +// CHECK: %[[REAL:.*]] = subf %[[LHS_REAL_TIMES_RHS_REAL]], %[[LHS_IMAG_TIMES_RHS_IMAG]] : f32 + +// CHECK: %[[LHS_IMAG_TIMES_RHS_REAL:.*]] = mulf %[[LHS_IMAG]], %[[RHS_REAL]] : f32 +// CHECK: %[[LHS_IMAG_TIMES_RHS_REAL_ABS:.*]] = absf %[[LHS_IMAG_TIMES_RHS_REAL]] : f32 +// CHECK: %[[LHS_REAL_TIMES_RHS_IMAG:.*]] = mulf %[[LHS_REAL]], %[[RHS_IMAG]] : f32 +// CHECK: %[[LHS_REAL_TIMES_RHS_IMAG_ABS:.*]] = absf %[[LHS_REAL_TIMES_RHS_IMAG]] : f32 +// CHECK: %[[IMAG:.*]] = addf %[[LHS_IMAG_TIMES_RHS_REAL]], %[[LHS_REAL_TIMES_RHS_IMAG]] : f32 + +// Handle cases where the "naive" calculation results in NaN values. +// CHECK: %[[REAL_IS_NAN:.*]] = cmpf uno, %[[REAL]], %[[REAL]] : f32 +// CHECK: %[[IMAG_IS_NAN:.*]] = cmpf uno, %[[IMAG]], %[[IMAG]] : f32 +// CHECK: %[[IS_NAN:.*]] = and %[[REAL_IS_NAN]], %[[IMAG_IS_NAN]] : i1 +// CHECK: %[[INF:.*]] = constant 0x7F800000 : f32 + +// Case 1. LHS_REAL or LHS_IMAG are infinite. +// CHECK: %[[LHS_REAL_IS_INF:.*]] = cmpf oeq, %[[LHS_REAL_ABS]], %[[INF]] : f32 +// CHECK: %[[LHS_IMAG_IS_INF:.*]] = cmpf oeq, %[[LHS_IMAG_ABS]], %[[INF]] : f32 +// CHECK: %[[LHS_IS_INF:.*]] = or %[[LHS_REAL_IS_INF]], %[[LHS_IMAG_IS_INF]] : i1 +// CHECK: %[[RHS_REAL_IS_NAN:.*]] = cmpf uno, %[[RHS_REAL]], %[[RHS_REAL]] : f32 +// CHECK: %[[RHS_IMAG_IS_NAN:.*]] = cmpf uno, %[[RHS_IMAG]], %[[RHS_IMAG]] : f32 +// CHECK: %[[ZERO:.*]] = constant 0.000000e+00 : f32 +// CHECK: %[[ONE:.*]] = constant 1.000000e+00 : f32 +// CHECK: %[[LHS_REAL_IS_INF_FLOAT:.*]] = select %[[LHS_REAL_IS_INF]], %[[ONE]], %[[ZERO]] : f32 +// CHECK: %[[TMP:.*]] = copysign %[[LHS_REAL_IS_INF_FLOAT]], %[[LHS_REAL]] : f32 +// CHECK: %[[LHS_REAL1:.*]] = select %[[LHS_IS_INF]], %[[TMP]], %[[LHS_REAL]] : f32 +// CHECK: %[[LHS_IMAG_IS_INF_FLOAT:.*]] = select %[[LHS_IMAG_IS_INF]], %[[ONE]], %[[ZERO]] : f32 +// CHECK: %[[TMP:.*]] = copysign %[[LHS_IMAG_IS_INF_FLOAT]], %[[LHS_IMAG]] : f32 +// CHECK: %[[LHS_IMAG1:.*]] = select %[[LHS_IS_INF]], %[[TMP]], %[[LHS_IMAG]] : f32 +// CHECK: %[[LHS_IS_INF_AND_RHS_REAL_IS_NAN:.*]] = and %[[LHS_IS_INF]], %[[RHS_REAL_IS_NAN]] : i1 +// CHECK: %[[TMP:.*]] = copysign %[[ZERO]], %[[RHS_REAL]] : f32 +// CHECK: %[[RHS_REAL1:.*]] = select %[[LHS_IS_INF_AND_RHS_REAL_IS_NAN]], %[[TMP]], %[[RHS_REAL]] : f32 +// CHECK: %[[LHS_IS_INF_AND_RHS_IMAG_IS_NAN:.*]] = and %[[LHS_IS_INF]], %[[RHS_IMAG_IS_NAN]] : i1 +// CHECK: %[[TMP:.*]] = copysign %[[ZERO]], %[[RHS_IMAG]] : f32 +// CHECK: %[[RHS_IMAG1:.*]] = select %[[LHS_IS_INF_AND_RHS_IMAG_IS_NAN]], %[[TMP]], %[[RHS_IMAG]] : f32 + +// Case 2. RHS_REAL or RHS_IMAG are infinite. +// CHECK: %[[RHS_REAL_IS_INF:.*]] = cmpf oeq, %[[RHS_REAL_ABS]], %[[INF]] : f32 +// CHECK: %[[RHS_IMAG_IS_INF:.*]] = cmpf oeq, %[[RHS_IMAG_ABS]], %[[INF]] : f32 +// CHECK: %[[RHS_IS_INF:.*]] = or %[[RHS_REAL_IS_INF]], %[[RHS_IMAG_IS_INF]] : i1 +// CHECK: %[[LHS_REAL_IS_NAN:.*]] = cmpf uno, %[[LHS_REAL1]], %[[LHS_REAL1]] : f32 +// CHECK: %[[LHS_IMAG_IS_NAN:.*]] = cmpf uno, %[[LHS_IMAG1]], %[[LHS_IMAG1]] : f32 +// CHECK: %[[RHS_REAL_IS_INF_FLOAT:.*]] = select %[[RHS_REAL_IS_INF]], %[[ONE]], %[[ZERO]] : f32 +// CHECK: %[[TMP:.*]] = copysign %[[RHS_REAL_IS_INF_FLOAT]], %[[RHS_REAL1]] : f32 +// CHECK: %[[RHS_REAL2:.*]] = select %[[RHS_IS_INF]], %[[TMP]], %[[RHS_REAL1]] : f32 +// CHECK: %[[RHS_IMAG_IS_INF_FLOAT:.*]] = select %[[RHS_IMAG_IS_INF]], %[[ONE]], %[[ZERO]] : f32 +// CHECK: %[[TMP:.*]] = copysign %[[RHS_IMAG_IS_INF_FLOAT]], %[[RHS_IMAG1]] : f32 +// CHECK: %[[RHS_IMAG2:.*]] = select %[[RHS_IS_INF]], %[[TMP]], %[[RHS_IMAG1]] : f32 +// CHECK: %[[RHS_IS_INF_AND_LHS_REAL_IS_NAN:.*]] = and %[[RHS_IS_INF]], %[[LHS_REAL_IS_NAN]] : i1 +// CHECK: %[[TMP:.*]] = copysign %[[ZERO]], %[[LHS_REAL1]] : f32 +// CHECK: %[[LHS_REAL2:.*]] = select %[[RHS_IS_INF_AND_LHS_REAL_IS_NAN]], %[[TMP]], %[[LHS_REAL1]] : f32 +// CHECK: %[[RHS_IS_INF_AND_LHS_IMAG_IS_NAN:.*]] = and %[[RHS_IS_INF]], %[[LHS_IMAG_IS_NAN]] : i1 +// CHECK: %[[TMP:.*]] = copysign %[[ZERO]], %[[LHS_IMAG1]] : f32 +// CHECK: %[[LHS_IMAG2:.*]] = select %[[RHS_IS_INF_AND_LHS_IMAG_IS_NAN]], %[[TMP]], %[[LHS_IMAG1]] : f32 +// CHECK: %[[RECALC:.*]] = or %[[LHS_IS_INF]], %[[RHS_IS_INF]] : i1 + +// Case 3. One of the pairwise products of left hand side with right hand side +// is infinite. +// CHECK: %[[LHS_REAL_TIMES_RHS_REAL_IS_INF:.*]] = cmpf oeq, %[[LHS_REAL_TIMES_RHS_REAL_ABS]], %[[INF]] : f32 +// CHECK: %[[LHS_IMAG_TIMES_RHS_IMAG_IS_INF:.*]] = cmpf oeq, %[[LHS_IMAG_TIMES_RHS_IMAG_ABS]], %[[INF]] : f32 +// CHECK: %[[IS_SPECIAL_CASE:.*]] = or %[[LHS_REAL_TIMES_RHS_REAL_IS_INF]], %[[LHS_IMAG_TIMES_RHS_IMAG_IS_INF]] : i1 +// CHECK: %[[LHS_REAL_TIMES_RHS_IMAG_IS_INF:.*]] = cmpf oeq, %[[LHS_REAL_TIMES_RHS_IMAG_ABS]], %[[INF]] : f32 +// CHECK: %[[IS_SPECIAL_CASE1:.*]] = or %[[IS_SPECIAL_CASE]], %[[LHS_REAL_TIMES_RHS_IMAG_IS_INF]] : i1 +// CHECK: %[[LHS_IMAG_TIMES_RHS_REAL_IS_INF:.*]] = cmpf oeq, %[[LHS_IMAG_TIMES_RHS_REAL_ABS]], %[[INF]] : f32 +// CHECK: %[[IS_SPECIAL_CASE2:.*]] = or %[[IS_SPECIAL_CASE1]], %[[LHS_IMAG_TIMES_RHS_REAL_IS_INF]] : i1 +// CHECK: %[[TRUE:.*]] = constant true +// CHECK: %[[NOT_RECALC:.*]] = xor %[[RECALC]], %[[TRUE]] : i1 +// CHECK: %[[IS_SPECIAL_CASE3:.*]] = and %[[IS_SPECIAL_CASE2]], %[[NOT_RECALC]] : i1 +// CHECK: %[[IS_SPECIAL_CASE_AND_LHS_REAL_IS_NAN:.*]] = and %[[IS_SPECIAL_CASE3]], %[[LHS_REAL_IS_NAN]] : i1 +// CHECK: %[[TMP:.*]] = copysign %[[ZERO]], %[[LHS_REAL2]] : f32 +// CHECK: %[[LHS_REAL3:.*]] = select %[[IS_SPECIAL_CASE_AND_LHS_REAL_IS_NAN]], %[[TMP]], %[[LHS_REAL2]] : f32 +// CHECK: %[[IS_SPECIAL_CASE_AND_LHS_IMAG_IS_NAN:.*]] = and %[[IS_SPECIAL_CASE3]], %[[LHS_IMAG_IS_NAN]] : i1 +// CHECK: %[[TMP:.*]] = copysign %[[ZERO]], %[[LHS_IMAG2]] : f32 +// CHECK: %[[LHS_IMAG3:.*]] = select %[[IS_SPECIAL_CASE_AND_LHS_IMAG_IS_NAN]], %[[TMP]], %[[LHS_IMAG2]] : f32 +// CHECK: %[[IS_SPECIAL_CASE_AND_RHS_REAL_IS_NAN:.*]] = and %[[IS_SPECIAL_CASE3]], %[[RHS_REAL_IS_NAN]] : i1 +// CHECK: %[[TMP:.*]] = copysign %[[ZERO]], %[[RHS_REAL2]] : f32 +// CHECK: %[[RHS_REAL3:.*]] = select %[[IS_SPECIAL_CASE_AND_RHS_REAL_IS_NAN]], %[[TMP]], %[[RHS_REAL2]] : f32 +// CHECK: %[[IS_SPECIAL_CASE_AND_RHS_IMAG_IS_NAN:.*]] = and %[[IS_SPECIAL_CASE3]], %[[RHS_IMAG_IS_NAN]] : i1 +// CHECK: %[[TMP:.*]] = copysign %[[ZERO]], %[[RHS_IMAG2]] : f32 +// CHECK: %[[RHS_IMAG3:.*]] = select %[[IS_SPECIAL_CASE_AND_RHS_IMAG_IS_NAN]], %[[TMP]], %[[RHS_IMAG2]] : f32 +// CHECK: %[[RECALC2:.*]] = or %[[RECALC]], %[[IS_SPECIAL_CASE3]] : i1 +// CHECK: %[[RECALC3:.*]] = and %[[IS_NAN]], %[[RECALC2]] : i1 + + // Recalculate real part. +// CHECK: %[[LHS_REAL_TIMES_RHS_REAL:.*]] = mulf %[[LHS_REAL3]], %[[RHS_REAL3]] : f32 +// CHECK: %[[LHS_IMAG_TIMES_RHS_IMAG:.*]] = mulf %[[LHS_IMAG3]], %[[RHS_IMAG3]] : f32 +// CHECK: %[[NEW_REAL:.*]] = subf %[[LHS_REAL_TIMES_RHS_REAL]], %[[LHS_IMAG_TIMES_RHS_IMAG]] : f32 +// CHECK: %[[NEW_REAL_TIMES_INF:.*]] = mulf %[[INF]], %[[NEW_REAL]] : f32 +// CHECK: %[[FINAL_REAL:.*]] = select %[[RECALC3]], %[[NEW_REAL_TIMES_INF]], %[[REAL]] : f32 + +// Recalculate imag part. +// CHECK: %[[LHS_IMAG_TIMES_RHS_REAL:.*]] = mulf %[[LHS_IMAG3]], %[[RHS_REAL3]] : f32 +// CHECK: %[[LHS_REAL_TIMES_RHS_IMAG:.*]] = mulf %[[LHS_REAL3]], %[[RHS_IMAG3]] : f32 +// CHECK: %[[NEW_IMAG:.*]] = addf %[[LHS_IMAG_TIMES_RHS_REAL]], %[[LHS_REAL_TIMES_RHS_IMAG]] : f32 +// CHECK: %[[NEW_IMAG_TIMES_INF:.*]] = mulf %[[INF]], %[[NEW_IMAG]] : f32 +// CHECK: %[[FINAL_IMAG:.*]] = select %[[RECALC3]], %[[NEW_IMAG_TIMES_INF]], %[[IMAG]] : f32 + +// CHECK: %[[RESULT:.*]] = complex.create %[[FINAL_REAL]], %[[FINAL_IMAG]] : complex +// CHECK: return %[[RESULT]] : complex + // CHECK-LABEL: func @complex_neg // CHECK-SAME: %[[ARG:.*]]: complex func @complex_neg(%arg: complex) -> complex {