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