[InstCombine] fold abs(srem X, 2)
authorSanjay Patel <spatel@rotateright.com>
Wed, 31 Mar 2021 15:26:22 +0000 (11:26 -0400)
committerSanjay Patel <spatel@rotateright.com>
Wed, 31 Mar 2021 15:29:20 +0000 (11:29 -0400)
This is a missing optimization based on an example in:
https://llvm.org/PR49763

As noted there and the test here, we could add a more
general fold if that is shown useful.

https://alive2.llvm.org/ce/z/xEHdTv
https://alive2.llvm.org/ce/z/97dcY5

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
llvm/test/Transforms/InstCombine/abs-intrinsic.ll

index 8377402..bf1c51e 100644 (file)
@@ -839,6 +839,12 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       return CastInst::Create(Instruction::ZExt, NarrowAbs, II->getType());
     }
 
+    // Match a complicated way to check if a number is odd/even:
+    // abs (srem X, 2) --> and X, 1
+    const APInt *C;
+    if (match(IIOperand, m_SRem(m_Value(X), m_APInt(C))) && *C == 2)
+      return BinaryOperator::CreateAnd(X, ConstantInt::get(II->getType(), 1));
+
     break;
   }
   case Intrinsic::umax:
index db70248..56ba17f 100644 (file)
@@ -391,8 +391,7 @@ define i32 @demand_low_bits(i32 %x) {
 
 define i32 @srem_by_2_int_min_is_poison(i32 %x) {
 ; CHECK-LABEL: @srem_by_2_int_min_is_poison(
-; CHECK-NEXT:    [[S:%.*]] = srem i32 [[X:%.*]], 2
-; CHECK-NEXT:    [[R:%.*]] = call i32 @llvm.abs.i32(i32 [[S]], i1 true)
+; CHECK-NEXT:    [[R:%.*]] = and i32 [[X:%.*]], 1
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %s = srem i32 %x, 2
@@ -404,7 +403,7 @@ define <3 x i82> @srem_by_2(<3 x i82> %x, <3 x i82>* %p) {
 ; CHECK-LABEL: @srem_by_2(
 ; CHECK-NEXT:    [[S:%.*]] = srem <3 x i82> [[X:%.*]], <i82 2, i82 2, i82 2>
 ; CHECK-NEXT:    store <3 x i82> [[S]], <3 x i82>* [[P:%.*]], align 64
-; CHECK-NEXT:    [[R:%.*]] = call <3 x i82> @llvm.abs.v3i82(<3 x i82> [[S]], i1 false)
+; CHECK-NEXT:    [[R:%.*]] = and <3 x i82> [[X]], <i82 1, i82 1, i82 1>
 ; CHECK-NEXT:    ret <3 x i82> [[R]]
 ;
   %s = srem <3 x i82> %x, <i82 2, i82 2, i82 2>
@@ -413,6 +412,8 @@ define <3 x i82> @srem_by_2(<3 x i82> %x, <3 x i82>* %p) {
   ret <3 x i82> %r
 }
 
+; TODO: A more general transform could sink the srem and turn it into urem.
+
 define i32 @srem_by_3(i32 %x) {
 ; CHECK-LABEL: @srem_by_3(
 ; CHECK-NEXT:    [[S:%.*]] = srem i32 [[X:%.*]], 3