Skip to content
This repository was archived by the owner on Oct 30, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/souper/Infer/Pruning.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class PruningManager {
std::vector<ValueCache> generateInputSets(std::vector<Inst *> &Inputs);
// For the LHS contained in @SC, check if the given input in @Cache is valid.
bool isInputValid(ValueCache &Cache);
std::unordered_map<Inst *, llvm::APInt> computeInputRestrictions();
Inst *Ante;
};

Expand Down
54 changes: 45 additions & 9 deletions lib/Infer/Pruning.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,35 @@ std::pair<llvm::APInt, llvm::APInt> knownBitsNarrowing
return {KnownNotZero, KnownNotOne};
}

std::unordered_map<Inst *, llvm::APInt>
PruningManager::computeInputRestrictions() {
std::unordered_map<Inst *, std::pair<llvm::APInt, llvm::APInt>> Seen;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you don't need to change it here but overall you should avoid using a std::pair for same-typed things like this, and instead pick an implementation which assigns appropriate names to things. here two separate variables would work, or else a struct with members called Zero and One or similar

// ^ SeenZero, SeenOne

for (auto &&V : InputVars) {
Seen[V].first = llvm::APInt(V->Width, 0);
Seen[V].second = llvm::APInt(V->Width, 0);
}

for (auto &&VC : InputVals) {
for (auto &&V : InputVars) {
if (VC[V].hasValue()) {
auto Val = VC[V].getValue();
Seen[V].first |= ~Val;
Seen[V].second |= Val;
}
}
}
std::unordered_map<Inst *, llvm::APInt> Result;
for (auto &&V : InputVars) {
Result[V] = ~(Seen[V].first & Seen[V].second);
}
return Result;
}

// TODO : Comment out debug stmts and conditions before benchmarking
bool PruningManager::isInfeasible(souper::Inst *RHS,
unsigned StatsLevel) {
unsigned StatsLevel) {
bool HasHole = !isConcrete(RHS, false, true);
bool RHSIsConcrete = isConcrete(RHS);

Expand All @@ -133,15 +159,25 @@ bool PruningManager::isInfeasible(souper::Inst *RHS,
getConstants(RHS, Constants);

if (!Constants.empty()) {
auto RestrictedBits = RestrictedBitsAnalysis().findRestrictedBits(RHS);
if ((~RestrictedBits & (LHSKnownBitsNoSpec.Zero | LHSKnownBitsNoSpec.One)) != 0) {
// if (RestrictedBits == 0 && (LHSKB.Zero != 0 || LHSKB.One != 0)) {
if (StatsLevel > 2) {
llvm::errs() << " pruned using restricted bits analysis.\n";
llvm::errs() << " LHSKB : " << KnownBitsAnalysis::knownBitsString(LHSKnownBitsNoSpec) << "\n";
llvm::errs() << " RB : " << RestrictedBits.toString(2, false) << "\n";
auto RBA = RestrictedBitsAnalysis();
if (!SC.PCs.empty()) {
// `Unrestricts` bits for which PC validated inputs
// have both zero and one values. Default is all `restricted`
// Instead of treating inputs as completely unrestricted,
// this imposes restrictions on inputs if there are no valid
// inputs to demonstrate otherwise.
RBA.RBCache = computeInputRestrictions();
}
if (SC.PCs.empty() || !InputVals.empty()) {
auto RestrictedBits = RBA.findRestrictedBits(RHS);
if ((~RestrictedBits & (LHSKnownBitsNoSpec.Zero | LHSKnownBitsNoSpec.One)) != 0) {
if (StatsLevel > 2) {
llvm::errs() << " pruned using restricted bits analysis.\n";
llvm::errs() << " LHSKB : " << KnownBitsAnalysis::knownBitsString(LHSKnownBitsNoSpec) << "\n";
llvm::errs() << " RB : " << RestrictedBits.toString(2, false) << "\n";
}
return true;
}
return true;
}

// auto LHSCR = ConstantRangeAnalysis().findConstantRange(SC.LHS, BlankCI, false);
Expand Down