[PATCH] D102864: [InstSimplify] Transform X * Y % Y --> 0.

David Goldblatt via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Thu May 20 12:11:25 PDT 2021


davidtgoldblatt created this revision.
Herald added a subscriber: hiraditya.
davidtgoldblatt requested review of this revision.
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

simplifyDiv already handles the case X * Y / Y --> X (barring overflow).
This adds the equivalent handling to simplifyRem.

Correctness:
https://alive2.llvm.org/ce/z/J2cUbS
https://alive2.llvm.org/ce/z/us9NUM

Extending the situations in which we apply this transform would not be
correct:
https://alive2.llvm.org/ce/z/Lf9V63
https://alive2.llvm.org/ce/z/6RPQK3
https://alive2.llvm.org/ce/z/p9UdxC
https://alive2.llvm.org/ce/z/A2zlhE


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D102864

Files:
  llvm/lib/Analysis/InstructionSimplify.cpp
  llvm/test/Transforms/InstSimplify/rem.ll


Index: llvm/test/Transforms/InstSimplify/rem.ll
===================================================================
--- llvm/test/Transforms/InstSimplify/rem.ll
+++ llvm/test/Transforms/InstSimplify/rem.ll
@@ -331,3 +331,65 @@
   %v = srem i8 -128, -1
   ret i8 %v
 }
+
+define i32 @srem_of_mul_nsw(i32 %x, i32 %y) {
+; CHECK-LABEL: @srem_of_mul_nsw(
+; CHECK-NEXT:    ret i32 0
+;
+  %mul = mul nsw i32 %x, %y
+  %mod = srem i32 %mul, %y
+  ret i32 %mod
+}
+
+define i32 @srem_of_mul_nuw(i32 %x, i32 %y) {
+; CHECK-LABEL: @srem_of_mul_nuw(
+; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MOD:%.*]] = srem i32 [[MUL]], [[Y]]
+; CHECK-NEXT:    ret i32 [[MOD]]
+;
+  %mul = mul nuw i32 %x, %y
+  %mod = srem i32 %mul, %y
+  ret i32 %mod
+}
+
+define i32 @srem_of_mul(i32 %x, i32 %y) {
+; CHECK-LABEL: @srem_of_mul(
+; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MOD:%.*]] = srem i32 [[MUL]], [[Y]]
+; CHECK-NEXT:    ret i32 [[MOD]]
+;
+  %mul = mul i32 %x, %y
+  %mod = srem i32 %mul, %y
+  ret i32 %mod
+}
+
+define i32 @urem_of_mul_nsw(i32 %x, i32 %y) {
+; CHECK-LABEL: @urem_of_mul_nsw(
+; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MOD:%.*]] = urem i32 [[MUL]], [[Y]]
+; CHECK-NEXT:    ret i32 [[MOD]]
+;
+  %mul = mul nsw i32 %x, %y
+  %mod = urem i32 %mul, %y
+  ret i32 %mod
+}
+
+define i32 @urem_of_mul_nuw(i32 %x, i32 %y) {
+; CHECK-LABEL: @urem_of_mul_nuw(
+; CHECK-NEXT:    ret i32 0
+;
+  %mul = mul nuw i32 %x, %y
+  %mod = urem i32 %mul, %y
+  ret i32 %mod
+}
+
+define i32 @urem_of_mul(i32 %x, i32 %y) {
+; CHECK-LABEL: @urem_of_mul(
+; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MOD:%.*]] = urem i32 [[MUL]], [[Y]]
+; CHECK-NEXT:    ret i32 [[MOD]]
+;
+  %mul = mul i32 %x, %y
+  %mod = urem i32 %mul, %y
+  ret i32 %mod
+}
Index: llvm/lib/Analysis/InstructionSimplify.cpp
===================================================================
--- llvm/lib/Analysis/InstructionSimplify.cpp
+++ llvm/lib/Analysis/InstructionSimplify.cpp
@@ -1115,6 +1115,16 @@
        match(Op0, m_URem(m_Value(), m_Specific(Op1)))))
     return Op0;
 
+  // (X * Y) % Y -> 0 if the multiplication does not overflow.
+  Value *X;
+  if (match(Op0, m_c_Mul(m_Value(X), m_Specific(Op1)))) {
+    bool IsSigned = Opcode == Instruction::SRem;
+    auto *Mul = cast<OverflowingBinaryOperator>(Op0);
+    if ((IsSigned && Q.IIQ.hasNoSignedWrap(Mul)) ||
+        (!IsSigned && Q.IIQ.hasNoUnsignedWrap(Mul)))
+      return Constant::getNullValue(Op0->getType());
+  }
+
   // (X << Y) % X -> 0
   if (Q.IIQ.UseInstrInfo &&
       ((Opcode == Instruction::SRem &&


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D102864.346819.patch
Type: text/x-patch
Size: 2694 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20210520/a1413c36/attachment.bin>


More information about the llvm-commits mailing list