[llvm] [LVI][CVP] `getRangeFor` propagates `MayIncludeUndef` (PR #68190)

via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 4 01:37:50 PDT 2023


https://github.com/DianQK created https://github.com/llvm/llvm-project/pull/68190

Fix mis-compilation encountered in https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Implementing.20niche.20checks.

I'm still thinking about interface changes and test cases.

>From be2a22b1bb4da30a08753bb6f3601b42ac48abe0 Mon Sep 17 00:00:00 2001
From: DianQK <dianqk at dianqk.net>
Date: Wed, 4 Oct 2023 15:50:25 +0800
Subject: [PATCH] [LVI][CVP] `getRangeFor` propagates `MayIncludeUndef`

---
 llvm/lib/Analysis/LazyValueInfo.cpp | 36 ++++++++++++++++++++---------
 1 file changed, 25 insertions(+), 11 deletions(-)

diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index 0892aa9d75fb417..8140b18d54e54d0 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -411,7 +411,8 @@ class LazyValueInfoImpl {
   std::optional<ValueLatticeElement> solveBlockValueSelect(SelectInst *S,
                                                            BasicBlock *BB);
   std::optional<ConstantRange> getRangeFor(Value *V, Instruction *CxtI,
-                                           BasicBlock *BB);
+                                           BasicBlock *BB,
+                                           bool &MayIncludeUndef);
   std::optional<ValueLatticeElement> solveBlockValueBinaryOpImpl(
       Instruction *I, BasicBlock *BB,
       std::function<ConstantRange(const ConstantRange &, const ConstantRange &)>
@@ -892,10 +893,14 @@ LazyValueInfoImpl::solveBlockValueSelect(SelectInst *SI, BasicBlock *BB) {
 }
 
 std::optional<ConstantRange>
-LazyValueInfoImpl::getRangeFor(Value *V, Instruction *CxtI, BasicBlock *BB) {
+LazyValueInfoImpl::getRangeFor(Value *V, Instruction *CxtI, BasicBlock *BB,
+                               bool &MayIncludeUndef) {
   std::optional<ValueLatticeElement> OptVal = getBlockValue(V, BB, CxtI);
   if (!OptVal)
     return std::nullopt;
+  // TODO: A better way to update MayIncludeUndef for multiple calls?
+  if (OptVal->isUndef() || OptVal->isConstantRangeIncludingUndef())
+    MayIncludeUndef = true;
   return getConstantRangeOrFull(*OptVal, V->getType(), DL);
 }
 
@@ -922,10 +927,12 @@ LazyValueInfoImpl::solveBlockValueCast(CastInst *CI, BasicBlock *BB) {
     return ValueLatticeElement::getOverdefined();
   }
 
+  bool MayIncludeUndef = false;
   // Figure out the range of the LHS.  If that fails, we still apply the
   // transfer rule on the full set since we may be able to locally infer
   // interesting facts.
-  std::optional<ConstantRange> LHSRes = getRangeFor(CI->getOperand(0), CI, BB);
+  std::optional<ConstantRange> LHSRes =
+      getRangeFor(CI->getOperand(0), CI, BB, MayIncludeUndef);
   if (!LHSRes)
     // More work to do before applying this transfer rule.
     return std::nullopt;
@@ -936,8 +943,8 @@ LazyValueInfoImpl::solveBlockValueCast(CastInst *CI, BasicBlock *BB) {
   // NOTE: We're currently limited by the set of operations that ConstantRange
   // can evaluate symbolically.  Enhancing that set will allows us to analyze
   // more definitions.
-  return ValueLatticeElement::getRange(LHSRange.castOp(CI->getOpcode(),
-                                                       ResultBitWidth));
+  return ValueLatticeElement::getRange(
+      LHSRange.castOp(CI->getOpcode(), ResultBitWidth), MayIncludeUndef);
 }
 
 std::optional<ValueLatticeElement>
@@ -949,15 +956,19 @@ LazyValueInfoImpl::solveBlockValueBinaryOpImpl(
   // conservative range, but apply the transfer rule anyways.  This
   // lets us pick up facts from expressions like "and i32 (call i32
   // @foo()), 32"
-  std::optional<ConstantRange> LHSRes = getRangeFor(I->getOperand(0), I, BB);
-  std::optional<ConstantRange> RHSRes = getRangeFor(I->getOperand(1), I, BB);
+  bool MayIncludeUndef = false;
+  std::optional<ConstantRange> LHSRes =
+      getRangeFor(I->getOperand(0), I, BB, MayIncludeUndef);
+  std::optional<ConstantRange> RHSRes =
+      getRangeFor(I->getOperand(1), I, BB, MayIncludeUndef);
   if (!LHSRes || !RHSRes)
     // More work to do before applying this transfer rule.
     return std::nullopt;
 
   const ConstantRange &LHSRange = *LHSRes;
   const ConstantRange &RHSRange = *RHSRes;
-  return ValueLatticeElement::getRange(OpFn(LHSRange, RHSRange));
+  return ValueLatticeElement::getRange(OpFn(LHSRange, RHSRange),
+                                       MayIncludeUndef);
 }
 
 std::optional<ValueLatticeElement>
@@ -1002,16 +1013,19 @@ LazyValueInfoImpl::solveBlockValueIntrinsic(IntrinsicInst *II, BasicBlock *BB) {
     return MetadataVal;
   }
 
+  bool MayIncludeUndef = false;
   SmallVector<ConstantRange, 2> OpRanges;
   for (Value *Op : II->args()) {
-    std::optional<ConstantRange> Range = getRangeFor(Op, II, BB);
+    std::optional<ConstantRange> Range =
+        getRangeFor(Op, II, BB, MayIncludeUndef);
     if (!Range)
       return std::nullopt;
     OpRanges.push_back(*Range);
   }
 
-  return intersect(ValueLatticeElement::getRange(ConstantRange::intrinsic(
-                       II->getIntrinsicID(), OpRanges)),
+  return intersect(ValueLatticeElement::getRange(
+                       ConstantRange::intrinsic(II->getIntrinsicID(), OpRanges),
+                       MayIncludeUndef),
                    MetadataVal);
 }
 



More information about the llvm-commits mailing list