LLVM 23.0.0git
KnownFPClass.cpp
Go to the documentation of this file.
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
15#include "llvm/ADT/APFloat.h"
17
18using namespace llvm;
19
21 : KnownFPClasses(C.classify()), SignBit(C.isNegative()) {}
22
23/// Return true if it's possible to assume IEEE treatment of input denormals in
24/// \p F for \p Val.
26 return Mode.Input == DenormalMode::IEEE;
27}
28
33
38
43
46 return false;
47
48 // If we know there are no denormals, nothing can be flushed to zero.
50 return true;
51
52 switch (Mode.Input) {
54 return true;
56 // Negative subnormal won't flush to +0
59 default:
60 // Both positive and negative subnormal could flush to +0
61 return false;
62 }
63
64 llvm_unreachable("covered switch over denormal mode");
65}
66
68 DenormalMode Mode) {
69 KnownFPClasses = Src.KnownFPClasses;
70 // If we aren't assuming the source can't be a zero, we don't have to check if
71 // a denormal input could be flushed.
72 if (!Src.isKnownNeverPosZero() && !Src.isKnownNeverNegZero())
73 return;
74
75 // If we know the input can't be a denormal, it can't be flushed to 0.
76 if (Src.isKnownNeverSubnormal())
77 return;
78
79 if (!Src.isKnownNeverPosSubnormal() && Mode != DenormalMode::getIEEE())
81
82 if (!Src.isKnownNeverNegSubnormal() && Mode != DenormalMode::getIEEE()) {
85
86 if (Mode.Input == DenormalMode::PositiveZero ||
87 Mode.Output == DenormalMode::PositiveZero ||
88 Mode.Input == DenormalMode::Dynamic ||
89 Mode.Output == DenormalMode::Dynamic)
91 }
92}
93
95 const KnownFPClass &RHS_, MinMaxKind Kind,
96 DenormalMode Mode) {
97 KnownFPClass KnownLHS = LHS_;
98 KnownFPClass KnownRHS = RHS_;
99
100 bool NeverNaN = KnownLHS.isKnownNeverNaN() || KnownRHS.isKnownNeverNaN();
101 KnownFPClass Known = KnownLHS | KnownRHS;
102
103 // If either operand is not NaN, the result is not NaN.
104 if (NeverNaN &&
105 (Kind == MinMaxKind::minnum || Kind == MinMaxKind::maxnum ||
107 Known.knownNot(fcNan);
108
109 if (Kind == MinMaxKind::maxnum || Kind == MinMaxKind::maximumnum) {
110 // If at least one operand is known to be positive, the result must be
111 // positive.
112 if ((KnownLHS.cannotBeOrderedLessThanZero() &&
113 KnownLHS.isKnownNeverNaN()) ||
114 (KnownRHS.cannotBeOrderedLessThanZero() && KnownRHS.isKnownNeverNaN()))
116 } else if (Kind == MinMaxKind::maximum) {
117 // If at least one operand is known to be positive, the result must be
118 // positive.
119 if (KnownLHS.cannotBeOrderedLessThanZero() ||
122 } else if (Kind == MinMaxKind::minnum || Kind == MinMaxKind::minimumnum) {
123 // If at least one operand is known to be negative, the result must be
124 // negative.
125 if ((KnownLHS.cannotBeOrderedGreaterThanZero() &&
126 KnownLHS.isKnownNeverNaN()) ||
127 (KnownRHS.cannotBeOrderedGreaterThanZero() &&
128 KnownRHS.isKnownNeverNaN()))
130 } else if (Kind == MinMaxKind::minimum) {
131 // If at least one operand is known to be negative, the result must be
132 // negative.
133 if (KnownLHS.cannotBeOrderedGreaterThanZero() ||
136 } else
137 llvm_unreachable("unhandled intrinsic");
138
139 // Fixup zero handling if denormals could be returned as a zero.
140 //
141 // As there's no spec for denormal flushing, be conservative with the
142 // treatment of denormals that could be flushed to zero. For older
143 // subtargets on AMDGPU the min/max instructions would not flush the
144 // output and return the original value.
145 //
146 if ((Known.KnownFPClasses & fcZero) != fcNone &&
147 !Known.isKnownNeverSubnormal()) {
148 if (Mode != DenormalMode::getIEEE())
149 Known.KnownFPClasses |= fcZero;
150 }
151
152 if (Known.isKnownNeverNaN()) {
153 if (KnownLHS.SignBit && KnownRHS.SignBit &&
154 *KnownLHS.SignBit == *KnownRHS.SignBit) {
155 if (*KnownLHS.SignBit)
156 Known.signBitMustBeOne();
157 else
158 Known.signBitMustBeZero();
159 } else if ((Kind == MinMaxKind::maximum || Kind == MinMaxKind::minimum ||
160 Kind == MinMaxKind::maximumnum ||
161 Kind == MinMaxKind::minimumnum) ||
162 // FIXME: Should be using logical zero versions
163 ((KnownLHS.isKnownNeverNegZero() ||
164 KnownRHS.isKnownNeverPosZero()) &&
165 (KnownLHS.isKnownNeverPosZero() ||
166 KnownRHS.isKnownNeverNegZero()))) {
167 // Don't take sign bit from NaN operands.
168 if (!KnownLHS.isKnownNeverNaN())
169 KnownLHS.SignBit = std::nullopt;
170 if (!KnownRHS.isKnownNeverNaN())
171 KnownRHS.SignBit = std::nullopt;
172 if ((Kind == MinMaxKind::maximum || Kind == MinMaxKind::maximumnum ||
173 Kind == MinMaxKind::maxnum) &&
174 (KnownLHS.SignBit == false || KnownRHS.SignBit == false))
175 Known.signBitMustBeZero();
176 else if ((Kind == MinMaxKind::minimum || Kind == MinMaxKind::minimumnum ||
177 Kind == MinMaxKind::minnum) &&
178 (KnownLHS.SignBit == true || KnownRHS.SignBit == true))
179 Known.signBitMustBeOne();
180 }
181 }
182
183 return Known;
184}
185
187 DenormalMode DenormMode) {
188 KnownFPClass Known;
189
190 // This is essentially a stronger form of
191 // propagateCanonicalizingSrc. Other "canonicalizing" operations don't
192 // actually have an IR canonicalization guarantee.
193
194 // Canonicalize may flush denormals to zero, so we have to consider the
195 // denormal mode to preserve known-not-0 knowledge.
196 Known.KnownFPClasses = KnownSrc.KnownFPClasses | fcZero | fcQNan;
197
198 // Stronger version of propagateNaN
199 // Canonicalize is guaranteed to quiet signaling nans.
200 if (KnownSrc.isKnownNeverNaN())
201 Known.knownNot(fcNan);
202 else
203 Known.knownNot(fcSNan);
204
205 // FIXME: Missing check of IEEE like types.
206
207 // If the parent function flushes denormals, the canonical output cannot be a
208 // denormal.
209 if (DenormMode == DenormalMode::getIEEE()) {
210 if (KnownSrc.isKnownNever(fcPosZero))
211 Known.knownNot(fcPosZero);
212 if (KnownSrc.isKnownNever(fcNegZero))
213 Known.knownNot(fcNegZero);
214 return Known;
215 }
216
217 if (DenormMode.inputsAreZero() || DenormMode.outputsAreZero())
218 Known.knownNot(fcSubnormal);
219
220 if (DenormMode == DenormalMode::getPreserveSign()) {
221 if (KnownSrc.isKnownNever(fcPosZero | fcPosSubnormal))
222 Known.knownNot(fcPosZero);
223 if (KnownSrc.isKnownNever(fcNegZero | fcNegSubnormal))
224 Known.knownNot(fcNegZero);
225 return Known;
226 }
227
228 if (DenormMode.Input == DenormalMode::PositiveZero ||
229 (DenormMode.Output == DenormalMode::PositiveZero &&
230 DenormMode.Input == DenormalMode::IEEE))
231 Known.knownNot(fcNegZero);
232
233 return Known;
234}
235
237 const KnownFPClass &KnownRHS,
238 DenormalMode Mode) {
239 KnownFPClass Known;
240
241 // Adding positive and negative infinity produces NaN.
242 // TODO: Check sign of infinities.
243 if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() &&
244 (KnownLHS.isKnownNeverInfinity() || KnownRHS.isKnownNeverInfinity()))
245 Known.knownNot(fcNan);
246
247 if (KnownLHS.cannotBeOrderedLessThanZero() &&
250
251 if (KnownLHS.cannotBeOrderedGreaterThanZero() &&
254
255 // (fadd x, 0.0) is guaranteed to return +0.0, not -0.0.
256 if ((KnownLHS.isKnownNeverLogicalNegZero(Mode) ||
257 KnownRHS.isKnownNeverLogicalNegZero(Mode)) &&
258 // Make sure output negative denormal can't flush to -0
259 (Mode.Output == DenormalMode::IEEE ||
260 Mode.Output == DenormalMode::PositiveZero))
261 Known.knownNot(fcNegZero);
262
263 return Known;
264}
265
267 DenormalMode Mode) {
268 KnownFPClass Known = fadd(KnownSrc, KnownSrc, Mode);
269
270 // Doubling 0 will give the same 0.
271 if (KnownSrc.isKnownNeverLogicalPosZero(Mode) &&
272 (Mode.Output == DenormalMode::IEEE ||
273 (Mode.Output == DenormalMode::PreserveSign &&
274 KnownSrc.isKnownNeverPosSubnormal()) ||
275 (Mode.Output == DenormalMode::PositiveZero &&
276 KnownSrc.isKnownNeverSubnormal())))
277 Known.knownNot(fcPosZero);
278
279 return Known;
280}
281
283 const KnownFPClass &KnownRHS,
284 DenormalMode Mode) {
285 KnownFPClass Known;
286
287 // xor sign bit.
288 if ((KnownLHS.isKnownNever(fcNegative) &&
289 KnownRHS.isKnownNever(fcNegative)) ||
290 (KnownLHS.isKnownNever(fcPositive) && KnownRHS.isKnownNever(fcPositive)))
291 Known.knownNot(fcNegative);
292
293 if ((KnownLHS.isKnownNever(fcPositive) &&
294 KnownRHS.isKnownNever(fcNegative)) ||
295 (KnownLHS.isKnownNever(fcNegative) && KnownRHS.isKnownNever(fcPositive)))
296 Known.knownNot(fcPositive);
297
298 // inf * anything => inf or nan
299 if (KnownLHS.isKnownAlways(fcInf | fcNan) ||
300 KnownRHS.isKnownAlways(fcInf | fcNan))
302
303 // 0 * anything => 0 or nan
304 if (KnownRHS.isKnownAlways(fcZero | fcNan) ||
305 KnownLHS.isKnownAlways(fcZero | fcNan))
307
308 // +/-0 * +/-inf = nan
309 if ((KnownLHS.isKnownAlways(fcZero | fcNan) &&
310 KnownRHS.isKnownAlways(fcInf | fcNan)) ||
311 (KnownLHS.isKnownAlways(fcInf | fcNan) &&
312 KnownRHS.isKnownAlways(fcZero | fcNan)))
313 Known.knownNot(~fcNan);
314
315 if (!KnownLHS.isKnownNeverNaN() || !KnownRHS.isKnownNeverNaN())
316 return Known;
317
318 if (KnownLHS.SignBit && KnownRHS.SignBit) {
319 if (*KnownLHS.SignBit == *KnownRHS.SignBit)
320 Known.signBitMustBeZero();
321 else
322 Known.signBitMustBeOne();
323 }
324
325 // If 0 * +/-inf produces NaN.
326 if ((KnownRHS.isKnownNeverInfinity() ||
327 KnownLHS.isKnownNeverLogicalZero(Mode)) &&
328 (KnownLHS.isKnownNeverInfinity() ||
329 KnownRHS.isKnownNeverLogicalZero(Mode)))
330 Known.knownNot(fcNan);
331
332 return Known;
333}
334
336 KnownFPClass Known;
337 Known.knownNot(fcNegative);
338
339 Known.propagateNaN(KnownSrc);
340
341 if (KnownSrc.cannotBeOrderedLessThanZero()) {
342 // If the source is positive this cannot underflow.
343 Known.knownNot(fcPosZero);
344
345 // Cannot introduce denormal values.
347 }
348
349 // If the source is negative, this cannot overflow to infinity.
350 if (KnownSrc.cannotBeOrderedGreaterThanZero())
351 Known.knownNot(fcPosInf);
352
353 return Known;
354}
355
357 DenormalMode Mode) {
358 propagateDenormal(Src, Mode);
359 propagateNaN(Src, /*PreserveSign=*/true);
360}
361
363 DenormalMode Mode) {
364 KnownFPClass Known;
365 Known.knownNot(fcNegZero);
366
367 if (KnownSrc.isKnownNeverPosInfinity())
368 Known.knownNot(fcPosInf);
369
370 if (KnownSrc.isKnownNeverNaN() && KnownSrc.cannotBeOrderedLessThanZero())
371 Known.knownNot(fcNan);
372
373 if (KnownSrc.isKnownNeverLogicalZero(Mode))
374 Known.knownNot(fcNegInf);
375
376 return Known;
377}
378
380 DenormalMode Mode) {
381 KnownFPClass Known;
383
384 if (KnownSrc.isKnownNeverPosInfinity())
385 Known.knownNot(fcPosInf);
386 if (KnownSrc.isKnownNever(fcSNan))
387 Known.knownNot(fcSNan);
388
389 // Any negative value besides -0 returns a nan.
390 if (KnownSrc.isKnownNeverNaN() && KnownSrc.cannotBeOrderedLessThanZero())
391 Known.knownNot(fcNan);
392
393 // The only negative value that can be returned is -0 for -0 inputs.
395
396 // If the input denormal mode could be PreserveSign, a negative
397 // subnormal input could produce a negative zero output.
398 if (KnownSrc.isKnownNeverLogicalNegZero(Mode))
399 Known.knownNot(fcNegZero);
400
401 return Known;
402}
403
405 const fltSemantics &DstTy,
406 const fltSemantics &SrcTy) {
407 // Infinity, nan and zero propagate from source.
408 KnownFPClass Known = KnownSrc;
409
410 // All subnormal inputs should be in the normal range in the result type.
411 if (APFloat::isRepresentableAsNormalIn(SrcTy, DstTy)) {
412 if (Known.KnownFPClasses & fcPosSubnormal)
414 if (Known.KnownFPClasses & fcNegSubnormal)
416 Known.knownNot(fcSubnormal);
417 }
418
419 // Sign bit of a nan isn't guaranteed.
420 if (!Known.isKnownNeverNaN())
421 Known.SignBit = std::nullopt;
422
423 return Known;
424}
425
427 bool IsTrunc,
428 bool IsMultiUnitFPType) {
429 KnownFPClass Known;
430
431 // Integer results cannot be subnormal.
432 Known.knownNot(fcSubnormal);
433
434 Known.propagateNaN(KnownSrc, true);
435
436 // Pass through infinities, except PPC_FP128 is a special case for
437 // intrinsics other than trunc.
438 if (IsTrunc || !IsMultiUnitFPType) {
439 if (KnownSrc.isKnownNeverPosInfinity())
440 Known.knownNot(fcPosInf);
441 if (KnownSrc.isKnownNeverNegInfinity())
442 Known.knownNot(fcNegInf);
443 }
444
445 // Negative round ups to 0 produce -0
446 if (KnownSrc.isKnownNever(fcPosFinite))
447 Known.knownNot(fcPosFinite);
448 if (KnownSrc.isKnownNever(fcNegFinite))
449 Known.knownNot(fcNegFinite);
450
451 return Known;
452}
This file declares a class to represent arbitrary precision floating point values and provide a varie...
static bool inputDenormalIsIEEE(DenormalMode Mode)
Return true if it's possible to assume IEEE treatment of input denormals in F for Val.
static bool inputDenormalIsIEEEOrPosZero(DenormalMode Mode)
static cl::opt< RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode > Mode("regalloc-enable-advisor", cl::Hidden, cl::init(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default), cl::desc("Enable regalloc advisor mode"), cl::values(clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default, "default", "Default"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Release, "release", "precompiled"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Development, "development", "for training")))
static LLVM_ABI bool isRepresentableAsNormalIn(const fltSemantics &Src, const fltSemantics &Dst)
Definition APFloat.cpp:263
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
Represent subnormal handling kind for floating point instruction inputs and outputs.
DenormalModeKind Input
Denormal treatment kind for floating point instruction inputs in the default floating-point environme...
constexpr bool outputsAreZero() const
Return true if output denormals should be flushed to 0.
@ PreserveSign
The sign of a flushed-to-zero number is preserved in the sign of 0.
@ PositiveZero
Denormals are flushed to positive zero.
@ Dynamic
Denormals have unknown treatment.
@ IEEE
IEEE-754 denormal numbers preserved.
static constexpr DenormalMode getPositiveZero()
constexpr bool inputsAreZero() const
Return true if input denormals must be implicitly treated as 0.
static constexpr DenormalMode getPreserveSign()
DenormalModeKind Output
Denormal flushing mode for floating point instruction results in the default floating point environme...
static constexpr DenormalMode getIEEE()
FPClassTest KnownFPClasses
Floating-point classes the value could be one of.
bool isKnownNeverInfinity() const
Return true if it's known this can never be an infinity.
KnownFPClass(FPClassTest Known=fcAllFlags, std::optional< bool > Sign={})
bool cannotBeOrderedGreaterThanZero() const
Return true if we can prove that the analyzed floating-point value is either NaN or never greater tha...
static constexpr FPClassTest OrderedGreaterThanZeroMask
static constexpr FPClassTest OrderedLessThanZeroMask
void knownNot(FPClassTest RuleOut)
static LLVM_ABI KnownFPClass fmul(const KnownFPClass &LHS, const KnownFPClass &RHS, DenormalMode Mode=DenormalMode::getDynamic())
Report known values for fmul.
static LLVM_ABI KnownFPClass fadd_self(const KnownFPClass &Src, DenormalMode Mode=DenormalMode::getDynamic())
Report known values for fadd x, x.
bool isKnownNeverZero() const
Return true if it's known this can never be a zero.
bool isKnownNeverSubnormal() const
Return true if it's known this can never be a subnormal.
bool isKnownAlways(FPClassTest Mask) const
static LLVM_ABI KnownFPClass canonicalize(const KnownFPClass &Src, DenormalMode DenormMode=DenormalMode::getDynamic())
Apply the canonicalize intrinsic to this value.
LLVM_ABI bool isKnownNeverLogicalZero(DenormalMode Mode) const
Return true if it's known this can never be interpreted as a zero.
static LLVM_ABI KnownFPClass log(const KnownFPClass &Src, DenormalMode Mode=DenormalMode::getDynamic())
Propagate known class for log/log2/log10.
LLVM_ABI void propagateDenormal(const KnownFPClass &Src, DenormalMode Mode)
Propagate knowledge from a source value that could be a denormal or zero.
static LLVM_ABI KnownFPClass roundToIntegral(const KnownFPClass &Src, bool IsTrunc, bool IsMultiUnitFPType)
Propagate known class for rounding intrinsics (trunc, floor, ceil, rint, nearbyint,...
static LLVM_ABI KnownFPClass minMaxLike(const KnownFPClass &LHS, const KnownFPClass &RHS, MinMaxKind Kind, DenormalMode DenormMode=DenormalMode::getDynamic())
bool isKnownNeverNegInfinity() const
Return true if it's known this can never be -infinity.
bool isKnownNeverNegSubnormal() const
Return true if it's known this can never be a negative subnormal.
bool isKnownNeverPosZero() const
Return true if it's known this can never be a literal positive zero.
static LLVM_ABI KnownFPClass exp(const KnownFPClass &Src)
Report known values for exp, exp2 and exp10.
std::optional< bool > SignBit
std::nullopt if the sign bit is unknown, true if the sign bit is definitely set or false if the sign ...
bool isKnownNeverNaN() const
Return true if it's known this can never be a nan.
bool isKnownNever(FPClassTest Mask) const
Return true if it's known this can never be one of the mask entries.
static LLVM_ABI KnownFPClass fpext(const KnownFPClass &KnownSrc, const fltSemantics &DstTy, const fltSemantics &SrcTy)
Propagate known class for fpext.
bool isKnownNeverNegZero() const
Return true if it's known this can never be a negative zero.
void propagateNaN(const KnownFPClass &Src, bool PreserveSign=false)
bool cannotBeOrderedLessThanZero() const
Return true if we can prove that the analyzed floating-point value is either NaN or never less than -...
void signBitMustBeOne()
Assume the sign bit is one.
LLVM_ABI void propagateCanonicalizingSrc(const KnownFPClass &Src, DenormalMode Mode)
Report known classes if Src is evaluated through a potentially canonicalizing operation.
void signBitMustBeZero()
Assume the sign bit is zero.
static LLVM_ABI KnownFPClass sqrt(const KnownFPClass &Src, DenormalMode Mode=DenormalMode::getDynamic())
Propagate known class for sqrt.
LLVM_ABI bool isKnownNeverLogicalPosZero(DenormalMode Mode) const
Return true if it's known this can never be interpreted as a positive zero.
bool isKnownNeverPosInfinity() const
Return true if it's known this can never be +infinity.
static LLVM_ABI KnownFPClass fadd(const KnownFPClass &LHS, const KnownFPClass &RHS, DenormalMode Mode=DenormalMode::getDynamic())
Report known values for fadd.
LLVM_ABI bool isKnownNeverLogicalNegZero(DenormalMode Mode) const
Return true if it's known this can never be interpreted as a negative zero.
bool isKnownNeverPosSubnormal() const
Return true if it's known this can never be a positive subnormal.