Skip to content

Commit 84d8a2a

Browse files
committed
[ValueTracking] Add a helper class to detect information loss
1 parent 770fd38 commit 84d8a2a

File tree

4 files changed

+136
-0
lines changed

4 files changed

+136
-0
lines changed

llvm/include/llvm/Analysis/ValueTracking.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "llvm/IR/Intrinsics.h"
2525
#include <cassert>
2626
#include <cstdint>
27+
#include <variant>
2728

2829
namespace llvm {
2930

@@ -1195,6 +1196,23 @@ std::optional<bool> isImpliedByDomCondition(CmpInst::Predicate Pred,
11951196
const Value *LHS, const Value *RHS,
11961197
const Instruction *ContextI,
11971198
const DataLayout &DL);
1199+
1200+
/// A helper class to see whether we will lose information (KnownBits,
1201+
/// KnownFPClass...) after replacing all uses of \p From to \p To . It will help
1202+
/// us salvage information during transformation.
1203+
class ValueTrackingCache final {
1204+
Instruction *From;
1205+
1206+
bool NoPoison;
1207+
bool NoUndef;
1208+
1209+
std::variant<std::monostate, KnownBits, KnownFPClass> BeforeKnown;
1210+
1211+
public:
1212+
explicit ValueTrackingCache(Instruction *FromInst, const SimplifyQuery &SQ);
1213+
void detectInformationLoss(Value *To, const SimplifyQuery &SQ);
1214+
Instruction *getFromInst() const noexcept { return From; }
1215+
};
11981216
} // end namespace llvm
11991217

12001218
#endif // LLVM_ANALYSIS_VALUETRACKING_H

