[llvm] 1c6ebe2 - [InstCombine] reduce multi-use casts+masks

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Sun Nov 6 06:07:25 PST 2022


Author: Sanjay Patel
Date: 2022-11-06T09:07:17-05:00
New Revision: 1c6ebe29d3c03382a62985fab764f5641db7f875

URL: https://github.com/llvm/llvm-project/commit/1c6ebe29d3c03382a62985fab764f5641db7f875
DIFF: https://github.com/llvm/llvm-project/commit/1c6ebe29d3c03382a62985fab764f5641db7f875.diff

LOG: [InstCombine] reduce multi-use casts+masks

As noted in the code comment, we could generalize this:
https://alive2.llvm.org/ce/z/N5m-eZ

It saves an instruction even without a constant operand,
but the 'and' is wider. We can do that as another step
if it doesn't harm anything.

I noticed that this missing pattern with a constant operand
inhibited other transforms in a recent bug report, so this
is enough to solve that case.

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
    llvm/test/Transforms/InstCombine/zext.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index c91786148beb4..dfe49fb525fc1 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -1328,6 +1328,17 @@ Instruction *InstCombinerImpl::visitZExt(ZExtInst &CI) {
     return BinaryOperator::CreateXor(Builder.CreateAnd(X, ZC), ZC);
   }
 
+  // If we are truncating, masking, and then zexting back to the original type,
+  // that's just a mask. This is not handled by canEvaluateZextd if the
+  // intermediate values have extra uses. This could be generalized further for
+  // a non-constant mask operand.
+  // zext (and (trunc X), C) --> and X, (zext C)
+  if (match(Src, m_And(m_Trunc(m_Value(X)), m_Constant(C))) &&
+      X->getType() == DestTy) {
+    Constant *ZextC = ConstantExpr::getZExt(C, DestTy);
+    return BinaryOperator::CreateAnd(X, ZextC);
+  }
+
   if (match(Src, m_VScale(DL))) {
     if (CI.getFunction() &&
         CI.getFunction()->hasFnAttribute(Attribute::VScaleRange)) {

diff  --git a/llvm/test/Transforms/InstCombine/zext.ll b/llvm/test/Transforms/InstCombine/zext.ll
index 06188de5751ed..25f59d5570ee2 100644
--- a/llvm/test/Transforms/InstCombine/zext.ll
+++ b/llvm/test/Transforms/InstCombine/zext.ll
@@ -537,6 +537,8 @@ join:
   ret i16 %conv4
 }
 
+; negative test - but this could be transformed to eliminate a use of 't'
+
 define i64 @and_trunc_extra_use1(i64 %x, i32 %y) {
 ; CHECK-LABEL: @and_trunc_extra_use1(
 ; CHECK-NEXT:    [[T:%.*]] = trunc i64 [[X:%.*]] to i32
@@ -552,6 +554,8 @@ define i64 @and_trunc_extra_use1(i64 %x, i32 %y) {
   ret i64 %z
 }
 
+; negative test - but this could be transformed to eliminate a use of 't'
+
 define i64 @and_trunc_extra_use1_commute(i64 %x, i32 %p) {
 ; CHECK-LABEL: @and_trunc_extra_use1_commute(
 ; CHECK-NEXT:    [[Y:%.*]] = mul i32 [[P:%.*]], [[P]]
@@ -569,6 +573,8 @@ define i64 @and_trunc_extra_use1_commute(i64 %x, i32 %p) {
   ret i64 %z
 }
 
+; negative test - avoid creating an extra instruction
+
 define i64 @and_trunc_extra_use2(i64 %x, i32 %y) {
 ; CHECK-LABEL: @and_trunc_extra_use2(
 ; CHECK-NEXT:    [[T:%.*]] = trunc i64 [[X:%.*]] to i32
@@ -584,12 +590,14 @@ define i64 @and_trunc_extra_use2(i64 %x, i32 %y) {
   ret i64 %z
 }
 
+; With constant mask, we duplicate it as a wider constant.
+
 define i64 @and_trunc_extra_use2_constant(i64 %x) {
 ; CHECK-LABEL: @and_trunc_extra_use2_constant(
 ; CHECK-NEXT:    [[T:%.*]] = trunc i64 [[X:%.*]] to i32
 ; CHECK-NEXT:    [[A:%.*]] = and i32 [[T]], 42
 ; CHECK-NEXT:    call void @use32(i32 [[A]])
-; CHECK-NEXT:    [[Z:%.*]] = zext i32 [[A]] to i64
+; CHECK-NEXT:    [[Z:%.*]] = and i64 [[X]], 42
 ; CHECK-NEXT:    ret i64 [[Z]]
 ;
   %t = trunc i64 %x to i32
@@ -599,13 +607,15 @@ define i64 @and_trunc_extra_use2_constant(i64 %x) {
   ret i64 %z
 }
 
+; Works with arbitrary vectors and verify that the constant is zext.
+
 define <2 x i17> @and_trunc_extra_use3_constant_vec(<2 x i17> %x) {
 ; CHECK-LABEL: @and_trunc_extra_use3_constant_vec(
 ; CHECK-NEXT:    [[T:%.*]] = trunc <2 x i17> [[X:%.*]] to <2 x i9>
 ; CHECK-NEXT:    call void @use_vec(<2 x i9> [[T]])
 ; CHECK-NEXT:    [[A:%.*]] = and <2 x i9> [[T]], <i9 42, i9 -3>
 ; CHECK-NEXT:    call void @use_vec(<2 x i9> [[A]])
-; CHECK-NEXT:    [[Z:%.*]] = zext <2 x i9> [[A]] to <2 x i17>
+; CHECK-NEXT:    [[Z:%.*]] = and <2 x i17> [[X]], <i17 42, i17 509>
 ; CHECK-NEXT:    ret <2 x i17> [[Z]]
 ;
   %t = trunc <2 x i17> %x to <2 x i9>
@@ -616,6 +626,8 @@ define <2 x i17> @and_trunc_extra_use3_constant_vec(<2 x i17> %x) {
   ret <2 x i17> %z
 }
 
+; negative test - would require another cast
+
 define i64 @and_trunc_extra_use1_wider_src(i65 %x, i32 %y) {
 ; CHECK-LABEL: @and_trunc_extra_use1_wider_src(
 ; CHECK-NEXT:    [[T:%.*]] = trunc i65 [[X:%.*]] to i32


        


More information about the llvm-commits mailing list