[InstCombine] enhance fold for subtract-from-constant -> xor
authorSanjay Patel <spatel@rotateright.com>
Fri, 8 Jul 2022 13:52:57 +0000 (09:52 -0400)
committerSanjay Patel <spatel@rotateright.com>
Fri, 8 Jul 2022 14:02:19 +0000 (10:02 -0400)
A low-bit mask is not required:
https://alive2.llvm.org/ce/z/yPShss

This matches the SDAG implementation that was updated at:
8b756713140f

llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
llvm/test/Transforms/InstCombine/sub-xor.ll

index f53cce10f61e5461eaffdb89eb04ef69044ca1a5..01821a71be4d2701ffb1b8674ec537f62784011e 100644 (file)
@@ -1965,14 +1965,12 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) {
       return BinaryOperator::CreateAdd(X, ConstantExpr::getSub(C, C2));
   }
 
+  // If there's no chance any bit will need to borrow from an adjacent bit:
+  // sub C, X --> xor X, C
   const APInt *Op0C;
-  if (match(Op0, m_APInt(Op0C)) && Op0C->isMask()) {
-    // Turn this into a xor if LHS is 2^n-1 and the remaining bits are known
-    // zero.
-    KnownBits RHSKnown = computeKnownBits(Op1, 0, &I);
-    if ((*Op0C | RHSKnown.Zero).isAllOnes())
-      return BinaryOperator::CreateXor(Op1, Op0);
-  }
+  if (match(Op0, m_APInt(Op0C)) &&
+      (~computeKnownBits(Op1, 0, &I).Zero).isSubsetOf(*Op0C))
+    return BinaryOperator::CreateXor(Op1, Op0);
 
   {
     Value *Y;
index 388fa920b0cf65ee68be73d15856eabc83b00a48..f47bc2fdae7e99816234fed921e2ec99539f7fe3 100644 (file)
@@ -28,7 +28,7 @@ define <2 x i32> @test1vec(<2 x i32> %x) {
 define i8 @masked_sub_i8(i8 %x) {
 ; CHECK-LABEL: @masked_sub_i8(
 ; CHECK-NEXT:    [[A:%.*]] = and i8 [[X:%.*]], 10
-; CHECK-NEXT:    [[M:%.*]] = sub nuw nsw i8 11, [[A]]
+; CHECK-NEXT:    [[M:%.*]] = xor i8 [[A]], 11
 ; CHECK-NEXT:    ret i8 [[M]]
 ;
   %a = and i8 %x, 10 ; 0b00001010
@@ -39,7 +39,7 @@ define i8 @masked_sub_i8(i8 %x) {
 define <2 x i5> @masked_sub_v2i5(<2 x i5> %x) {
 ; CHECK-LABEL: @masked_sub_v2i5(
 ; CHECK-NEXT:    [[A:%.*]] = and <2 x i5> [[X:%.*]], <i5 -8, i5 -8>
-; CHECK-NEXT:    [[M:%.*]] = sub nuw nsw <2 x i5> <i5 -6, i5 -6>, [[A]]
+; CHECK-NEXT:    [[M:%.*]] = xor <2 x i5> [[A]], <i5 -6, i5 -6>
 ; CHECK-NEXT:    ret <2 x i5> [[M]]
 ;
   %a = and <2 x i5> %x, <i5 24, i5 24> ; 0b11000
@@ -47,6 +47,8 @@ define <2 x i5> @masked_sub_v2i5(<2 x i5> %x) {
   ret <2 x i5> %m
 }
 
+; negative test - sub constant isn't superset of masked bits
+
 define i8 @not_masked_sub_i8(i8 %x) {
 ; CHECK-LABEL: @not_masked_sub_i8(
 ; CHECK-NEXT:    [[A:%.*]] = and i8 [[X:%.*]], 7