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. destroy()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 MergeOptionsMergeOptions123 MergeOptions() : MergeOptions(false, false) {} 124 125 MergeOptions(bool MayIncludeUndef, bool CheckWiden, 126 unsigned MaxWidenSteps = 1) MayIncludeUndefMergeOptions127 : 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. ValueLatticeElement()148 ValueLatticeElement() : Tag(unknown), NumRangeExtensions(0) {} 149 ~ValueLatticeElement()150 ~ValueLatticeElement() { destroy(); } 151 ValueLatticeElement(const ValueLatticeElement & Other)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 ValueLatticeElement(ValueLatticeElement && Other)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 get(Constant * C)203 static ValueLatticeElement get(Constant *C) { 204 ValueLatticeElement Res; 205 Res.markConstant(C); 206 return Res; 207 } getNot(Constant * C)208 static ValueLatticeElement getNot(Constant *C) { 209 ValueLatticeElement Res; 210 assert(!isa<UndefValue>(C) && "!= undef is not supported"); 211 Res.markNotConstant(C); 212 return Res; 213 } 214 static ValueLatticeElement getRange(ConstantRange CR, 215 bool MayIncludeUndef = false) { 216 if (CR.isFullSet()) 217 return getOverdefined(); 218 219 if (CR.isEmptySet()) { 220 ValueLatticeElement Res; 221 if (MayIncludeUndef) 222 Res.markUndef(); 223 return Res; 224 } 225 226 ValueLatticeElement Res; 227 Res.markConstantRange(std::move(CR), 228 MergeOptions().setMayIncludeUndef(MayIncludeUndef)); 229 return Res; 230 } getOverdefined()231 static ValueLatticeElement getOverdefined() { 232 ValueLatticeElement Res; 233 Res.markOverdefined(); 234 return Res; 235 } 236 isUndef()237 bool isUndef() const { return Tag == undef; } isUnknown()238 bool isUnknown() const { return Tag == unknown; } isUnknownOrUndef()239 bool isUnknownOrUndef() const { return Tag == unknown || Tag == undef; } isConstant()240 bool isConstant() const { return Tag == constant; } isNotConstant()241 bool isNotConstant() const { return Tag == notconstant; } isConstantRangeIncludingUndef()242 bool isConstantRangeIncludingUndef() const { 243 return Tag == constantrange_including_undef; 244 } 245 /// Returns true if this value is a constant range. Use \p UndefAllowed to 246 /// exclude non-singleton constant ranges that may also be undef. Note that 247 /// this function also returns true if the range may include undef, but only 248 /// contains a single element. In that case, it can be replaced by a constant. 249 bool isConstantRange(bool UndefAllowed = true) const { 250 return Tag == constantrange || (Tag == constantrange_including_undef && 251 (UndefAllowed || Range.isSingleElement())); 252 } isOverdefined()253 bool isOverdefined() const { return Tag == overdefined; } 254 getConstant()255 Constant *getConstant() const { 256 assert(isConstant() && "Cannot get the constant of a non-constant!"); 257 return ConstVal; 258 } 259 getNotConstant()260 Constant *getNotConstant() const { 261 assert(isNotConstant() && "Cannot get the constant of a non-notconstant!"); 262 return ConstVal; 263 } 264 265 /// Returns the constant range for this value. Use \p UndefAllowed to exclude 266 /// non-singleton constant ranges that may also be undef. Note that this 267 /// function also returns a range if the range may include undef, but only 268 /// contains a single element. In that case, it can be replaced by a constant. 269 const ConstantRange &getConstantRange(bool UndefAllowed = true) const { 270 assert(isConstantRange(UndefAllowed) && 271 "Cannot get the constant-range of a non-constant-range!"); 272 return Range; 273 } 274 asConstantInteger()275 std::optional<APInt> asConstantInteger() const { 276 if (isConstant() && isa<ConstantInt>(getConstant())) { 277 return cast<ConstantInt>(getConstant())->getValue(); 278 } else if (isConstantRange() && getConstantRange().isSingleElement()) { 279 return *getConstantRange().getSingleElement(); 280 } 281 return std::nullopt; 282 } 283 284 ConstantRange asConstantRange(unsigned BW, bool UndefAllowed = false) const { 285 if (isConstantRange(UndefAllowed)) 286 return getConstantRange(); 287 if (isConstant()) 288 return getConstant()->toConstantRange(); 289 if (isUnknown()) 290 return ConstantRange::getEmpty(BW); 291 return ConstantRange::getFull(BW); 292 } 293 294 ConstantRange asConstantRange(Type *Ty, bool UndefAllowed = false) const { 295 assert(Ty->isIntOrIntVectorTy() && "Must be integer type"); 296 return asConstantRange(Ty->getScalarSizeInBits(), UndefAllowed); 297 } 298 markOverdefined()299 bool markOverdefined() { 300 if (isOverdefined()) 301 return false; 302 destroy(); 303 Tag = overdefined; 304 return true; 305 } 306 markUndef()307 bool markUndef() { 308 if (isUndef()) 309 return false; 310 311 assert(isUnknown()); 312 Tag = undef; 313 return true; 314 } 315 316 bool markConstant(Constant *V, bool MayIncludeUndef = false) { 317 if (isa<UndefValue>(V)) 318 return markUndef(); 319 320 if (isConstant()) { 321 assert(getConstant() == V && "Marking constant with different value"); 322 return false; 323 } 324 325 if (ConstantInt *CI = dyn_cast<ConstantInt>(V)) 326 return markConstantRange( 327 ConstantRange(CI->getValue()), 328 MergeOptions().setMayIncludeUndef(MayIncludeUndef)); 329 330 assert(isUnknown() || isUndef()); 331 Tag = constant; 332 ConstVal = V; 333 return true; 334 } 335 markNotConstant(Constant * V)336 bool markNotConstant(Constant *V) { 337 assert(V && "Marking constant with NULL"); 338 if (ConstantInt *CI = dyn_cast<ConstantInt>(V)) 339 return markConstantRange( 340 ConstantRange(CI->getValue() + 1, CI->getValue())); 341 342 if (isa<UndefValue>(V)) 343 return false; 344 345 if (isNotConstant()) { 346 assert(getNotConstant() == V && "Marking !constant with different value"); 347 return false; 348 } 349 350 assert(isUnknown()); 351 Tag = notconstant; 352 ConstVal = V; 353 return true; 354 } 355 356 /// Mark the object as constant range with \p NewR. If the object is already a 357 /// constant range, nothing changes if the existing range is equal to \p 358 /// NewR and the tag. Otherwise \p NewR must be a superset of the existing 359 /// range or the object must be undef. The tag is set to 360 /// constant_range_including_undef if either the existing value or the new 361 /// range may include undef. 362 bool markConstantRange(ConstantRange NewR, 363 MergeOptions Opts = MergeOptions()) { 364 assert(!NewR.isEmptySet() && "should only be called for non-empty sets"); 365 366 if (NewR.isFullSet()) 367 return markOverdefined(); 368 369 ValueLatticeElementTy OldTag = Tag; 370 ValueLatticeElementTy NewTag = 371 (isUndef() || isConstantRangeIncludingUndef() || Opts.MayIncludeUndef) 372 ? constantrange_including_undef 373 : constantrange; 374 if (isConstantRange()) { 375 Tag = NewTag; 376 if (getConstantRange() == NewR) 377 return Tag != OldTag; 378 379 // Simple form of widening. If a range is extended multiple times, go to 380 // overdefined. 381 if (Opts.CheckWiden && ++NumRangeExtensions > Opts.MaxWidenSteps) 382 return markOverdefined(); 383 384 assert(NewR.contains(getConstantRange()) && 385 "Existing range must be a subset of NewR"); 386 Range = std::move(NewR); 387 return true; 388 } 389 390 assert(isUnknown() || isUndef() || isConstant()); 391 assert((!isConstant() || NewR.contains(getConstant()->toConstantRange())) && 392 "Constant must be subset of new range"); 393 394 NumRangeExtensions = 0; 395 Tag = NewTag; 396 new (&Range) ConstantRange(std::move(NewR)); 397 return true; 398 } 399 400 /// Updates this object to approximate both this object and RHS. Returns 401 /// true if this object has been changed. 402 bool mergeIn(const ValueLatticeElement &RHS, 403 MergeOptions Opts = MergeOptions()) { 404 if (RHS.isUnknown() || isOverdefined()) 405 return false; 406 if (RHS.isOverdefined()) { 407 markOverdefined(); 408 return true; 409 } 410 411 if (isUndef()) { 412 assert(!RHS.isUnknown()); 413 if (RHS.isUndef()) 414 return false; 415 if (RHS.isConstant()) 416 return markConstant(RHS.getConstant(), true); 417 if (RHS.isConstantRange()) 418 return markConstantRange(RHS.getConstantRange(true), 419 Opts.setMayIncludeUndef()); 420 return markOverdefined(); 421 } 422 423 if (isUnknown()) { 424 assert(!RHS.isUnknown() && "Unknow RHS should be handled earlier"); 425 *this = RHS; 426 return true; 427 } 428 429 if (isConstant()) { 430 if (RHS.isConstant() && getConstant() == RHS.getConstant()) 431 return false; 432 if (RHS.isUndef()) 433 return false; 434 // If the constant is a vector of integers, try to treat it as a range. 435 if (getConstant()->getType()->isVectorTy() && 436 getConstant()->getType()->getScalarType()->isIntegerTy()) { 437 ConstantRange L = getConstant()->toConstantRange(); 438 ConstantRange NewR = L.unionWith( 439 RHS.asConstantRange(L.getBitWidth(), /*UndefAllowed=*/true)); 440 return markConstantRange( 441 std::move(NewR), 442 Opts.setMayIncludeUndef(RHS.isConstantRangeIncludingUndef())); 443 } 444 markOverdefined(); 445 return true; 446 } 447 448 if (isNotConstant()) { 449 if (RHS.isNotConstant() && getNotConstant() == RHS.getNotConstant()) 450 return false; 451 markOverdefined(); 452 return true; 453 } 454 455 auto OldTag = Tag; 456 assert(isConstantRange() && "New ValueLattice type?"); 457 if (RHS.isUndef()) { 458 Tag = constantrange_including_undef; 459 return OldTag != Tag; 460 } 461 462 const ConstantRange &L = getConstantRange(); 463 ConstantRange NewR = L.unionWith( 464 RHS.asConstantRange(L.getBitWidth(), /*UndefAllowed=*/true)); 465 return markConstantRange( 466 std::move(NewR), 467 Opts.setMayIncludeUndef(RHS.isConstantRangeIncludingUndef())); 468 } 469 470 // Compares this symbolic value with Other using Pred and returns either 471 /// true, false or undef constants, or nullptr if the comparison cannot be 472 /// evaluated. 473 Constant *getCompare(CmpInst::Predicate Pred, Type *Ty, 474 const ValueLatticeElement &Other, 475 const DataLayout &DL) const; 476 getNumRangeExtensions()477 unsigned getNumRangeExtensions() const { return NumRangeExtensions; } setNumRangeExtensions(unsigned N)478 void setNumRangeExtensions(unsigned N) { NumRangeExtensions = N; } 479 }; 480 481 static_assert(sizeof(ValueLatticeElement) <= 40, 482 "size of ValueLatticeElement changed unexpectedly"); 483 484 raw_ostream &operator<<(raw_ostream &OS, const ValueLatticeElement &Val); 485 } // end namespace llvm 486 #endif 487