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 at least one operand is known to be positive, the result must be
112 // positive.
113 if ((KnownLHS.cannotBeOrderedLessThanZero() &&
114 KnownLHS.isKnownNeverNaN()) ||
115 (KnownRHS.cannotBeOrderedLessThanZero() && KnownRHS.isKnownNeverNaN()))
116 Known.knownNot(RuleOut: KnownFPClass::OrderedLessThanZeroMask);
117 } else if (Kind == MinMaxKind::maximum) {
118 // If at least one operand is known to be positive, the result must be
119 // positive.
120 if (KnownLHS.cannotBeOrderedLessThanZero() ||
121 KnownRHS.cannotBeOrderedLessThanZero())
122 Known.knownNot(RuleOut: KnownFPClass::OrderedLessThanZeroMask);
123 } else if (Kind == MinMaxKind::minnum || Kind == MinMaxKind::minimumnum) {
124 // If at least one operand is known to be negative, the result must be
125 // negative.
126 if ((KnownLHS.cannotBeOrderedGreaterThanZero() &&
127 KnownLHS.isKnownNeverNaN()) ||
128 (KnownRHS.cannotBeOrderedGreaterThanZero() &&
129 KnownRHS.isKnownNeverNaN()))
130 Known.knownNot(RuleOut: KnownFPClass::OrderedGreaterThanZeroMask);
131 } else if (Kind == MinMaxKind::minimum) {
132 // If at least one operand is known to be negative, the result must be
133 // negative.
134 if (KnownLHS.cannotBeOrderedGreaterThanZero() ||
135 KnownRHS.cannotBeOrderedGreaterThanZero())
136 Known.knownNot(RuleOut: KnownFPClass::OrderedGreaterThanZeroMask);
137 } else
138 llvm_unreachable("unhandled intrinsic");
139
140 // Fixup zero handling if denormals could be returned as a zero.
141 //
142 // As there's no spec for denormal flushing, be conservative with the
143 // treatment of denormals that could be flushed to zero. For older
144 // subtargets on AMDGPU the min/max instructions would not flush the
145 // output and return the original value.
146 //
147 if ((Known.KnownFPClasses & fcZero) != fcNone &&
148 !Known.isKnownNeverSubnormal()) {
149 if (Mode != DenormalMode::getIEEE())
150 Known.KnownFPClasses |= fcZero;
151 }
152
153 if (Known.isKnownNeverNaN()) {
154 if (KnownLHS.SignBit && KnownRHS.SignBit &&
155 *KnownLHS.SignBit == *KnownRHS.SignBit) {
156 if (*KnownLHS.SignBit)
157 Known.signBitMustBeOne();
158 else
159 Known.signBitMustBeZero();
160 } else if ((Kind == MinMaxKind::maximum || Kind == MinMaxKind::minimum ||
161 Kind == MinMaxKind::maximumnum ||
162 Kind == MinMaxKind::minimumnum) ||
163 // FIXME: Should be using logical zero versions
164 ((KnownLHS.isKnownNeverNegZero() ||
165 KnownRHS.isKnownNeverPosZero()) &&
166 (KnownLHS.isKnownNeverPosZero() ||
167 KnownRHS.isKnownNeverNegZero()))) {
168 // Don't take sign bit from NaN operands.
169 if (!KnownLHS.isKnownNeverNaN())
170 KnownLHS.SignBit = std::nullopt;
171 if (!KnownRHS.isKnownNeverNaN())
172 KnownRHS.SignBit = std::nullopt;
173 if ((Kind == MinMaxKind::maximum || Kind == MinMaxKind::maximumnum ||
174 Kind == MinMaxKind::maxnum) &&
175 (KnownLHS.SignBit == false || KnownRHS.SignBit == false))
176 Known.signBitMustBeZero();
177 else if ((Kind == MinMaxKind::minimum || Kind == MinMaxKind::minimumnum ||
178 Kind == MinMaxKind::minnum) &&
179 (KnownLHS.SignBit == true || KnownRHS.SignBit == true))
180 Known.signBitMustBeOne();
181 }
182 }
183
184 return Known;
185}
186
187KnownFPClass KnownFPClass::canonicalize(const KnownFPClass &KnownSrc,
188 DenormalMode DenormMode) {
189 KnownFPClass Known;
190
191 // This is essentially a stronger form of
192 // propagateCanonicalizingSrc. Other "canonicalizing" operations don't
193 // actually have an IR canonicalization guarantee.
194
195 // Canonicalize may flush denormals to zero, so we have to consider the
196 // denormal mode to preserve known-not-0 knowledge.
197 Known.KnownFPClasses = KnownSrc.KnownFPClasses | fcZero | fcQNan;
198
199 // Stronger version of propagateNaN
200 // Canonicalize is guaranteed to quiet signaling nans.
201 if (KnownSrc.isKnownNeverNaN())
202 Known.knownNot(RuleOut: fcNan);
203 else
204 Known.knownNot(RuleOut: fcSNan);
205
206 // FIXME: Missing check of IEEE like types.
207
208 // If the parent function flushes denormals, the canonical output cannot be a
209 // denormal.
210 if (DenormMode == DenormalMode::getIEEE()) {
211 if (KnownSrc.isKnownNever(Mask: fcPosZero))
212 Known.knownNot(RuleOut: fcPosZero);
213 if (KnownSrc.isKnownNever(Mask: fcNegZero))
214 Known.knownNot(RuleOut: fcNegZero);
215 return Known;
216 }
217
218 if (DenormMode.inputsAreZero() || DenormMode.outputsAreZero())
219 Known.knownNot(RuleOut: fcSubnormal);
220
221 if (DenormMode == DenormalMode::getPreserveSign()) {
222 if (KnownSrc.isKnownNever(Mask: fcPosZero | fcPosSubnormal))
223 Known.knownNot(RuleOut: fcPosZero);
224 if (KnownSrc.isKnownNever(Mask: fcNegZero | fcNegSubnormal))
225 Known.knownNot(RuleOut: fcNegZero);
226 return Known;
227 }
228
229 if (DenormMode.Input == DenormalMode::PositiveZero ||
230 (DenormMode.Output == DenormalMode::PositiveZero &&
231 DenormMode.Input == DenormalMode::IEEE))
232 Known.knownNot(RuleOut: fcNegZero);
233
234 return Known;
235}
236
237KnownFPClass KnownFPClass::bitcast(const fltSemantics &FltSemantics,
238 const KnownBits &Bits) {
239 assert(FltSemantics.sizeInBits == Bits.getBitWidth() &&
240 "Bitcast operand has incorrect bit width");
241 KnownFPClass Known;
242
243 // Transfer information from the sign bit.
244 if (Bits.isNonNegative())
245 Known.signBitMustBeZero();
246 else if (Bits.isNegative())
247 Known.signBitMustBeOne();
248
249 if (APFloat::isIEEELikeFP(FltSemantics)) {
250 // IEEE floats are NaN when all bits of the exponent plus at least one of
251 // the fraction bits are 1. This means:
252 // - If we assume unknown bits are 0 and the value is NaN, it will
253 // always be NaN
254 // - If we assume unknown bits are 1 and the value is not NaN, it can
255 // never be NaN
256 // Note: They do not hold for x86_fp80 format.
257 if (APFloat(FltSemantics, Bits.One).isNaN())
258 Known.KnownFPClasses = fcNan;
259 else if (!APFloat(FltSemantics, ~Bits.Zero).isNaN())
260 Known.knownNot(RuleOut: fcNan);
261
262 // Build KnownBits representing Inf and check if it must be equal or
263 // unequal to this value.
264 auto InfKB =
265 KnownBits::makeConstant(C: APFloat::getInf(Sem: FltSemantics).bitcastToAPInt());
266 InfKB.Zero.clearSignBit();
267 if (const auto InfResult = KnownBits::eq(LHS: Bits, RHS: InfKB)) {
268 assert(!InfResult.value());
269 Known.knownNot(RuleOut: fcInf);
270 } else if (Bits == InfKB) {
271 Known.KnownFPClasses = fcInf;
272 }
273
274 // Build KnownBits representing Zero and check if it must be equal or
275 // unequal to this value.
276 auto ZeroKB = KnownBits::makeConstant(
277 C: APFloat::getZero(Sem: FltSemantics).bitcastToAPInt());
278 ZeroKB.Zero.clearSignBit();
279 if (const auto ZeroResult = KnownBits::eq(LHS: Bits, RHS: ZeroKB)) {
280 assert(!ZeroResult.value());
281 Known.knownNot(RuleOut: fcZero);
282 } else if (Bits == ZeroKB) {
283 Known.KnownFPClasses = fcZero;
284 }
285 }
286
287 return Known;
288}
289
290// Handle known sign bit and nan cases for fadd.
291static KnownFPClass fadd_impl(const KnownFPClass &KnownLHS,
292 const KnownFPClass &KnownRHS, DenormalMode Mode) {
293 KnownFPClass Known;
294
295 // Adding positive and negative infinity produces NaN.
296 // TODO: Check sign of infinities.
297 if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() &&
298 (KnownLHS.isKnownNeverInfinity() || KnownRHS.isKnownNeverInfinity()))
299 Known.knownNot(RuleOut: fcNan);
300
301 if (KnownLHS.cannotBeOrderedLessThanZero() &&
302 KnownRHS.cannotBeOrderedLessThanZero()) {
303 Known.knownNot(RuleOut: KnownFPClass::OrderedLessThanZeroMask);
304
305 // This can't underflow if one of the operands is known normal.
306 if (KnownLHS.isKnownNever(Mask: fcZero | fcPosSubnormal) ||
307 KnownRHS.isKnownNever(Mask: fcZero | fcPosSubnormal))
308 Known.knownNot(RuleOut: fcZero | fcPosSubnormal);
309 }
310
311 if (KnownLHS.cannotBeOrderedGreaterThanZero() &&
312 KnownRHS.cannotBeOrderedGreaterThanZero()) {
313 Known.knownNot(RuleOut: KnownFPClass::OrderedGreaterThanZeroMask);
314
315 // This can't underflow if one of the operands is known normal.
316 if (KnownLHS.isKnownNever(Mask: fcZero | fcNegSubnormal) ||
317 KnownRHS.isKnownNever(Mask: fcZero | fcNegSubnormal))
318 Known.knownNot(RuleOut: fcZero | fcNegSubnormal);
319 }
320
321 return Known;
322}
323
324KnownFPClass KnownFPClass::fadd(const KnownFPClass &KnownLHS,
325 const KnownFPClass &KnownRHS,
326 DenormalMode Mode) {
327 KnownFPClass Known = fadd_impl(KnownLHS, KnownRHS, Mode);
328
329 // (fadd x, 0.0) is guaranteed to return +0.0, not -0.0.
330 if ((KnownLHS.isKnownNeverLogicalNegZero(Mode) ||
331 KnownRHS.isKnownNeverLogicalNegZero(Mode)) &&
332 // Make sure output negative denormal can't flush to -0
333 (Mode.Output == DenormalMode::IEEE ||
334 Mode.Output == DenormalMode::PositiveZero))
335 Known.knownNot(RuleOut: fcNegZero);
336
337 return Known;
338}
339
340KnownFPClass KnownFPClass::fadd_self(const KnownFPClass &KnownSrc,
341 DenormalMode Mode) {
342 KnownFPClass Known = fadd(KnownLHS: KnownSrc, KnownRHS: KnownSrc, Mode);
343
344 // Doubling 0 will give the same 0.
345 if (KnownSrc.isKnownNeverLogicalPosZero(Mode) &&
346 (Mode.Output == DenormalMode::IEEE ||
347 (Mode.Output == DenormalMode::PreserveSign &&
348 KnownSrc.isKnownNeverPosSubnormal()) ||
349 (Mode.Output == DenormalMode::PositiveZero &&
350 KnownSrc.isKnownNeverSubnormal())))
351 Known.knownNot(RuleOut: fcPosZero);
352
353 return Known;
354}
355
356KnownFPClass KnownFPClass::fsub(const KnownFPClass &KnownLHS,
357 const KnownFPClass &KnownRHS,
358 DenormalMode Mode) {
359 return fadd(KnownLHS, KnownRHS: fneg(Src: KnownRHS), Mode);
360}
361
362KnownFPClass KnownFPClass::fmul(const KnownFPClass &KnownLHS,
363 const KnownFPClass &KnownRHS,
364 DenormalMode Mode) {
365 KnownFPClass Known;
366
367 // xor sign bit.
368 if ((KnownLHS.isKnownNever(Mask: fcNegative) &&
369 KnownRHS.isKnownNever(Mask: fcNegative)) ||
370 (KnownLHS.isKnownNever(Mask: fcPositive) && KnownRHS.isKnownNever(Mask: fcPositive)))
371 Known.knownNot(RuleOut: fcNegative);
372
373 if ((KnownLHS.isKnownNever(Mask: fcPositive) &&
374 KnownRHS.isKnownNever(Mask: fcNegative)) ||
375 (KnownLHS.isKnownNever(Mask: fcNegative) && KnownRHS.isKnownNever(Mask: fcPositive)))
376 Known.knownNot(RuleOut: fcPositive);
377
378 // inf * anything => inf or nan
379 if (KnownLHS.isKnownAlways(Mask: fcInf | fcNan) ||
380 KnownRHS.isKnownAlways(Mask: fcInf | fcNan))
381 Known.knownNot(RuleOut: fcNormal | fcSubnormal | fcZero);
382
383 // 0 * anything => 0 or nan
384 if (KnownRHS.isKnownAlways(Mask: fcZero | fcNan) ||
385 KnownLHS.isKnownAlways(Mask: fcZero | fcNan))
386 Known.knownNot(RuleOut: fcNormal | fcSubnormal | fcInf);
387
388 // +/-0 * +/-inf = nan
389 if ((KnownLHS.isKnownAlways(Mask: fcZero | fcNan) &&
390 KnownRHS.isKnownAlways(Mask: fcInf | fcNan)) ||
391 (KnownLHS.isKnownAlways(Mask: fcInf | fcNan) &&
392 KnownRHS.isKnownAlways(Mask: fcZero | fcNan)))
393 Known.knownNot(RuleOut: ~fcNan);
394
395 if (!KnownLHS.isKnownNeverNaN() || !KnownRHS.isKnownNeverNaN())
396 return Known;
397
398 // If 0 * +/-inf produces NaN.
399 if ((KnownRHS.isKnownNeverInfinity() ||
400 KnownLHS.isKnownNeverLogicalZero(Mode)) &&
401 (KnownLHS.isKnownNeverInfinity() ||
402 KnownRHS.isKnownNeverLogicalZero(Mode)))
403 Known.knownNot(RuleOut: fcNan);
404
405 return Known;
406}
407
408// TODO: This generalizes to known ranges
409KnownFPClass KnownFPClass::fmul(const KnownFPClass &KnownLHS,
410 const APFloat &CRHS, DenormalMode Mode) {
411 // Match denormal scaling pattern, similar to the case in ldexp. If the
412 // constant's exponent is sufficiently large, the result cannot be subnormal.
413
414 const fltSemantics &Flt = CRHS.getSemantics();
415 unsigned Precision = APFloat::semanticsPrecision(Flt);
416 const int MantissaBits = Precision - 1;
417
418 int MinKnownExponent = ilogb(Arg: CRHS);
419 bool CannotBeSubnormal = (MinKnownExponent >= MantissaBits);
420
421 KnownFPClass Known = KnownFPClass::fmul(KnownLHS, KnownRHS: KnownFPClass(CRHS), Mode);
422 if (CannotBeSubnormal)
423 Known.knownNot(RuleOut: fcSubnormal);
424
425 // Multiply of values <= 1 cannot introduce overflow.
426 if (KnownLHS.isKnownNever(Mask: fcInf)) {
427 if (MinKnownExponent < 0)
428 Known.knownNot(RuleOut: fcInf);
429 else if (MinKnownExponent == 0 && CRHS.compareAbsoluteValue(RHS: APFloat::getOne(
430 Sem: Flt)) == APFloat::cmpEqual)
431 Known.knownNot(RuleOut: fcInf);
432 }
433
434 return Known;
435}
436
437KnownFPClass KnownFPClass::fdiv(const KnownFPClass &KnownLHS,
438 const KnownFPClass &KnownRHS,
439 DenormalMode Mode) {
440 KnownFPClass Known;
441
442 // Only 0/0, Inf/Inf produce NaN.
443 if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() &&
444 (KnownLHS.isKnownNeverInfinity() || KnownRHS.isKnownNeverInfinity()) &&
445 (KnownLHS.isKnownNeverLogicalZero(Mode) ||
446 KnownRHS.isKnownNeverLogicalZero(Mode))) {
447 Known.knownNot(RuleOut: fcNan);
448 }
449
450 // xor sign bit.
451 // X / -0.0 is -Inf (or NaN).
452 // +X / +X is +X
453 if ((KnownLHS.isKnownNever(Mask: fcNegative) &&
454 KnownRHS.isKnownNever(Mask: fcNegative)) ||
455 (KnownLHS.isKnownNever(Mask: fcPositive) && KnownRHS.isKnownNever(Mask: fcPositive)))
456 Known.knownNot(RuleOut: fcNegative);
457
458 if ((KnownLHS.isKnownNever(Mask: fcPositive) &&
459 KnownRHS.isKnownNever(Mask: fcNegative)) ||
460 (KnownLHS.isKnownNever(Mask: fcNegative) && KnownRHS.isKnownNever(Mask: fcPositive)))
461 Known.knownNot(RuleOut: fcPositive);
462
463 // 0 / x => 0 or nan
464 if (KnownLHS.isKnownAlways(Mask: fcZero))
465 Known.knownNot(RuleOut: fcSubnormal | fcNormal | fcInf);
466
467 // x / 0 => nan or inf
468 if (KnownRHS.isKnownAlways(Mask: fcZero))
469 Known.knownNot(RuleOut: fcFinite);
470
471 return Known;
472}
473
474KnownFPClass KnownFPClass::fdiv_self(const KnownFPClass &KnownSrc,
475 DenormalMode Mode) {
476 // X / X is always exactly 1.0 or a NaN.
477 KnownFPClass Known(fcNan | fcPosNormal);
478
479 if (KnownSrc.isKnownNeverInfOrNaN() && KnownSrc.isKnownNeverLogicalZero(Mode))
480 Known.knownNot(RuleOut: fcNan);
481 else if (KnownSrc.isKnownNever(Mask: fcSNan))
482 Known.knownNot(RuleOut: fcSNan);
483
484 return Known;
485}
486KnownFPClass KnownFPClass::frem_self(const KnownFPClass &KnownSrc,
487 DenormalMode Mode) {
488 // X % X is always exactly [+-]0.0 or a NaN.
489 KnownFPClass Known(fcNan | fcZero);
490
491 if (KnownSrc.isKnownNeverInfOrNaN() && KnownSrc.isKnownNeverLogicalZero(Mode))
492 Known.knownNot(RuleOut: fcNan);
493 else if (KnownSrc.isKnownNever(Mask: fcSNan))
494 Known.knownNot(RuleOut: fcSNan);
495
496 return Known;
497}
498
499KnownFPClass KnownFPClass::fma(const KnownFPClass &KnownLHS,
500 const KnownFPClass &KnownRHS,
501 const KnownFPClass &KnownAddend,
502 DenormalMode Mode) {
503 KnownFPClass Mul = fmul(KnownLHS, KnownRHS, Mode);
504
505 // FMA differs from the base fmul + fadd handling only in the treatment of -0
506 // results.
507 //
508 // If the multiply is a -0 due to rounding, the final -0 + 0 will be -0,
509 // unlike for a separate fadd.
510 return fadd_impl(KnownLHS: Mul, KnownRHS: KnownAddend, Mode);
511}
512
513KnownFPClass KnownFPClass::fma_square(const KnownFPClass &KnownSquared,
514 const KnownFPClass &KnownAddend,
515 DenormalMode Mode) {
516 KnownFPClass Squared = square(Src: KnownSquared, Mode);
517 KnownFPClass Known = fadd_impl(KnownLHS: Squared, KnownRHS: KnownAddend, Mode);
518
519 // Since we know the squared input must be positive, the add of opposite sign
520 // infinities nan hazard only applies for negative inf.
521 //
522 // TODO: Alternatively to proving addend is not -inf, we could know Squared is
523 // not pinf. Other than the degenerate always-subnormal input case, we can't
524 // prove that without a known range.
525 if (KnownAddend.isKnownNever(Mask: fcNegInf | fcNan) && Squared.isKnownNever(Mask: fcNan))
526 Known.knownNot(RuleOut: fcNan);
527
528 return Known;
529}
530
531KnownFPClass KnownFPClass::exp(const KnownFPClass &KnownSrc) {
532 KnownFPClass Known;
533 Known.knownNot(RuleOut: fcNegative);
534
535 Known.propagateNaN(Src: KnownSrc);
536
537 if (KnownSrc.cannotBeOrderedLessThanZero()) {
538 // If the source is positive this cannot underflow.
539 Known.knownNot(RuleOut: fcPosZero);
540
541 // Cannot introduce denormal values.
542 Known.knownNot(RuleOut: fcPosSubnormal);
543 }
544
545 // If the source is negative, this cannot overflow to infinity.
546 if (KnownSrc.cannotBeOrderedGreaterThanZero())
547 Known.knownNot(RuleOut: fcPosInf);
548
549 return Known;
550}
551
552void KnownFPClass::propagateCanonicalizingSrc(const KnownFPClass &Src,
553 DenormalMode Mode) {
554 propagateDenormal(Src, Mode);
555 propagateNaN(Src, /*PreserveSign=*/true);
556}
557
558KnownFPClass KnownFPClass::log(const KnownFPClass &KnownSrc,
559 DenormalMode Mode) {
560 KnownFPClass Known;
561 Known.knownNot(RuleOut: fcNegZero | fcSubnormal);
562
563 if (KnownSrc.isKnownNeverPosInfinity())
564 Known.knownNot(RuleOut: fcPosInf);
565
566 if (KnownSrc.isKnownNeverNaN() && KnownSrc.cannotBeOrderedLessThanZero())
567 Known.knownNot(RuleOut: fcNan);
568
569 if (KnownSrc.isKnownNeverLogicalZero(Mode))
570 Known.knownNot(RuleOut: fcNegInf);
571
572 return Known;
573}
574
575KnownFPClass KnownFPClass::sqrt(const KnownFPClass &KnownSrc,
576 DenormalMode Mode) {
577 KnownFPClass Known;
578 Known.knownNot(RuleOut: fcPosSubnormal);
579
580 if (KnownSrc.isKnownNeverPosInfinity())
581 Known.knownNot(RuleOut: fcPosInf);
582 if (KnownSrc.isKnownNever(Mask: fcSNan))
583 Known.knownNot(RuleOut: fcSNan);
584
585 // Any negative value besides -0 returns a nan.
586 if (KnownSrc.isKnownNeverNaN() && KnownSrc.cannotBeOrderedLessThanZero())
587 Known.knownNot(RuleOut: fcNan);
588
589 // The only negative value that can be returned is -0 for -0 inputs.
590 Known.knownNot(RuleOut: fcNegInf | fcNegSubnormal | fcNegNormal);
591
592 // If the input denormal mode could be PreserveSign, a negative
593 // subnormal input could produce a negative zero output.
594 if (KnownSrc.isKnownNeverLogicalNegZero(Mode))
595 Known.knownNot(RuleOut: fcNegZero);
596
597 return Known;
598}
599
600KnownFPClass KnownFPClass::sin(const KnownFPClass &KnownSrc) {
601 KnownFPClass Known;
602
603 // Return NaN on infinite inputs.
604 Known.knownNot(RuleOut: fcInf);
605 if (KnownSrc.isKnownNeverNaN() && KnownSrc.isKnownNeverInfinity())
606 Known.knownNot(RuleOut: fcNan);
607
608 return Known;
609}
610
611KnownFPClass KnownFPClass::cos(const KnownFPClass &KnownSrc) {
612 return sin(KnownSrc);
613}
614
615KnownFPClass KnownFPClass::fpext(const KnownFPClass &KnownSrc,
616 const fltSemantics &DstTy,
617 const fltSemantics &SrcTy) {
618 // Infinity, nan and zero propagate from source.
619 KnownFPClass Known = KnownSrc;
620
621 // All subnormal inputs should be in the normal range in the result type.
622 if (APFloat::isRepresentableAsNormalIn(Src: SrcTy, Dst: DstTy)) {
623 if (Known.KnownFPClasses & fcPosSubnormal)
624 Known.KnownFPClasses |= fcPosNormal;
625 if (Known.KnownFPClasses & fcNegSubnormal)
626 Known.KnownFPClasses |= fcNegNormal;
627 Known.knownNot(RuleOut: fcSubnormal);
628 }
629
630 // Sign bit of a nan isn't guaranteed.
631 if (!Known.isKnownNeverNaN())
632 Known.SignBit = std::nullopt;
633
634 return Known;
635}
636
637KnownFPClass KnownFPClass::fptrunc(const KnownFPClass &KnownSrc) {
638 KnownFPClass Known;
639
640 // Sign should be preserved
641 // TODO: Handle cannot be ordered greater than zero
642 if (KnownSrc.cannotBeOrderedLessThanZero())
643 Known.knownNot(RuleOut: KnownFPClass::OrderedLessThanZeroMask);
644
645 Known.propagateNaN(Src: KnownSrc, PreserveSign: true);
646
647 // Infinity needs a range check.
648 return Known;
649}
650
651KnownFPClass KnownFPClass::roundToIntegral(const KnownFPClass &KnownSrc,
652 bool IsTrunc,
653 bool IsMultiUnitFPType) {
654 KnownFPClass Known;
655
656 // Integer results cannot be subnormal.
657 Known.knownNot(RuleOut: fcSubnormal);
658
659 Known.propagateNaN(Src: KnownSrc, PreserveSign: true);
660
661 // Pass through infinities, except PPC_FP128 is a special case for
662 // intrinsics other than trunc.
663 if (IsTrunc || !IsMultiUnitFPType) {
664 if (KnownSrc.isKnownNeverPosInfinity())
665 Known.knownNot(RuleOut: fcPosInf);
666 if (KnownSrc.isKnownNeverNegInfinity())
667 Known.knownNot(RuleOut: fcNegInf);
668 }
669
670 // Negative round ups to 0 produce -0
671 if (KnownSrc.isKnownNever(Mask: fcPosFinite))
672 Known.knownNot(RuleOut: fcPosFinite);
673 if (KnownSrc.isKnownNever(Mask: fcNegFinite))
674 Known.knownNot(RuleOut: fcNegFinite);
675
676 return Known;
677}
678
679KnownFPClass KnownFPClass::frexp_mant(const KnownFPClass &KnownSrc,
680 DenormalMode Mode) {
681 KnownFPClass Known;
682 Known.knownNot(RuleOut: fcSubnormal);
683
684 if (KnownSrc.isKnownNever(Mask: fcNegative))
685 Known.knownNot(RuleOut: fcNegative);
686 else {
687 if (KnownSrc.isKnownNeverLogicalNegZero(Mode))
688 Known.knownNot(RuleOut: fcNegZero);
689 if (KnownSrc.isKnownNever(Mask: fcNegInf))
690 Known.knownNot(RuleOut: fcNegInf);
691 }
692
693 if (KnownSrc.isKnownNever(Mask: fcPositive))
694 Known.knownNot(RuleOut: fcPositive);
695 else {
696 if (KnownSrc.isKnownNeverLogicalPosZero(Mode))
697 Known.knownNot(RuleOut: fcPosZero);
698 if (KnownSrc.isKnownNever(Mask: fcPosInf))
699 Known.knownNot(RuleOut: fcPosInf);
700 }
701
702 Known.propagateNaN(Src: KnownSrc);
703 return Known;
704}
705
706KnownFPClass KnownFPClass::ldexp(const KnownFPClass &KnownSrc,
707 const KnownBits &ExpBits,
708 const fltSemantics &Flt, DenormalMode Mode) {
709 KnownFPClass Known;
710 Known.propagateNaN(Src: KnownSrc, /*PropagateSign=*/PreserveSign: true);
711
712 // Sign is preserved, but underflows may produce zeroes.
713 if (KnownSrc.isKnownNever(Mask: fcNegative))
714 Known.knownNot(RuleOut: fcNegative);
715 else if (KnownSrc.cannotBeOrderedLessThanZero())
716 Known.knownNot(RuleOut: OrderedLessThanZeroMask);
717
718 if (KnownSrc.isKnownNever(Mask: fcPositive))
719 Known.knownNot(RuleOut: fcPositive);
720 else if (KnownSrc.cannotBeOrderedGreaterThanZero())
721 Known.knownNot(RuleOut: OrderedGreaterThanZeroMask);
722
723 unsigned Precision = APFloat::semanticsPrecision(Flt);
724 const int MantissaBits = Precision - 1;
725
726 if (ExpBits.getSignedMinValue().sge(RHS: static_cast<int64_t>(MantissaBits)))
727 Known.knownNot(RuleOut: fcSubnormal);
728
729 if (ExpBits.isConstant() && ExpBits.getConstant().isZero()) {
730 // ldexp(x, 0) -> x, so propagate everything.
731 Known.propagateCanonicalizingSrc(Src: KnownSrc, Mode);
732 } else if (ExpBits.isNegative()) {
733 // If we know the power is <= 0, can't introduce inf
734 if (KnownSrc.isKnownNeverPosInfinity())
735 Known.knownNot(RuleOut: fcPosInf);
736 if (KnownSrc.isKnownNeverNegInfinity())
737 Known.knownNot(RuleOut: fcNegInf);
738 } else if (ExpBits.isNonNegative()) {
739 // If we know the power is >= 0, can't introduce subnormal or zero
740 if (KnownSrc.isKnownNeverPosSubnormal())
741 Known.knownNot(RuleOut: fcPosSubnormal);
742 if (KnownSrc.isKnownNeverNegSubnormal())
743 Known.knownNot(RuleOut: fcNegSubnormal);
744 if (KnownSrc.isKnownNeverLogicalPosZero(Mode))
745 Known.knownNot(RuleOut: fcPosZero);
746 if (KnownSrc.isKnownNeverLogicalNegZero(Mode))
747 Known.knownNot(RuleOut: fcNegZero);
748 }
749
750 return Known;
751}
752
753// TODO: Detect no-infinity cases
754KnownFPClass KnownFPClass::powi(const KnownFPClass &KnownSrc,
755 const KnownBits &ExponentKnownBits) {
756 KnownFPClass Known;
757 Known.propagateNaN(Src: KnownSrc);
758
759 if (ExponentKnownBits.isZero()) {
760 // powi(QNaN, 0) returns 1.0, and powi(SNaN, 0) may non-deterministically
761 // return 1.0 or a NaN.
762 if (KnownSrc.isKnownNever(Mask: fcSNan)) {
763 Known.knownNot(RuleOut: ~fcPosNormal);
764 return Known;
765 }
766
767 Known.knownNot(RuleOut: ~(fcPosNormal | fcNan));
768 return Known;
769 }
770
771 if (ExponentKnownBits.isEven()) {
772 Known.knownNot(RuleOut: fcNegative);
773 return Known;
774 }
775
776 // Given that exp is an integer, here are the
777 // ways that pow can return a negative value:
778 //
779 // pow(-x, exp) --> negative if exp is odd and x is negative.
780 // pow(-0, exp) --> -inf if exp is negative odd.
781 // pow(-0, exp) --> -0 if exp is positive odd.
782 // pow(-inf, exp) --> -0 if exp is negative odd.
783 // pow(-inf, exp) --> -inf if exp is positive odd.
784 if (KnownSrc.isKnownNever(Mask: fcNegative))
785 Known.knownNot(RuleOut: fcNegative);
786
787 return Known;
788}
789