LLVM 22.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 // xor sign bit.
242 if ((KnownLHS.isKnownNever(fcNegative) &&
243 KnownRHS.isKnownNever(fcNegative)) ||
244 (KnownLHS.isKnownNever(fcPositive) && KnownRHS.isKnownNever(fcPositive)))
245 Known.knownNot(fcNegative);
246
247 if ((KnownLHS.isKnownNever(fcPositive) &&
248 KnownRHS.isKnownNever(fcNegative)) ||
249 (KnownLHS.isKnownNever(fcNegative) && KnownRHS.isKnownNever(fcPositive)))
250 Known.knownNot(fcPositive);
251
252 // inf * anything => inf or nan
253 if (KnownLHS.isKnownAlways(fcInf | fcNan) ||
254 KnownRHS.isKnownAlways(fcInf | fcNan))
256
257 // 0 * anything => 0 or nan
258 if (KnownRHS.isKnownAlways(fcZero | fcNan) ||
259 KnownLHS.isKnownAlways(fcZero | fcNan))
261
262 // +/-0 * +/-inf = nan
263 if ((KnownLHS.isKnownAlways(fcZero | fcNan) &&
264 KnownRHS.isKnownAlways(fcInf | fcNan)) ||
265 (KnownLHS.isKnownAlways(fcInf | fcNan) &&
266 KnownRHS.isKnownAlways(fcZero | fcNan)))
267 Known.knownNot(~fcNan);
268
269 if (!KnownLHS.isKnownNeverNaN() || !KnownRHS.isKnownNeverNaN())
270 return Known;
271
272 if (KnownLHS.SignBit && KnownRHS.SignBit) {
273 if (*KnownLHS.SignBit == *KnownRHS.SignBit)
274 Known.signBitMustBeZero();
275 else
276 Known.signBitMustBeOne();
277 }
278
279 // If 0 * +/-inf produces NaN.
280 if ((KnownRHS.isKnownNeverInfinity() ||
281 KnownLHS.isKnownNeverLogicalZero(Mode)) &&
282 (KnownLHS.isKnownNeverInfinity() ||
283 KnownRHS.isKnownNeverLogicalZero(Mode)))
284 Known.knownNot(fcNan);
285
286 return Known;
287}
288
290 KnownFPClass Known;
291 Known.knownNot(fcNegative);
292
293 Known.propagateNaN(KnownSrc);
294
295 if (KnownSrc.cannotBeOrderedLessThanZero()) {
296 // If the source is positive this cannot underflow.
297 Known.knownNot(fcPosZero);
298
299 // Cannot introduce denormal values.
301 }
302
303 // If the source is negative, this cannot overflow to infinity.
304 if (KnownSrc.cannotBeOrderedGreaterThanZero())
305 Known.knownNot(fcPosInf);
306
307 return Known;
308}
309
311 DenormalMode Mode) {
312 propagateDenormal(Src, Mode);
313 propagateNaN(Src, /*PreserveSign=*/true);
314}
315
317 DenormalMode Mode) {
318 KnownFPClass Known;
319 Known.knownNot(fcNegZero);
320
321 if (KnownSrc.isKnownNeverPosInfinity())
322 Known.knownNot(fcPosInf);
323
324 if (KnownSrc.isKnownNeverNaN() && KnownSrc.cannotBeOrderedLessThanZero())
325 Known.knownNot(fcNan);
326
327 if (KnownSrc.isKnownNeverLogicalZero(Mode))
328 Known.knownNot(fcNegInf);
329
330 return Known;
331}
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")))
#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.
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 minMaxLike(const KnownFPClass &LHS, const KnownFPClass &RHS, MinMaxKind Kind, DenormalMode DenormMode=DenormalMode::getDynamic())
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.
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.
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.
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.