llvm/include/llvm/Transforms/InstCombine/InstCombiner.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner {
9191
/// Order of predecessors to canonicalize phi nodes towards.
9292
SmallDenseMap<BasicBlock *, SmallVector<BasicBlock *>, 8> PredOrder;
9393

94+
/// ValueTrackingCache is used for detecting information loss.
95+
#ifndef NDEBUG
96+
ValueTrackingCache *VTC = nullptr;
97+
#endif
98+
9499
public:
95100
InstCombiner(InstructionWorklist &Worklist, BuilderTy &Builder,
96101
bool MinimizeSize, AAResults *AA, AssumptionCache &AC,
@@ -402,6 +407,10 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner {
402407
V->takeName(&I);
403408

404409
I.replaceAllUsesWith(V);
410+
#ifndef NDEBUG
411+
if (&I == VTC->getFromInst())
412+
VTC->detectInformationLoss(V, SQ);
413+
#endif
405414
return &I;
406415
}
407416

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
#include <cstdint>
7979
#include <optional>
8080
#include <utility>
81+
#include <variant>
8182

8283
using namespace llvm;
8384
using namespace llvm::PatternMatch;
@@ -87,6 +88,9 @@ using namespace llvm::PatternMatch;
8788
static cl::opt<unsigned> DomConditionsMaxUses("dom-conditions-max-uses",
8889
cl::Hidden, cl::init(20));
8990

91+
// Checks whether we will lose information after simplification.
92+
static cl::opt<bool> DetectInformationLoss("detect-information-loss",
93+
cl::Hidden, cl::init(false));
9094

9195
/// Returns the bitwidth of the given scalar or pointer type. For vector types,
9296
/// returns the element type's bitwidth.
@@ -9053,3 +9057,101 @@ ConstantRange llvm::computeConstantRange(const Value *V, bool ForSigned,
90539057

90549058
return CR;
90559059
}
9060+
9061+
#ifndef NDEBUG
9062+
llvm::ValueTrackingCache::ValueTrackingCache(Instruction *FromInst,
9063+
const SimplifyQuery &SQ)
9064+
: From(FromInst) {
9065+
if (!DetectInformationLoss)
9066+
return;
9067+
9068+
NoPoison = isGuaranteedNotToBePoison(From, SQ.AC, From, SQ.DT);
9069+
NoUndef = isGuaranteedNotToBeUndef(From, SQ.AC, From, SQ.DT);
9070+
9071+
Type *Ty = From->getType();
9072+
if (Ty->isIntOrIntVectorTy() || Ty->isPtrOrPtrVectorTy()) {
9073+
// KnownBits
9074+
KnownBits Known =
9075+
computeKnownBits(From, /*Depth=*/0, SQ.getWithInstruction(From));
9076+
if (!Known.isUnknown())
9077+
BeforeKnown = Known;
9078+
} else if (Ty->isFPOrFPVectorTy()) {
9079+
// KnownFPClass
9080+
// TODO: use FMF flags
9081+
KnownFPClass Known = computeKnownFPClass(From, fcAllFlags, /*Depth=*/0,
9082+
SQ.getWithInstruction(From));
9083+
if (Known.KnownFPClasses != fcAllFlags || Known.SignBit)
9084+
BeforeKnown = Known;
9085+
}
9086+
}
9087+
9088+
void llvm::ValueTrackingCache::detectInformationLoss(Value *To,
9089+
const SimplifyQuery &SQ) {
9090+
if (!DetectInformationLoss)
9091+
return;
9092+
9093+
Instruction *ToInst = dyn_cast<Instruction>(To);
9094+
if (!ToInst)
9095+
return;
9096+
9097+
bool Inserted = false;
9098+
if (!ToInst->getParent()) {
9099+
ToInst->insertAfter(From);
9100+
Inserted = true;
9101+
}
9102+
9103+
auto WarnOnInformationLoss = [&](StringRef Attr) {
9104+
errs() << "Warning: the attribute " << Attr << " got lost when simplifying "
9105+
<< *From << " into " << *To << '\n';
9106+
};
9107+
9108+
// Poison
9109+
if (NoPoison && !isGuaranteedNotToBePoison(To, SQ.AC, ToInst, SQ.DT))
9110+
WarnOnInformationLoss("non-poison");
9111+
9112+
// Undef
9113+
if (NoUndef && !isGuaranteedNotToBeUndef(To, SQ.AC, ToInst, SQ.DT))
9114+
WarnOnInformationLoss("non-undef");
9115+
9116+
Type *Ty = From->getType();
9117+
if ((Ty->isIntOrIntVectorTy() || Ty->isPtrOrPtrVectorTy()) &&
9118+
std::holds_alternative<KnownBits>(BeforeKnown)) {
9119+
KnownBits &Before = std::get<KnownBits>(BeforeKnown);
9120+
KnownBits After =
9121+
computeKnownBits(To, /*Depth=*/0, SQ.getWithInstruction(ToInst));
9122+
// KnownBits of From should be a subset of KnownBits of To.
9123+
if (!Before.Zero.isSubsetOf(After.Zero) ||
9124+
!Before.One.isSubsetOf(After.One)) {
9125+
WarnOnInformationLoss("knownbits");
9126+
errs() << "Before: " << Before << '\n';
9127+
errs() << "After: " << After << '\n';
9128+
}
9129+
assert((Before.One & After.Zero).isZero() && "Possible miscompilation");
9130+
assert((Before.Zero & After.One).isZero() && "Possible miscompilation");
9131+
} else if (Ty->isFPOrFPVectorTy() &&
9132+
std::holds_alternative<KnownFPClass>(BeforeKnown)) {
9133+
// KnownFPClass
9134+
KnownFPClass &Before = std::get<KnownFPClass>(BeforeKnown);
9135+
// TODO: use FMF flags
9136+
KnownFPClass After = computeKnownFPClass(To, fcAllFlags, /*Depth=*/0,
9137+
SQ.getWithInstruction(ToInst));
9138+
// KnownFPClass of From should be a subset of KnownFPClass of To.
9139+
if ((Before.KnownFPClasses & After.KnownFPClasses) !=
9140+
Before.KnownFPClasses) {
9141+
WarnOnInformationLoss("fpclasses");
9142+
errs() << "Before: " << Before.KnownFPClasses << '\n';
9143+
errs() << "After: " << After.KnownFPClasses << '\n';
9144+
}
9145+
assert((Before.KnownFPClasses & After.KnownFPClasses) != fcNone &&
9146+
"Possible miscompilation");
9147+
if (Before.SignBit.has_value() && !After.SignBit.has_value())
9148+
WarnOnInformationLoss("sign");
9149+
assert((!Before.SignBit.has_value() || !After.SignBit.has_value() ||
9150+
Before.SignBit == After.SignBit) &&
9151+
"Possible miscompilation");
9152+
}
9153+
9154+
if (Inserted)
9155+
ToInst->removeFromParent();
9156+
}
9157+
#endif

llvm/lib/Transforms/InstCombine/InstructionCombining.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4683,6 +4683,10 @@ bool InstCombinerImpl::run() {
46834683
#endif
46844684
LLVM_DEBUG(raw_string_ostream SS(OrigI); I->print(SS); OrigI = SS.str(););
46854685
LLVM_DEBUG(dbgs() << "IC: Visiting: " << OrigI << '\n');
4686+
#ifndef NDEBUG
4687+
ValueTrackingCache Cache(I, SQ);
4688+
VTC = &Cache;
4689+
#endif
46864690

46874691
if (Instruction *Result = visit(*I)) {
46884692
++NumCombined;
@@ -4718,6 +4722,9 @@ bool InstCombinerImpl::run() {
47184722
Worklist.pushUsersToWorkList(*Result);
47194723
Worklist.push(Result);
47204724

4725+
#ifndef NDEBUG
4726+
Cache.detectInformationLoss(Result, SQ);
4727+
#endif
47214728
eraseInstFromFunction(*I);
47224729
} else {
47234730
LLVM_DEBUG(dbgs() << "IC: Mod = " << OrigI << '\n'

0 commit comments

Comments
 (0)