1//===- llvm/Support/KnownFPClass.h - Stores known fplcass -------*- C++ -*-===//
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 contains a class for representing known fpclasses used by
10// computeKnownFPClass.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/Support/KnownFPClass.h"
15#include "llvm/ADT/APFloat.h"
16#include "llvm/Support/ErrorHandling.h"
17#include "llvm/Support/KnownBits.h"
18
19using namespace llvm;
20
21KnownFPClass::KnownFPClass(const APFloat &C)
22 : KnownFPClasses(C.classify()), SignBit(C.isNegative()) {}
23
24/// Return true if it's possible to assume IEEE treatment of input denormals in
25/// \p F for \p Val.
26static bool inputDenormalIsIEEE(DenormalMode Mode) {
27 return Mode.Input == DenormalMode::IEEE;
28}
29
30static bool inputDenormalIsIEEEOrPosZero(DenormalMode Mode) {
31 return Mode.Input == DenormalMode::IEEE ||
32 Mode.Input == DenormalMode::PositiveZero;
33}
34
35bool KnownFPClass::isKnownNeverLogicalZero(DenormalMode Mode) const {
36 return isKnownNeverZero() &&
37 (isKnownNeverSubnormal() || inputDenormalIsIEEE(Mode));
38}
39
40bool KnownFPClass::isKnownNeverLogicalNegZero(DenormalMode Mode) const {
41 return isKnownNeverNegZero() &&
42 (isKnownNeverNegSubnormal() || inputDenormalIsIEEEOrPosZero(Mode));
43}
44
45bool KnownFPClass::isKnownNeverLogicalPosZero(DenormalMode Mode) const {
46 if (!isKnownNeverPosZero())
47 return false;
48
49 // If we know there are no denormals, nothing can be flushed to zero.
50 if (isKnownNeverSubnormal())
51 return true;
52
53 switch (Mode.Input) {
54 case DenormalMode::IEEE:
55 return true;
56 case DenormalMode::PreserveSign:
57 // Negative subnormal won't flush to +0
58 return isKnownNeverPosSubnormal();
59 case DenormalMode::PositiveZero:
60 default:
61 // Both positive and negative subnormal could flush to +0
62 return false;
63 }
64
65 llvm_unreachable("covered switch over denormal mode");
66}
67
68void KnownFPClass::propagateDenormal(const KnownFPClass &Src,
69 DenormalMode Mode) {
70 KnownFPClasses = Src.KnownFPClasses;
71 // If we aren't assuming the source can't be a zero, we don't have to check if
72 // a denormal input could be flushed.
73 if (!Src.isKnownNeverPosZero() && !Src.isKnownNeverNegZero())
74 return;
75
76 // If we know the input can't be a denormal, it can't be flushed to 0.
77 if (Src.isKnownNeverSubnormal())
78 return;
79
80 if (!Src.isKnownNeverPosSubnormal() && Mode != DenormalMode::getIEEE())
81 KnownFPClasses |= fcPosZero;
82
83 if (!Src.isKnownNeverNegSubnormal() && Mode != DenormalMode::getIEEE()) {
84 if (Mode != DenormalMode::getPositiveZero())
85 KnownFPClasses |= fcNegZero;
86
87 if (Mode.Input == DenormalMode::PositiveZero ||
88 Mode.Output == DenormalMode::PositiveZero ||
89 Mode.Input == DenormalMode::Dynamic ||
90 Mode.Output == DenormalMode::Dynamic)
91 KnownFPClasses |= fcPosZero;
92 }
93}
94
95KnownFPClass KnownFPClass::minMaxLike(const KnownFPClass &LHS_,
96 const KnownFPClass &RHS_, MinMaxKind Kind,
97 DenormalMode Mode) {
98 KnownFPClass KnownLHS = LHS_;
99 KnownFPClass KnownRHS = RHS_;
100
101 bool NeverNaN = KnownLHS.isKnownNeverNaN() || KnownRHS.isKnownNeverNaN();
102 KnownFPClass Known = KnownLHS | KnownRHS;
103
104 // If either operand is not NaN, the result is not NaN.
105 if (NeverNaN &&
106 (Kind == MinMaxKind::minnum || Kind == MinMaxKind::maxnum ||
107 Kind == MinMaxKind::minimumnum || Kind == MinMaxKind::maximumnum))
108 Known.knownNot(RuleOut: fcNan);
109
110 if (Kind == MinMaxKind::maxnum || Kind == MinMaxKind::maximumnum) {
111 if (KnownLHS.isKnownNeverNaN())
112 Known.knownNot(RuleOut: orderedStrictlyLess(Mask: KnownLHS.KnownFPClasses));
113 if (KnownRHS.isKnownNeverNaN())
114 Known.knownNot(RuleOut: orderedStrictlyLess(Mask: KnownRHS.KnownFPClasses));
115 } else if (Kind == MinMaxKind::maximum) {
116 Known.knownNot(RuleOut: orderedStrictlyLess(Mask: KnownLHS.KnownFPClasses) |
117 orderedStrictlyLess(Mask: KnownRHS.KnownFPClasses));
118 } else if (Kind == MinMaxKind::minnum || Kind == MinMaxKind::minimumnum) {
119 if (KnownLHS.isKnownNeverNaN())
120 Known.knownNot(RuleOut: orderedStrictlyGreater(Mask: KnownLHS.KnownFPClasses));
121 if (KnownRHS.isKnownNeverNaN())
122 Known.knownNot(RuleOut: orderedStrictlyGreater(Mask: KnownRHS.KnownFPClasses));
123 } else if (Kind == MinMaxKind::minimum) {
124 Known.knownNot(RuleOut: orderedStrictlyGreater(Mask: KnownLHS.KnownFPClasses) |
125 orderedStrictlyGreater(Mask: KnownRHS.KnownFPClasses));
126 } else
127 llvm_unreachable("unhandled intrinsic");
128
129 // Fixup zero handling if denormals could be returned as a zero.
130 //
131 // As there's no spec for denormal flushing, be conservative with the
132 // treatment of denormals that could be flushed to zero. For older
133 // subtargets on AMDGPU the min/max instructions would not flush the
134 // output and return the original value.
135 //
136 if ((Known.KnownFPClasses & fcZero) != fcNone &&
137 !Known.isKnownNeverSubnormal()) {
138 if (Mode != DenormalMode::getIEEE())
139 Known.KnownFPClasses |= fcZero;
140 }
141
142 if (Known.isKnownNeverNaN()) {
143 if (KnownLHS.SignBit && KnownRHS.SignBit &&
144 *KnownLHS.SignBit == *KnownRHS.SignBit) {
145 if (*KnownLHS.SignBit)
146 Known.signBitMustBeOne();
147 else
148 Known.signBitMustBeZero();
149 } else if ((Kind == MinMaxKind::maximum || Kind == MinMaxKind::minimum ||
150 Kind == MinMaxKind::maximumnum ||
151 Kind == MinMaxKind::minimumnum) ||
152 // FIXME: Should be using logical zero versions
153 ((KnownLHS.isKnownNeverNegZero() ||
154 KnownRHS.isKnownNeverPosZero()) &&
155 (KnownLHS.isKnownNeverPosZero() ||
156 KnownRHS.isKnownNeverNegZero()))) {
157 // Don't take sign bit from NaN operands.
158 if (!KnownLHS.isKnownNeverNaN())
159 KnownLHS.SignBit = std::nullopt;
160 if (!KnownRHS.isKnownNeverNaN())
161 KnownRHS.SignBit = std::nullopt;
162 if ((Kind == MinMaxKind::maximum || Kind == MinMaxKind::maximumnum ||
163 Kind == MinMaxKind::maxnum) &&
164 (KnownLHS.SignBit == false || KnownRHS.SignBit == false))
165 Known.signBitMustBeZero();
166 else if ((Kind == MinMaxKind::minimum || Kind == MinMaxKind::minimumnum ||
167 Kind == MinMaxKind::minnum) &&
168 (KnownLHS.SignBit == true || KnownRHS.SignBit == true))
169 Known.signBitMustBeOne();
170 }
171 }
172
173 return Known;
174}
175
176KnownFPClass KnownFPClass::canonicalize(const KnownFPClass &KnownSrc,
177 DenormalMode DenormMode) {
178 KnownFPClass Known;
179
180 // This is essentially a stronger form of
181 // propagateCanonicalizingSrc. Other "canonicalizing" operations don't
182 // actually have an IR canonicalization guarantee.
183
184 // Canonicalize may flush denormals to zero, so we have to consider the
185 // denormal mode to preserve known-not-0 knowledge.
186 Known.KnownFPClasses = KnownSrc.KnownFPClasses | fcZero | fcQNan;
187
188 // Stronger version of propagateNaN
189 // Canonicalize is guaranteed to quiet signaling nans.
190 if (KnownSrc.isKnownNeverNaN())
191 Known.knownNot(RuleOut: fcNan);
192 else
193 Known.knownNot(RuleOut: fcSNan);
194
195 // FIXME: Missing check of IEEE like types.
196
197 // If the parent function flushes denormals, the canonical output cannot be a
198 // denormal.
199 if (DenormMode == DenormalMode::getIEEE()) {
200 if (KnownSrc.isKnownNever(Mask: fcPosZero))
201 Known.knownNot(RuleOut: fcPosZero);
202 if (KnownSrc.isKnownNever(Mask: fcNegZero))
203 Known.knownNot(RuleOut: fcNegZero);
204 return Known;
205 }
206
207 if (DenormMode.inputsAreZero() || DenormMode.outputsAreZero())
208 Known.knownNot(RuleOut: fcSubnormal);
209
210 if (DenormMode == DenormalMode::getPreserveSign()) {
211 if (KnownSrc.isKnownNever(Mask: fcPosZero | fcPosSubnormal))
212 Known.knownNot(RuleOut: fcPosZero);
213 if (KnownSrc.isKnownNever(Mask: fcNegZero | fcNegSubnormal))
214 Known.knownNot(RuleOut: fcNegZero);
215 return Known;
216 }
217
218 if (DenormMode.Input == DenormalMode::PositiveZero ||
219 (DenormMode.Output == DenormalMode::PositiveZero &&
220 DenormMode.Input == DenormalMode::IEEE)) {
221 // -0.0 is not a subnormal and should not be flushed.
222 if (KnownSrc.isKnownNever(Mask: fcNegZero))
223 Known.knownNot(RuleOut: fcNegZero);
224
225 if (KnownSrc.isKnownNever(Mask: fcPosZero | fcSubnormal))
226 Known.knownNot(RuleOut: fcPosZero);
227 }
228
229 return Known;
230}
231
232KnownFPClass KnownFPClass::bitcast(const fltSemantics &FltSemantics,
233 const KnownBits &Bits) {
234 assert(FltSemantics.sizeInBits == Bits.getBitWidth() &&
235 "Bitcast operand has incorrect bit width");
236 KnownFPClass Known;
237
238 // Transfer information from the sign bit.
239 if (Bits.isNonNegative())
240 Known.signBitMustBeZero();
241 else if (Bits.isNegative())
242 Known.signBitMustBeOne();
243
244 if (APFloat::isIEEELikeFP(FltSemantics)) {
245 // IEEE floats are NaN when all bits of the exponent plus at least one of
246 // the fraction bits are 1. This means:
247 // - If we assume unknown bits are 0 and the value is NaN, it will
248 // always be NaN
249 // - If we assume unknown bits are 1 and the value is not NaN, it can
250 // never be NaN
251 // Note: They do not hold for x86_fp80 format.
252 if (APFloat(FltSemantics, Bits.One).isNaN())
253 Known.KnownFPClasses = fcNan;
254 else if (!APFloat(FltSemantics, ~Bits.Zero).isNaN())
255 Known.knownNot(RuleOut: fcNan);
256
257 // Build KnownBits representing Inf and check if it must be equal or
258 // unequal to this value.
259 auto InfKB =
260 KnownBits::makeConstant(C: APFloat::getInf(Sem: FltSemantics).bitcastToAPInt());
261 InfKB.Zero.clearSignBit();
262 if (const auto InfResult = KnownBits::eq(LHS: Bits, RHS: InfKB)) {
263 assert(!InfResult.value());
264 Known.knownNot(RuleOut: fcInf);
265 } else if (Bits == InfKB) {
266 Known.KnownFPClasses = fcInf;
267 }
268
269 // Build KnownBits representing Zero and check if it must be equal or
270 // unequal to this value.
271 auto ZeroKB = KnownBits::makeConstant(
272 C: APFloat::getZero(Sem: FltSemantics).bitcastToAPInt());
273 ZeroKB.Zero.clearSignBit();
274 if (const auto ZeroResult = KnownBits::eq(LHS: Bits, RHS: ZeroKB)) {
275 assert(!ZeroResult.value());
276 Known.knownNot(RuleOut: fcZero);
277 } else if (Bits == ZeroKB) {
278 Known.KnownFPClasses = fcZero;
279 }
280 }
281
282 return Known;
283}
284
285// Handle known sign bit and nan cases for fadd.
286static KnownFPClass fadd_impl(const KnownFPClass &KnownLHS,
287 const KnownFPClass &KnownRHS, DenormalMode Mode) {
288 KnownFPClass Known;
289
290 // Adding positive and negative infinity produces NaN, but only if both
291 // opposite-sign infinity combinations are possible.
292 if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() &&
293 (KnownLHS.isKnownNever(Mask: fcPosInf) || KnownRHS.isKnownNever(Mask: fcNegInf)) &&
294 (KnownLHS.isKnownNever(Mask: fcNegInf) || KnownRHS.isKnownNever(Mask: fcPosInf)))
295 Known.knownNot(RuleOut: fcNan);
296
297 if (KnownLHS.cannotBeOrderedLessThanZero() &&
298 KnownRHS.cannotBeOrderedLessThanZero()) {
299 Known.knownNot(RuleOut: KnownFPClass::OrderedLessThanZeroMask);
300
301 // This can't underflow if one of the operands is known normal.
302 if (KnownLHS.isKnownNever(Mask: fcZero | fcPosSubnormal) ||
303 KnownRHS.isKnownNever(Mask: fcZero | fcPosSubnormal))
304 Known.knownNot(RuleOut: fcZero | fcPosSubnormal);
305 }
306
307 if (KnownLHS.cannotBeOrderedGreaterThanZero() &&
308 KnownRHS.cannotBeOrderedGreaterThanZero()) {
309 Known.knownNot(RuleOut: KnownFPClass::OrderedGreaterThanZeroMask);
310
311 // This can't underflow if one of the operands is known normal.
312 if (KnownLHS.isKnownNever(Mask: fcZero | fcNegSubnormal) ||
313 KnownRHS.isKnownNever(Mask: fcZero | fcNegSubnormal))
314 Known.knownNot(RuleOut: fcZero | fcNegSubnormal);
315 }
316
317 return Known;
318}
319
320KnownFPClass KnownFPClass::fadd(const KnownFPClass &KnownLHS,
321 const KnownFPClass &KnownRHS,
322 DenormalMode Mode) {
323 KnownFPClass Known = fadd_impl(KnownLHS, KnownRHS, Mode);
324
325 // (fadd x, 0.0) is guaranteed to return +0.0, not -0.0.
326 if ((KnownLHS.isKnownNeverLogicalNegZero(Mode) ||
327 KnownRHS.isKnownNeverLogicalNegZero(Mode)) &&
328 // Make sure output negative denormal can't flush to -0
329 (Mode.Output == DenormalMode::IEEE ||
330 Mode.Output == DenormalMode::PositiveZero))
331 Known.knownNot(RuleOut: fcNegZero);
332
333 return Known;
334}
335
336KnownFPClass KnownFPClass::fadd_self(const KnownFPClass &KnownSrc,
337 DenormalMode Mode) {
338 KnownFPClass Known = fadd(KnownLHS: KnownSrc, KnownRHS: KnownSrc, Mode);
339
340 // Doubling 0 will give the same 0.
341 if (KnownSrc.isKnownNeverLogicalPosZero(Mode) &&
342 (Mode.Output == DenormalMode::IEEE ||
343 (Mode.Output == DenormalMode::PreserveSign &&
344 KnownSrc.isKnownNeverPosSubnormal()) ||
345 (Mode.Output == DenormalMode::PositiveZero &&
346 KnownSrc.isKnownNeverSubnormal())))
347 Known.knownNot(RuleOut: fcPosZero);
348
349 return Known;
350}
351
352KnownFPClass KnownFPClass::fsub(const KnownFPClass &KnownLHS,
353 const KnownFPClass &KnownRHS,
354 DenormalMode Mode) {
355 return fadd(KnownLHS, KnownRHS: fneg(Src: KnownRHS), Mode);
356}
357
358KnownFPClass KnownFPClass::fmul(const KnownFPClass &KnownLHS,
359 const KnownFPClass &KnownRHS,
360 DenormalMode Mode) {
361 KnownFPClass Known;
362
363 // +X * +Y or -X * -Y => +Q
364 // +X * -Y or -X * +Y => -Q
365 Known.propagateXorSign(LHS: KnownLHS, RHS: KnownRHS);
366
367 // Inf * Y => Inf or NaN
368 if (KnownLHS.isKnownAlways(Mask: fcInf | fcNan) ||
369 KnownRHS.isKnownAlways(Mask: fcInf | fcNan))
370 Known.knownNot(RuleOut: fcNormal | fcSubnormal | fcZero);
371
372 // 0 * Y => 0 or NaN
373 if (KnownRHS.isKnownAlways(Mask: fcZero | fcNan) ||
374 KnownLHS.isKnownAlways(Mask: fcZero | fcNan))
375 Known.knownNot(RuleOut: fcNormal | fcSubnormal | fcInf);
376
377 if (!KnownLHS.isKnownNeverNaN() || !KnownRHS.isKnownNeverNaN())
378 return Known;
379
380 // 0 * +/-inf => NaN
381 if ((KnownRHS.isKnownNeverInfinity() ||
382 KnownLHS.isKnownNeverLogicalZero(Mode)) &&
383 (KnownLHS.isKnownNeverInfinity() ||
384 KnownRHS.isKnownNeverLogicalZero(Mode)))
385 Known.knownNot(RuleOut: fcNan);
386
387 return Known;
388}
389
390// TODO: This generalizes to known ranges
391KnownFPClass KnownFPClass::fmul(const KnownFPClass &KnownLHS,
392 const APFloat &CRHS, DenormalMode Mode) {
393 // Match denormal scaling pattern, similar to the case in ldexp. If the
394 // constant's exponent is sufficiently large, the result cannot be subnormal.
395
396 const fltSemantics &Flt = CRHS.getSemantics();
397 unsigned Precision = APFloat::semanticsPrecision(Flt);
398 const int MantissaBits = Precision - 1;
399
400 int MinKnownExponent = ilogb(Arg: CRHS);
401 bool CannotBeSubnormal = (MinKnownExponent >= MantissaBits);
402
403 KnownFPClass Known = KnownFPClass::fmul(KnownLHS, KnownRHS: KnownFPClass(CRHS), Mode);
404 if (CannotBeSubnormal)
405 Known.knownNot(RuleOut: fcSubnormal);
406
407 // Multiply of values <= 1 cannot introduce overflow.
408 if (KnownLHS.isKnownNever(Mask: fcInf)) {
409 if (MinKnownExponent < 0)
410 Known.knownNot(RuleOut: fcInf);
411 else if (MinKnownExponent == 0 && CRHS.compareAbsoluteValue(RHS: APFloat::getOne(
412 Sem: Flt)) == APFloat::cmpEqual)
413 Known.knownNot(RuleOut: fcInf);
414 }
415
416 return Known;
417}
418
419KnownFPClass KnownFPClass::fdiv(const KnownFPClass &KnownLHS,
420 const KnownFPClass &KnownRHS,
421 DenormalMode Mode) {
422 KnownFPClass Known;
423
424 // Only 0/0, Inf/Inf produce NaN.
425 if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() &&
426 (KnownLHS.isKnownNeverInfinity() || KnownRHS.isKnownNeverInfinity()) &&
427 (KnownLHS.isKnownNeverLogicalZero(Mode) ||
428 KnownRHS.isKnownNeverLogicalZero(Mode))) {
429 Known.knownNot(RuleOut: fcNan);
430 }
431
432 // X / -0.0 => -Inf (or NaN)
433 // +X / +Y or -X / -Y => +Q
434 // +X / -Y or -X / +Y => -Q
435 Known.propagateXorSign(LHS: KnownLHS, RHS: KnownRHS);
436
437 // 0 / X => 0 or NaN
438 if (KnownLHS.isKnownAlways(Mask: fcZero))
439 Known.knownNot(RuleOut: fcSubnormal | fcNormal | fcInf);
440
441 // X / 0 => NaN or Inf
442 if (KnownRHS.isKnownAlways(Mask: fcZero))
443 Known.knownNot(RuleOut: fcFinite);
444
445 return Known;
446}
447
448KnownFPClass KnownFPClass::fdiv_self(const KnownFPClass &KnownSrc,
449 DenormalMode Mode) {
450 // X / X is always exactly 1.0 or a NaN.
451 KnownFPClass Known(fcNan | fcPosNormal);
452
453 if (KnownSrc.isKnownNeverInfOrNaN() && KnownSrc.isKnownNeverLogicalZero(Mode))
454 Known.knownNot(RuleOut: fcNan);
455 else if (KnownSrc.isKnownNever(Mask: fcSNan))
456 Known.knownNot(RuleOut: fcSNan);
457
458 return Known;
459}
460KnownFPClass KnownFPClass::frem_self(const KnownFPClass &KnownSrc,
461 DenormalMode Mode) {
462 // X % X is always exactly [+-]0.0 or a NaN.
463 KnownFPClass Known(fcNan | fcZero);
464
465 if (KnownSrc.isKnownNeverInfOrNaN() && KnownSrc.isKnownNeverLogicalZero(Mode))
466 Known.knownNot(RuleOut: fcNan);
467 else if (KnownSrc.isKnownNever(Mask: fcSNan))
468 Known.knownNot(RuleOut: fcSNan);
469
470 return Known;
471}
472
473KnownFPClass KnownFPClass::fma(const KnownFPClass &KnownLHS,
474 const KnownFPClass &KnownRHS,
475 const KnownFPClass &KnownAddend,
476 DenormalMode Mode) {
477 KnownFPClass Mul = fmul(KnownLHS, KnownRHS, Mode);
478
479 // FMA differs from the base fmul + fadd handling only in the treatment of -0
480 // results.
481 //
482 // If the multiply is a -0 due to rounding, the final -0 + 0 will be -0,
483 // unlike for a separate fadd.
484 return fadd_impl(KnownLHS: Mul, KnownRHS: KnownAddend, Mode);
485}
486
487KnownFPClass KnownFPClass::fma_square(const KnownFPClass &KnownSquared,
488 const KnownFPClass &KnownAddend,
489 DenormalMode Mode) {
490 KnownFPClass Squared = square(Src: KnownSquared, Mode);
491 KnownFPClass Known = fadd_impl(KnownLHS: Squared, KnownRHS: KnownAddend, Mode);
492
493 // Since we know the squared input must be positive, the add of opposite sign
494 // infinities nan hazard only applies for negative inf.
495 //
496 // TODO: Alternatively to proving addend is not -inf, we could know Squared is
497 // not pinf. Other than the degenerate always-subnormal input case, we can't
498 // prove that without a known range.
499 if (KnownAddend.isKnownNever(Mask: fcNegInf | fcNan) && Squared.isKnownNever(Mask: fcNan))
500 Known.knownNot(RuleOut: fcNan);
501
502 return Known;
503}
504
505KnownFPClass KnownFPClass::exp(const KnownFPClass &KnownSrc) {
506 KnownFPClass Known;
507 Known.knownNot(RuleOut: fcNegative);
508
509 Known.propagateNaN(Src: KnownSrc);
510
511 if (KnownSrc.cannotBeOrderedLessThanZero()) {
512 // If the source is positive this cannot underflow.
513 Known.knownNot(RuleOut: fcPosZero);
514
515 // Cannot introduce denormal values.
516 Known.knownNot(RuleOut: fcPosSubnormal);
517 }
518
519 // If the source is negative, this cannot overflow to infinity.
520 if (KnownSrc.cannotBeOrderedGreaterThanZero())
521 Known.knownNot(RuleOut: fcPosInf);
522
523 return Known;
524}
525
526void KnownFPClass::propagateCanonicalizingSrc(const KnownFPClass &Src,
527 DenormalMode Mode) {
528 propagateDenormal(Src, Mode);
529 propagateNaN(Src, /*PreserveSign=*/true);
530}
531
532KnownFPClass KnownFPClass::log(const KnownFPClass &KnownSrc,
533 DenormalMode Mode) {
534 KnownFPClass Known;
535 Known.knownNot(RuleOut: fcNegZero | fcSubnormal);
536
537 if (KnownSrc.isKnownNeverPosInfinity())
538 Known.knownNot(RuleOut: fcPosInf);
539
540 if (KnownSrc.isKnownNeverNaN() && KnownSrc.cannotBeOrderedLessThanZero())
541 Known.knownNot(RuleOut: fcNan);
542
543 if (KnownSrc.isKnownNeverLogicalZero(Mode))
544 Known.knownNot(RuleOut: fcNegInf);
545
546 return Known;
547}
548
549KnownFPClass KnownFPClass::sqrt(const KnownFPClass &KnownSrc,
550 DenormalMode Mode) {
551 KnownFPClass Known;
552 Known.knownNot(RuleOut: fcPosSubnormal);
553
554 if (KnownSrc.isKnownNeverPosInfinity())
555 Known.knownNot(RuleOut: fcPosInf);
556 if (KnownSrc.isKnownNever(Mask: fcSNan))
557 Known.knownNot(RuleOut: fcSNan);
558
559 // Any negative value besides -0 returns a nan.
560 if (KnownSrc.isKnownNeverNaN() && KnownSrc.cannotBeOrderedLessThanZero())
561 Known.knownNot(RuleOut: fcNan);
562
563 // The only negative value that can be returned is -0 for -0 inputs.
564 Known.knownNot(RuleOut: fcNegInf | fcNegSubnormal | fcNegNormal);
565
566 // If the input denormal mode could be PreserveSign, a negative
567 // subnormal input could produce a negative zero output.
568 if (KnownSrc.isKnownNeverLogicalNegZero(Mode))
569 Known.knownNot(RuleOut: fcNegZero);
570
571 return Known;
572}
573
574KnownFPClass KnownFPClass::sin(const KnownFPClass &KnownSrc) {
575 KnownFPClass Known;
576
577 // Return NaN on infinite inputs.
578 Known.knownNot(RuleOut: fcInf);
579 if (KnownSrc.isKnownNeverNaN() && KnownSrc.isKnownNeverInfinity())
580 Known.knownNot(RuleOut: fcNan);
581
582 return Known;
583}
584
585KnownFPClass KnownFPClass::cos(const KnownFPClass &KnownSrc) {
586 return sin(KnownSrc);
587}
588
589KnownFPClass KnownFPClass::tan(const KnownFPClass &KnownSrc) {
590 KnownFPClass Known;
591
592 // tan never returns Inf (tan(+-Inf) = NaN; tan(finite) = finite).
593 Known.knownNot(RuleOut: fcInf);
594
595 // NaN propagates. tan(+-Inf) is NaN.
596 if (KnownSrc.isKnownNeverNaN() && KnownSrc.isKnownNeverInfinity())
597 Known.knownNot(RuleOut: fcNan);
598
599 return Known;
600}
601
602KnownFPClass KnownFPClass::sinh(const KnownFPClass &KnownSrc) {
603 KnownFPClass Known;
604
605 // sinh is sign-preserving: sinh(x) < 0 iff x < 0.
606 if (KnownSrc.isKnownNever(Mask: fcNegative))
607 Known.knownNot(RuleOut: fcNegative);
608
609 Known.propagateNaN(Src: KnownSrc);
610
611 return Known;
612}
613
614KnownFPClass KnownFPClass::cosh(const KnownFPClass &KnownSrc) {
615 KnownFPClass Known;
616
617 // cosh(x) >= 1 for all real x; cosh(+-Inf) = +Inf. Never negative.
618 Known.knownNot(RuleOut: fcNegative);
619
620 Known.propagateNaN(Src: KnownSrc);
621
622 return Known;
623}
624
625KnownFPClass KnownFPClass::tanh(const KnownFPClass &KnownSrc) {
626 KnownFPClass Known;
627
628 // tanh is bounded to (-1, 1), never Inf.
629 Known.knownNot(RuleOut: fcInf);
630
631 // tanh is sign-preserving: tanh(x) < 0 iff x < 0.
632 if (KnownSrc.isKnownNever(Mask: fcNegative))
633 Known.knownNot(RuleOut: fcNegative);
634
635 Known.propagateNaN(Src: KnownSrc);
636
637 return Known;
638}
639
640KnownFPClass KnownFPClass::asin(const KnownFPClass &KnownSrc) {
641 KnownFPClass Known;
642
643 // asin is bounded to [-pi/2, pi/2], never Inf.
644 Known.knownNot(RuleOut: fcInf);
645
646 // asin is sign-preserving.
647 if (KnownSrc.isKnownNever(Mask: fcNegative))
648 Known.knownNot(RuleOut: fcNegative);
649
650 // NaN propagates. asin(x) is also NaN for |x| > 1, so we cannot rule
651 // out NaN without knowing the source is in [-1, 1].
652 Known.propagateNaN(Src: KnownSrc);
653
654 return Known;
655}
656
657KnownFPClass KnownFPClass::acos(const KnownFPClass &KnownSrc) {
658 KnownFPClass Known;
659
660 // acos is bounded to [0, pi], never Inf or negative.
661 Known.knownNot(RuleOut: fcInf);
662 Known.knownNot(RuleOut: fcNegative);
663
664 // NaN propagates. acos(x) is also NaN for |x| > 1, so we cannot rule
665 // out NaN without knowing the source is in [-1, 1].
666 Known.propagateNaN(Src: KnownSrc);
667
668 return Known;
669}
670
671KnownFPClass KnownFPClass::atan(const KnownFPClass &KnownSrc) {
672 KnownFPClass Known;
673
674 // atan is bounded to (-pi/2, pi/2), never Inf. atan(+-Inf) = +-pi/2 (finite).
675 Known.knownNot(RuleOut: fcInf);
676
677 // atan is sign-preserving: atan(x) < 0 iff x < 0.
678 if (KnownSrc.isKnownNever(Mask: fcNegative))
679 Known.knownNot(RuleOut: fcNegative);
680
681 Known.propagateNaN(Src: KnownSrc);
682
683 return Known;
684}
685
686KnownFPClass KnownFPClass::atan2(const KnownFPClass &KnownLHS,
687 const KnownFPClass &KnownRHS) {
688 KnownFPClass Known;
689
690 // atan2 result is in (-pi, pi], never Inf.
691 Known.knownNot(RuleOut: fcInf);
692
693 // NaN if either operand is NaN.
694 if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN())
695 Known.knownNot(RuleOut: fcNan);
696
697 return Known;
698}
699
700KnownFPClass KnownFPClass::fpext(const KnownFPClass &KnownSrc,
701 const fltSemantics &DstTy,
702 const fltSemantics &SrcTy) {
703 // Infinity, nan and zero propagate from source.
704 KnownFPClass Known = KnownSrc;
705
706 // All subnormal inputs should be in the normal range in the result type.
707 if (APFloat::isRepresentableAsNormalIn(Src: SrcTy, Dst: DstTy)) {
708 if (Known.KnownFPClasses & fcPosSubnormal)
709 Known.KnownFPClasses |= fcPosNormal;
710 if (Known.KnownFPClasses & fcNegSubnormal)
711 Known.KnownFPClasses |= fcNegNormal;
712 Known.knownNot(RuleOut: fcSubnormal);
713 }
714
715 // Sign bit of a nan isn't guaranteed.
716 if (!Known.isKnownNeverNaN())
717 Known.SignBit = std::nullopt;
718
719 return Known;
720}
721
722KnownFPClass KnownFPClass::fptrunc(const KnownFPClass &KnownSrc) {
723 KnownFPClass Known;
724
725 // Sign should be preserved
726 // TODO: Handle cannot be ordered greater than zero
727 if (KnownSrc.cannotBeOrderedLessThanZero())
728 Known.knownNot(RuleOut: KnownFPClass::OrderedLessThanZeroMask);
729
730 Known.propagateNaN(Src: KnownSrc, PreserveSign: true);
731
732 // Infinity needs a range check.
733 return Known;
734}
735
736KnownFPClass KnownFPClass::roundToIntegral(const KnownFPClass &KnownSrc,
737 bool IsTrunc,
738 bool IsMultiUnitFPType) {
739 KnownFPClass Known;
740
741 // Integer results cannot be subnormal.
742 Known.knownNot(RuleOut: fcSubnormal);
743
744 Known.propagateNaN(Src: KnownSrc, PreserveSign: true);
745
746 // Pass through infinities, except PPC_FP128 is a special case for
747 // intrinsics other than trunc.
748 if (IsTrunc || !IsMultiUnitFPType) {
749 if (KnownSrc.isKnownNeverPosInfinity())
750 Known.knownNot(RuleOut: fcPosInf);
751 if (KnownSrc.isKnownNeverNegInfinity())
752 Known.knownNot(RuleOut: fcNegInf);
753 }
754
755 // Negative round ups to 0 produce -0
756 if (KnownSrc.isKnownNever(Mask: fcPosFinite))
757 Known.knownNot(RuleOut: fcPosFinite);
758 if (KnownSrc.isKnownNever(Mask: fcNegFinite))
759 Known.knownNot(RuleOut: fcNegFinite);
760
761 return Known;
762}
763
764KnownFPClass KnownFPClass::frexp_mant(const KnownFPClass &KnownSrc,
765 DenormalMode Mode) {
766 KnownFPClass Known;
767 Known.knownNot(RuleOut: fcSubnormal);
768
769 if (KnownSrc.isKnownNever(Mask: fcNegative))
770 Known.knownNot(RuleOut: fcNegative);
771 else {
772 if (KnownSrc.isKnownNeverLogicalNegZero(Mode))
773 Known.knownNot(RuleOut: fcNegZero);
774 if (KnownSrc.isKnownNever(Mask: fcNegInf))
775 Known.knownNot(RuleOut: fcNegInf);
776 }
777
778 if (KnownSrc.isKnownNever(Mask: fcPositive))
779 Known.knownNot(RuleOut: fcPositive);
780 else {
781 if (KnownSrc.isKnownNeverLogicalPosZero(Mode))
782 Known.knownNot(RuleOut: fcPosZero);
783 if (KnownSrc.isKnownNever(Mask: fcPosInf))
784 Known.knownNot(RuleOut: fcPosInf);
785 }
786
787 Known.propagateNaN(Src: KnownSrc);
788 return Known;
789}
790
791KnownFPClass KnownFPClass::ldexp(const KnownFPClass &KnownSrc,
792 const KnownBits &ExpBits,
793 const fltSemantics &Flt, DenormalMode Mode) {
794 KnownFPClass Known;
795 Known.propagateNaN(Src: KnownSrc, /*PropagateSign=*/PreserveSign: true);
796
797 // Sign is preserved, but underflows may produce zeroes.
798 if (KnownSrc.isKnownNever(Mask: fcNegative))
799 Known.knownNot(RuleOut: fcNegative);
800 else if (KnownSrc.cannotBeOrderedLessThanZero())
801 Known.knownNot(RuleOut: OrderedLessThanZeroMask);
802
803 if (KnownSrc.isKnownNever(Mask: fcPositive))
804 Known.knownNot(RuleOut: fcPositive);
805 else if (KnownSrc.cannotBeOrderedGreaterThanZero())
806 Known.knownNot(RuleOut: OrderedGreaterThanZeroMask);
807
808 unsigned Precision = APFloat::semanticsPrecision(Flt);
809 const int MantissaBits = Precision - 1;
810
811 if (ExpBits.getSignedMinValue().sge(RHS: static_cast<int64_t>(MantissaBits)))
812 Known.knownNot(RuleOut: fcSubnormal);
813
814 if (ExpBits.isConstant() && ExpBits.getConstant().isZero()) {
815 // ldexp(x, 0) -> x, so propagate everything.
816 Known.propagateCanonicalizingSrc(Src: KnownSrc, Mode);
817 } else if (ExpBits.isNegative()) {
818 // If we know the power is <= 0, can't introduce inf
819 if (KnownSrc.isKnownNeverPosInfinity())
820 Known.knownNot(RuleOut: fcPosInf);
821 if (KnownSrc.isKnownNeverNegInfinity())
822 Known.knownNot(RuleOut: fcNegInf);
823 } else if (ExpBits.isNonNegative()) {
824 // If we know the power is >= 0, can't introduce subnormal or zero
825 if (KnownSrc.isKnownNeverPosSubnormal())
826 Known.knownNot(RuleOut: fcPosSubnormal);
827 if (KnownSrc.isKnownNeverNegSubnormal())
828 Known.knownNot(RuleOut: fcNegSubnormal);
829 if (KnownSrc.isKnownNeverLogicalPosZero(Mode))
830 Known.knownNot(RuleOut: fcPosZero);
831 if (KnownSrc.isKnownNeverLogicalNegZero(Mode))
832 Known.knownNot(RuleOut: fcNegZero);
833 }
834
835 return Known;
836}
837
838KnownFPClass KnownFPClass::powi(const KnownFPClass &KnownSrc,
839 const KnownBits &ExponentKnownBits) {
840 KnownFPClass Known;
841 Known.propagateNaN(Src: KnownSrc);
842
843 if (ExponentKnownBits.isZero()) {
844 // powi(QNaN, 0) returns 1.0, and powi(SNaN, 0) may non-deterministically
845 // return 1.0 or a NaN.
846 if (KnownSrc.isKnownNever(Mask: fcSNan)) {
847 Known.knownNot(RuleOut: ~fcPosNormal);
848 return Known;
849 }
850
851 Known.knownNot(RuleOut: ~(fcPosNormal | fcNan));
852 return Known;
853 }
854
855 // powi(x, exp) --> inf
856 // when:
857 // * powi(inf, exp), exp > 0
858 // * powi(+/-0, exp), exp < 0
859 // * powi(finite, exp), |exp| > 1
860 // * powi(subnormal, -1)
861 // TODO:
862 // 1. This simple all or nothing approach. We can do better
863 // and cover sign/parity and exp > 1 vs exp < -1 separately.
864 // 2. powi(0/nan, exp), exp > 0 can be refinable
865 // to fcNan | fcZero | fcPosNormal.
866 {
867 APInt MinExp = ExponentKnownBits.getSignedMinValue();
868 APInt MaxExp = ExponentKnownBits.getSignedMaxValue();
869
870 // powi(inf, exp), exp > 0
871 bool MayInfSrc =
872 !KnownSrc.isKnownNever(Mask: fcInf) && MaxExp.isStrictlyPositive();
873
874 // powi(+/-0, exp), exp < 0
875 bool MayDivByZero = !KnownSrc.isKnownNever(Mask: fcZero) && MinExp.isNegative();
876
877 // powi(finite, exp), |exp| > 1
878 bool MayFinite = !KnownSrc.isKnownNever(Mask: fcNormal | fcSubnormal);
879 bool MayAbsExpGT1 = MinExp.slt(RHS: -1) || MaxExp.sgt(RHS: 1);
880 bool MayFiniteOverflow = MayFinite && MayAbsExpGT1;
881
882 // powi(subnormal, -1)
883 bool MayBeNegOne = ExponentKnownBits.Zero.isZero();
884 bool MaySubnormInv = !KnownSrc.isKnownNever(Mask: fcSubnormal) && MayBeNegOne;
885
886 if (!MayInfSrc && !MayDivByZero && !MayFiniteOverflow && !MaySubnormInv)
887 Known.knownNot(RuleOut: fcInf);
888 }
889
890 if (ExponentKnownBits.isEven()) {
891 Known.knownNot(RuleOut: fcNegative);
892 return Known;
893 }
894
895 // Given that exp is an integer, here are the
896 // ways that pow can return a negative value:
897 //
898 // pow(-x, exp) --> negative if exp is odd and x is negative.
899 // pow(-0, exp) --> -inf if exp is negative odd.
900 // pow(-0, exp) --> -0 if exp is positive odd.
901 // pow(-inf, exp) --> -0 if exp is negative odd.
902 // pow(-inf, exp) --> -inf if exp is positive odd.
903 if (KnownSrc.isKnownNever(Mask: fcNegative))
904 Known.knownNot(RuleOut: fcNegative);
905
906 return Known;
907}
908