Skip to content

Commit fa824dc

Browse files
authored
[LLVM][IR] Add constant range support for floating-point types (#86483)
This patch adds basic constant range support for floating-point types to enable range-based optimizations.
1 parent 915fe84 commit fa824dc

File tree

7 files changed

+898
-2
lines changed

7 files changed

+898
-2
lines changed

llvm/include/llvm/ADT/APFloat.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1534,6 +1534,11 @@ inline APFloat maximumnum(const APFloat &A, const APFloat &B) {
15341534
return A < B ? B : A;
15351535
}
15361536

1537+
inline raw_ostream &operator<<(raw_ostream &OS, const APFloat &V) {
1538+
V.print(OS);
1539+
return OS;
1540+
}
1541+
15371542
// We want the following functions to be available in the header for inlining.
15381543
// We cannot define them inline in the class definition of `DoubleAPFloat`
15391544
// because doing so would instantiate `std::unique_ptr<APFloat[]>` before
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
//===- ConstantFPRange.h - Represent a range for floating-point -*- 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+
// Represent a range of possible values that may occur when the program is run
10+
// for a floating-point value. This keeps track of a lower and upper bound for
11+
// the constant.
12+
//
13+
// Range = [Lower, Upper] U (MayBeQNaN ? QNaN : {}) U (MayBeSNaN ? SNaN : {})
14+
// Specifically, [inf, -inf] represents an empty set.
15+
// Note:
16+
// 1. Bounds are inclusive.
17+
// 2. -0 is considered to be less than 0. That is, range [0, 0] doesn't contain
18+
// -0.
19+
// 3. Currently wrapping ranges are not supported.
20+
//
21+
//===----------------------------------------------------------------------===//
22+
23+
#ifndef LLVM_IR_CONSTANTFPRANGE_H
24+
#define LLVM_IR_CONSTANTFPRANGE_H
25+
26+
#include "llvm/ADT/APFloat.h"
27+
#include "llvm/IR/Instructions.h"
28+
#include <optional>
29+
30+
namespace llvm {
31+
32+
class raw_ostream;
33+
struct KnownFPClass;
34+
35+
/// This class represents a range of floating-point values.
36+
class [[nodiscard]] ConstantFPRange {
37+
APFloat Lower, Upper;
38+
bool MayBeQNaN : 1;
39+
bool MayBeSNaN : 1;
40+
41+
/// Create empty constant range with same semantics.
42+
ConstantFPRange getEmpty() const {
43+
return ConstantFPRange(getSemantics(), /*IsFullSet=*/false);
44+
}
45+
46+
/// Create full constant range with same semantics.
47+
ConstantFPRange getFull() const {
48+
return ConstantFPRange(getSemantics(), /*IsFullSet=*/true);
49+
}
50+
51+
void makeEmpty();
52+
void makeFull();
53+
bool isNaNOnly() const;
54+
55+
/// Initialize a full or empty set for the specified semantics.
56+
explicit ConstantFPRange(const fltSemantics &Sem, bool IsFullSet);
57+
58+
public:
59+
/// Initialize a range to hold the single specified value.
60+
explicit ConstantFPRange(const APFloat &Value);
61+
62+
/// Initialize a range of values explicitly.
63+
/// Note: If \p LowerVal is greater than \p UpperVal, please use the canonical
64+
/// form [Inf, -Inf].
65+
ConstantFPRange(APFloat LowerVal, APFloat UpperVal, bool MayBeQNaN,
66+
bool MayBeSNaN);
67+
68+
/// Create empty constant range with the given semantics.
69+
static ConstantFPRange getEmpty(const fltSemantics &Sem) {
70+
return ConstantFPRange(Sem, /*IsFullSet=*/false);
71+
}
72+
73+
/// Create full constant range with the given semantics.
74+
static ConstantFPRange getFull(const fltSemantics &Sem) {
75+
return ConstantFPRange(Sem, /*IsFullSet=*/true);
76+
}
77+
78+
/// Helper for (-inf, inf) to represent all finite values.
79+
static ConstantFPRange getFinite(const fltSemantics &Sem);
80+
81+
/// Create a range which doesn't contain NaNs.
82+
static ConstantFPRange getNonNaN(APFloat LowerVal, APFloat UpperVal) {
83+
return ConstantFPRange(std::move(LowerVal), std::move(UpperVal),
84+
/*MayBeQNaN=*/false, /*MayBeSNaN=*/false);
85+
}
86+
87+
/// Create a range which may contain NaNs.
88+
static ConstantFPRange getMayBeNaN(APFloat LowerVal, APFloat UpperVal) {
89+
return ConstantFPRange(std::move(LowerVal), std::move(UpperVal),
90+
/*MayBeQNaN=*/true, /*MayBeSNaN=*/true);
91+
}
92+
93+
/// Create a range which only contains NaNs.
94+
static ConstantFPRange getNaNOnly(const fltSemantics &Sem, bool MayBeQNaN,
95+
bool MayBeSNaN);
96+
97+
/// Produce the smallest range such that all values that may satisfy the given
98+
/// predicate with any value contained within Other is contained in the
99+
/// returned range. Formally, this returns a superset of
100+
/// 'union over all y in Other . { x : fcmp op x y is true }'. If the exact
101+
/// answer is not representable as a ConstantFPRange, the return value will be
102+
/// a proper superset of the above.
103+
///
104+
/// Example: Pred = ole and Other = float [2, 5] returns Result = [-inf, 5]
105+
static ConstantFPRange makeAllowedFCmpRegion(FCmpInst::Predicate Pred,
106+
const ConstantFPRange &Other);
107+
108+
/// Produce the largest range such that all values in the returned range
109+
/// satisfy the given predicate with all values contained within Other.
110+
/// Formally, this returns a subset of
111+
/// 'intersection over all y in Other . { x : fcmp op x y is true }'. If the
112+
/// exact answer is not representable as a ConstantFPRange, the return value
113+
/// will be a proper subset of the above.
114+
///
115+
/// Example: Pred = ole and Other = float [2, 5] returns [-inf, 2]
116+
static ConstantFPRange makeSatisfyingFCmpRegion(FCmpInst::Predicate Pred,
117+
const ConstantFPRange &Other);
118+
119+
/// Produce the exact range such that all values in the returned range satisfy
120+
/// the given predicate with any value contained within Other. Formally, this
121+
/// returns the exact answer when the superset of 'union over all y in Other
122+
/// is exactly same as the subset of intersection over all y in Other.
123+
/// { x : fcmp op x y is true}'.
124+
///
125+
/// Example: Pred = olt and Other = float 3 returns [-inf, 3)
126+
static ConstantFPRange makeExactFCmpRegion(FCmpInst::Predicate Pred,
127+
const APFloat &Other);
128+
129+
/// Does the predicate \p Pred hold between ranges this and \p Other?
130+
/// NOTE: false does not mean that inverse predicate holds!
131+
bool fcmp(FCmpInst::Predicate Pred, const ConstantFPRange &Other) const;
132+
133+
/// Return the lower value for this range.
134+
const APFloat &getLower() const { return Lower; }
135+
136+
/// Return the upper value for this range.
137+
const APFloat &getUpper() const { return Upper; }
138+
139+
bool containsNaN() const { return MayBeQNaN || MayBeSNaN; }
140+
bool containsQNaN() const { return MayBeQNaN; }
141+
bool containsSNaN() const { return MayBeSNaN; }
142+
143+
/// Get the semantics of this ConstantFPRange.
144+
const fltSemantics &getSemantics() const { return Lower.getSemantics(); }
145+
146+
/// Return true if this set contains all of the elements possible
147+
/// for this data-type.
148+
bool isFullSet() const;
149+
150+
/// Return true if this set contains no members.
151+
bool isEmptySet() const;
152+
153+
/// Return true if the specified value is in the set.
154+
bool contains(const APFloat &Val) const;
155+
156+
/// Return true if the other range is a subset of this one.
157+
bool contains(const ConstantFPRange &CR) const;
158+
159+
/// If this set contains a single element, return it, otherwise return null.
160+
const APFloat *getSingleElement() const;
161+
162+
/// Return true if this set contains exactly one member.
163+
bool isSingleElement() const { return getSingleElement() != nullptr; }
164+
165+
/// Return true if the sign bit of all values in this range is 1.
166+
/// Return false if the sign bit of all values in this range is 0.
167+
/// Otherwise, return std::nullopt.
168+
std::optional<bool> getSignBit() const;
169+
170+
/// Return true if this range is equal to another range.
171+
bool operator==(const ConstantFPRange &CR) const;
172+
/// Return true if this range is not equal to another range.
173+
bool operator!=(const ConstantFPRange &CR) const { return !operator==(CR); }
174+
175+
/// Return the FPClassTest which will return true for the value.
176+
FPClassTest classify() const;
177+
178+
/// Return known floating-point classes for values in this range.
179+
KnownFPClass toKnownFPClass() const;
180+
181+
/// Print out the bounds to a stream.
182+
void print(raw_ostream &OS) const;
183+
184+
/// Allow printing from a debugger easily.
185+
void dump() const;
186+
187+
/// Return the range that results from the intersection of this range with
188+
/// another range.
189+
ConstantFPRange intersectWith(const ConstantFPRange &CR) const;
190+
191+
/// Return the range that results from the union of this range
192+
/// with another range. The resultant range is guaranteed to include the
193+
/// elements of both sets, but may contain more.
194+
ConstantFPRange unionWith(const ConstantFPRange &CR) const;
195+
};
196+
197+
inline raw_ostream &operator<<(raw_ostream &OS, const ConstantFPRange &CR) {
198+
CR.print(OS);
199+
return OS;
200+
}
201+
202+
} // end namespace llvm
203+
204+
#endif // LLVM_IR_CONSTANTFPRANGE_H

llvm/lib/IR/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ add_llvm_component_library(LLVMCore
88
BuiltinGCs.cpp
99
Comdat.cpp
1010
ConstantFold.cpp
11+
ConstantFPRange.cpp
1112
ConstantRange.cpp
1213
ConstantRangeList.cpp
1314
Constants.cpp

0 commit comments

Comments
 (0)