forked from OSchip/llvm-project
[InstCombine] Move foldSelectICmpAnd helper function earlier in the file to enable reuse in a future patch.
llvm-svn: 312518
This commit is contained in:
parent
4c766a0559
commit
28d6d962d5
|
@ -70,6 +70,111 @@ static Value *generateMinMaxSelectPattern(InstCombiner::BuilderTy &Builder,
|
|||
return Builder.CreateSelect(Builder.CreateICmp(Pred, A, B), A, B);
|
||||
}
|
||||
|
||||
/// If one of the constants is zero (we know they can't both be) and we have an
|
||||
/// icmp instruction with zero, and we have an 'and' with the non-constant value
|
||||
/// and a power of two we can turn the select into a shift on the result of the
|
||||
/// 'and'.
|
||||
/// This folds:
|
||||
/// select (icmp eq (and X, C1)), C2, C3
|
||||
/// iff C1 is a power 2 and the difference between C2 and C3 is a power of 2.
|
||||
/// To something like:
|
||||
/// (shr (and (X, C1)), (log2(C1) - log2(C2-C3))) + C3
|
||||
/// Or:
|
||||
/// (shl (and (X, C1)), (log2(C2-C3) - log2(C1))) + C3
|
||||
/// With some variations depending if C3 is larger than C2, or the shift
|
||||
/// isn't needed, or the bit widths don't match.
|
||||
static Value *foldSelectICmpAnd(Type *SelType, const ICmpInst *IC,
|
||||
APInt TrueVal, APInt FalseVal,
|
||||
InstCombiner::BuilderTy &Builder) {
|
||||
assert(SelType->isIntOrIntVectorTy() && "Not an integer select?");
|
||||
|
||||
// If this is a vector select, we need a vector compare.
|
||||
if (SelType->isVectorTy() != IC->getType()->isVectorTy())
|
||||
return nullptr;
|
||||
|
||||
Value *V;
|
||||
APInt AndMask;
|
||||
bool CreateAnd = false;
|
||||
ICmpInst::Predicate Pred = IC->getPredicate();
|
||||
if (ICmpInst::isEquality(Pred)) {
|
||||
if (!match(IC->getOperand(1), m_Zero()))
|
||||
return nullptr;
|
||||
|
||||
V = IC->getOperand(0);
|
||||
|
||||
const APInt *AndRHS;
|
||||
if (!match(V, m_And(m_Value(), m_Power2(AndRHS))))
|
||||
return nullptr;
|
||||
|
||||
AndMask = *AndRHS;
|
||||
} else if (decomposeBitTestICmp(IC->getOperand(0), IC->getOperand(1),
|
||||
Pred, V, AndMask)) {
|
||||
assert(ICmpInst::isEquality(Pred) && "Not equality test?");
|
||||
|
||||
if (!AndMask.isPowerOf2())
|
||||
return nullptr;
|
||||
|
||||
CreateAnd = true;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If both select arms are non-zero see if we have a select of the form
|
||||
// 'x ? 2^n + C : C'. Then we can offset both arms by C, use the logic
|
||||
// for 'x ? 2^n : 0' and fix the thing up at the end.
|
||||
APInt Offset(TrueVal.getBitWidth(), 0);
|
||||
if (!TrueVal.isNullValue() && !FalseVal.isNullValue()) {
|
||||
if ((TrueVal - FalseVal).isPowerOf2())
|
||||
Offset = FalseVal;
|
||||
else if ((FalseVal - TrueVal).isPowerOf2())
|
||||
Offset = TrueVal;
|
||||
else
|
||||
return nullptr;
|
||||
|
||||
// Adjust TrueVal and FalseVal to the offset.
|
||||
TrueVal -= Offset;
|
||||
FalseVal -= Offset;
|
||||
}
|
||||
|
||||
// Make sure one of the select arms is a power of 2.
|
||||
if (!TrueVal.isPowerOf2() && !FalseVal.isPowerOf2())
|
||||
return nullptr;
|
||||
|
||||
// Determine which shift is needed to transform result of the 'and' into the
|
||||
// desired result.
|
||||
const APInt &ValC = !TrueVal.isNullValue() ? TrueVal : FalseVal;
|
||||
unsigned ValZeros = ValC.logBase2();
|
||||
unsigned AndZeros = AndMask.logBase2();
|
||||
|
||||
if (CreateAnd) {
|
||||
// Insert the AND instruction on the input to the truncate.
|
||||
V = Builder.CreateAnd(V, ConstantInt::get(V->getType(), AndMask));
|
||||
}
|
||||
|
||||
// If types don't match we can still convert the select by introducing a zext
|
||||
// or a trunc of the 'and'.
|
||||
if (ValZeros > AndZeros) {
|
||||
V = Builder.CreateZExtOrTrunc(V, SelType);
|
||||
V = Builder.CreateShl(V, ValZeros - AndZeros);
|
||||
} else if (ValZeros < AndZeros) {
|
||||
V = Builder.CreateLShr(V, AndZeros - ValZeros);
|
||||
V = Builder.CreateZExtOrTrunc(V, SelType);
|
||||
} else
|
||||
V = Builder.CreateZExtOrTrunc(V, SelType);
|
||||
|
||||
// Okay, now we know that everything is set up, we just don't know whether we
|
||||
// have a icmp_ne or icmp_eq and whether the true or false val is the zero.
|
||||
bool ShouldNotVal = !TrueVal.isNullValue();
|
||||
ShouldNotVal ^= Pred == ICmpInst::ICMP_NE;
|
||||
if (ShouldNotVal)
|
||||
V = Builder.CreateXor(V, ValC);
|
||||
|
||||
// Apply an offset if needed.
|
||||
if (!Offset.isNullValue())
|
||||
V = Builder.CreateAdd(V, ConstantInt::get(V->getType(), Offset));
|
||||
return V;
|
||||
}
|
||||
|
||||
/// We want to turn code that looks like this:
|
||||
/// %C = or %A, %B
|
||||
/// %D = select %cond, %C, %A
|
||||
|
@ -592,111 +697,6 @@ canonicalizeMinMaxWithConstant(SelectInst &Sel, ICmpInst &Cmp,
|
|||
return &Sel;
|
||||
}
|
||||
|
||||
/// If one of the constants is zero (we know they can't both be) and we have an
|
||||
/// icmp instruction with zero, and we have an 'and' with the non-constant value
|
||||
/// and a power of two we can turn the select into a shift on the result of the
|
||||
/// 'and'.
|
||||
/// This folds:
|
||||
/// select (icmp eq (and X, C1)), C2, C3
|
||||
/// iff C1 is a power 2 and the difference between C2 and C3 is a power of 2.
|
||||
/// To something like:
|
||||
/// (shr (and (X, C1)), (log2(C1) - log2(C2-C3))) + C3
|
||||
/// Or:
|
||||
/// (shl (and (X, C1)), (log2(C2-C3) - log2(C1))) + C3
|
||||
/// With some variations depending if C3 is larger than C2, or the shift
|
||||
/// isn't needed, or the bit widths don't match.
|
||||
static Value *foldSelectICmpAnd(Type *SelType, const ICmpInst *IC,
|
||||
APInt TrueVal, APInt FalseVal,
|
||||
InstCombiner::BuilderTy &Builder) {
|
||||
assert(SelType->isIntOrIntVectorTy() && "Not an integer select?");
|
||||
|
||||
// If this is a vector select, we need a vector compare.
|
||||
if (SelType->isVectorTy() != IC->getType()->isVectorTy())
|
||||
return nullptr;
|
||||
|
||||
Value *V;
|
||||
APInt AndMask;
|
||||
bool CreateAnd = false;
|
||||
ICmpInst::Predicate Pred = IC->getPredicate();
|
||||
if (ICmpInst::isEquality(Pred)) {
|
||||
if (!match(IC->getOperand(1), m_Zero()))
|
||||
return nullptr;
|
||||
|
||||
V = IC->getOperand(0);
|
||||
|
||||
const APInt *AndRHS;
|
||||
if (!match(V, m_And(m_Value(), m_Power2(AndRHS))))
|
||||
return nullptr;
|
||||
|
||||
AndMask = *AndRHS;
|
||||
} else if (decomposeBitTestICmp(IC->getOperand(0), IC->getOperand(1),
|
||||
Pred, V, AndMask)) {
|
||||
assert(ICmpInst::isEquality(Pred) && "Not equality test?");
|
||||
|
||||
if (!AndMask.isPowerOf2())
|
||||
return nullptr;
|
||||
|
||||
CreateAnd = true;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If both select arms are non-zero see if we have a select of the form
|
||||
// 'x ? 2^n + C : C'. Then we can offset both arms by C, use the logic
|
||||
// for 'x ? 2^n : 0' and fix the thing up at the end.
|
||||
APInt Offset(TrueVal.getBitWidth(), 0);
|
||||
if (!TrueVal.isNullValue() && !FalseVal.isNullValue()) {
|
||||
if ((TrueVal - FalseVal).isPowerOf2())
|
||||
Offset = FalseVal;
|
||||
else if ((FalseVal - TrueVal).isPowerOf2())
|
||||
Offset = TrueVal;
|
||||
else
|
||||
return nullptr;
|
||||
|
||||
// Adjust TrueVal and FalseVal to the offset.
|
||||
TrueVal -= Offset;
|
||||
FalseVal -= Offset;
|
||||
}
|
||||
|
||||
// Make sure one of the select arms is a power of 2.
|
||||
if (!TrueVal.isPowerOf2() && !FalseVal.isPowerOf2())
|
||||
return nullptr;
|
||||
|
||||
// Determine which shift is needed to transform result of the 'and' into the
|
||||
// desired result.
|
||||
const APInt &ValC = !TrueVal.isNullValue() ? TrueVal : FalseVal;
|
||||
unsigned ValZeros = ValC.logBase2();
|
||||
unsigned AndZeros = AndMask.logBase2();
|
||||
|
||||
if (CreateAnd) {
|
||||
// Insert the AND instruction on the input to the truncate.
|
||||
V = Builder.CreateAnd(V, ConstantInt::get(V->getType(), AndMask));
|
||||
}
|
||||
|
||||
// If types don't match we can still convert the select by introducing a zext
|
||||
// or a trunc of the 'and'.
|
||||
if (ValZeros > AndZeros) {
|
||||
V = Builder.CreateZExtOrTrunc(V, SelType);
|
||||
V = Builder.CreateShl(V, ValZeros - AndZeros);
|
||||
} else if (ValZeros < AndZeros) {
|
||||
V = Builder.CreateLShr(V, AndZeros - ValZeros);
|
||||
V = Builder.CreateZExtOrTrunc(V, SelType);
|
||||
} else
|
||||
V = Builder.CreateZExtOrTrunc(V, SelType);
|
||||
|
||||
// Okay, now we know that everything is set up, we just don't know whether we
|
||||
// have a icmp_ne or icmp_eq and whether the true or false val is the zero.
|
||||
bool ShouldNotVal = !TrueVal.isNullValue();
|
||||
ShouldNotVal ^= Pred == ICmpInst::ICMP_NE;
|
||||
if (ShouldNotVal)
|
||||
V = Builder.CreateXor(V, ValC);
|
||||
|
||||
// Apply an offset if needed.
|
||||
if (!Offset.isNullValue())
|
||||
V = Builder.CreateAdd(V, ConstantInt::get(V->getType(), Offset));
|
||||
return V;
|
||||
}
|
||||
|
||||
/// Visit a SelectInst that has an ICmpInst as its first operand.
|
||||
Instruction *InstCombiner::foldSelectInstWithICmp(SelectInst &SI,
|
||||
ICmpInst *ICI) {
|
||||
|
|
Loading…
Reference in New Issue