]> granicus.if.org Git - llvm/commitdiff
[InstCombine] add (sext i1 X), 1 --> zext (not X)
authorSanjay Patel <spatel@rotateright.com>
Sun, 25 Jun 2017 14:15:28 +0000 (14:15 +0000)
committerSanjay Patel <spatel@rotateright.com>
Sun, 25 Jun 2017 14:15:28 +0000 (14:15 +0000)
http://rise4fun.com/Alive/i8Q

A narrow bitwise logic op is obviously better than math for value tracking,
and zext is better than sext. Typically, the 'not' will be folded into an
icmp predicate.

The IR difference would even survive through codegen for x86, so we would see
worse code:

https://godbolt.org/g/C14HMF

one_or_zero(int, int):                      # @one_or_zero(int, int)
        xorl    %eax, %eax
        cmpl    %esi, %edi
        setle   %al
        retq

one_or_zero_alt(int, int):                  # @one_or_zero_alt(int, int)
        xorl    %ecx, %ecx
        cmpl    %esi, %edi
        setg    %cl
        movl    $1, %eax
        subl    %ecx, %eax
        retq

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

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

index 287a5167fe2ae9e23cbd6bcee127f9ed449493cc..d5f0dd1914157d9690d2bb40706b02e5337e3291 100644 (file)
@@ -988,15 +988,24 @@ 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->isOneValue() &&
-      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));
+  if (C->isOneValue() && Op0->hasOneUse()) {
+    // add (sext i1 X), 1 --> zext (not X)
+    // TODO: The smallest IR representation is (select X, 0, 1), and that would
+    // not require the one-use check. But we need to remove a transform in
+    // visitSelect and make sure that IR value tracking for select is equal or
+    // better than for these ops.
+    if (match(Op0, m_SExt(m_Value(X))) &&
+        X->getType()->getScalarSizeInBits() == 1)
+      return new ZExtInst(Builder.CreateNot(X), 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 (match(Op0, 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 5f7101e8feca0e0427dd8ba43fa31c9cdd4ef7d5..9cc2ae4fcb0949d7609de4438de6ab4a067f68bd 100644 (file)
@@ -1,12 +1,10 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt < %s -instcombine -S | FileCheck %s
 
-; TODO: This should be canonicalized to either a select or xor+zext.
-
 define i32 @select_0_or_1_from_bool(i1 %x) {
 ; CHECK-LABEL: @select_0_or_1_from_bool(
-; CHECK-NEXT:    [[EXT:%.*]] = sext i1 %x to i32
-; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[EXT]], 1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i1 %x, true
+; CHECK-NEXT:    [[ADD:%.*]] = zext i1 [[TMP1]] to i32
 ; CHECK-NEXT:    ret i32 [[ADD]]
 ;
   %ext = sext i1 %x to i32
@@ -14,12 +12,10 @@ define i32 @select_0_or_1_from_bool(i1 %x) {
   ret i32 %add
 }
 
-; TODO: This should be canonicalized to either a select or xor+zext.
-
 define <2 x i32> @select_0_or_1_from_bool_vec(<2 x i1> %x) {
 ; CHECK-LABEL: @select_0_or_1_from_bool_vec(
-; CHECK-NEXT:    [[EXT:%.*]] = sext <2 x i1> %x to <2 x i32>
-; CHECK-NEXT:    [[ADD:%.*]] = add nsw <2 x i32> [[EXT]], <i32 1, i32 1>
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <2 x i1> %x, <i1 true, i1 true>
+; CHECK-NEXT:    [[ADD:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i32>
 ; CHECK-NEXT:    ret <2 x i32> [[ADD]]
 ;
   %ext = sext <2 x i1> %x to <2 x i32>