diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 4f557532f9f783..56aac0edc5335c 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -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)) @@ -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; diff --git a/llvm/test/Transforms/InstCombine/xor.ll b/llvm/test/Transforms/InstCombine/xor.ll index ea7f7382ee7c8e..8308dc503d4da2 100644 --- a/llvm/test/Transforms/InstCombine/xor.ll +++ b/llvm/test/Transforms/InstCombine/xor.ll @@ -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> +; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], +; CHECK-NEXT: [[OR:%.*]] = or disjoint <2 x i32> [[S]], [[SHL]] +; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i32> [[OR]], +; CHECK-NEXT: ret <2 x i32> [[XOR]] +; +entry: + %s = select i1 %c, <2 x i32> , <2 x i32> + %shl = shl <2 x i32> %a, + %or = or <2 x i32> %s, %shl + %xor = xor <2 x i32> %or, + 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> +; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], +; CHECK-NEXT: [[OR:%.*]] = or disjoint <2 x i32> [[S]], [[SHL]] +; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw <2 x i32> [[OR]], +; CHECK-NEXT: ret <2 x i32> [[ADD]] +; +entry: + %s = select i1 %c, <2 x i32> , <2 x i32> + %shl = shl <2 x i32> %a, + %or = or <2 x i32> %s, %shl + %add = add <2 x i32> %or, + 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 +}