xref: /freebsd/contrib/llvm-project/llvm/include/llvm/Analysis/ValueLattice.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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/Support/Compiler.h"
15 
16 //===----------------------------------------------------------------------===//
17 //                               ValueLatticeElement
18 //===----------------------------------------------------------------------===//
19 
20 namespace llvm {
21 
22 /// This class represents lattice values for constants.
23 ///
24 /// FIXME: This is basically just for bringup, this can be made a lot more rich
25 /// in the future.
26 ///
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     Res.markConstant(C);
204     return Res;
205   }
getNot(Constant * C)206   static ValueLatticeElement getNot(Constant *C) {
207     ValueLatticeElement Res;
208     assert(!isa<UndefValue>(C) && "!= undef is not supported");
209     Res.markNotConstant(C);
210     return Res;
211   }
212   static ValueLatticeElement getRange(ConstantRange CR,
213                                       bool MayIncludeUndef = false) {
214     if (CR.isFullSet())
215       return getOverdefined();
216 
217     if (CR.isEmptySet()) {
218       ValueLatticeElement Res;
219       if (MayIncludeUndef)
220         Res.markUndef();
221       return Res;
222     }
223 
224     ValueLatticeElement Res;
225     Res.markConstantRange(std::move(CR),
226                           MergeOptions().setMayIncludeUndef(MayIncludeUndef));
227     return Res;
228   }
getOverdefined()229   static ValueLatticeElement getOverdefined() {
230     ValueLatticeElement Res;
231     Res.markOverdefined();
232     return Res;
233   }
234 
isUndef()235   bool isUndef() const { return Tag == undef; }
isUnknown()236   bool isUnknown() const { return Tag == unknown; }
isUnknownOrUndef()237   bool isUnknownOrUndef() const { return Tag == unknown || Tag == undef; }
isConstant()238   bool isConstant() const { return Tag == constant; }
isNotConstant()239   bool isNotConstant() const { return Tag == notconstant; }
isConstantRangeIncludingUndef()240   bool isConstantRangeIncludingUndef() const {
241     return Tag == constantrange_including_undef;
242   }
243   /// Returns true if this value is a constant range. Use \p UndefAllowed to
244   /// exclude non-singleton constant ranges that may also be undef. Note that
245   /// this function also returns true if the range may include undef, but only
246   /// contains a single element. In that case, it can be replaced by a constant.
247   bool isConstantRange(bool UndefAllowed = true) const {
248     return Tag == constantrange || (Tag == constantrange_including_undef &&
249                                     (UndefAllowed || Range.isSingleElement()));
250   }
isOverdefined()251   bool isOverdefined() const { return Tag == overdefined; }
252 
getConstant()253   Constant *getConstant() const {
254     assert(isConstant() && "Cannot get the constant of a non-constant!");
255     return ConstVal;
256   }
257 
getNotConstant()258   Constant *getNotConstant() const {
259     assert(isNotConstant() && "Cannot get the constant of a non-notconstant!");
260     return ConstVal;
261   }
262 
263   /// Returns the constant range for this value. Use \p UndefAllowed to exclude
264   /// non-singleton constant ranges that may also be undef. Note that this
265   /// function also returns a range if the range may include undef, but only
266   /// contains a single element. In that case, it can be replaced by a constant.
267   const ConstantRange &getConstantRange(bool UndefAllowed = true) const {
268     assert(isConstantRange(UndefAllowed) &&
269            "Cannot get the constant-range of a non-constant-range!");
270     return Range;
271   }
272 
asConstantInteger()273   std::optional<APInt> asConstantInteger() const {
274     if (isConstant() && isa<ConstantInt>(getConstant())) {
275       return cast<ConstantInt>(getConstant())->getValue();
276     } else if (isConstantRange() && getConstantRange().isSingleElement()) {
277       return *getConstantRange().getSingleElement();
278     }
279     return std::nullopt;
280   }
281 
282   ConstantRange asConstantRange(unsigned BW, bool UndefAllowed = false) const {
283     if (isConstantRange(UndefAllowed))
284       return getConstantRange();
285     if (isConstant())
286       return getConstant()->toConstantRange();
287     if (isUnknown())
288       return ConstantRange::getEmpty(BW);
289     return ConstantRange::getFull(BW);
290   }
291 
292   ConstantRange asConstantRange(Type *Ty, bool UndefAllowed = false) const {
293     assert(Ty->isIntOrIntVectorTy() && "Must be integer type");
294     return asConstantRange(Ty->getScalarSizeInBits(), UndefAllowed);
295   }
296 
markOverdefined()297   bool markOverdefined() {
298     if (isOverdefined())
299       return false;
300     destroy();
301     Tag = overdefined;
302     return true;
303   }
304 
markUndef()305   bool markUndef() {
306     if (isUndef())
307       return false;
308 
309     assert(isUnknown());
310     Tag = undef;
311     return true;
312   }
313 
314   bool markConstant(Constant *V, bool MayIncludeUndef = false) {
315     if (isa<UndefValue>(V))
316       return markUndef();
317 
318     if (isConstant()) {
319       assert(getConstant() == V && "Marking constant with different value");
320       return false;
321     }
322 
323     if (ConstantInt *CI = dyn_cast<ConstantInt>(V))
324       return markConstantRange(
325           ConstantRange(CI->getValue()),
326           MergeOptions().setMayIncludeUndef(MayIncludeUndef));
327 
328     assert(isUnknown() || isUndef());
329     Tag = constant;
330     ConstVal = V;
331     return true;
332   }
333 
markNotConstant(Constant * V)334   bool markNotConstant(Constant *V) {
335     assert(V && "Marking constant with NULL");
336     if (ConstantInt *CI = dyn_cast<ConstantInt>(V))
337       return markConstantRange(
338           ConstantRange(CI->getValue() + 1, CI->getValue()));
339 
340     if (isa<UndefValue>(V))
341       return false;
342 
343     if (isNotConstant()) {
344       assert(getNotConstant() == V && "Marking !constant with different value");
345       return false;
346     }
347 
348     assert(isUnknown());
349     Tag = notconstant;
350     ConstVal = V;
351     return true;
352   }
353 
354   /// Mark the object as constant range with \p NewR. If the object is already a
355   /// constant range, nothing changes if the existing range is equal to \p
356   /// NewR and the tag. Otherwise \p NewR must be a superset of the existing
357   /// range or the object must be undef. The tag is set to
358   /// constant_range_including_undef if either the existing value or the new
359   /// range may include undef.
360   bool markConstantRange(ConstantRange NewR,
361                          MergeOptions Opts = MergeOptions()) {
362     assert(!NewR.isEmptySet() && "should only be called for non-empty sets");
363 
364     if (NewR.isFullSet())
365       return markOverdefined();
366 
367     ValueLatticeElementTy OldTag = Tag;
368     ValueLatticeElementTy NewTag =
369         (isUndef() || isConstantRangeIncludingUndef() || Opts.MayIncludeUndef)
370             ? constantrange_including_undef
371             : constantrange;
372     if (isConstantRange()) {
373       Tag = NewTag;
374       if (getConstantRange() == NewR)
375         return Tag != OldTag;
376 
377       // Simple form of widening. If a range is extended multiple times, go to
378       // overdefined.
379       if (Opts.CheckWiden && ++NumRangeExtensions > Opts.MaxWidenSteps)
380         return markOverdefined();
381 
382       assert(NewR.contains(getConstantRange()) &&
383              "Existing range must be a subset of NewR");
384       Range = std::move(NewR);
385       return true;
386     }
387 
388     assert(isUnknown() || isUndef() || isConstant());
389     assert((!isConstant() || NewR.contains(getConstant()->toConstantRange())) &&
390            "Constant must be subset of new range");
391 
392     NumRangeExtensions = 0;
393     Tag = NewTag;
394     new (&Range) ConstantRange(std::move(NewR));
395     return true;
396   }
397 
398   /// Updates this object to approximate both this object and RHS. Returns
399   /// true if this object has been changed.
400   bool mergeIn(const ValueLatticeElement &RHS,
401                MergeOptions Opts = MergeOptions()) {
402     if (RHS.isUnknown() || isOverdefined())
403       return false;
404     if (RHS.isOverdefined()) {
405       markOverdefined();
406       return true;
407     }
408 
409     if (isUndef()) {
410       assert(!RHS.isUnknown());
411       if (RHS.isUndef())
412         return false;
413       if (RHS.isConstant())
414         return markConstant(RHS.getConstant(), true);
415       if (RHS.isConstantRange())
416         return markConstantRange(RHS.getConstantRange(true),
417                                  Opts.setMayIncludeUndef());
418       return markOverdefined();
419     }
420 
421     if (isUnknown()) {
422       assert(!RHS.isUnknown() && "Unknow RHS should be handled earlier");
423       *this = RHS;
424       return true;
425     }
426 
427     if (isConstant()) {
428       if (RHS.isConstant() && getConstant() == RHS.getConstant())
429         return false;
430       if (RHS.isUndef())
431         return false;
432       // If the constant is a vector of integers, try to treat it as a range.
433       if (getConstant()->getType()->isVectorTy() &&
434           getConstant()->getType()->getScalarType()->isIntegerTy()) {
435         ConstantRange L = getConstant()->toConstantRange();
436         ConstantRange NewR = L.unionWith(
437             RHS.asConstantRange(L.getBitWidth(), /*UndefAllowed=*/true));
438         return markConstantRange(
439             std::move(NewR),
440             Opts.setMayIncludeUndef(RHS.isConstantRangeIncludingUndef()));
441       }
442       markOverdefined();
443       return true;
444     }
445 
446     if (isNotConstant()) {
447       if (RHS.isNotConstant() && getNotConstant() == RHS.getNotConstant())
448         return false;
449       markOverdefined();
450       return true;
451     }
452 
453     auto OldTag = Tag;
454     assert(isConstantRange() && "New ValueLattice type?");
455     if (RHS.isUndef()) {
456       Tag = constantrange_including_undef;
457       return OldTag != Tag;
458     }
459 
460     const ConstantRange &L = getConstantRange();
461     ConstantRange NewR = L.unionWith(
462         RHS.asConstantRange(L.getBitWidth(), /*UndefAllowed=*/true));
463     return markConstantRange(
464         std::move(NewR),
465         Opts.setMayIncludeUndef(RHS.isConstantRangeIncludingUndef()));
466   }
467 
468   // Compares this symbolic value with Other using Pred and returns either
469   /// true, false or undef constants, or nullptr if the comparison cannot be
470   /// evaluated.
471   LLVM_ABI Constant *getCompare(CmpInst::Predicate Pred, Type *Ty,
472                                 const ValueLatticeElement &Other,
473                                 const DataLayout &DL) const;
474 
475   /// Combine two sets of facts about the same value into a single set of
476   /// facts.  Note that this method is not suitable for merging facts along
477   /// different paths in a CFG; that's what the mergeIn function is for.  This
478   /// is for merging facts gathered about the same value at the same location
479   /// through two independent means.
480   /// Notes:
481   /// * This method does not promise to return the most precise possible lattice
482   ///   value implied by A and B.  It is allowed to return any lattice element
483   ///   which is at least as strong as *either* A or B (unless our facts
484   ///   conflict, see below).
485   /// * Due to unreachable code, the intersection of two lattice values could be
486   ///   contradictory.  If this happens, we return some valid lattice value so
487   ///   as not confuse the rest of LVI.  Ideally, we'd always return Undefined,
488   ///   but we do not make this guarantee.  TODO: This would be a useful
489   ///   enhancement.
490   LLVM_ABI ValueLatticeElement
491   intersect(const ValueLatticeElement &Other) const;
492 
getNumRangeExtensions()493   unsigned getNumRangeExtensions() const { return NumRangeExtensions; }
setNumRangeExtensions(unsigned N)494   void setNumRangeExtensions(unsigned N) { NumRangeExtensions = N; }
495 };
496 
497 static_assert(sizeof(ValueLatticeElement) <= 40,
498               "size of ValueLatticeElement changed unexpectedly");
499 
500 LLVM_ABI raw_ostream &operator<<(raw_ostream &OS,
501                                  const ValueLatticeElement &Val);
502 } // end namespace llvm
503 #endif
504