Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 1 | //===- ValueLattice.h - Value constraint analysis ---------------*- C++ -*-===// |
| 2 | // |
Andrew Walbran | 16937d0 | 2019-10-22 13:54:20 +0100 | [diff] [blame] | 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 |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 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" |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 14 | #include "llvm/IR/Instructions.h" |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 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". |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 33 | /// Transition to any other state allowed. |
| 34 | unknown, |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 35 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 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 |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 51 | constant, |
| 52 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 53 | /// This Value is known to not have the specified value. (For constant |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 54 | /// integers, constantrange is used instead. As above, integer typed |
| 55 | /// constantexprs can appear here.) |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 56 | /// Transition allowed to the following states: |
| 57 | /// overdefined |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 58 | notconstant, |
| 59 | |
| 60 | /// The Value falls within this range. (Used only for integer typed values.) |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 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 |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 65 | constantrange, |
| 66 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 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 | |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 74 | /// We can not precisely model the dynamic values this value might take. |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 75 | /// No transitions are allowed after reaching overdefined. |
| 76 | overdefined, |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 77 | }; |
| 78 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 79 | ValueLatticeElementTy Tag : 8; |
| 80 | /// Number of times a constant range has been extended with widening enabled. |
| 81 | unsigned NumRangeExtensions : 8; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 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 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 91 | /// Destroy contents of lattice value, without destructing the object. |
| 92 | void destroy() { |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 93 | switch (Tag) { |
| 94 | case overdefined: |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 95 | case unknown: |
| 96 | case undef: |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 97 | case constant: |
| 98 | case notconstant: |
| 99 | break; |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 100 | case constantrange_including_undef: |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 101 | case constantrange: |
| 102 | Range.~ConstantRange(); |
| 103 | break; |
| 104 | }; |
| 105 | } |
| 106 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 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; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 112 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 113 | /// Handle repeatedly extending a range by going to overdefined after a |
| 114 | /// number of steps. |
| 115 | bool CheckWiden; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 116 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 117 | /// The number of allowed widening steps (including setting the range |
| 118 | /// initially). |
| 119 | unsigned MaxWidenSteps; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 120 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 121 | MergeOptions() : MergeOptions(false, false) {} |
| 122 | |
| 123 | MergeOptions(bool MayIncludeUndef, bool CheckWiden, |
| 124 | unsigned MaxWidenSteps = 1) |
| 125 | : 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. |
| 146 | ValueLatticeElement() : Tag(unknown), NumRangeExtensions(0) {} |
| 147 | |
| 148 | ~ValueLatticeElement() { destroy(); } |
| 149 | |
| 150 | ValueLatticeElement(const ValueLatticeElement &Other) |
| 151 | : Tag(Other.Tag), NumRangeExtensions(0) { |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 152 | switch (Other.Tag) { |
| 153 | case constantrange: |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 154 | case constantrange_including_undef: |
| 155 | new (&Range) ConstantRange(Other.Range); |
| 156 | NumRangeExtensions = Other.NumRangeExtensions; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 157 | break; |
| 158 | case constant: |
| 159 | case notconstant: |
| 160 | ConstVal = Other.ConstVal; |
| 161 | break; |
| 162 | case overdefined: |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 163 | case unknown: |
| 164 | case undef: |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 165 | break; |
| 166 | } |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 167 | } |
| 168 | |
| 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)); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 198 | return *this; |
| 199 | } |
| 200 | |
| 201 | static ValueLatticeElement get(Constant *C) { |
| 202 | ValueLatticeElement Res; |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 203 | if (isa<UndefValue>(C)) |
| 204 | Res.markUndef(); |
| 205 | else |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 206 | Res.markConstant(C); |
| 207 | return Res; |
| 208 | } |
| 209 | static ValueLatticeElement getNot(Constant *C) { |
| 210 | ValueLatticeElement Res; |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 211 | assert(!isa<UndefValue>(C) && "!= undef is not supported"); |
| 212 | Res.markNotConstant(C); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 213 | return Res; |
| 214 | } |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 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 | |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 227 | ValueLatticeElement Res; |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 228 | Res.markConstantRange(std::move(CR), |
| 229 | MergeOptions().setMayIncludeUndef(MayIncludeUndef)); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 230 | return Res; |
| 231 | } |
| 232 | static ValueLatticeElement getOverdefined() { |
| 233 | ValueLatticeElement Res; |
| 234 | Res.markOverdefined(); |
| 235 | return Res; |
| 236 | } |
| 237 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 238 | bool isUndef() const { return Tag == undef; } |
| 239 | bool isUnknown() const { return Tag == unknown; } |
| 240 | bool isUnknownOrUndef() const { return Tag == unknown || Tag == undef; } |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 241 | bool isConstant() const { return Tag == constant; } |
| 242 | bool isNotConstant() const { return Tag == notconstant; } |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 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 | } |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 254 | bool isOverdefined() const { return Tag == overdefined; } |
| 255 | |
| 256 | Constant *getConstant() const { |
| 257 | assert(isConstant() && "Cannot get the constant of a non-constant!"); |
| 258 | return ConstVal; |
| 259 | } |
| 260 | |
| 261 | Constant *getNotConstant() const { |
| 262 | assert(isNotConstant() && "Cannot get the constant of a non-notconstant!"); |
| 263 | return ConstVal; |
| 264 | } |
| 265 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 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) && |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 272 | "Cannot get the constant-range of a non-constant-range!"); |
| 273 | return Range; |
| 274 | } |
| 275 | |
| 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 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 285 | bool markOverdefined() { |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 286 | if (isOverdefined()) |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 287 | return false; |
| 288 | destroy(); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 289 | Tag = overdefined; |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 290 | return true; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 291 | } |
| 292 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 293 | bool markUndef() { |
| 294 | if (isUndef()) |
| 295 | return false; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 296 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 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()); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 317 | Tag = constant; |
| 318 | ConstVal = V; |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 319 | return true; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 320 | } |
| 321 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 322 | bool markNotConstant(Constant *V) { |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 323 | assert(V && "Marking constant with NULL"); |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 324 | if (ConstantInt *CI = dyn_cast<ConstantInt>(V)) |
| 325 | return markConstantRange( |
| 326 | ConstantRange(CI->getValue() + 1, CI->getValue())); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 327 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 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()); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 337 | Tag = notconstant; |
| 338 | ConstVal = V; |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 339 | return true; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 340 | } |
| 341 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 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; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 360 | if (isConstantRange()) { |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 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; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 374 | } |
| 375 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 376 | assert(isUnknown() || isUndef()); |
| 377 | |
| 378 | NumRangeExtensions = 0; |
| 379 | Tag = NewTag; |
| 380 | new (&Range) ConstantRange(std::move(NewR)); |
| 381 | return true; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 382 | } |
| 383 | |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 384 | /// Updates this object to approximate both this object and RHS. Returns |
| 385 | /// true if this object has been changed. |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 386 | bool mergeIn(const ValueLatticeElement &RHS, |
| 387 | MergeOptions Opts = MergeOptions()) { |
| 388 | if (RHS.isUnknown() || isOverdefined()) |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 389 | return false; |
| 390 | if (RHS.isOverdefined()) { |
| 391 | markOverdefined(); |
| 392 | return true; |
| 393 | } |
| 394 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 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"); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 409 | *this = RHS; |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 410 | return true; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 411 | } |
| 412 | |
| 413 | if (isConstant()) { |
| 414 | if (RHS.isConstant() && getConstant() == RHS.getConstant()) |
| 415 | return false; |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 416 | if (RHS.isUndef()) |
| 417 | return false; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 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 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 429 | auto OldTag = Tag; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 430 | assert(isConstantRange() && "New ValueLattice type?"); |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 431 | if (RHS.isUndef()) { |
| 432 | Tag = constantrange_including_undef; |
| 433 | return OldTag != Tag; |
| 434 | } |
| 435 | |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 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 | } |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 442 | |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 443 | ConstantRange NewR = getConstantRange().unionWith(RHS.getConstantRange()); |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 444 | return markConstantRange( |
| 445 | std::move(NewR), |
| 446 | Opts.setMayIncludeUndef(RHS.isConstantRangeIncludingUndef())); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 447 | } |
| 448 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 449 | // Compares this symbolic value with Other using Pred and returns either |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 450 | /// true, false or undef constants, or nullptr if the comparison cannot be |
| 451 | /// evaluated. |
| 452 | Constant *getCompare(CmpInst::Predicate Pred, Type *Ty, |
| 453 | const ValueLatticeElement &Other) const { |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 454 | if (isUnknownOrUndef() || Other.isUnknownOrUndef()) |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 455 | return UndefValue::get(Ty); |
| 456 | |
| 457 | if (isConstant() && Other.isConstant()) |
| 458 | return ConstantExpr::getCompare(Pred, getConstant(), Other.getConstant()); |
| 459 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 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 | |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 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 | } |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 486 | |
| 487 | unsigned getNumRangeExtensions() const { return NumRangeExtensions; } |
| 488 | void setNumRangeExtensions(unsigned N) { NumRangeExtensions = N; } |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 489 | }; |
| 490 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 491 | static_assert(sizeof(ValueLatticeElement) <= 40, |
| 492 | "size of ValueLatticeElement changed unexpectedly"); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 493 | |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 494 | raw_ostream &operator<<(raw_ostream &OS, const ValueLatticeElement &Val); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 495 | } // end namespace llvm |
| 496 | #endif |