SimplifyCFG: Refactor GatherConstantCompares() result in a struct

Code seems cleaner and easier to understand this way

llvm-svn: 222416
This commit is contained in:
Mehdi Amini 2014-11-20 06:51:02 +00:00
parent eeea5f88aa
commit 65253e76ed
1 changed files with 147 additions and 136 deletions

View File

@ -357,29 +357,55 @@ static ConstantInt *GetConstantInt(Value *V, const DataLayout *DL) {
return nullptr; return nullptr;
} }
/// Given a chain of or (||) or and (&&) comparison of a value against a
/// constant, this will try to recover the information required for a switch
/// structure.
/// It will depth-first traverse the chain of comparison, seeking for patterns
/// like %a == 12 or %a < 4 and combine them to produce a set of integer
/// representing the different cases for the switch.
/// Note that if the chain is composed of '||' it will build the set of elements
/// that matches the comparisons (i.e. any of this value validate the chain)
/// while for a chain of '&&' it will build the set elements that make the test
/// fail.
struct ConstantComparesGatherer {
Value *CompValue = nullptr; /// Value found for the switch comparison
Value *Extra = nullptr; /// Extra clause to be checked before the switch
SmallVector<ConstantInt*, 8> Vals; /// Set of integers to match in switch
unsigned UsedICmps = 0; /// Number of comparisons matched in the and/or chain
// Try to match Instruction I as a comparison against a constant and populates /// Construct and compute the result for the comparison instruction Cond
// Vals with the set of value that match (or does not depending on isEQ). ConstantComparesGatherer(Instruction *Cond, const DataLayout *DL) {
// Return nullptr on failure, or return the Value the comparison matched against gather(Cond, DL);
// on success }
// CurrValue, if supplied, is the value we want to match against. The function
// is expected to fail if a match is found but the value compared to is not the
// one expected. If CurrValue is supplied, the return value has to be either
// nullptr or CurrValue
static Value* GatherConstantComparesMatch(Instruction *I,
Value *CurrValue,
SmallVectorImpl<ConstantInt*> &Vals,
const DataLayout *DL,
unsigned &UsedICmps,
bool isEQ) {
/// Prevent copy
ConstantComparesGatherer(const ConstantComparesGatherer&) = delete;
ConstantComparesGatherer &operator=(const ConstantComparesGatherer&) = delete;
private:
/// Try to set the current value used for the comparison, it succeeds only if
/// it wasn't set before or if the new value is the same as the old one
bool setValueOnce(Value *NewVal) {
if(CompValue && CompValue != NewVal) return false;
return CompValue = NewVal;
}
/// Try to match Instruction "I" as a comparison against a constant and
/// populates the array Vals with the set of values that match (or do not
/// match depending on isEQ).
/// Return false on failure. On success, the Value the comparison matched
/// against is placed in CompValue.
/// If CompValue is already set, the function is expected to fail if a match
/// is found but the value compared to is different.
bool matchInstruction(Instruction *I, const DataLayout *DL, bool isEQ) {
// If this is an icmp against a constant, handle this as one of the cases. // If this is an icmp against a constant, handle this as one of the cases.
ICmpInst *ICI; ICmpInst *ICI;
ConstantInt *C; ConstantInt *C;
if (!((ICI = dyn_cast<ICmpInst>(I)) && if (!((ICI = dyn_cast<ICmpInst>(I)) &&
(C = GetConstantInt(I->getOperand(1), DL)))) { (C = GetConstantInt(I->getOperand(1), DL)))) {
return nullptr; return false;
} }
Value *RHSVal; Value *RHSVal;
@ -394,20 +420,20 @@ static Value* GatherConstantComparesMatch(Instruction *I,
APInt Not = ~RHSC->getValue(); APInt Not = ~RHSC->getValue();
if (Not.isPowerOf2()) { if (Not.isPowerOf2()) {
// If we already have a value for the switch, it has to match! // If we already have a value for the switch, it has to match!
if(CurrValue && CurrValue != RHSVal) if(!setValueOnce(RHSVal))
return nullptr; return false;
Vals.push_back(C); Vals.push_back(C);
Vals.push_back(ConstantInt::get(C->getContext(), Vals.push_back(ConstantInt::get(C->getContext(),
C->getValue() | Not)); C->getValue() | Not));
UsedICmps++; UsedICmps++;
return RHSVal; return true;
} }
} }
// If we already have a value for the switch, it has to match! // If we already have a value for the switch, it has to match!
if(CurrValue && CurrValue != ICI->getOperand(0)) if(!setValueOnce(ICI->getOperand(0)))
return nullptr; return false;
UsedICmps++; UsedICmps++;
Vals.push_back(C); Vals.push_back(C);
@ -426,10 +452,6 @@ static Value* GatherConstantComparesMatch(Instruction *I,
CandidateVal = RHSVal; CandidateVal = RHSVal;
} }
// If we already have a value for the switch, it has to match!
if(CurrValue && CurrValue != CandidateVal)
return nullptr;
// If this is an and/!= check, then we are looking to build the set of // If this is an and/!= check, then we are looking to build the set of
// value that *don't* pass the and chain. I.e. to turn "x ugt 2" into // value that *don't* pass the and chain. I.e. to turn "x ugt 2" into
// x != 0 && x != 1. // x != 0 && x != 1.
@ -438,29 +460,29 @@ static Value* GatherConstantComparesMatch(Instruction *I,
// If there are a ton of values, we don't want to make a ginormous switch. // If there are a ton of values, we don't want to make a ginormous switch.
if (Span.getSetSize().ugt(8) || Span.isEmptySet()) { if (Span.getSetSize().ugt(8) || Span.isEmptySet()) {
return nullptr; return false;
} }
// If we already have a value for the switch, it has to match!
if(!setValueOnce(CandidateVal))
return false;
// Add all values from the range to the set // Add all values from the range to the set
for (APInt Tmp = Span.getLower(); Tmp != Span.getUpper(); ++Tmp) for (APInt Tmp = Span.getLower(); Tmp != Span.getUpper(); ++Tmp)
Vals.push_back(ConstantInt::get(I->getContext(), Tmp)); Vals.push_back(ConstantInt::get(I->getContext(), Tmp));
UsedICmps++; UsedICmps++;
return CandidateVal; return true;
} }
/// GatherConstantCompares - Given a potentially 'or'd or 'and'd together /// gather - Given a potentially 'or'd or 'and'd together collection of icmp
/// collection of icmp eq/ne instructions that compare a value against a /// eq/ne/lt/gt instructions that compare a value against a constant, extract
/// constant, return the value being compared, and stick the constant into the /// the value being compared, and stick the list constants into the Vals
/// Values vector. /// vector.
/// One "Extra" case is allowed to differ from the other. /// One "Extra" case is allowed to differ from the other.
static Value * void gather(Value *V, const DataLayout *DL) {
GatherConstantCompares(Value *V, SmallVectorImpl<ConstantInt*> &Vals, Value *&Extra,
const DataLayout *DL, unsigned &UsedICmps) {
Instruction *I = dyn_cast<Instruction>(V); Instruction *I = dyn_cast<Instruction>(V);
if (!I) return nullptr;
bool isEQ = (I->getOpcode() == Instruction::Or); bool isEQ = (I->getOpcode() == Instruction::Or);
// Keep a stack (SmallVector for efficiency) for depth-first traversal // Keep a stack (SmallVector for efficiency) for depth-first traversal
@ -469,14 +491,10 @@ GatherConstantCompares(Value *V, SmallVectorImpl<ConstantInt*> &Vals, Value *&Ex
// Initialize // Initialize
DFT.push_back(V); DFT.push_back(V);
// Will hold the value used for the switch comparison
Value *CurrValue = nullptr;
while(!DFT.empty()) { while(!DFT.empty()) {
V = DFT.pop_back_val(); V = DFT.pop_back_val();
if (Instruction *I = dyn_cast<Instruction>(V)) { if (Instruction *I = dyn_cast<Instruction>(V)) {
// If it is a || (or && depending on isEQ), process the operands. // If it is a || (or && depending on isEQ), process the operands.
if (I->getOpcode() == (isEQ ? Instruction::Or : Instruction::And)) { if (I->getOpcode() == (isEQ ? Instruction::Or : Instruction::And)) {
DFT.push_back(I->getOperand(1)); DFT.push_back(I->getOperand(1));
@ -485,32 +503,24 @@ GatherConstantCompares(Value *V, SmallVectorImpl<ConstantInt*> &Vals, Value *&Ex
} }
// Try to match the current instruction // Try to match the current instruction
if (Value *Matched = GatherConstantComparesMatch(I, if (matchInstruction(I, DL, isEQ))
CurrValue,
Vals,
DL,
UsedICmps,
isEQ)) {
// Match succeed, continue the loop // Match succeed, continue the loop
CurrValue = Matched;
continue; continue;
} }
}
// One element of the sequence of || (or &&) could not be match as a // One element of the sequence of || (or &&) could not be match as a
// comparison against the same value as the others. // comparison against the same value as the others.
// We allow only one "Extra" case to be checked before the switch // We allow only one "Extra" case to be checked before the switch
if (Extra == nullptr) { if (!Extra) {
Extra = V; Extra = V;
continue; continue;
} }
return nullptr; // Failed to parse a proper sequence, abort now
CompValue = nullptr;
break;
} }
}
// Return the value to be used for the switch comparison (if any) };
return CurrValue;
}
static void EraseTerminatorInstAndDCECond(TerminatorInst *TI) { static void EraseTerminatorInstAndDCECond(TerminatorInst *TI) {
Instruction *Cond = nullptr; Instruction *Cond = nullptr;
@ -2810,18 +2820,17 @@ static bool SimplifyBranchOnICmpChain(BranchInst *BI, const DataLayout *DL,
Instruction *Cond = dyn_cast<Instruction>(BI->getCondition()); Instruction *Cond = dyn_cast<Instruction>(BI->getCondition());
if (!Cond) return false; if (!Cond) return false;
// Change br (X == 0 | X == 1), T, F into a switch instruction. // Change br (X == 0 | X == 1), T, F into a switch instruction.
// If this is a bunch of seteq's or'd together, or if it's a bunch of // If this is a bunch of seteq's or'd together, or if it's a bunch of
// 'setne's and'ed together, collect them. // 'setne's and'ed together, collect them.
Value *CompVal = nullptr;
SmallVector<ConstantInt*, 8> Values;
bool TrueWhenEqual = (Cond->getOpcode() == Instruction::Or);
Value *ExtraCase = nullptr;
unsigned UsedICmps = 0;
// Try to gather values from a chain of and/or to be turned into a switch // Try to gather values from a chain of and/or to be turned into a switch
CompVal = GatherConstantCompares(Cond, Values, ExtraCase, DL, UsedICmps); ConstantComparesGatherer ConstantCompare{Cond, DL};
// Unpack the result
SmallVectorImpl<ConstantInt*> &Values = ConstantCompare.Vals;
Value *CompVal = ConstantCompare.CompValue;
unsigned UsedICmps = ConstantCompare.UsedICmps;
Value *ExtraCase = ConstantCompare.Extra;
// If we didn't have a multiply compared value, fail. // If we didn't have a multiply compared value, fail.
if (!CompVal) return false; if (!CompVal) return false;
@ -2830,6 +2839,8 @@ static bool SimplifyBranchOnICmpChain(BranchInst *BI, const DataLayout *DL,
if (UsedICmps <= 1) if (UsedICmps <= 1)
return false; return false;
bool TrueWhenEqual = (Cond->getOpcode() == Instruction::Or);
// There might be duplicate constants in the list, which the switch // There might be duplicate constants in the list, which the switch
// instruction can't handle, remove them now. // instruction can't handle, remove them now.
array_pod_sort(Values.begin(), Values.end(), ConstantIntSortPredicate); array_pod_sort(Values.begin(), Values.end(), ConstantIntSortPredicate);