[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