blob: 56519d7d0857cfea4f67d495fe5e6ba3e1f7d04d [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===- ValueLattice.h - Value constraint analysis ---------------*- C++ -*-===//
2//
Andrew Walbran16937d02019-10-22 13:54:20 +01003// 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
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01006//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLVM_ANALYSIS_VALUELATTICE_H
10#define LLVM_ANALYSIS_VALUELATTICE_H
11
12#include "llvm/IR/ConstantRange.h"
13#include "llvm/IR/Constants.h"
14//
15//===----------------------------------------------------------------------===//
16// ValueLatticeElement
17//===----------------------------------------------------------------------===//
18
19/// This class represents lattice values for constants.
20///
21/// FIXME: This is basically just for bringup, this can be made a lot more rich
22/// in the future.
23///
24
25namespace llvm {
26class ValueLatticeElement {
27 enum ValueLatticeElementTy {
28 /// This Value has no known value yet. As a result, this implies the
29 /// producing instruction is dead. Caution: We use this as the starting
30 /// state in our local meet rules. In this usage, it's taken to mean
31 /// "nothing known yet".
32 undefined,
33
34 /// This Value has a specific constant value. (For constant integers,
35 /// constantrange is used instead. Integer typed constantexprs can appear
36 /// as constant.)
37 constant,
38
39 /// This Value is known to not have the specified value. (For constant
40 /// integers, constantrange is used instead. As above, integer typed
41 /// constantexprs can appear here.)
42 notconstant,
43
44 /// The Value falls within this range. (Used only for integer typed values.)
45 constantrange,
46
47 /// We can not precisely model the dynamic values this value might take.
48 overdefined
49 };
50
51 ValueLatticeElementTy Tag;
52
53 /// The union either stores a pointer to a constant or a constant range,
54 /// associated to the lattice element. We have to ensure that Range is
55 /// initialized or destroyed when changing state to or from constantrange.
56 union {
57 Constant *ConstVal;
58 ConstantRange Range;
59 };
60
61public:
62 // Const and Range are initialized on-demand.
63 ValueLatticeElement() : Tag(undefined) {}
64
65 /// Custom destructor to ensure Range is properly destroyed, when the object
66 /// is deallocated.
67 ~ValueLatticeElement() {
68 switch (Tag) {
69 case overdefined:
70 case undefined:
71 case constant:
72 case notconstant:
73 break;
74 case constantrange:
75 Range.~ConstantRange();
76 break;
77 };
78 }
79
80 /// Custom copy constructor, to ensure Range gets initialized when
81 /// copying a constant range lattice element.
82 ValueLatticeElement(const ValueLatticeElement &Other) : Tag(undefined) {
83 *this = Other;
84 }
85
86 /// Custom assignment operator, to ensure Range gets initialized when
87 /// assigning a constant range lattice element.
88 ValueLatticeElement &operator=(const ValueLatticeElement &Other) {
89 // If we change the state of this from constant range to non constant range,
90 // destroy Range.
91 if (isConstantRange() && !Other.isConstantRange())
92 Range.~ConstantRange();
93
94 // If we change the state of this from a valid ConstVal to another a state
95 // without a valid ConstVal, zero the pointer.
96 if ((isConstant() || isNotConstant()) && !Other.isConstant() &&
97 !Other.isNotConstant())
98 ConstVal = nullptr;
99
100 switch (Other.Tag) {
101 case constantrange:
102 if (!isConstantRange())
103 new (&Range) ConstantRange(Other.Range);
104 else
105 Range = Other.Range;
106 break;
107 case constant:
108 case notconstant:
109 ConstVal = Other.ConstVal;
110 break;
111 case overdefined:
112 case undefined:
113 break;
114 }
115 Tag = Other.Tag;
116 return *this;
117 }
118
119 static ValueLatticeElement get(Constant *C) {
120 ValueLatticeElement Res;
121 if (!isa<UndefValue>(C))
122 Res.markConstant(C);
123 return Res;
124 }
125 static ValueLatticeElement getNot(Constant *C) {
126 ValueLatticeElement Res;
127 if (!isa<UndefValue>(C))
128 Res.markNotConstant(C);
129 return Res;
130 }
131 static ValueLatticeElement getRange(ConstantRange CR) {
132 ValueLatticeElement Res;
133 Res.markConstantRange(std::move(CR));
134 return Res;
135 }
136 static ValueLatticeElement getOverdefined() {
137 ValueLatticeElement Res;
138 Res.markOverdefined();
139 return Res;
140 }
141
142 bool isUndefined() const { return Tag == undefined; }
143 bool isConstant() const { return Tag == constant; }
144 bool isNotConstant() const { return Tag == notconstant; }
145 bool isConstantRange() const { return Tag == constantrange; }
146 bool isOverdefined() const { return Tag == overdefined; }
147
148 Constant *getConstant() const {
149 assert(isConstant() && "Cannot get the constant of a non-constant!");
150 return ConstVal;
151 }
152
153 Constant *getNotConstant() const {
154 assert(isNotConstant() && "Cannot get the constant of a non-notconstant!");
155 return ConstVal;
156 }
157
158 const ConstantRange &getConstantRange() const {
159 assert(isConstantRange() &&
160 "Cannot get the constant-range of a non-constant-range!");
161 return Range;
162 }
163
164 Optional<APInt> asConstantInteger() const {
165 if (isConstant() && isa<ConstantInt>(getConstant())) {
166 return cast<ConstantInt>(getConstant())->getValue();
167 } else if (isConstantRange() && getConstantRange().isSingleElement()) {
168 return *getConstantRange().getSingleElement();
169 }
170 return None;
171 }
172
173private:
174 void markOverdefined() {
175 if (isOverdefined())
176 return;
177 if (isConstant() || isNotConstant())
178 ConstVal = nullptr;
179 if (isConstantRange())
180 Range.~ConstantRange();
181 Tag = overdefined;
182 }
183
184 void markConstant(Constant *V) {
185 assert(V && "Marking constant with NULL");
186 if (ConstantInt *CI = dyn_cast<ConstantInt>(V)) {
187 markConstantRange(ConstantRange(CI->getValue()));
188 return;
189 }
190 if (isa<UndefValue>(V))
191 return;
192
193 assert((!isConstant() || getConstant() == V) &&
194 "Marking constant with different value");
195 assert(isUndefined());
196 Tag = constant;
197 ConstVal = V;
198 }
199
200 void markNotConstant(Constant *V) {
201 assert(V && "Marking constant with NULL");
202 if (ConstantInt *CI = dyn_cast<ConstantInt>(V)) {
203 markConstantRange(ConstantRange(CI->getValue() + 1, CI->getValue()));
204 return;
205 }
206 if (isa<UndefValue>(V))
207 return;
208
209 assert((!isConstant() || getConstant() != V) &&
210 "Marking constant !constant with same value");
211 assert((!isNotConstant() || getNotConstant() == V) &&
212 "Marking !constant with different value");
213 assert(isUndefined() || isConstant());
214 Tag = notconstant;
215 ConstVal = V;
216 }
217
218 void markConstantRange(ConstantRange NewR) {
219 if (isConstantRange()) {
220 if (NewR.isEmptySet())
221 markOverdefined();
222 else {
223 Range = std::move(NewR);
224 }
225 return;
226 }
227
228 assert(isUndefined());
229 if (NewR.isEmptySet())
230 markOverdefined();
231 else {
232 Tag = constantrange;
233 new (&Range) ConstantRange(std::move(NewR));
234 }
235 }
236
237public:
238 /// Updates this object to approximate both this object and RHS. Returns
239 /// true if this object has been changed.
240 bool mergeIn(const ValueLatticeElement &RHS, const DataLayout &DL) {
241 if (RHS.isUndefined() || isOverdefined())
242 return false;
243 if (RHS.isOverdefined()) {
244 markOverdefined();
245 return true;
246 }
247
248 if (isUndefined()) {
249 *this = RHS;
250 return !RHS.isUndefined();
251 }
252
253 if (isConstant()) {
254 if (RHS.isConstant() && getConstant() == RHS.getConstant())
255 return false;
256 markOverdefined();
257 return true;
258 }
259
260 if (isNotConstant()) {
261 if (RHS.isNotConstant() && getNotConstant() == RHS.getNotConstant())
262 return false;
263 markOverdefined();
264 return true;
265 }
266
267 assert(isConstantRange() && "New ValueLattice type?");
268 if (!RHS.isConstantRange()) {
269 // We can get here if we've encountered a constantexpr of integer type
270 // and merge it with a constantrange.
271 markOverdefined();
272 return true;
273 }
274 ConstantRange NewR = getConstantRange().unionWith(RHS.getConstantRange());
275 if (NewR.isFullSet())
276 markOverdefined();
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100277 else if (NewR == getConstantRange())
278 return false;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100279 else
280 markConstantRange(std::move(NewR));
281 return true;
282 }
283
284 ConstantInt *getConstantInt() const {
285 assert(isConstant() && isa<ConstantInt>(getConstant()) &&
286 "No integer constant");
287 return cast<ConstantInt>(getConstant());
288 }
289
290 /// Compares this symbolic value with Other using Pred and returns either
291 /// true, false or undef constants, or nullptr if the comparison cannot be
292 /// evaluated.
293 Constant *getCompare(CmpInst::Predicate Pred, Type *Ty,
294 const ValueLatticeElement &Other) const {
295 if (isUndefined() || Other.isUndefined())
296 return UndefValue::get(Ty);
297
298 if (isConstant() && Other.isConstant())
299 return ConstantExpr::getCompare(Pred, getConstant(), Other.getConstant());
300
301 // Integer constants are represented as ConstantRanges with single
302 // elements.
303 if (!isConstantRange() || !Other.isConstantRange())
304 return nullptr;
305
306 const auto &CR = getConstantRange();
307 const auto &OtherCR = Other.getConstantRange();
308 if (ConstantRange::makeSatisfyingICmpRegion(Pred, OtherCR).contains(CR))
309 return ConstantInt::getTrue(Ty);
310 if (ConstantRange::makeSatisfyingICmpRegion(
311 CmpInst::getInversePredicate(Pred), OtherCR)
312 .contains(CR))
313 return ConstantInt::getFalse(Ty);
314
315 return nullptr;
316 }
317};
318
319raw_ostream &operator<<(raw_ostream &OS, const ValueLatticeElement &Val);
320
321} // end namespace llvm
322#endif