1 | //===- DivisionConverter.cpp - Complex division conversion ----------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file implements functions for two different complex number division |
10 | // algorithms, the `algebraic formula` and `Smith's range reduction method`. |
11 | // These are used in two conversions: `ComplexToLLVM` and `ComplexToStandard`. |
12 | // When modifying the algorithms, both `ToLLVM` and `ToStandard` must be |
13 | // changed. |
14 | // |
15 | //===----------------------------------------------------------------------===// |
16 | |
17 | #include "mlir/Conversion/ComplexCommon/DivisionConverter.h" |
18 | #include "mlir/Dialect/Math/IR/Math.h" |
19 | |
20 | using namespace mlir; |
21 | |
22 | void mlir::complex::convertDivToLLVMUsingAlgebraic( |
23 | ConversionPatternRewriter &rewriter, Location loc, Value lhsRe, Value lhsIm, |
24 | Value rhsRe, Value rhsIm, LLVM::FastmathFlagsAttr fmf, Value *resultRe, |
25 | Value *resultIm) { |
26 | Value rhsSqNorm = rewriter.create<LLVM::FAddOp>( |
27 | loc, rewriter.create<LLVM::FMulOp>(loc, rhsRe, rhsRe, fmf), |
28 | rewriter.create<LLVM::FMulOp>(loc, rhsIm, rhsIm, fmf), fmf); |
29 | |
30 | Value realNumerator = rewriter.create<LLVM::FAddOp>( |
31 | loc, rewriter.create<LLVM::FMulOp>(loc, lhsRe, rhsRe, fmf), |
32 | rewriter.create<LLVM::FMulOp>(loc, lhsIm, rhsIm, fmf), fmf); |
33 | |
34 | Value imagNumerator = rewriter.create<LLVM::FSubOp>( |
35 | loc, rewriter.create<LLVM::FMulOp>(loc, lhsIm, rhsRe, fmf), |
36 | rewriter.create<LLVM::FMulOp>(loc, lhsRe, rhsIm, fmf), fmf); |
37 | |
38 | *resultRe = rewriter.create<LLVM::FDivOp>(loc, realNumerator, rhsSqNorm, fmf); |
39 | *resultIm = rewriter.create<LLVM::FDivOp>(loc, imagNumerator, rhsSqNorm, fmf); |
40 | } |
41 | |
42 | void mlir::complex::convertDivToStandardUsingAlgebraic( |
43 | ConversionPatternRewriter &rewriter, Location loc, Value lhsRe, Value lhsIm, |
44 | Value rhsRe, Value rhsIm, arith::FastMathFlagsAttr fmf, Value *resultRe, |
45 | Value *resultIm) { |
46 | Value rhsSqNorm = rewriter.create<arith::AddFOp>( |
47 | loc, rewriter.create<arith::MulFOp>(loc, rhsRe, rhsRe, fmf), |
48 | rewriter.create<arith::MulFOp>(loc, rhsIm, rhsIm, fmf), fmf); |
49 | |
50 | Value realNumerator = rewriter.create<arith::AddFOp>( |
51 | loc, rewriter.create<arith::MulFOp>(loc, lhsRe, rhsRe, fmf), |
52 | rewriter.create<arith::MulFOp>(loc, lhsIm, rhsIm, fmf), fmf); |
53 | Value imagNumerator = rewriter.create<arith::SubFOp>( |
54 | loc, rewriter.create<arith::MulFOp>(loc, lhsIm, rhsRe, fmf), |
55 | rewriter.create<arith::MulFOp>(loc, lhsRe, rhsIm, fmf), fmf); |
56 | |
57 | *resultRe = |
58 | rewriter.create<arith::DivFOp>(loc, realNumerator, rhsSqNorm, fmf); |
59 | *resultIm = |
60 | rewriter.create<arith::DivFOp>(loc, imagNumerator, rhsSqNorm, fmf); |
61 | } |
62 | |
63 | // Smith's algorithm to divide complex numbers. It is just a bit smarter |
64 | // way to compute the following algebraic formula: |
65 | // (lhsRe + lhsIm * i) / (rhsRe + rhsIm * i) |
66 | // = (lhsRe + lhsIm * i) (rhsRe - rhsIm * i) / |
67 | // ((rhsRe + rhsIm * i)(rhsRe - rhsIm * i)) |
68 | // = ((lhsRe * rhsRe + lhsIm * rhsIm) + |
69 | // (lhsIm * rhsRe - lhsRe * rhsIm) * i) / ||rhs||^2 |
70 | // |
71 | // Depending on whether |rhsRe| < |rhsIm| we compute either |
72 | // rhsRealImagRatio = rhsRe / rhsIm |
73 | // rhsRealImagDenom = rhsIm + rhsRe * rhsRealImagRatio |
74 | // resultRe = (lhsRe * rhsRealImagRatio + lhsIm) / |
75 | // rhsRealImagDenom |
76 | // resultIm = (lhsIm * rhsRealImagRatio - lhsRe) / |
77 | // rhsRealImagDenom |
78 | // |
79 | // or |
80 | // |
81 | // rhsImagRealRatio = rhsIm / rhsRe |
82 | // rhsImagRealDenom = rhsRe + rhsIm * rhsImagRealRatio |
83 | // resultRe = (lhsRe + lhsIm * rhsImagRealRatio) / |
84 | // rhsImagRealDenom |
85 | // resultIm = (lhsIm - lhsRe * rhsImagRealRatio) / |
86 | // rhsImagRealDenom |
87 | // |
88 | // See https://dl.acm.org/citation.cfm?id=368661 for more details. |
89 | |
90 | void mlir::complex::convertDivToLLVMUsingRangeReduction( |
91 | ConversionPatternRewriter &rewriter, Location loc, Value lhsRe, Value lhsIm, |
92 | Value rhsRe, Value rhsIm, LLVM::FastmathFlagsAttr fmf, Value *resultRe, |
93 | Value *resultIm) { |
94 | auto elementType = cast<FloatType>(rhsRe.getType()); |
95 | |
96 | Value rhsRealImagRatio = |
97 | rewriter.create<LLVM::FDivOp>(loc, rhsRe, rhsIm, fmf); |
98 | Value rhsRealImagDenom = rewriter.create<LLVM::FAddOp>( |
99 | loc, rhsIm, |
100 | rewriter.create<LLVM::FMulOp>(loc, rhsRealImagRatio, rhsRe, fmf), fmf); |
101 | Value realNumerator1 = rewriter.create<LLVM::FAddOp>( |
102 | loc, rewriter.create<LLVM::FMulOp>(loc, lhsRe, rhsRealImagRatio, fmf), |
103 | lhsIm, fmf); |
104 | Value resultReal1 = |
105 | rewriter.create<LLVM::FDivOp>(loc, realNumerator1, rhsRealImagDenom, fmf); |
106 | Value imagNumerator1 = rewriter.create<LLVM::FSubOp>( |
107 | loc, rewriter.create<LLVM::FMulOp>(loc, lhsIm, rhsRealImagRatio, fmf), |
108 | lhsRe, fmf); |
109 | Value resultImag1 = |
110 | rewriter.create<LLVM::FDivOp>(loc, imagNumerator1, rhsRealImagDenom, fmf); |
111 | |
112 | Value rhsImagRealRatio = |
113 | rewriter.create<LLVM::FDivOp>(loc, rhsIm, rhsRe, fmf); |
114 | Value rhsImagRealDenom = rewriter.create<LLVM::FAddOp>( |
115 | loc, rhsRe, |
116 | rewriter.create<LLVM::FMulOp>(loc, rhsImagRealRatio, rhsIm, fmf), fmf); |
117 | Value realNumerator2 = rewriter.create<LLVM::FAddOp>( |
118 | loc, lhsRe, |
119 | rewriter.create<LLVM::FMulOp>(loc, lhsIm, rhsImagRealRatio, fmf), fmf); |
120 | Value resultReal2 = |
121 | rewriter.create<LLVM::FDivOp>(loc, realNumerator2, rhsImagRealDenom, fmf); |
122 | Value imagNumerator2 = rewriter.create<LLVM::FSubOp>( |
123 | loc, lhsIm, |
124 | rewriter.create<LLVM::FMulOp>(loc, lhsRe, rhsImagRealRatio, fmf), fmf); |
125 | Value resultImag2 = |
126 | rewriter.create<LLVM::FDivOp>(loc, imagNumerator2, rhsImagRealDenom, fmf); |
127 | |
128 | // Consider corner cases. |
129 | // Case 1. Zero denominator, numerator contains at most one NaN value. |
130 | Value zero = rewriter.create<LLVM::ConstantOp>( |
131 | loc, elementType, rewriter.getZeroAttr(elementType)); |
132 | Value rhsRealAbs = rewriter.create<LLVM::FAbsOp>(loc, rhsRe, fmf); |
133 | Value rhsRealIsZero = rewriter.create<LLVM::FCmpOp>( |
134 | loc, LLVM::FCmpPredicate::oeq, rhsRealAbs, zero); |
135 | Value rhsImagAbs = rewriter.create<LLVM::FAbsOp>(loc, rhsIm, fmf); |
136 | Value rhsImagIsZero = rewriter.create<LLVM::FCmpOp>( |
137 | loc, LLVM::FCmpPredicate::oeq, rhsImagAbs, zero); |
138 | Value lhsRealIsNotNaN = |
139 | rewriter.create<LLVM::FCmpOp>(loc, LLVM::FCmpPredicate::ord, lhsRe, zero); |
140 | Value lhsImagIsNotNaN = |
141 | rewriter.create<LLVM::FCmpOp>(loc, LLVM::FCmpPredicate::ord, lhsIm, zero); |
142 | Value lhsContainsNotNaNValue = |
143 | rewriter.create<LLVM::OrOp>(loc, lhsRealIsNotNaN, lhsImagIsNotNaN); |
144 | Value resultIsInfinity = rewriter.create<LLVM::AndOp>( |
145 | loc, lhsContainsNotNaNValue, |
146 | rewriter.create<LLVM::AndOp>(loc, rhsRealIsZero, rhsImagIsZero)); |
147 | Value inf = rewriter.create<LLVM::ConstantOp>( |
148 | loc, elementType, |
149 | rewriter.getFloatAttr(elementType, |
150 | APFloat::getInf(elementType.getFloatSemantics()))); |
151 | Value infWithSignOfrhsReal = |
152 | rewriter.create<LLVM::CopySignOp>(loc, inf, rhsRe); |
153 | Value infinityResultReal = |
154 | rewriter.create<LLVM::FMulOp>(loc, infWithSignOfrhsReal, lhsRe, fmf); |
155 | Value infinityResultImag = |
156 | rewriter.create<LLVM::FMulOp>(loc, infWithSignOfrhsReal, lhsIm, fmf); |
157 | |
158 | // Case 2. Infinite numerator, finite denominator. |
159 | Value rhsRealFinite = rewriter.create<LLVM::FCmpOp>( |
160 | loc, LLVM::FCmpPredicate::one, rhsRealAbs, inf); |
161 | Value rhsImagFinite = rewriter.create<LLVM::FCmpOp>( |
162 | loc, LLVM::FCmpPredicate::one, rhsImagAbs, inf); |
163 | Value rhsFinite = |
164 | rewriter.create<LLVM::AndOp>(loc, rhsRealFinite, rhsImagFinite); |
165 | Value lhsRealAbs = rewriter.create<LLVM::FAbsOp>(loc, lhsRe, fmf); |
166 | Value lhsRealInfinite = rewriter.create<LLVM::FCmpOp>( |
167 | loc, LLVM::FCmpPredicate::oeq, lhsRealAbs, inf); |
168 | Value lhsImagAbs = rewriter.create<LLVM::FAbsOp>(loc, lhsIm, fmf); |
169 | Value lhsImagInfinite = rewriter.create<LLVM::FCmpOp>( |
170 | loc, LLVM::FCmpPredicate::oeq, lhsImagAbs, inf); |
171 | Value lhsInfinite = |
172 | rewriter.create<LLVM::OrOp>(loc, lhsRealInfinite, lhsImagInfinite); |
173 | Value infNumFiniteDenom = |
174 | rewriter.create<LLVM::AndOp>(loc, lhsInfinite, rhsFinite); |
175 | Value one = rewriter.create<LLVM::ConstantOp>( |
176 | loc, elementType, rewriter.getFloatAttr(elementType, 1)); |
177 | Value lhsRealIsInfWithSign = rewriter.create<LLVM::CopySignOp>( |
178 | loc, rewriter.create<LLVM::SelectOp>(loc, lhsRealInfinite, one, zero), |
179 | lhsRe); |
180 | Value lhsImagIsInfWithSign = rewriter.create<LLVM::CopySignOp>( |
181 | loc, rewriter.create<LLVM::SelectOp>(loc, lhsImagInfinite, one, zero), |
182 | lhsIm); |
183 | Value lhsRealIsInfWithSignTimesrhsReal = |
184 | rewriter.create<LLVM::FMulOp>(loc, lhsRealIsInfWithSign, rhsRe, fmf); |
185 | Value lhsImagIsInfWithSignTimesrhsImag = |
186 | rewriter.create<LLVM::FMulOp>(loc, lhsImagIsInfWithSign, rhsIm, fmf); |
187 | Value resultReal3 = rewriter.create<LLVM::FMulOp>( |
188 | loc, inf, |
189 | rewriter.create<LLVM::FAddOp>(loc, lhsRealIsInfWithSignTimesrhsReal, |
190 | lhsImagIsInfWithSignTimesrhsImag, fmf), |
191 | fmf); |
192 | Value lhsRealIsInfWithSignTimesrhsImag = |
193 | rewriter.create<LLVM::FMulOp>(loc, lhsRealIsInfWithSign, rhsIm, fmf); |
194 | Value lhsImagIsInfWithSignTimesrhsReal = |
195 | rewriter.create<LLVM::FMulOp>(loc, lhsImagIsInfWithSign, rhsRe, fmf); |
196 | Value resultImag3 = rewriter.create<LLVM::FMulOp>( |
197 | loc, inf, |
198 | rewriter.create<LLVM::FSubOp>(loc, lhsImagIsInfWithSignTimesrhsReal, |
199 | lhsRealIsInfWithSignTimesrhsImag, fmf), |
200 | fmf); |
201 | |
202 | // Case 3: Finite numerator, infinite denominator. |
203 | Value lhsRealFinite = rewriter.create<LLVM::FCmpOp>( |
204 | loc, LLVM::FCmpPredicate::one, lhsRealAbs, inf); |
205 | Value lhsImagFinite = rewriter.create<LLVM::FCmpOp>( |
206 | loc, LLVM::FCmpPredicate::one, lhsImagAbs, inf); |
207 | Value lhsFinite = |
208 | rewriter.create<LLVM::AndOp>(loc, lhsRealFinite, lhsImagFinite); |
209 | Value rhsRealInfinite = rewriter.create<LLVM::FCmpOp>( |
210 | loc, LLVM::FCmpPredicate::oeq, rhsRealAbs, inf); |
211 | Value rhsImagInfinite = rewriter.create<LLVM::FCmpOp>( |
212 | loc, LLVM::FCmpPredicate::oeq, rhsImagAbs, inf); |
213 | Value rhsInfinite = |
214 | rewriter.create<LLVM::OrOp>(loc, rhsRealInfinite, rhsImagInfinite); |
215 | Value finiteNumInfiniteDenom = |
216 | rewriter.create<LLVM::AndOp>(loc, lhsFinite, rhsInfinite); |
217 | Value rhsRealIsInfWithSign = rewriter.create<LLVM::CopySignOp>( |
218 | loc, rewriter.create<LLVM::SelectOp>(loc, rhsRealInfinite, one, zero), |
219 | rhsRe); |
220 | Value rhsImagIsInfWithSign = rewriter.create<LLVM::CopySignOp>( |
221 | loc, rewriter.create<LLVM::SelectOp>(loc, rhsImagInfinite, one, zero), |
222 | rhsIm); |
223 | Value rhsRealIsInfWithSignTimeslhsReal = |
224 | rewriter.create<LLVM::FMulOp>(loc, lhsRe, rhsRealIsInfWithSign, fmf); |
225 | Value rhsImagIsInfWithSignTimeslhsImag = |
226 | rewriter.create<LLVM::FMulOp>(loc, lhsIm, rhsImagIsInfWithSign, fmf); |
227 | Value resultReal4 = rewriter.create<LLVM::FMulOp>( |
228 | loc, zero, |
229 | rewriter.create<LLVM::FAddOp>(loc, rhsRealIsInfWithSignTimeslhsReal, |
230 | rhsImagIsInfWithSignTimeslhsImag, fmf), |
231 | fmf); |
232 | Value rhsRealIsInfWithSignTimeslhsImag = |
233 | rewriter.create<LLVM::FMulOp>(loc, lhsIm, rhsRealIsInfWithSign, fmf); |
234 | Value rhsImagIsInfWithSignTimeslhsReal = |
235 | rewriter.create<LLVM::FMulOp>(loc, lhsRe, rhsImagIsInfWithSign, fmf); |
236 | Value resultImag4 = rewriter.create<LLVM::FMulOp>( |
237 | loc, zero, |
238 | rewriter.create<LLVM::FSubOp>(loc, rhsRealIsInfWithSignTimeslhsImag, |
239 | rhsImagIsInfWithSignTimeslhsReal, fmf), |
240 | fmf); |
241 | |
242 | Value realAbsSmallerThanImagAbs = rewriter.create<LLVM::FCmpOp>( |
243 | loc, LLVM::FCmpPredicate::olt, rhsRealAbs, rhsImagAbs); |
244 | Value resultReal5 = rewriter.create<LLVM::SelectOp>( |
245 | loc, realAbsSmallerThanImagAbs, resultReal1, resultReal2); |
246 | Value resultImag5 = rewriter.create<LLVM::SelectOp>( |
247 | loc, realAbsSmallerThanImagAbs, resultImag1, resultImag2); |
248 | Value resultRealSpecialCase3 = rewriter.create<LLVM::SelectOp>( |
249 | loc, finiteNumInfiniteDenom, resultReal4, resultReal5); |
250 | Value resultImagSpecialCase3 = rewriter.create<LLVM::SelectOp>( |
251 | loc, finiteNumInfiniteDenom, resultImag4, resultImag5); |
252 | Value resultRealSpecialCase2 = rewriter.create<LLVM::SelectOp>( |
253 | loc, infNumFiniteDenom, resultReal3, resultRealSpecialCase3); |
254 | Value resultImagSpecialCase2 = rewriter.create<LLVM::SelectOp>( |
255 | loc, infNumFiniteDenom, resultImag3, resultImagSpecialCase3); |
256 | Value resultRealSpecialCase1 = rewriter.create<LLVM::SelectOp>( |
257 | loc, resultIsInfinity, infinityResultReal, resultRealSpecialCase2); |
258 | Value resultImagSpecialCase1 = rewriter.create<LLVM::SelectOp>( |
259 | loc, resultIsInfinity, infinityResultImag, resultImagSpecialCase2); |
260 | |
261 | Value resultRealIsNaN = rewriter.create<LLVM::FCmpOp>( |
262 | loc, LLVM::FCmpPredicate::uno, resultReal5, zero); |
263 | Value resultImagIsNaN = rewriter.create<LLVM::FCmpOp>( |
264 | loc, LLVM::FCmpPredicate::uno, resultImag5, zero); |
265 | Value resultIsNaN = |
266 | rewriter.create<LLVM::AndOp>(loc, resultRealIsNaN, resultImagIsNaN); |
267 | |
268 | *resultRe = rewriter.create<LLVM::SelectOp>( |
269 | loc, resultIsNaN, resultRealSpecialCase1, resultReal5); |
270 | *resultIm = rewriter.create<LLVM::SelectOp>( |
271 | loc, resultIsNaN, resultImagSpecialCase1, resultImag5); |
272 | } |
273 | |
274 | void mlir::complex::convertDivToStandardUsingRangeReduction( |
275 | ConversionPatternRewriter &rewriter, Location loc, Value lhsRe, Value lhsIm, |
276 | Value rhsRe, Value rhsIm, arith::FastMathFlagsAttr fmf, Value *resultRe, |
277 | Value *resultIm) { |
278 | auto elementType = cast<FloatType>(rhsRe.getType()); |
279 | |
280 | Value rhsRealImagRatio = |
281 | rewriter.create<arith::DivFOp>(loc, rhsRe, rhsIm, fmf); |
282 | Value rhsRealImagDenom = rewriter.create<arith::AddFOp>( |
283 | loc, rhsIm, |
284 | rewriter.create<arith::MulFOp>(loc, rhsRealImagRatio, rhsRe, fmf), fmf); |
285 | Value realNumerator1 = rewriter.create<arith::AddFOp>( |
286 | loc, rewriter.create<arith::MulFOp>(loc, lhsRe, rhsRealImagRatio, fmf), |
287 | lhsIm, fmf); |
288 | Value resultReal1 = rewriter.create<arith::DivFOp>(loc, realNumerator1, |
289 | rhsRealImagDenom, fmf); |
290 | Value imagNumerator1 = rewriter.create<arith::SubFOp>( |
291 | loc, rewriter.create<arith::MulFOp>(loc, lhsIm, rhsRealImagRatio, fmf), |
292 | lhsRe, fmf); |
293 | Value resultImag1 = rewriter.create<arith::DivFOp>(loc, imagNumerator1, |
294 | rhsRealImagDenom, fmf); |
295 | |
296 | Value rhsImagRealRatio = |
297 | rewriter.create<arith::DivFOp>(loc, rhsIm, rhsRe, fmf); |
298 | Value rhsImagRealDenom = rewriter.create<arith::AddFOp>( |
299 | loc, rhsRe, |
300 | rewriter.create<arith::MulFOp>(loc, rhsImagRealRatio, rhsIm, fmf), fmf); |
301 | Value realNumerator2 = rewriter.create<arith::AddFOp>( |
302 | loc, lhsRe, |
303 | rewriter.create<arith::MulFOp>(loc, lhsIm, rhsImagRealRatio, fmf), fmf); |
304 | Value resultReal2 = rewriter.create<arith::DivFOp>(loc, realNumerator2, |
305 | rhsImagRealDenom, fmf); |
306 | Value imagNumerator2 = rewriter.create<arith::SubFOp>( |
307 | loc, lhsIm, |
308 | rewriter.create<arith::MulFOp>(loc, lhsRe, rhsImagRealRatio, fmf), fmf); |
309 | Value resultImag2 = rewriter.create<arith::DivFOp>(loc, imagNumerator2, |
310 | rhsImagRealDenom, fmf); |
311 | |
312 | // Consider corner cases. |
313 | // Case 1. Zero denominator, numerator contains at most one NaN value. |
314 | Value zero = rewriter.create<arith::ConstantOp>( |
315 | loc, elementType, rewriter.getZeroAttr(elementType)); |
316 | Value rhsRealAbs = rewriter.create<math::AbsFOp>(loc, rhsRe, fmf); |
317 | Value rhsRealIsZero = rewriter.create<arith::CmpFOp>( |
318 | loc, arith::CmpFPredicate::OEQ, rhsRealAbs, zero); |
319 | Value rhsImagAbs = rewriter.create<math::AbsFOp>(loc, rhsIm, fmf); |
320 | Value rhsImagIsZero = rewriter.create<arith::CmpFOp>( |
321 | loc, arith::CmpFPredicate::OEQ, rhsImagAbs, zero); |
322 | Value lhsRealIsNotNaN = rewriter.create<arith::CmpFOp>( |
323 | loc, arith::CmpFPredicate::ORD, lhsRe, zero); |
324 | Value lhsImagIsNotNaN = rewriter.create<arith::CmpFOp>( |
325 | loc, arith::CmpFPredicate::ORD, lhsIm, zero); |
326 | Value lhsContainsNotNaNValue = |
327 | rewriter.create<arith::OrIOp>(loc, lhsRealIsNotNaN, lhsImagIsNotNaN); |
328 | Value resultIsInfinity = rewriter.create<arith::AndIOp>( |
329 | loc, lhsContainsNotNaNValue, |
330 | rewriter.create<arith::AndIOp>(loc, rhsRealIsZero, rhsImagIsZero)); |
331 | Value inf = rewriter.create<arith::ConstantOp>( |
332 | loc, elementType, |
333 | rewriter.getFloatAttr(elementType, |
334 | APFloat::getInf(elementType.getFloatSemantics()))); |
335 | Value infWithSignOfRhsReal = |
336 | rewriter.create<math::CopySignOp>(loc, inf, rhsRe); |
337 | Value infinityResultReal = |
338 | rewriter.create<arith::MulFOp>(loc, infWithSignOfRhsReal, lhsRe, fmf); |
339 | Value infinityResultImag = |
340 | rewriter.create<arith::MulFOp>(loc, infWithSignOfRhsReal, lhsIm, fmf); |
341 | |
342 | // Case 2. Infinite numerator, finite denominator. |
343 | Value rhsRealFinite = rewriter.create<arith::CmpFOp>( |
344 | loc, arith::CmpFPredicate::ONE, rhsRealAbs, inf); |
345 | Value rhsImagFinite = rewriter.create<arith::CmpFOp>( |
346 | loc, arith::CmpFPredicate::ONE, rhsImagAbs, inf); |
347 | Value rhsFinite = |
348 | rewriter.create<arith::AndIOp>(loc, rhsRealFinite, rhsImagFinite); |
349 | Value lhsRealAbs = rewriter.create<math::AbsFOp>(loc, lhsRe, fmf); |
350 | Value lhsRealInfinite = rewriter.create<arith::CmpFOp>( |
351 | loc, arith::CmpFPredicate::OEQ, lhsRealAbs, inf); |
352 | Value lhsImagAbs = rewriter.create<math::AbsFOp>(loc, lhsIm, fmf); |
353 | Value lhsImagInfinite = rewriter.create<arith::CmpFOp>( |
354 | loc, arith::CmpFPredicate::OEQ, lhsImagAbs, inf); |
355 | Value lhsInfinite = |
356 | rewriter.create<arith::OrIOp>(loc, lhsRealInfinite, lhsImagInfinite); |
357 | Value infNumFiniteDenom = |
358 | rewriter.create<arith::AndIOp>(loc, lhsInfinite, rhsFinite); |
359 | Value one = rewriter.create<arith::ConstantOp>( |
360 | loc, elementType, rewriter.getFloatAttr(elementType, 1)); |
361 | Value lhsRealIsInfWithSign = rewriter.create<math::CopySignOp>( |
362 | loc, rewriter.create<arith::SelectOp>(loc, lhsRealInfinite, one, zero), |
363 | lhsRe); |
364 | Value lhsImagIsInfWithSign = rewriter.create<math::CopySignOp>( |
365 | loc, rewriter.create<arith::SelectOp>(loc, lhsImagInfinite, one, zero), |
366 | lhsIm); |
367 | Value lhsRealIsInfWithSignTimesRhsReal = |
368 | rewriter.create<arith::MulFOp>(loc, lhsRealIsInfWithSign, rhsRe, fmf); |
369 | Value lhsImagIsInfWithSignTimesRhsImag = |
370 | rewriter.create<arith::MulFOp>(loc, lhsImagIsInfWithSign, rhsIm, fmf); |
371 | Value resultReal3 = rewriter.create<arith::MulFOp>( |
372 | loc, inf, |
373 | rewriter.create<arith::AddFOp>(loc, lhsRealIsInfWithSignTimesRhsReal, |
374 | lhsImagIsInfWithSignTimesRhsImag, fmf), |
375 | fmf); |
376 | Value lhsRealIsInfWithSignTimesRhsImag = |
377 | rewriter.create<arith::MulFOp>(loc, lhsRealIsInfWithSign, rhsIm, fmf); |
378 | Value lhsImagIsInfWithSignTimesRhsReal = |
379 | rewriter.create<arith::MulFOp>(loc, lhsImagIsInfWithSign, rhsRe, fmf); |
380 | Value resultImag3 = rewriter.create<arith::MulFOp>( |
381 | loc, inf, |
382 | rewriter.create<arith::SubFOp>(loc, lhsImagIsInfWithSignTimesRhsReal, |
383 | lhsRealIsInfWithSignTimesRhsImag, fmf), |
384 | fmf); |
385 | |
386 | // Case 3: Finite numerator, infinite denominator. |
387 | Value lhsRealFinite = rewriter.create<arith::CmpFOp>( |
388 | loc, arith::CmpFPredicate::ONE, lhsRealAbs, inf); |
389 | Value lhsImagFinite = rewriter.create<arith::CmpFOp>( |
390 | loc, arith::CmpFPredicate::ONE, lhsImagAbs, inf); |
391 | Value lhsFinite = |
392 | rewriter.create<arith::AndIOp>(loc, lhsRealFinite, lhsImagFinite); |
393 | Value rhsRealInfinite = rewriter.create<arith::CmpFOp>( |
394 | loc, arith::CmpFPredicate::OEQ, rhsRealAbs, inf); |
395 | Value rhsImagInfinite = rewriter.create<arith::CmpFOp>( |
396 | loc, arith::CmpFPredicate::OEQ, rhsImagAbs, inf); |
397 | Value rhsInfinite = |
398 | rewriter.create<arith::OrIOp>(loc, rhsRealInfinite, rhsImagInfinite); |
399 | Value finiteNumInfiniteDenom = |
400 | rewriter.create<arith::AndIOp>(loc, lhsFinite, rhsInfinite); |
401 | Value rhsRealIsInfWithSign = rewriter.create<math::CopySignOp>( |
402 | loc, rewriter.create<arith::SelectOp>(loc, rhsRealInfinite, one, zero), |
403 | rhsRe); |
404 | Value rhsImagIsInfWithSign = rewriter.create<math::CopySignOp>( |
405 | loc, rewriter.create<arith::SelectOp>(loc, rhsImagInfinite, one, zero), |
406 | rhsIm); |
407 | Value rhsRealIsInfWithSignTimesLhsReal = |
408 | rewriter.create<arith::MulFOp>(loc, lhsRe, rhsRealIsInfWithSign, fmf); |
409 | Value rhsImagIsInfWithSignTimesLhsImag = |
410 | rewriter.create<arith::MulFOp>(loc, lhsIm, rhsImagIsInfWithSign, fmf); |
411 | Value resultReal4 = rewriter.create<arith::MulFOp>( |
412 | loc, zero, |
413 | rewriter.create<arith::AddFOp>(loc, rhsRealIsInfWithSignTimesLhsReal, |
414 | rhsImagIsInfWithSignTimesLhsImag, fmf), |
415 | fmf); |
416 | Value rhsRealIsInfWithSignTimesLhsImag = |
417 | rewriter.create<arith::MulFOp>(loc, lhsIm, rhsRealIsInfWithSign, fmf); |
418 | Value rhsImagIsInfWithSignTimesLhsReal = |
419 | rewriter.create<arith::MulFOp>(loc, lhsRe, rhsImagIsInfWithSign, fmf); |
420 | Value resultImag4 = rewriter.create<arith::MulFOp>( |
421 | loc, zero, |
422 | rewriter.create<arith::SubFOp>(loc, rhsRealIsInfWithSignTimesLhsImag, |
423 | rhsImagIsInfWithSignTimesLhsReal, fmf), |
424 | fmf); |
425 | |
426 | Value realAbsSmallerThanImagAbs = rewriter.create<arith::CmpFOp>( |
427 | loc, arith::CmpFPredicate::OLT, rhsRealAbs, rhsImagAbs); |
428 | Value resultReal5 = rewriter.create<arith::SelectOp>( |
429 | loc, realAbsSmallerThanImagAbs, resultReal1, resultReal2); |
430 | Value resultImag5 = rewriter.create<arith::SelectOp>( |
431 | loc, realAbsSmallerThanImagAbs, resultImag1, resultImag2); |
432 | Value resultRealSpecialCase3 = rewriter.create<arith::SelectOp>( |
433 | loc, finiteNumInfiniteDenom, resultReal4, resultReal5); |
434 | Value resultImagSpecialCase3 = rewriter.create<arith::SelectOp>( |
435 | loc, finiteNumInfiniteDenom, resultImag4, resultImag5); |
436 | Value resultRealSpecialCase2 = rewriter.create<arith::SelectOp>( |
437 | loc, infNumFiniteDenom, resultReal3, resultRealSpecialCase3); |
438 | Value resultImagSpecialCase2 = rewriter.create<arith::SelectOp>( |
439 | loc, infNumFiniteDenom, resultImag3, resultImagSpecialCase3); |
440 | Value resultRealSpecialCase1 = rewriter.create<arith::SelectOp>( |
441 | loc, resultIsInfinity, infinityResultReal, resultRealSpecialCase2); |
442 | Value resultImagSpecialCase1 = rewriter.create<arith::SelectOp>( |
443 | loc, resultIsInfinity, infinityResultImag, resultImagSpecialCase2); |
444 | |
445 | Value resultRealIsNaN = rewriter.create<arith::CmpFOp>( |
446 | loc, arith::CmpFPredicate::UNO, resultReal5, zero); |
447 | Value resultImagIsNaN = rewriter.create<arith::CmpFOp>( |
448 | loc, arith::CmpFPredicate::UNO, resultImag5, zero); |
449 | Value resultIsNaN = |
450 | rewriter.create<arith::AndIOp>(loc, resultRealIsNaN, resultImagIsNaN); |
451 | |
452 | *resultRe = rewriter.create<arith::SelectOp>( |
453 | loc, resultIsNaN, resultRealSpecialCase1, resultReal5); |
454 | *resultIm = rewriter.create<arith::SelectOp>( |
455 | loc, resultIsNaN, resultImagSpecialCase1, resultImag5); |
456 | } |
457 | |