From: Roman Lebedev Date: Sun, 15 Apr 2018 18:59:44 +0000 (+0000) Subject: [InstCombine] Simplify 'xor' to 'or' if no common bits are set. X-Git-Tag: llvmorg-7.0.0-rc1~8134 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f84bfb2147e404e7bddb4eb0cd701f2b35b1b80f;p=platform%2Fupstream%2Fllvm.git [InstCombine] Simplify 'xor' to 'or' if no common bits are set. Summary: In order to get the whole fold as specified in [[ https://bugs.llvm.org/show_bug.cgi?id=6773 | PR6773 ]], let's first handle the simple straight-forward things. Let's start with the `and` -> `or` simplification. The one obvious thing missing here: the constant mask is not handled. I have an idea how to handle it, but it will require some thinking, and is not strictly required here, so i've left that for later. https://rise4fun.com/Alive/Pkmg Reviewers: spatel, craig.topper, eli.friedman, jingyue Reviewed By: spatel Subscribers: llvm-commits Was reviewed as part of https://reviews.llvm.org/D45631 llvm-svn: 330103 --- diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 9ba92f7..28d68a3 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2446,6 +2446,10 @@ Instruction *InstCombiner::visitXor(BinaryOperator &I) { if (Value *V = SimplifyBSwap(I, Builder)) return replaceInstUsesWith(I, V); + // A^B --> A|B iff A and B have no bits set in common. + if (haveNoCommonBitsSet(Op0, Op1, DL, &AC, &I, &DT)) + return BinaryOperator::CreateOr(Op0, Op1); + // Apply DeMorgan's Law for 'nand' / 'nor' logic with an inverted operand. Value *X, *Y; diff --git a/llvm/test/Transforms/InstCombine/logical-select.ll b/llvm/test/Transforms/InstCombine/logical-select.ll index 3e3aa60..d31af5e 100644 --- a/llvm/test/Transforms/InstCombine/logical-select.ll +++ b/llvm/test/Transforms/InstCombine/logical-select.ll @@ -399,11 +399,8 @@ define i1 @bools_multi_uses1(i1 %a, i1 %b, i1 %c) { define i1 @bools_multi_uses2(i1 %a, i1 %b, i1 %c) { ; CHECK-LABEL: @bools_multi_uses2( -; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[C:%.*]], true -; CHECK-NEXT: [[AND1:%.*]] = and i1 [[NOT]], [[A:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i1 [[C]], [[B:%.*]] -; CHECK-NEXT: [[ADD:%.*]] = xor i1 [[AND1]], [[AND2]] -; CHECK-NEXT: ret i1 [[ADD]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[C:%.*]], i1 [[B:%.*]], i1 [[A:%.*]] +; CHECK-NEXT: ret i1 [[TMP1]] ; %not = xor i1 %c, -1 %and1 = and i1 %not, %a diff --git a/llvm/test/Transforms/InstCombine/masked-merge-xor.ll b/llvm/test/Transforms/InstCombine/masked-merge-xor.ll index f8b763a..3f6a10d 100644 --- a/llvm/test/Transforms/InstCombine/masked-merge-xor.ll +++ b/llvm/test/Transforms/InstCombine/masked-merge-xor.ll @@ -21,7 +21,7 @@ define i32 @p(i32 %x, i32 %y, i32 %m) { ; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]] ; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 ; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]] -; CHECK-NEXT: [[RET:%.*]] = xor i32 [[AND]], [[AND1]] +; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND]], [[AND1]] ; CHECK-NEXT: ret i32 [[RET]] ; %and = and i32 %x, %m @@ -36,7 +36,7 @@ define <2 x i32> @p_splatvec(<2 x i32> %x, <2 x i32> %y, <2 x i32> %m) { ; CHECK-NEXT: [[AND:%.*]] = and <2 x i32> [[X:%.*]], [[M:%.*]] ; CHECK-NEXT: [[NEG:%.*]] = xor <2 x i32> [[M]], ; CHECK-NEXT: [[AND1:%.*]] = and <2 x i32> [[NEG]], [[Y:%.*]] -; CHECK-NEXT: [[RET:%.*]] = xor <2 x i32> [[AND]], [[AND1]] +; CHECK-NEXT: [[RET:%.*]] = or <2 x i32> [[AND]], [[AND1]] ; CHECK-NEXT: ret <2 x i32> [[RET]] ; %and = and <2 x i32> %x, %m @@ -51,7 +51,7 @@ define <3 x i32> @p_vec_undef(<3 x i32> %x, <3 x i32> %y, <3 x i32> %m) { ; CHECK-NEXT: [[AND:%.*]] = and <3 x i32> [[X:%.*]], [[M:%.*]] ; CHECK-NEXT: [[NEG:%.*]] = xor <3 x i32> [[M]], ; CHECK-NEXT: [[AND1:%.*]] = and <3 x i32> [[NEG]], [[Y:%.*]] -; CHECK-NEXT: [[RET:%.*]] = xor <3 x i32> [[AND]], [[AND1]] +; CHECK-NEXT: [[RET:%.*]] = or <3 x i32> [[AND]], [[AND1]] ; CHECK-NEXT: ret <3 x i32> [[RET]] ; %and = and <3 x i32> %x, %m @@ -129,7 +129,7 @@ define i32 @p_commutative0(i32 %x, i32 %y, i32 %m) { ; CHECK-NEXT: [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]] ; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 ; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]] -; CHECK-NEXT: [[RET:%.*]] = xor i32 [[AND]], [[AND1]] +; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND]], [[AND1]] ; CHECK-NEXT: ret i32 [[RET]] ; %and = and i32 %m, %x ; swapped order @@ -145,7 +145,7 @@ define i32 @p_commutative1(i32 %x, i32 %m) { ; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]] ; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 ; CHECK-NEXT: [[AND1:%.*]] = and i32 [[Y]], [[NEG]] -; CHECK-NEXT: [[RET:%.*]] = xor i32 [[AND]], [[AND1]] +; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND]], [[AND1]] ; CHECK-NEXT: ret i32 [[RET]] ; %y = call i32 @gen32() @@ -161,7 +161,7 @@ define i32 @p_commutative2(i32 %x, i32 %y, i32 %m) { ; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]] ; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 ; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]] -; CHECK-NEXT: [[RET:%.*]] = xor i32 [[AND1]], [[AND]] +; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND1]], [[AND]] ; CHECK-NEXT: ret i32 [[RET]] ; %and = and i32 %x, %m @@ -177,7 +177,7 @@ define i32 @p_commutative3(i32 %x, i32 %m) { ; CHECK-NEXT: [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]] ; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 ; CHECK-NEXT: [[AND1:%.*]] = and i32 [[Y]], [[NEG]] -; CHECK-NEXT: [[RET:%.*]] = xor i32 [[AND]], [[AND1]] +; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND]], [[AND1]] ; CHECK-NEXT: ret i32 [[RET]] ; %y = call i32 @gen32() @@ -193,7 +193,7 @@ define i32 @p_commutative4(i32 %x, i32 %y, i32 %m) { ; CHECK-NEXT: [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]] ; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 ; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]] -; CHECK-NEXT: [[RET:%.*]] = xor i32 [[AND1]], [[AND]] +; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND1]], [[AND]] ; CHECK-NEXT: ret i32 [[RET]] ; %and = and i32 %m, %x ; swapped order @@ -209,7 +209,7 @@ define i32 @p_commutative5(i32 %x, i32 %m) { ; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]] ; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 ; CHECK-NEXT: [[AND1:%.*]] = and i32 [[Y]], [[NEG]] -; CHECK-NEXT: [[RET:%.*]] = xor i32 [[AND1]], [[AND]] +; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND1]], [[AND]] ; CHECK-NEXT: ret i32 [[RET]] ; %y = call i32 @gen32() @@ -226,7 +226,7 @@ define i32 @p_commutative6(i32 %x, i32 %m) { ; CHECK-NEXT: [[AND:%.*]] = and i32 [[M:%.*]], [[X:%.*]] ; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 ; CHECK-NEXT: [[AND1:%.*]] = and i32 [[Y]], [[NEG]] -; CHECK-NEXT: [[RET:%.*]] = xor i32 [[AND1]], [[AND]] +; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND1]], [[AND]] ; CHECK-NEXT: ret i32 [[RET]] ; %y = call i32 @gen32() @@ -263,7 +263,7 @@ define i32 @n0_oneuse(i32 %x, i32 %y, i32 %m) { ; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[M:%.*]] ; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[M]], -1 ; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NEG]], [[Y:%.*]] -; CHECK-NEXT: [[RET:%.*]] = xor i32 [[AND]], [[AND1]] +; CHECK-NEXT: [[RET:%.*]] = or i32 [[AND]], [[AND1]] ; CHECK-NEXT: call void @use32(i32 [[AND]]) ; CHECK-NEXT: call void @use32(i32 [[NEG]]) ; CHECK-NEXT: call void @use32(i32 [[AND1]])