[llvm] [ValueTracking] Add a helper to detect information loss (PR #82674)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 22 10:47:59 PST 2024


https://github.com/dtcxzyw created https://github.com/llvm/llvm-project/pull/82674

None

>From b707230e49e0fc31cf345aec11447ee096855dd7 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 23 Feb 2024 02:14:01 +0800
Subject: [PATCH] [ValueTracking] Add a helper to detect information loss

---
 llvm/include/llvm/Analysis/ValueTracking.h    |  6 ++
 .../Transforms/InstCombine/InstCombiner.h     |  1 +
 llvm/lib/Analysis/ValueTracking.cpp           | 81 +++++++++++++++++++
 .../InstCombine/InstructionCombining.cpp      |  1 +
 4 files changed, 89 insertions(+)

diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index f0d0ee554f12b2..f5c31732d9f9bb 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -1195,6 +1195,12 @@ std::optional<bool> isImpliedByDomCondition(CmpInst::Predicate Pred,
                                             const Value *LHS, const Value *RHS,
                                             const Instruction *ContextI,
                                             const DataLayout &DL);
+
+/// A helper function to see whether we will lose information (KnownBits,
+/// KnownFPClass...) after replacing all uses of \p From to \p To . It will help
+/// us salvage information during transformation.
+void detectInformationLoss(Instruction *From, Value *To,
+                           const SimplifyQuery &SQ);
 } // end namespace llvm
 
 #endif // LLVM_ANALYSIS_VALUETRACKING_H
diff --git a/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h b/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
index 93090431cbb69f..d42848ebf90a33 100644
--- a/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
+++ b/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
@@ -401,6 +401,7 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner {
     if (V->use_empty() && isa<Instruction>(V) && !V->hasName() && I.hasName())
       V->takeName(&I);
 
+    detectInformationLoss(&I, V, SQ);
     I.replaceAllUsesWith(V);
     return &I;
   }
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 04f317228b3ea7..e1103d7f9151b9 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -87,6 +87,9 @@ using namespace llvm::PatternMatch;
 static cl::opt<unsigned> DomConditionsMaxUses("dom-conditions-max-uses",
                                               cl::Hidden, cl::init(20));
 
+// Checks whether we will lose information after simplification.
+static cl::opt<bool> DetectInformationLoss("detect-information-loss",
+                                           cl::Hidden, cl::init(false));
 
 /// Returns the bitwidth of the given scalar or pointer type. For vector types,
 /// returns the element type's bitwidth.
@@ -9053,3 +9056,81 @@ ConstantRange llvm::computeConstantRange(const Value *V, bool ForSigned,
 
   return CR;
 }
+
+void llvm::detectInformationLoss(Instruction *From, Value *To,
+                                 const SimplifyQuery &SQ) {
+#ifdef NDEBUG
+  return;
+#endif
+  if (!DetectInformationLoss)
+    return;
+
+  if (From == To)
+    return;
+  Instruction *ToInst = dyn_cast<Instruction>(To);
+  if (!ToInst)
+    return;
+
+  bool Inserted = false;
+  if (!ToInst->getParent()) {
+    ToInst->insertAfter(From);
+    Inserted = true;
+  }
+
+  auto WarnOnInformationLoss = [&](StringRef Attr) {
+    errs() << "Warning: the attribute " << Attr << " got lost when simplifying "
+           << *From << " into " << *To << '\n';
+  };
+
+  // Poison
+  if (isGuaranteedNotToBePoison(From, SQ.AC, From, SQ.DT) &&
+      !isGuaranteedNotToBePoison(To, SQ.AC, ToInst, SQ.DT))
+    WarnOnInformationLoss("non-poison");
+
+  // Undef
+  if (isGuaranteedNotToBeUndef(From, SQ.AC, From, SQ.DT) &&
+      !isGuaranteedNotToBeUndef(To, SQ.AC, ToInst, SQ.DT))
+    WarnOnInformationLoss("non-undef");
+
+  Type *Ty = From->getType();
+  if (Ty->isIntOrIntVectorTy() || Ty->isPtrOrPtrVectorTy()) {
+    // KnownBits
+    KnownBits Before =
+        computeKnownBits(From, /*Depth=*/0, SQ.getWithInstruction(From));
+    KnownBits After =
+        computeKnownBits(To, /*Depth=*/0, SQ.getWithInstruction(ToInst));
+    // KnownBits of From should be a subset of KnownBits of To.
+    if (!Before.Zero.isSubsetOf(After.Zero) ||
+        !Before.One.isSubsetOf(After.One)) {
+      WarnOnInformationLoss("knownbits");
+      errs() << "Before: " << Before << '\n';
+      errs() << "After: " << After << '\n';
+    }
+    assert((Before.One & After.Zero).isZero() && "Possible miscompilation");
+    assert((Before.Zero & After.One).isZero() && "Possible miscompilation");
+  } else if (Ty->isFPOrFPVectorTy()) {
+    // KnownFPClass
+    // TODO: use FMF flags
+    KnownFPClass Before = computeKnownFPClass(From, fcAllFlags, /*Depth=*/0,
+                                              SQ.getWithInstruction(From));
+    KnownFPClass After = computeKnownFPClass(To, fcAllFlags, /*Depth=*/0,
+                                             SQ.getWithInstruction(ToInst));
+    // KnownFPClass of From should be a subset of KnownFPClass of To.
+    if ((Before.KnownFPClasses & After.KnownFPClasses) !=
+        Before.KnownFPClasses) {
+      WarnOnInformationLoss("fpclasses");
+      errs() << "Before: " << Before.KnownFPClasses << '\n';
+      errs() << "After: " << After.KnownFPClasses << '\n';
+    }
+    assert((Before.KnownFPClasses & After.KnownFPClasses) != fcNone &&
+           "Possible miscompilation");
+    if (Before.SignBit.has_value() && !After.SignBit.has_value())
+      WarnOnInformationLoss("sign");
+    assert((!Before.SignBit.has_value() || !After.SignBit.has_value() ||
+            Before.SignBit == After.SignBit) &&
+           "Possible miscompilation");
+  }
+
+  if (Inserted)
+    ToInst->removeFromParent();
+}
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 4af455c37c788c..bfbf9f95b81a10 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -4694,6 +4694,7 @@ bool InstCombinerImpl::run() {
         Result->copyMetadata(*I,
                              {LLVMContext::MD_dbg, LLVMContext::MD_annotation});
         // Everything uses the new instruction now.
+        detectInformationLoss(I, Result, SQ);
         I->replaceAllUsesWith(Result);
 
         // Move the name to the new instruction first.



More information about the llvm-commits mailing list