Skip to content

Commit

Permalink
[InstCombine] Fold Xor with or disjoint (llvm#105992)
Browse files Browse the repository at this point in the history
Implement a missing optimization fold `(X | Y) ^ M to (X ^ M) ^ Y` and
`(X | Y) ^ M to (Y ^ M) ^ X`
  • Loading branch information
AmrDeveloper authored Sep 22, 2024
1 parent 2f1e04f commit 9614f69
Show file tree
Hide file tree
Showing 2 changed files with 193 additions and 2 deletions.
16 changes: 14 additions & 2 deletions llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4693,7 +4693,20 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) {
// calls in there are unnecessary as SimplifyDemandedInstructionBits should
// have already taken care of those cases.
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
Value *M;
Value *X, *Y, *M;

// (X | Y) ^ M -> (X ^ M) ^ Y
// (X | Y) ^ M -> (Y ^ M) ^ X
if (match(&I, m_c_Xor(m_OneUse(m_DisjointOr(m_Value(X), m_Value(Y))),
m_Value(M)))) {
if (Value *XorAC =
simplifyBinOp(Instruction::Xor, X, M, SQ.getWithInstruction(&I)))
return BinaryOperator::CreateXor(XorAC, Y);

if (Value *XorBC = simplifyBinOp(Instruction::Xor, Y, M, SQ))
return BinaryOperator::CreateXor(XorBC, X);
}

if (match(&I, m_c_Xor(m_c_And(m_Not(m_Value(M)), m_Value()),
m_c_And(m_Deferred(M), m_Value())))) {
if (isGuaranteedNotToBeUndef(M))
Expand All @@ -4705,7 +4718,6 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) {
if (Instruction *Xor = visitMaskedMerge(I, Builder))
return Xor;

Value *X, *Y;
Constant *C1;
if (match(Op1, m_Constant(C1))) {
Constant *C2;
Expand Down
179 changes: 179 additions & 0 deletions llvm/test/Transforms/InstCombine/xor.ll
Original file line number Diff line number Diff line change
Expand Up @@ -1485,3 +1485,182 @@ define i4 @PR96857_xor_without_noundef(i4 %val0, i4 %val1, i4 %val2) {
%val7 = xor i4 %val4, %val6
ret i4 %val7
}

define i32 @or_disjoint_with_xor(i32 %a, i32 %b) {
; CHECK-LABEL: @or_disjoint_with_xor(
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32 [[B:%.*]]
;
entry:
%or = or disjoint i32 %a, %b
%xor = xor i32 %or, %a
ret i32 %xor
}

define i32 @xor_with_or_disjoint_ab(i32 %a, i32 %b) {
; CHECK-LABEL: @xor_with_or_disjoint_ab(
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32 [[B:%.*]]
;
entry:
%or = or disjoint i32 %a, %b
%xor = xor i32 %a, %or
ret i32 %xor
}

define i32 @xor_with_or_disjoint_ba(i32 %a, i32 %b) {
; CHECK-LABEL: @xor_with_or_disjoint_ba(
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32 [[B:%.*]]
;
entry:
%or = or disjoint i32 %b, %a
%xor = xor i32 %b, %or
ret i32 %xor
}

define <2 x i32> @or_disjoint_with_xor_vec(<2 x i32> %a, < 2 x i32> %b) {
; CHECK-LABEL: @or_disjoint_with_xor_vec(
; CHECK-NEXT: entry:
; CHECK-NEXT: ret <2 x i32> [[B:%.*]]
;
entry:
%or = or disjoint <2 x i32> %a, %b
%xor = xor <2 x i32> %or, %a
ret <2 x i32> %xor
}

define <2 x i32> @xor_with_or_disjoint_vec(<2 x i32> %a, < 2 x i32> %b) {
; CHECK-LABEL: @xor_with_or_disjoint_vec(
; CHECK-NEXT: entry:
; CHECK-NEXT: ret <2 x i32> [[B:%.*]]
;
entry:
%or = or disjoint <2 x i32> %a, %b
%xor = xor <2 x i32> %a, %or
ret <2 x i32> %xor
}

define i32 @select_or_disjoint_xor(i32 %a, i1 %c) {
; CHECK-LABEL: @select_or_disjoint_xor(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[S:%.*]] = select i1 [[C:%.*]], i32 0, i32 4
; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], 4
; CHECK-NEXT: [[OR:%.*]] = or disjoint i32 [[S]], [[SHL]]
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[OR]], 4
; CHECK-NEXT: ret i32 [[XOR]]
;
entry:
%s = select i1 %c, i32 0, i32 4
%shl = shl i32 %a, 4
%or = or disjoint i32 %s, %shl
%xor = xor i32 %or, 4
ret i32 %xor
}

define <2 x i32> @select_or_disjoint_xor_vec(<2 x i32> %a, i1 %c) {
; CHECK-LABEL: @select_or_disjoint_xor_vec(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[S:%.*]] = select i1 [[C:%.*]], <2 x i32> zeroinitializer, <2 x i32> <i32 4, i32 4>
; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], <i32 4, i32 4>
; CHECK-NEXT: [[OR:%.*]] = or disjoint <2 x i32> [[S]], [[SHL]]
; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i32> [[OR]], <i32 4, i32 4>
; CHECK-NEXT: ret <2 x i32> [[XOR]]
;
entry:
%s = select i1 %c, <2 x i32> <i32 0, i32 0>, <2 x i32> <i32 4, i32 4>
%shl = shl <2 x i32> %a, <i32 4, i32 4>
%or = or <2 x i32> %s, %shl
%xor = xor <2 x i32> %or, <i32 4, i32 4>
ret <2 x i32> %xor
}

define i32 @select_or_disjoint_or(i32 %a, i1 %c) {
; CHECK-LABEL: @select_or_disjoint_or(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[S:%.*]] = select i1 [[C:%.*]], i32 0, i32 4
; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], 4
; CHECK-NEXT: [[OR:%.*]] = or disjoint i32 [[S]], [[SHL]]
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[OR]], 4
; CHECK-NEXT: ret i32 [[ADD]]
;
entry:
%s = select i1 %c, i32 0, i32 4
%shl = shl i32 %a, 4
%or = or disjoint i32 %s, %shl
%add = add i32 %or, 4
ret i32 %add
}

define <2 x i32> @select_or_disjoint_or_vec(<2 x i32> %a, i1 %c) {
; CHECK-LABEL: @select_or_disjoint_or_vec(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[S:%.*]] = select i1 [[C:%.*]], <2 x i32> zeroinitializer, <2 x i32> <i32 4, i32 4>
; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], <i32 4, i32 4>
; CHECK-NEXT: [[OR:%.*]] = or disjoint <2 x i32> [[S]], [[SHL]]
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw <2 x i32> [[OR]], <i32 4, i32 4>
; CHECK-NEXT: ret <2 x i32> [[ADD]]
;
entry:
%s = select i1 %c, <2 x i32> <i32 0, i32 0>, <2 x i32> <i32 4, i32 4>
%shl = shl <2 x i32> %a, <i32 4, i32 4>
%or = or <2 x i32> %s, %shl
%add = add <2 x i32> %or, <i32 4, i32 4>
ret <2 x i32> %add
}

define i32 @or_multi_use_disjoint_with_xor(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_multi_use_disjoint_with_xor(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[OR:%.*]] = or disjoint i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[OR]], [[C:%.*]]
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[OR]], [[XOR]]
; CHECK-NEXT: ret i32 [[ADD]]
;
entry:
%or = or disjoint i32 %a, %b
%xor = xor i32 %or, %c
%add = add i32 %or, %xor
ret i32 %add
}

