[InstCombine] reorder mask folds for efficiency

This shows narrowing improvements on the logic tests
(transforms recently added with e247b0e5c9).

This is not a complete fix. That would require adding
folds to visitOr/visitXor. But it enables the expected
transforms for the basic patterns in the affected tests.
This commit is contained in:
Sanjay Patel 2022-06-10 15:51:05 -04:00
parent 30bb659c6f
commit 310adb658c
2 changed files with 27 additions and 29 deletions

View File

@ -1796,25 +1796,6 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
return BinaryOperator::CreateOr(And, ConstantInt::get(Ty, Together));
}
// If the mask is only needed on one incoming arm, push the 'and' op up.
if (match(Op0, m_OneUse(m_Xor(m_Value(X), m_Value(Y)))) ||
match(Op0, m_OneUse(m_Or(m_Value(X), m_Value(Y))))) {
APInt NotAndMask(~(*C));
BinaryOperator::BinaryOps BinOp = cast<BinaryOperator>(Op0)->getOpcode();
if (MaskedValueIsZero(X, NotAndMask, 0, &I)) {
// Not masking anything out for the LHS, move mask to RHS.
// and ({x}or X, Y), C --> {x}or X, (and Y, C)
Value *NewRHS = Builder.CreateAnd(Y, Op1, Y->getName() + ".masked");
return BinaryOperator::Create(BinOp, X, NewRHS);
}
if (!isa<Constant>(Y) && MaskedValueIsZero(Y, NotAndMask, 0, &I)) {
// Not masking anything out for the RHS, move mask to LHS.
// and ({x}or X, Y), C --> {x}or (and X, C), Y
Value *NewLHS = Builder.CreateAnd(X, Op1, X->getName() + ".masked");
return BinaryOperator::Create(BinOp, NewLHS, Y);
}
}
unsigned Width = Ty->getScalarSizeInBits();
const APInt *ShiftC;
if (match(Op0, m_OneUse(m_SExt(m_AShr(m_Value(X), m_APInt(ShiftC)))))) {
@ -1912,6 +1893,27 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
}
}
// This is intentionally placed after the narrowing transforms for
// efficiency (transform directly to the narrow logic op if possible).
// If the mask is only needed on one incoming arm, push the 'and' op up.
if (match(Op0, m_OneUse(m_Xor(m_Value(X), m_Value(Y)))) ||
match(Op0, m_OneUse(m_Or(m_Value(X), m_Value(Y))))) {
APInt NotAndMask(~(*C));
BinaryOperator::BinaryOps BinOp = cast<BinaryOperator>(Op0)->getOpcode();
if (MaskedValueIsZero(X, NotAndMask, 0, &I)) {
// Not masking anything out for the LHS, move mask to RHS.
// and ({x}or X, Y), C --> {x}or X, (and Y, C)
Value *NewRHS = Builder.CreateAnd(Y, Op1, Y->getName() + ".masked");
return BinaryOperator::Create(BinOp, X, NewRHS);
}
if (!isa<Constant>(Y) && MaskedValueIsZero(Y, NotAndMask, 0, &I)) {
// Not masking anything out for the RHS, move mask to LHS.
// and ({x}or X, Y), C --> {x}or (and X, C), Y
Value *NewLHS = Builder.CreateAnd(X, Op1, X->getName() + ".masked");
return BinaryOperator::Create(BinOp, NewLHS, Y);
}
}
Constant *C1, *C2;
const APInt *C3 = C;
Value *X;

View File

@ -862,14 +862,12 @@ define i32 @lowmask_mul_zext(i8 %x, i32 %y) {
ret i32 %r
}
; TODO: we could have narrowed the xor
define i32 @lowmask_xor_zext_commute(i8 %x, i32 %p) {
; CHECK-LABEL: @lowmask_xor_zext_commute(
; CHECK-NEXT: [[Y:%.*]] = mul i32 [[P:%.*]], [[P]]
; CHECK-NEXT: [[ZX:%.*]] = zext i8 [[X:%.*]] to i32
; CHECK-NEXT: [[Y_MASKED:%.*]] = and i32 [[Y]], 255
; CHECK-NEXT: [[R:%.*]] = xor i32 [[Y_MASKED]], [[ZX]]
; CHECK-NEXT: [[Y_TR:%.*]] = trunc i32 [[Y]] to i8
; CHECK-NEXT: [[BO_NARROW:%.*]] = xor i8 [[Y_TR]], [[X:%.*]]
; CHECK-NEXT: [[R:%.*]] = zext i8 [[BO_NARROW]] to i32
; CHECK-NEXT: ret i32 [[R]]
;
%y = mul i32 %p, %p ; thwart complexity-based canonicalization
@ -879,13 +877,11 @@ define i32 @lowmask_xor_zext_commute(i8 %x, i32 %p) {
ret i32 %r
}
; TODO: we could have narrowed the or
define i24 @lowmask_or_zext_commute(i16 %x, i24 %y) {
; CHECK-LABEL: @lowmask_or_zext_commute(
; CHECK-NEXT: [[ZX:%.*]] = zext i16 [[X:%.*]] to i24
; CHECK-NEXT: [[Y_MASKED:%.*]] = and i24 [[Y:%.*]], 65535
; CHECK-NEXT: [[R:%.*]] = or i24 [[Y_MASKED]], [[ZX]]
; CHECK-NEXT: [[Y_TR:%.*]] = trunc i24 [[Y:%.*]] to i16
; CHECK-NEXT: [[BO_NARROW:%.*]] = or i16 [[Y_TR]], [[X:%.*]]
; CHECK-NEXT: [[R:%.*]] = zext i16 [[BO_NARROW]] to i24
; CHECK-NEXT: ret i24 [[R]]
;
%zx = zext i16 %x to i24