• 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 #include "llvm/IR/Instructions.h"
15 //
16 //===----------------------------------------------------------------------===//
17 //                               ValueLatticeElement
18 //===----------------------------------------------------------------------===//
19 
20 /// This class represents lattice values for constants.
21 ///
22 /// FIXME: This is basically just for bringup, this can be made a lot more rich
23 /// in the future.
24 ///
25 
26 namespace llvm {
27 class ValueLatticeElement {
28   enum ValueLatticeElementTy {
29     /// This Value has no known value yet.  As a result, this implies the
30     /// producing instruction is dead.  Caution: We use this as the starting
31     /// state in our local meet rules.  In this usage, it's taken to mean
32     /// "nothing known yet".
33     /// Transition to any other state allowed.
34     unknown,
35 
36     /// This Value is an UndefValue constant or produces undef. Undefined values
37     /// can be merged with constants (or single element constant ranges),
38     /// assuming all uses of the result will be replaced.
39     /// Transition allowed to the following states:
40     ///  constant
41     ///  constantrange_including_undef
42     ///  overdefined
43     undef,
44 
45     /// This Value has a specific constant value.  The constant cannot be undef.
46     /// (For constant integers, constantrange is used instead. Integer typed
47     /// constantexprs can appear as constant.) Note that the constant state
48     /// can be reached by merging undef & constant states.
49     /// Transition allowed to the following states:
50     ///  overdefined
51     constant,
52 
53     /// This Value is known to not have the specified value. (For constant
54     /// integers, constantrange is used instead.  As above, integer typed
55     /// constantexprs can appear here.)
56     /// Transition allowed to the following states:
57     ///  overdefined
58     notconstant,
59 
60     /// The Value falls within this range. (Used only for integer typed values.)
61     /// Transition allowed to the following states:
62     ///  constantrange (new range must be a superset of the existing range)
63     ///  constantrange_including_undef
64     ///  overdefined
65     constantrange,
66 
67     /// This Value falls within this range, but also may be undef.
68     /// Merging it with other constant ranges results in
69     /// constantrange_including_undef.
70     /// Transition allowed to the following states:
71     ///  overdefined
72     constantrange_including_undef,
73 
74     /// We can not precisely model the dynamic values this value might take.
75     /// No transitions are allowed after reaching overdefined.
76     overdefined,
77   };
78 
79   ValueLatticeElementTy Tag : 8;
80   /// Number of times a constant range has been extended with widening enabled.
81   unsigned NumRangeExtensions : 8;
82 
83   /// The union either stores a pointer to a constant or a constant range,
84   /// associated to the lattice element. We have to ensure that Range is
85   /// initialized or destroyed when changing state to or from constantrange.
86   union {
87     Constant *ConstVal;
88     ConstantRange Range;
89   };
90 
91   /// Destroy contents of lattice value, without destructing the object.
destroy()92   void destroy() {
93     switch (Tag) {
94     case overdefined:
95     case unknown:
96     case undef:
97     case constant:
98     case notconstant:
99       break;
100     case constantrange_including_undef:
101     case constantrange:
102       Range.~ConstantRange();
103       break;
104     };
105   }
106 
107 public:
108   /// Struct to control some aspects related to merging constant ranges.
109   struct MergeOptions {
110     /// The merge value may include undef.
111     bool MayIncludeUndef;
112 
113     /// Handle repeatedly extending a range by going to overdefined after a
114     /// number of steps.
115     bool CheckWiden;
116 
117     /// The number of allowed widening steps (including setting the range
118     /// initially).
119     unsigned MaxWidenSteps;
120 
MergeOptionsMergeOptions121     MergeOptions() : MergeOptions(false, false) {}
122 
123     MergeOptions(bool MayIncludeUndef, bool CheckWiden,
124                  unsigned MaxWidenSteps = 1)
MayIncludeUndefMergeOptions125         : MayIncludeUndef(MayIncludeUndef), CheckWiden(CheckWiden),
126           MaxWidenSteps(MaxWidenSteps) {}
127 
128     MergeOptions &setMayIncludeUndef(bool V = true) {
129       MayIncludeUndef = V;
130       return *this;
131     }
132 
133     MergeOptions &setCheckWiden(bool V = true) {
134       CheckWiden = V;
135       return *this;
136     }
137 
138     MergeOptions &setMaxWidenSteps(unsigned Steps = 1) {
139       CheckWiden = true;
140       MaxWidenSteps = Steps;
141       return *this;
142     }
143   };
144 
145   // ConstVal and Range are initialized on-demand.
ValueLatticeElement()146   ValueLatticeElement() : Tag(unknown), NumRangeExtensions(0) {}
147 
~ValueLatticeElement()148   ~ValueLatticeElement() { destroy(); }
149 
ValueLatticeElement(const ValueLatticeElement & Other)150   ValueLatticeElement(const ValueLatticeElement &Other)
151       : Tag(Other.Tag), NumRangeExtensions(0) {
152     switch (Other.Tag) {
153     case constantrange:
154     case constantrange_including_undef:
155       new (&Range) ConstantRange(Other.Range);
156       NumRangeExtensions = Other.NumRangeExtensions;
157       break;
158     case constant:
159     case notconstant:
160       ConstVal = Other.ConstVal;
161       break;
162     case overdefined:
163     case unknown:
164     case undef:
165       break;
166     }
167   }
168 
ValueLatticeElement(ValueLatticeElement && Other)169   ValueLatticeElement(ValueLatticeElement &&Other)
170       : Tag(Other.Tag), NumRangeExtensions(0) {
171     switch (Other.Tag) {
172     case constantrange:
173     case constantrange_including_undef:
174       new (&Range) ConstantRange(std::move(Other.Range));
175       NumRangeExtensions = Other.NumRangeExtensions;
176       break;
177     case constant:
178     case notconstant:
179       ConstVal = Other.ConstVal;
180       break;
181     case overdefined:
182     case unknown:
183     case undef:
184       break;
185     }
186     Other.Tag = unknown;
187   }
188 
189   ValueLatticeElement &operator=(const ValueLatticeElement &Other) {
190     destroy();
191     new (this) ValueLatticeElement(Other);
192     return *this;
193   }
194 
195   ValueLatticeElement &operator=(ValueLatticeElement &&Other) {
196     destroy();
197     new (this) ValueLatticeElement(std::move(Other));
198     return *this;
199   }
200 
get(Constant * C)201   static ValueLatticeElement get(Constant *C) {
202     ValueLatticeElement Res;
203     if (isa<UndefValue>(C))
204       Res.markUndef();
205     else
206       Res.markConstant(C);
207     return Res;
208   }
getNot(Constant * C)209   static ValueLatticeElement getNot(Constant *C) {
210     ValueLatticeElement Res;
211     assert(!isa<UndefValue>(C) && "!= undef is not supported");
212     Res.markNotConstant(C);
213     return Res;
214   }
215   static ValueLatticeElement getRange(ConstantRange CR,
216                                       bool MayIncludeUndef = false) {
217     if (CR.isFullSet())
218       return getOverdefined();
219 
220     if (CR.isEmptySet()) {
221       ValueLatticeElement Res;
222       if (MayIncludeUndef)
223         Res.markUndef();
224       return Res;
225     }
226 
227     ValueLatticeElement Res;
228     Res.markConstantRange(std::move(CR),
229                           MergeOptions().setMayIncludeUndef(MayIncludeUndef));
230     return Res;
231   }
getOverdefined()232   static ValueLatticeElement getOverdefined() {
233     ValueLatticeElement Res;
234     Res.markOverdefined();
235     return Res;
236   }
237 
isUndef()238   bool isUndef() const { return Tag == undef; }
isUnknown()239   bool isUnknown() const { return Tag == unknown; }
isUnknownOrUndef()240   bool isUnknownOrUndef() const { return Tag == unknown || Tag == undef; }
isConstant()241   bool isConstant() const { return Tag == constant; }
isNotConstant()242   bool isNotConstant() const { return Tag == notconstant; }
isConstantRangeIncludingUndef()243   bool isConstantRangeIncludingUndef() const {
244     return Tag == constantrange_including_undef;
245   }
246   /// Returns true if this value is a constant range. Use \p UndefAllowed to
247   /// exclude non-singleton constant ranges that may also be undef. Note that
248   /// this function also returns true if the range may include undef, but only
249   /// contains a single element. In that case, it can be replaced by a constant.
250   bool isConstantRange(bool UndefAllowed = true) const {
251     return Tag == constantrange || (Tag == constantrange_including_undef &&
252                                     (UndefAllowed || Range.isSingleElement()));
253   }
isOverdefined()254   bool isOverdefined() const { return Tag == overdefined; }
255 
getConstant()256   Constant *getConstant() const {
257     assert(isConstant() && "Cannot get the constant of a non-constant!");
258     return ConstVal;
259   }
260 
getNotConstant()261   Constant *getNotConstant() const {
262     assert(isNotConstant() && "Cannot get the constant of a non-notconstant!");
263     return ConstVal;
264   }
265 
266   /// Returns the constant range for this value. Use \p UndefAllowed to exclude
267   /// non-singleton constant ranges that may also be undef. Note that this
268   /// function also returns a range if the range may include undef, but only
269   /// contains a single element. In that case, it can be replaced by a constant.
270   const ConstantRange &getConstantRange(bool UndefAllowed = true) const {
271     assert(isConstantRange(UndefAllowed) &&
272            "Cannot get the constant-range of a non-constant-range!");
273     return Range;
274   }
275 
asConstantInteger()276   Optional<APInt> asConstantInteger() const {
277     if (isConstant() && isa<ConstantInt>(getConstant())) {
278       return cast<ConstantInt>(getConstant())->getValue();
279     } else if (isConstantRange() && getConstantRange().isSingleElement()) {
280       return *getConstantRange().getSingleElement();
281     }
282     return None;
283   }
284 
markOverdefined()285   bool markOverdefined() {
286     if (isOverdefined())
287       return false;
288     destroy();
289     Tag = overdefined;
290     return true;
291   }
292 
markUndef()293   bool markUndef() {
294     if (isUndef())
295       return false;
296 
297     assert(isUnknown());
298     Tag = undef;
299     return true;
300   }
301 
302   bool markConstant(Constant *V, bool MayIncludeUndef = false) {
303     if (isa<UndefValue>(V))
304       return markUndef();
305 
306     if (isConstant()) {
307       assert(getConstant() == V && "Marking constant with different value");
308       return false;
309     }
310 
311     if (ConstantInt *CI = dyn_cast<ConstantInt>(V))
312       return markConstantRange(
313           ConstantRange(CI->getValue()),
314           MergeOptions().setMayIncludeUndef(MayIncludeUndef));
315 
316     assert(isUnknown() || isUndef());
317     Tag = constant;
318     ConstVal = V;
319     return true;
320   }
321 
markNotConstant(Constant * V)322   bool markNotConstant(Constant *V) {
323     assert(V && "Marking constant with NULL");
324     if (ConstantInt *CI = dyn_cast<ConstantInt>(V))
325       return markConstantRange(
326           ConstantRange(CI->getValue() + 1, CI->getValue()));
327 
328     if (isa<UndefValue>(V))
329       return false;
330 
331     if (isNotConstant()) {
332       assert(getNotConstant() == V && "Marking !constant with different value");
333       return false;
334     }
335 
336     assert(isUnknown());
337     Tag = notconstant;
338     ConstVal = V;
339     return true;
340   }
341 
342   /// Mark the object as constant range with \p NewR. If the object is already a
343   /// constant range, nothing changes if the existing range is equal to \p
344   /// NewR and the tag. Otherwise \p NewR must be a superset of the existing
345   /// range or the object must be undef. The tag is set to
346   /// constant_range_including_undef if either the existing value or the new
347   /// range may include undef.
348   bool markConstantRange(ConstantRange NewR,
349                          MergeOptions Opts = MergeOptions()) {
350     assert(!NewR.isEmptySet() && "should only be called for non-empty sets");
351 
352     if (NewR.isFullSet())
353       return markOverdefined();
354 
355     ValueLatticeElementTy OldTag = Tag;
356     ValueLatticeElementTy NewTag =
357         (isUndef() || isConstantRangeIncludingUndef() || Opts.MayIncludeUndef)
358             ? constantrange_including_undef
359             : constantrange;
360     if (isConstantRange()) {
361       Tag = NewTag;
362       if (getConstantRange() == NewR)
363         return Tag != OldTag;
364 
365       // Simple form of widening. If a range is extended multiple times, go to
366       // overdefined.
367       if (Opts.CheckWiden && ++NumRangeExtensions > Opts.MaxWidenSteps)
368         return markOverdefined();
369 
370       assert(NewR.contains(getConstantRange()) &&
371              "Existing range must be a subset of NewR");
372       Range = std::move(NewR);
373       return true;
374     }
375 
376     assert(isUnknown() || isUndef());
377 
378     NumRangeExtensions = 0;
379     Tag = NewTag;
380     new (&Range) ConstantRange(std::move(NewR));
381     return true;
382   }
383 
384   /// Updates this object to approximate both this object and RHS. Returns
385   /// true if this object has been changed.
386   bool mergeIn(const ValueLatticeElement &RHS,
387                MergeOptions Opts = MergeOptions()) {
388     if (RHS.isUnknown() || isOverdefined())
389       return false;
390     if (RHS.isOverdefined()) {
391       markOverdefined();
392       return true;
393     }
394 
395     if (isUndef()) {
396       assert(!RHS.isUnknown());
397       if (RHS.isUndef())
398         return false;
399       if (RHS.isConstant())
400         return markConstant(RHS.getConstant(), true);
401       if (RHS.isConstantRange())
402         return markConstantRange(RHS.getConstantRange(true),
403                                  Opts.setMayIncludeUndef());
404       return markOverdefined();
405     }
406 
407     if (isUnknown()) {
408       assert(!RHS.isUnknown() && "Unknow RHS should be handled earlier");
409       *this = RHS;
410       return true;
411     }
412 
413     if (isConstant()) {
414       if (RHS.isConstant() && getConstant() == RHS.getConstant())
415         return false;
416       if (RHS.isUndef())
417         return false;
418       markOverdefined();
419       return true;
420     }
421 
422     if (isNotConstant()) {
423       if (RHS.isNotConstant() && getNotConstant() == RHS.getNotConstant())
424         return false;
425       markOverdefined();
426       return true;
427     }
428 
429     auto OldTag = Tag;
430     assert(isConstantRange() && "New ValueLattice type?");
431     if (RHS.isUndef()) {
432       Tag = constantrange_including_undef;
433       return OldTag != Tag;
434     }
435 
436     if (!RHS.isConstantRange()) {
437       // We can get here if we've encountered a constantexpr of integer type
438       // and merge it with a constantrange.
439       markOverdefined();
440       return true;
441     }
442 
443     ConstantRange NewR = getConstantRange().unionWith(RHS.getConstantRange());
444     return markConstantRange(
445         std::move(NewR),
446         Opts.setMayIncludeUndef(RHS.isConstantRangeIncludingUndef()));
447   }
448 
449   // Compares this symbolic value with Other using Pred and returns either
450   /// true, false or undef constants, or nullptr if the comparison cannot be
451   /// evaluated.
getCompare(CmpInst::Predicate Pred,Type * Ty,const ValueLatticeElement & Other)452   Constant *getCompare(CmpInst::Predicate Pred, Type *Ty,
453                        const ValueLatticeElement &Other) const {
454     if (isUnknownOrUndef() || Other.isUnknownOrUndef())
455       return UndefValue::get(Ty);
456 
457     if (isConstant() && Other.isConstant())
458       return ConstantExpr::getCompare(Pred, getConstant(), Other.getConstant());
459 
460     if (ICmpInst::isEquality(Pred)) {
461       // not(C) != C => true, not(C) == C => false.
462       if ((isNotConstant() && Other.isConstant() &&
463            getNotConstant() == Other.getConstant()) ||
464           (isConstant() && Other.isNotConstant() &&
465            getConstant() == Other.getNotConstant()))
466         return Pred == ICmpInst::ICMP_NE
467             ? ConstantInt::getTrue(Ty) : ConstantInt::getFalse(Ty);
468     }
469 
470     // Integer constants are represented as ConstantRanges with single
471     // elements.
472     if (!isConstantRange() || !Other.isConstantRange())
473       return nullptr;
474 
475     const auto &CR = getConstantRange();
476     const auto &OtherCR = Other.getConstantRange();
477     if (ConstantRange::makeSatisfyingICmpRegion(Pred, OtherCR).contains(CR))
478       return ConstantInt::getTrue(Ty);
479     if (ConstantRange::makeSatisfyingICmpRegion(
480             CmpInst::getInversePredicate(Pred), OtherCR)
481             .contains(CR))
482       return ConstantInt::getFalse(Ty);
483 
484     return nullptr;
485   }
486 
getNumRangeExtensions()487   unsigned getNumRangeExtensions() const { return NumRangeExtensions; }
setNumRangeExtensions(unsigned N)488   void setNumRangeExtensions(unsigned N) { NumRangeExtensions = N; }
489 };
490 
491 static_assert(sizeof(ValueLatticeElement) <= 40,
492               "size of ValueLatticeElement changed unexpectedly");
493 
494 raw_ostream &operator<<(raw_ostream &OS, const ValueLatticeElement &Val);
495 } // end namespace llvm
496 #endif
497