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 if (isa<UndefValue>(C)) 206 Res.markUndef(); 207 else 208 Res.markConstant(C); 209 return Res; 210 } getNot(Constant * C)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 } getOverdefined()234 static ValueLatticeElement getOverdefined() { 235 ValueLatticeElement Res; 236 Res.markOverdefined(); 237 return Res; 238 } 239 isUndef()240 bool isUndef() const { return Tag == undef; } isUnknown()241 bool isUnknown() const { return Tag == unknown; } isUnknownOrUndef()242 bool isUnknownOrUndef() const { return Tag == unknown || Tag == undef; } isConstant()243 bool isConstant() const { return Tag == constant; } isNotConstant()244 bool isNotConstant() const { return Tag == notconstant; } isConstantRangeIncludingUndef()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 } isOverdefined()256 bool isOverdefined() const { return Tag == overdefined; } 257 getConstant()258 Constant *getConstant() const { 259 assert(isConstant() && "Cannot get the constant of a non-constant!"); 260 return ConstVal; 261 } 262 getNotConstant()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 asConstantInteger()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 markOverdefined()287 bool markOverdefined() { 288 if (isOverdefined()) 289 return false; 290 destroy(); 291 Tag = overdefined; 292 return true; 293 } 294 markUndef()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 markNotConstant(Constant * V)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 getNumRangeExtensions()458 unsigned getNumRangeExtensions() const { return NumRangeExtensions; } setNumRangeExtensions(unsigned N)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 468