define <2 x i32> @or_multi_use_disjoint_with_xor_vec(<2 x i32> %a, <2 x i32> %b, <2 x i32> %c) {
; CHECK-LABEL: @or_multi_use_disjoint_with_xor_vec(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[OR:%.*]] = or disjoint <2 x i32> [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i32> [[OR]], [[C:%.*]]
; CHECK-NEXT: [[ADD:%.*]] = add <2 x i32> [[OR]], [[XOR]]
; CHECK-NEXT: ret <2 x i32> [[ADD]]
;
entry:
%or = or disjoint <2 x i32> %a, %b
%xor = xor <2 x i32> %or, %c
%add = add <2 x i32> %or, %xor
ret <2 x i32> %add
}

define i32 @add_with_or(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @add_with_or(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[OR:%.*]] = or i32 [[ADD]], [[C:%.*]]
; CHECK-NEXT: ret i32 [[OR]]
;
entry:
%add = add i32 %a, %b
%or = or i32 %add, %c
ret i32 %or
}

define <2 x i32> @add_with_or_vec(<2 x i32> %a, <2 x i32> %b, <2 x i32> %c) {
; CHECK-LABEL: @add_with_or_vec(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[ADD:%.*]] = add <2 x i32> [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[OR:%.*]] = or <2 x i32> [[ADD]], [[C:%.*]]
; CHECK-NEXT: ret <2 x i32> [[OR]]
;
entry:
%add = add <2 x i32> %a, %b
%or = or <2 x i32> %add, %c
ret <2 x i32> %or
}

0 comments on commit 9614f69

Please sign in to comment.