]> granicus.if.org Git - llvm/commitdiff
[InstCombine] add (ashr (shl i32 X, 31), 31), 1 --> and (not X), 1
authorSanjay Patel <spatel@rotateright.com>
Wed, 10 May 2017 13:56:52 +0000 (13:56 +0000)
committerSanjay Patel <spatel@rotateright.com>
Wed, 10 May 2017 13:56:52 +0000 (13:56 +0000)
This is another step towards favoring 'not' ops over random 'xor' in IR:
https://bugs.llvm.org/show_bug.cgi?id=32706

This transformation may have occurred in longer IR sequences using computeKnownBits,
but that could be much more expensive to calculate.

As the scalar result shows, we do not currently favor 'not' in all cases. The 'not'
created by the transform is transformed again (unnecessarily). Vectors don't have
this problem because vectors are (wrongly) excluded from several other combines.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@302659 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/InstCombine/InstCombineAddSub.cpp
test/Transforms/InstCombine/add.ll

index 659b6c326c559f62f07648994582a3cec63eb9d3..3709360226f507929d87bb675688e725bc64f5ff 100644 (file)
@@ -1079,6 +1079,16 @@ static Instruction *foldAddWithConstant(BinaryOperator &Add,
     return new ZExtInst(Builder.CreateNUWAdd(X, NewC), Ty);
   }
 
+  // Shifts and add used to flip and mask off the low bit:
+  // add (ashr (shl i32 X, 31), 31), 1 --> and (not X), 1
+  const APInt *C3;
+  if (*C == 1 && match(Op0, m_OneUse(m_AShr(m_Shl(m_Value(X), m_APInt(C2)),
+                                            m_APInt(C3)))) &&
+      C2 == C3 && *C2 == Ty->getScalarSizeInBits() - 1) {
+    Value *NotX = Builder.CreateNot(X);
+    return BinaryOperator::CreateAnd(NotX, ConstantInt::get(Ty, 1));
+  }
+
   return nullptr;
 }
 
index 955ffaaeecdf46f0509579d17abb26149dcb39c9..5f7101e8feca0e0427dd8ba43fa31c9cdd4ef7d5 100644 (file)
@@ -31,9 +31,8 @@ define <2 x i32> @select_0_or_1_from_bool_vec(<2 x i1> %x) {
 
 define i32 @flip_and_mask(i32 %x) {
 ; CHECK-LABEL: @flip_and_mask(
-; CHECK-NEXT:    [[SHL:%.*]] = shl i32 %x, 31
-; CHECK-NEXT:    [[SHR:%.*]] = ashr exact i32 [[SHL]], 31
-; CHECK-NEXT:    [[INC:%.*]] = add nsw i32 [[SHR]], 1
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 %x, 1
+; CHECK-NEXT:    [[INC:%.*]] = xor i32 [[TMP1]], 1
 ; CHECK-NEXT:    ret i32 [[INC]]
 ;
   %shl = shl i32 %x, 31
@@ -44,9 +43,8 @@ define i32 @flip_and_mask(i32 %x) {
 
 define <2 x i8> @flip_and_mask_splat(<2 x i8> %x) {
 ; CHECK-LABEL: @flip_and_mask_splat(
-; CHECK-NEXT:    [[SHL:%.*]] = shl <2 x i8> %x, <i8 7, i8 7>
-; CHECK-NEXT:    [[SHR:%.*]] = ashr exact <2 x i8> [[SHL]], <i8 7, i8 7>
-; CHECK-NEXT:    [[INC:%.*]] = add nsw <2 x i8> [[SHR]], <i8 1, i8 1>
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <2 x i8> %x, <i8 1, i8 1>
+; CHECK-NEXT:    [[INC:%.*]] = and <2 x i8> [[TMP1]], <i8 1, i8 1>
 ; CHECK-NEXT:    ret <2 x i8> [[INC]]
 ;
   %shl = shl <2 x i8> %x, <i8 7, i8 7>