[clang] Add test for CWG190 "Layout-compatible POD-struct types" (#121668)
[llvm-project.git] / llvm / lib / IR / ConstantFPRange.cpp
blob750918812852486225a2b75ddf17d3a77fd911da
1 //===- ConstantFPRange.cpp - ConstantFPRange implementation ---------------===//
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 //===----------------------------------------------------------------------===//
9 #include "llvm/IR/ConstantFPRange.h"
10 #include "llvm/ADT/APFloat.h"
11 #include "llvm/Support/Debug.h"
12 #include "llvm/Support/raw_ostream.h"
13 #include <cassert>
15 using namespace llvm;
17 void ConstantFPRange::makeEmpty() {
18 auto &Sem = Lower.getSemantics();
19 Lower = APFloat::getInf(Sem, /*Negative=*/false);
20 Upper = APFloat::getInf(Sem, /*Negative=*/true);
21 MayBeQNaN = false;
22 MayBeSNaN = false;
25 void ConstantFPRange::makeFull() {
26 auto &Sem = Lower.getSemantics();
27 Lower = APFloat::getInf(Sem, /*Negative=*/true);
28 Upper = APFloat::getInf(Sem, /*Negative=*/false);
29 MayBeQNaN = true;
30 MayBeSNaN = true;
33 bool ConstantFPRange::isNaNOnly() const {
34 return Lower.isPosInfinity() && Upper.isNegInfinity();
37 ConstantFPRange::ConstantFPRange(const fltSemantics &Sem, bool IsFullSet)
38 : Lower(Sem, APFloat::uninitialized), Upper(Sem, APFloat::uninitialized) {
39 Lower = APFloat::getInf(Sem, /*Negative=*/IsFullSet);
40 Upper = APFloat::getInf(Sem, /*Negative=*/!IsFullSet);
41 MayBeQNaN = IsFullSet;
42 MayBeSNaN = IsFullSet;
45 ConstantFPRange::ConstantFPRange(const APFloat &Value)
46 : Lower(Value.getSemantics(), APFloat::uninitialized),
47 Upper(Value.getSemantics(), APFloat::uninitialized) {
48 if (Value.isNaN()) {
49 makeEmpty();
50 bool IsSNaN = Value.isSignaling();
51 MayBeQNaN = !IsSNaN;
52 MayBeSNaN = IsSNaN;
53 } else {
54 Lower = Upper = Value;
55 MayBeQNaN = MayBeSNaN = false;
59 // We treat that -0 is less than 0 here.
60 static APFloat::cmpResult strictCompare(const APFloat &LHS,
61 const APFloat &RHS) {
62 assert(!LHS.isNaN() && !RHS.isNaN() && "Unordered compare");
63 if (LHS.isZero() && RHS.isZero()) {
64 if (LHS.isNegative() == RHS.isNegative())
65 return APFloat::cmpEqual;
66 return LHS.isNegative() ? APFloat::cmpLessThan : APFloat::cmpGreaterThan;
68 return LHS.compare(RHS);
71 static bool isNonCanonicalEmptySet(const APFloat &Lower, const APFloat &Upper) {
72 return strictCompare(Lower, Upper) == APFloat::cmpGreaterThan &&
73 !(Lower.isInfinity() && Upper.isInfinity());
76 static void canonicalizeRange(APFloat &Lower, APFloat &Upper) {
77 if (isNonCanonicalEmptySet(Lower, Upper)) {
78 Lower = APFloat::getInf(Lower.getSemantics(), /*Negative=*/false);
79 Upper = APFloat::getInf(Upper.getSemantics(), /*Negative=*/true);
83 ConstantFPRange::ConstantFPRange(APFloat LowerVal, APFloat UpperVal,
84 bool MayBeQNaNVal, bool MayBeSNaNVal)
85 : Lower(std::move(LowerVal)), Upper(std::move(UpperVal)),
86 MayBeQNaN(MayBeQNaNVal), MayBeSNaN(MayBeSNaNVal) {
87 assert(&Lower.getSemantics() == &Upper.getSemantics() &&
88 "Should only use the same semantics");
89 assert(!isNonCanonicalEmptySet(Lower, Upper) && "Non-canonical form");
92 ConstantFPRange ConstantFPRange::getFinite(const fltSemantics &Sem) {
93 return ConstantFPRange(APFloat::getLargest(Sem, /*Negative=*/true),
94 APFloat::getLargest(Sem, /*Negative=*/false),
95 /*MayBeQNaN=*/false, /*MayBeSNaN=*/false);
98 ConstantFPRange ConstantFPRange::getNaNOnly(const fltSemantics &Sem,
99 bool MayBeQNaN, bool MayBeSNaN) {
100 return ConstantFPRange(APFloat::getInf(Sem, /*Negative=*/false),
101 APFloat::getInf(Sem, /*Negative=*/true), MayBeQNaN,
102 MayBeSNaN);
105 ConstantFPRange ConstantFPRange::getNonNaN(const fltSemantics &Sem) {
106 return ConstantFPRange(APFloat::getInf(Sem, /*Negative=*/true),
107 APFloat::getInf(Sem, /*Negative=*/false),
108 /*MayBeQNaN=*/false, /*MayBeSNaN=*/false);
111 /// Return true for ULT/UGT/OLT/OGT
112 static bool fcmpPredExcludesEqual(FCmpInst::Predicate Pred) {
113 return !(Pred & FCmpInst::FCMP_OEQ);
116 /// Return [-inf, V) or [-inf, V]
117 static ConstantFPRange makeLessThan(APFloat V, FCmpInst::Predicate Pred) {
118 const fltSemantics &Sem = V.getSemantics();
119 if (fcmpPredExcludesEqual(Pred)) {
120 if (V.isNegInfinity())
121 return ConstantFPRange::getEmpty(Sem);
122 V.next(/*nextDown=*/true);
124 return ConstantFPRange::getNonNaN(APFloat::getInf(Sem, /*Negative=*/true),
125 std::move(V));
128 /// Return (V, +inf] or [V, +inf]
129 static ConstantFPRange makeGreaterThan(APFloat V, FCmpInst::Predicate Pred) {
130 const fltSemantics &Sem = V.getSemantics();
131 if (fcmpPredExcludesEqual(Pred)) {
132 if (V.isPosInfinity())
133 return ConstantFPRange::getEmpty(Sem);
134 V.next(/*nextDown=*/false);
136 return ConstantFPRange::getNonNaN(std::move(V),
137 APFloat::getInf(Sem, /*Negative=*/false));
140 /// Make sure that +0/-0 are both included in the range.
141 static ConstantFPRange extendZeroIfEqual(const ConstantFPRange &CR,
142 FCmpInst::Predicate Pred) {
143 if (fcmpPredExcludesEqual(Pred))
144 return CR;
146 APFloat Lower = CR.getLower();
147 APFloat Upper = CR.getUpper();
148 if (Lower.isPosZero())
149 Lower = APFloat::getZero(Lower.getSemantics(), /*Negative=*/true);
150 if (Upper.isNegZero())
151 Upper = APFloat::getZero(Upper.getSemantics(), /*Negative=*/false);
152 return ConstantFPRange(std::move(Lower), std::move(Upper), CR.containsQNaN(),
153 CR.containsSNaN());
156 static ConstantFPRange setNaNField(const ConstantFPRange &CR,
157 FCmpInst::Predicate Pred) {
158 bool ContainsNaN = FCmpInst::isUnordered(Pred);
159 return ConstantFPRange(CR.getLower(), CR.getUpper(),
160 /*MayBeQNaN=*/ContainsNaN, /*MayBeSNaN=*/ContainsNaN);
163 ConstantFPRange
164 ConstantFPRange::makeAllowedFCmpRegion(FCmpInst::Predicate Pred,
165 const ConstantFPRange &Other) {
166 if (Other.isEmptySet())
167 return Other;
168 if (Other.containsNaN() && FCmpInst::isUnordered(Pred))
169 return getFull(Other.getSemantics());
170 if (Other.isNaNOnly() && FCmpInst::isOrdered(Pred))
171 return getEmpty(Other.getSemantics());
173 switch (Pred) {
174 case FCmpInst::FCMP_TRUE:
175 return getFull(Other.getSemantics());
176 case FCmpInst::FCMP_FALSE:
177 return getEmpty(Other.getSemantics());
178 case FCmpInst::FCMP_ORD:
179 return getNonNaN(Other.getSemantics());
180 case FCmpInst::FCMP_UNO:
181 return getNaNOnly(Other.getSemantics(), /*MayBeQNaN=*/true,
182 /*MayBeSNaN=*/true);
183 case FCmpInst::FCMP_OEQ:
184 case FCmpInst::FCMP_UEQ:
185 return setNaNField(extendZeroIfEqual(Other, Pred), Pred);
186 case FCmpInst::FCMP_ONE:
187 case FCmpInst::FCMP_UNE:
188 if (const APFloat *SingleElement =
189 Other.getSingleElement(/*ExcludesNaN=*/true)) {
190 const fltSemantics &Sem = SingleElement->getSemantics();
191 if (SingleElement->isPosInfinity())
192 return setNaNField(
193 getNonNaN(APFloat::getInf(Sem, /*Negative=*/true),
194 APFloat::getLargest(Sem, /*Negative=*/false)),
195 Pred);
196 if (SingleElement->isNegInfinity())
197 return setNaNField(
198 getNonNaN(APFloat::getLargest(Sem, /*Negative=*/true),
199 APFloat::getInf(Sem, /*Negative=*/false)),
200 Pred);
202 return Pred == FCmpInst::FCMP_ONE ? getNonNaN(Other.getSemantics())
203 : getFull(Other.getSemantics());
204 case FCmpInst::FCMP_OLT:
205 case FCmpInst::FCMP_OLE:
206 case FCmpInst::FCMP_ULT:
207 case FCmpInst::FCMP_ULE:
208 return setNaNField(
209 extendZeroIfEqual(makeLessThan(Other.getUpper(), Pred), Pred), Pred);
210 case FCmpInst::FCMP_OGT:
211 case FCmpInst::FCMP_OGE:
212 case FCmpInst::FCMP_UGT:
213 case FCmpInst::FCMP_UGE:
214 return setNaNField(
215 extendZeroIfEqual(makeGreaterThan(Other.getLower(), Pred), Pred), Pred);
216 default:
217 llvm_unreachable("Unexpected predicate");
221 ConstantFPRange
222 ConstantFPRange::makeSatisfyingFCmpRegion(FCmpInst::Predicate Pred,
223 const ConstantFPRange &Other) {
224 if (Other.isEmptySet())
225 return getFull(Other.getSemantics());
226 if (Other.containsNaN() && FCmpInst::isOrdered(Pred))
227 return getEmpty(Other.getSemantics());
228 if (Other.isNaNOnly() && FCmpInst::isUnordered(Pred))
229 return getFull(Other.getSemantics());
231 switch (Pred) {
232 case FCmpInst::FCMP_TRUE:
233 return getFull(Other.getSemantics());
234 case FCmpInst::FCMP_FALSE:
235 return getEmpty(Other.getSemantics());
236 case FCmpInst::FCMP_ORD:
237 return getNonNaN(Other.getSemantics());
238 case FCmpInst::FCMP_UNO:
239 return getNaNOnly(Other.getSemantics(), /*MayBeQNaN=*/true,
240 /*MayBeSNaN=*/true);
241 case FCmpInst::FCMP_OEQ:
242 case FCmpInst::FCMP_UEQ:
243 return setNaNField(Other.isSingleElement(/*ExcludesNaN=*/true) ||
244 ((Other.classify() & ~fcNan) == fcZero)
245 ? extendZeroIfEqual(Other, Pred)
246 : getEmpty(Other.getSemantics()),
247 Pred);
248 case FCmpInst::FCMP_ONE:
249 case FCmpInst::FCMP_UNE:
250 return getEmpty(Other.getSemantics());
251 case FCmpInst::FCMP_OLT:
252 case FCmpInst::FCMP_OLE:
253 case FCmpInst::FCMP_ULT:
254 case FCmpInst::FCMP_ULE:
255 return setNaNField(
256 extendZeroIfEqual(makeLessThan(Other.getLower(), Pred), Pred), Pred);
257 case FCmpInst::FCMP_OGT:
258 case FCmpInst::FCMP_OGE:
259 case FCmpInst::FCMP_UGT:
260 case FCmpInst::FCMP_UGE:
261 return setNaNField(
262 extendZeroIfEqual(makeGreaterThan(Other.getUpper(), Pred), Pred), Pred);
263 default:
264 llvm_unreachable("Unexpected predicate");
268 std::optional<ConstantFPRange>
269 ConstantFPRange::makeExactFCmpRegion(FCmpInst::Predicate Pred,
270 const APFloat &Other) {
271 if ((Pred == FCmpInst::FCMP_UNE || Pred == FCmpInst::FCMP_ONE) &&
272 !Other.isNaN())
273 return std::nullopt;
274 return makeSatisfyingFCmpRegion(Pred, ConstantFPRange(Other));
277 bool ConstantFPRange::fcmp(FCmpInst::Predicate Pred,
278 const ConstantFPRange &Other) const {
279 return makeSatisfyingFCmpRegion(Pred, Other).contains(*this);
282 bool ConstantFPRange::isFullSet() const {
283 return Lower.isNegInfinity() && Upper.isPosInfinity() && MayBeQNaN &&
284 MayBeSNaN;
287 bool ConstantFPRange::isEmptySet() const {
288 return Lower.isPosInfinity() && Upper.isNegInfinity() && !MayBeQNaN &&
289 !MayBeSNaN;
292 bool ConstantFPRange::contains(const APFloat &Val) const {
293 assert(&getSemantics() == &Val.getSemantics() &&
294 "Should only use the same semantics");
296 if (Val.isNaN())
297 return Val.isSignaling() ? MayBeSNaN : MayBeQNaN;
298 return strictCompare(Lower, Val) != APFloat::cmpGreaterThan &&
299 strictCompare(Val, Upper) != APFloat::cmpGreaterThan;
302 bool ConstantFPRange::contains(const ConstantFPRange &CR) const {
303 assert(&getSemantics() == &CR.getSemantics() &&
304 "Should only use the same semantics");
306 if (CR.MayBeQNaN && !MayBeQNaN)
307 return false;
309 if (CR.MayBeSNaN && !MayBeSNaN)
310 return false;
312 return strictCompare(Lower, CR.Lower) != APFloat::cmpGreaterThan &&
313 strictCompare(CR.Upper, Upper) != APFloat::cmpGreaterThan;
316 const APFloat *ConstantFPRange::getSingleElement(bool ExcludesNaN) const {
317 if (!ExcludesNaN && (MayBeSNaN || MayBeQNaN))
318 return nullptr;
319 return Lower.bitwiseIsEqual(Upper) ? &Lower : nullptr;
322 std::optional<bool> ConstantFPRange::getSignBit() const {
323 if (!MayBeSNaN && !MayBeQNaN && Lower.isNegative() == Upper.isNegative())
324 return Lower.isNegative();
325 return std::nullopt;
328 bool ConstantFPRange::operator==(const ConstantFPRange &CR) const {
329 if (MayBeSNaN != CR.MayBeSNaN || MayBeQNaN != CR.MayBeQNaN)
330 return false;
331 return Lower.bitwiseIsEqual(CR.Lower) && Upper.bitwiseIsEqual(CR.Upper);
334 FPClassTest ConstantFPRange::classify() const {
335 uint32_t Mask = fcNone;
336 if (MayBeSNaN)
337 Mask |= fcSNan;
338 if (MayBeQNaN)
339 Mask |= fcQNan;
340 if (!isNaNOnly()) {
341 FPClassTest LowerMask = Lower.classify();
342 FPClassTest UpperMask = Upper.classify();
343 assert(LowerMask <= UpperMask && "Range is nan-only.");
344 // Set all bits from log2(LowerMask) to log2(UpperMask).
345 Mask |= (UpperMask << 1) - LowerMask;
347 return static_cast<FPClassTest>(Mask);
350 void ConstantFPRange::print(raw_ostream &OS) const {
351 if (isFullSet())
352 OS << "full-set";
353 else if (isEmptySet())
354 OS << "empty-set";
355 else {
356 bool NaNOnly = isNaNOnly();
357 if (!NaNOnly)
358 OS << '[' << Lower << ", " << Upper << ']';
360 if (MayBeSNaN || MayBeQNaN) {
361 if (!NaNOnly)
362 OS << " with ";
363 if (MayBeSNaN && MayBeQNaN)
364 OS << "NaN";
365 else if (MayBeSNaN)
366 OS << "SNaN";
367 else if (MayBeQNaN)
368 OS << "QNaN";
373 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
374 LLVM_DUMP_METHOD void ConstantFPRange::dump() const { print(dbgs()); }
375 #endif
377 ConstantFPRange
378 ConstantFPRange::intersectWith(const ConstantFPRange &CR) const {
379 assert(&getSemantics() == &CR.getSemantics() &&
380 "Should only use the same semantics");
381 APFloat NewLower = maxnum(Lower, CR.Lower);
382 APFloat NewUpper = minnum(Upper, CR.Upper);
383 canonicalizeRange(NewLower, NewUpper);
384 return ConstantFPRange(std::move(NewLower), std::move(NewUpper),
385 MayBeQNaN & CR.MayBeQNaN, MayBeSNaN & CR.MayBeSNaN);
388 ConstantFPRange ConstantFPRange::unionWith(const ConstantFPRange &CR) const {
389 assert(&getSemantics() == &CR.getSemantics() &&
390 "Should only use the same semantics");
391 return ConstantFPRange(minnum(Lower, CR.Lower), maxnum(Upper, CR.Upper),
392 MayBeQNaN | CR.MayBeQNaN, MayBeSNaN | CR.MayBeSNaN);