Extend CanEvaluateZExtd to handle and/or/xor more aggressively in the
authorChris Lattner <sabre@nondot.org>
Mon, 11 Jan 2010 04:05:13 +0000 (04:05 +0000)
committerChris Lattner <sabre@nondot.org>
Mon, 11 Jan 2010 04:05:13 +0000 (04:05 +0000)
BitsToClear case.  This allows it to promote expressions which have an
and/or/xor after the lshr, promoting cases like test2 (from PR4216)
and test3 (random extample extracted from a spec benchmark).

clang now compiles the code in PR4216 into:

_test_bitfield:                                             ## @test_bitfield
movl %edi, %eax
orl $194, %eax
movl $4294902010, %ecx
andq %rax, %rcx
orl $32768, %edi
andq $39936, %rdi
movq %rdi, %rax
orq %rcx, %rax
ret

instead of:

_test_bitfield:                                             ## @test_bitfield
movl %edi, %eax
orl $194, %eax
movl $4294902010, %ecx
andq %rax, %rcx
shrl $8, %edi
orl $128, %edi
shlq $8, %rdi
andq $39936, %rdi
movq %rdi, %rax
orq %rcx, %rax
ret

which is still not great, but is progress.

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

lib/Transforms/InstCombine/InstCombineCasts.cpp
test/Transforms/InstCombine/cast.ll

index be0734c7a43347fe36a5d1b316c1d9715c4ba559..939c2b1937e82dc108979f902de1b92f203c23d7 100644 (file)
@@ -634,6 +634,20 @@ static bool CanEvaluateZExtd(Value *V, const Type *Ty, unsigned &BitsToClear) {
     if (BitsToClear == 0 && Tmp == 0)
       return true;
       
+    // If the operation is an AND/OR/XOR and the bits to clear are zero in the
+    // other side, BitsToClear is ok.
+    if (Tmp == 0 &&
+        (Opc == Instruction::And || Opc == Instruction::Or ||
+         Opc == Instruction::Xor)) {
+      // We use MaskedValueIsZero here for generality, but the case we care
+      // about the most is constant RHS.
+      unsigned VSize = V->getType()->getScalarSizeInBits();
+      if (MaskedValueIsZero(I->getOperand(1),
+                            APInt::getHighBitsSet(VSize, BitsToClear)))
+        return true;
+    }
+      
+    // Otherwise, we don't know how to analyze this BitsToClear case yet.
     return false;
       
   case Instruction::LShr:
@@ -652,6 +666,8 @@ static bool CanEvaluateZExtd(Value *V, const Type *Ty, unsigned &BitsToClear) {
   case Instruction::Select:
     if (!CanEvaluateZExtd(I->getOperand(1), Ty, Tmp) ||
         !CanEvaluateZExtd(I->getOperand(2), Ty, BitsToClear) ||
+        // TODO: If important, we could handle the case when the BitsToClear are
+        // known zero in the disagreeing side.
         Tmp != BitsToClear)
       return false;
     return true;
@@ -665,6 +681,8 @@ static bool CanEvaluateZExtd(Value *V, const Type *Ty, unsigned &BitsToClear) {
       return false;
     for (unsigned i = 1, e = PN->getNumIncomingValues(); i != e; ++i)
       if (!CanEvaluateZExtd(PN->getIncomingValue(i), Ty, Tmp) ||
+          // TODO: If important, we could handle the case when the BitsToClear
+          // are known zero in the disagreeing input.
           Tmp != BitsToClear)
         return false;
     return true;
index 3bfed2af284b3d814326bcf9e0520f549593d6e9..bcfb636887ef9557bb92030f6683ad80003b08d3 100644 (file)
@@ -572,3 +572,34 @@ define i64 @test57(i64 %A) nounwind {
 ; CHECK-NEXT: %E = and i64 %C, 16777215
 ; CHECK-NEXT: ret i64 %E
 }
+
+define i64 @test58(i64 %A) nounwind {
+ %B = trunc i64 %A to i32
+ %C = lshr i32 %B, 8
+ %D = or i32 %C, 128
+ %E = zext i32 %D to i64
+ ret i64 %E
+; CHECK: @test58
+; CHECK-NEXT:   %C = lshr i64 %A, 8
+; CHECK-NEXT:   %D = or i64 %C, 128
+; CHECK-NEXT:   %E = and i64 %D, 16777215
+; CHECK-NEXT:   ret i64 %E
+}
+
+define i64 @test59(i8 %A, i8 %B) nounwind {
+  %C = zext i8 %A to i32
+  %D = shl i32 %C, 4
+  %E = and i32 %D, 48
+  %F = zext i8 %B to i32
+  %G = lshr i32 %F, 4
+  %H = or i32 %G, %E
+  %I = zext i32 %H to i64
+  ret i64 %I
+; CHECK: @test59
+; CHECK-NEXT:   %C = zext i8 %A to i64
+; CHECK-NOT: i32
+; CHECK:   %F = zext i8 %B to i64
+; CHECK-NOT: i32
+; CHECK:   ret i64 %H
+}