[llvm] r312518 - [InstCombine] Move foldSelectICmpAnd helper function earlier in the file to enable reuse in a future patch.
Craig Topper via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 4 22:26:37 PDT 2017
Author: ctopper
Date: Mon Sep 4 22:26:37 2017
New Revision: 312518
URL: http://llvm.org/viewvc/llvm-project?rev=312518&view=rev
Log:
[InstCombine] Move foldSelectICmpAnd helper function earlier in the file to enable reuse in a future patch.
Modified:
llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp
Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp?rev=312518&r1=312517&r2=312518&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp Mon Sep 4 22:26:37 2017
@@ -70,6 +70,111 @@ static Value *generateMinMaxSelectPatter
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(SelectIns
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) {
More information about the llvm-commits
mailing list