forked from OSchip/llvm-project
[InstCombine] add folds for binop with sexted bool and constant operands
This is a generalization/extension of the existing and/or folds noted with TODO comments. Those have a one-use constraint that is not necessary. Potential follow-ups are noted by the TODO comments in the new function. We can also call this function from other binop visit* functions, but we need to add tests first. This solves: https://llvm.org/PR52543 https://alive2.llvm.org/ce/z/NWuCR5
This commit is contained in:
parent
1d007d0e5a
commit
337948ac6e
|
@ -2061,7 +2061,14 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
|
|||
if (Instruction *CastedAnd = foldCastedBitwiseLogic(I))
|
||||
return CastedAnd;
|
||||
|
||||
if (Instruction *Sel = foldBinopOfSextBoolToSelect(I))
|
||||
return Sel;
|
||||
|
||||
// and(sext(A), B) / and(B, sext(A)) --> A ? B : 0, where A is i1 or <N x i1>.
|
||||
// TODO: Move this into foldBinopOfSextBoolToSelect as a more generalized fold
|
||||
// with binop identity constant. But creating a select with non-constant
|
||||
// arm may not be reversible due to poison semantics. Is that a good
|
||||
// canonicalization?
|
||||
Value *A;
|
||||
if (match(Op0, m_OneUse(m_SExt(m_Value(A)))) &&
|
||||
A->getType()->isIntOrIntVectorTy(1))
|
||||
|
@ -2788,7 +2795,14 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
|
|||
if (Instruction *CastedOr = foldCastedBitwiseLogic(I))
|
||||
return CastedOr;
|
||||
|
||||
if (Instruction *Sel = foldBinopOfSextBoolToSelect(I))
|
||||
return Sel;
|
||||
|
||||
// or(sext(A), B) / or(B, sext(A)) --> A ? -1 : B, where A is i1 or <N x i1>.
|
||||
// TODO: Move this into foldBinopOfSextBoolToSelect as a more generalized fold
|
||||
// with binop identity constant. But creating a select with non-constant
|
||||
// arm may not be reversible due to poison semantics. Is that a good
|
||||
// canonicalization?
|
||||
if (match(Op0, m_OneUse(m_SExt(m_Value(A)))) &&
|
||||
A->getType()->isIntOrIntVectorTy(1))
|
||||
return SelectInst::Create(A, ConstantInt::getSigned(I.getType(), -1), Op1);
|
||||
|
|
|
@ -319,6 +319,7 @@ private:
|
|||
Instruction *scalarizePHI(ExtractElementInst &EI, PHINode *PN);
|
||||
Instruction *foldBitcastExtElt(ExtractElementInst &ExtElt);
|
||||
Instruction *foldCastedBitwiseLogic(BinaryOperator &I);
|
||||
Instruction *foldBinopOfSextBoolToSelect(BinaryOperator &I);
|
||||
Instruction *narrowBinOp(TruncInst &Trunc);
|
||||
Instruction *narrowMaskedBinOp(BinaryOperator &And);
|
||||
Instruction *narrowMathIfNoOverflow(BinaryOperator &I);
|
||||
|
|
|
@ -967,6 +967,29 @@ Value *InstCombinerImpl::dyn_castNegVal(Value *V) const {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
/// A binop with a constant operand and a sign-extended boolean operand may be
|
||||
/// converted into a select of constants by applying the binary operation to
|
||||
/// the constant with the two possible values of the extended boolean (0 or -1).
|
||||
Instruction *InstCombinerImpl::foldBinopOfSextBoolToSelect(BinaryOperator &BO) {
|
||||
// TODO: Handle non-commutative binop (constant is operand 0).
|
||||
// TODO: Handle zext.
|
||||
// TODO: Peek through 'not' of cast.
|
||||
Value *BO0 = BO.getOperand(0);
|
||||
Value *BO1 = BO.getOperand(1);
|
||||
Value *X;
|
||||
Constant *C;
|
||||
if (!match(BO0, m_SExt(m_Value(X))) || !match(BO1, m_ImmConstant(C)) ||
|
||||
!X->getType()->isIntOrIntVectorTy(1))
|
||||
return nullptr;
|
||||
|
||||
// bo (sext i1 X), C --> select X, (bo -1, C), (bo 0, C)
|
||||
Constant *Ones = ConstantInt::getAllOnesValue(BO.getType());
|
||||
Constant *Zero = ConstantInt::getNullValue(BO.getType());
|
||||
Constant *TVal = ConstantExpr::get(BO.getOpcode(), Ones, C);
|
||||
Constant *FVal = ConstantExpr::get(BO.getOpcode(), Zero, C);
|
||||
return SelectInst::Create(X, TVal, FVal);
|
||||
}
|
||||
|
||||
static Value *foldOperationIntoSelectOperand(Instruction &I, Value *SO,
|
||||
InstCombiner::BuilderTy &Builder) {
|
||||
if (auto *Cast = dyn_cast<CastInst>(&I))
|
||||
|
|
|
@ -1510,7 +1510,7 @@ define i32 @sext_to_sel_multi_use_constant_mask(i1 %y) {
|
|||
; CHECK-LABEL: @sext_to_sel_multi_use_constant_mask(
|
||||
; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[Y:%.*]] to i32
|
||||
; CHECK-NEXT: call void @use32(i32 [[SEXT]])
|
||||
; CHECK-NEXT: [[R:%.*]] = and i32 [[SEXT]], 42
|
||||
; CHECK-NEXT: [[R:%.*]] = select i1 [[Y]], i32 42, i32 0
|
||||
; CHECK-NEXT: ret i32 [[R]]
|
||||
;
|
||||
%sext = sext i1 %y to i32
|
||||
|
|
|
@ -657,7 +657,7 @@ define i32 @sext_to_sel_multi_use_constant_mask(i1 %y) {
|
|||
; CHECK-LABEL: @sext_to_sel_multi_use_constant_mask(
|
||||
; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[Y:%.*]] to i32
|
||||
; CHECK-NEXT: call void @use(i32 [[SEXT]])
|
||||
; CHECK-NEXT: [[R:%.*]] = or i32 [[SEXT]], 42
|
||||
; CHECK-NEXT: [[R:%.*]] = select i1 [[Y]], i32 -1, i32 42
|
||||
; CHECK-NEXT: ret i32 [[R]]
|
||||
;
|
||||
%sext = sext i1 %y to i32
|
||||
|
|
Loading…
Reference in New Issue