• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- ValueLattice.h - Value constraint analysis ---------------*- 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 #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 
25 namespace llvm {
26 class 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 
61 public:
62   // Const and Range are initialized on-demand.
ValueLatticeElement()63   ValueLatticeElement() : Tag(undefined) {}
64 
65   /// Custom destructor to ensure Range is properly destroyed, when the object
66   /// is deallocated.
~ValueLatticeElement()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.
ValueLatticeElement(const ValueLatticeElement & Other)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 
get(Constant * C)119   static ValueLatticeElement get(Constant *C) {
120     ValueLatticeElement Res;
121     if (!isa<UndefValue>(C))
122       Res.markConstant(C);
123     return Res;
124   }
getNot(Constant * C)125   static ValueLatticeElement getNot(Constant *C) {
126     ValueLatticeElement Res;
127     if (!isa<UndefValue>(C))
128       Res.markNotConstant(C);
129     return Res;
130   }
getRange(ConstantRange CR)131   static ValueLatticeElement getRange(ConstantRange CR) {
132     ValueLatticeElement Res;
133     Res.markConstantRange(std::move(CR));
134     return Res;
135   }
getOverdefined()136   static ValueLatticeElement getOverdefined() {
137     ValueLatticeElement Res;
138     Res.markOverdefined();
139     return Res;
140   }
141 
isUndefined()142   bool isUndefined() const { return Tag == undefined; }
isConstant()143   bool isConstant() const { return Tag == constant; }
isNotConstant()144   bool isNotConstant() const { return Tag == notconstant; }
isConstantRange()145   bool isConstantRange() const { return Tag == constantrange; }
isOverdefined()146   bool isOverdefined() const { return Tag == overdefined; }
147 
getConstant()148   Constant *getConstant() const {
149     assert(isConstant() && "Cannot get the constant of a non-constant!");
150     return ConstVal;
151   }
152 
getNotConstant()153   Constant *getNotConstant() const {
154     assert(isNotConstant() && "Cannot get the constant of a non-notconstant!");
155     return ConstVal;
156   }
157 
getConstantRange()158   const ConstantRange &getConstantRange() const {
159     assert(isConstantRange() &&
160            "Cannot get the constant-range of a non-constant-range!");
161     return Range;
162   }
163 
asConstantInteger()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 
173 private:
markOverdefined()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 
markConstant(Constant * V)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 
markNotConstant(Constant * V)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 
markConstantRange(ConstantRange NewR)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 
237 public:
238   /// Updates this object to approximate both this object and RHS. Returns
239   /// true if this object has been changed.
mergeIn(const ValueLatticeElement & RHS,const DataLayout & DL)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();
277     else if (NewR == getConstantRange())
278       return false;
279     else
280       markConstantRange(std::move(NewR));
281     return true;
282   }
283 
getConstantInt()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.
getCompare(CmpInst::Predicate Pred,Type * Ty,const ValueLatticeElement & Other)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 
319 raw_ostream &operator<<(raw_ostream &OS, const ValueLatticeElement &Val);
320 
321 } // end namespace llvm
322 #endif
323