[llvm] c636899 - [GlobalISel] Combine: (G_*MULO x, 0) -> 0 + no carry out

Jessica Paquette via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 3 14:24:25 PST 2022


Author: Jessica Paquette
Date: 2022-02-03T14:23:58-08:00
New Revision: c636899dc1fad6ecd0a1846d531df72fc7e76e22

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

LOG: [GlobalISel] Combine: (G_*MULO x, 0) -> 0 + no carry out

Similar to the following combine in `DAGCombiner::visitMULO`:

```
  // fold (mulo x, 0) -> 0 + no carry out
  if (isNullOrNullSplat(N1))
    return CombineTo(N, DAG.getConstant(0, DL, VT),
                     DAG.getConstant(0, DL, CarryVT));
```

This fixes some generally poor codegen for `*mulo`:

https://godbolt.org/z/eTxYsvz8f

Differential Revision: https://reviews.llvm.org/D118635

Added: 
    llvm/test/CodeGen/AArch64/GlobalISel/prelegalizer-combiner-mulo-zero.mir

Modified: 
    llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
    llvm/include/llvm/Target/GlobalISel/Combine.td
    llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
index 45c27c25aea0b..af23060d6585c 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
@@ -645,6 +645,10 @@ class CombinerHelper {
   ///   (G_SMULO x, 2) -> (G_SADDO x, x)
   bool matchMulOBy2(MachineInstr &MI, BuildFnTy &MatchInfo);
 
+  /// Match:
+  /// (G_*MULO x, 0) -> 0 + no carry out
+  bool matchMulOBy0(MachineInstr &MI, BuildFnTy &MatchInfo);
+
   /// Transform (fadd x, fneg(y)) -> (fsub x, y)
   ///           (fadd fneg(x), y) -> (fsub y, x)
   ///           (fsub x, fneg(y)) -> (fadd x, y)

diff  --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 4859cf6b57b71..c271eb0bf6ccc 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -753,6 +753,12 @@ def mulo_by_2: GICombineRule<
          [{ return Helper.matchMulOBy2(*${root}, ${matchinfo}); }]),
   (apply [{ Helper.applyBuildFnNoErase(*${root}, ${matchinfo}); }])>;
 
+def mulo_by_0: GICombineRule<
+  (defs root:$root, build_fn_matchinfo:$matchinfo),
+  (match (wip_match_opcode G_UMULO, G_SMULO):$root,
+         [{ return Helper.matchMulOBy0(*${root}, ${matchinfo}); }]),
+  (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>;
+
 def mulh_to_lshr : GICombineRule<
   (defs root:$root),
   (match (wip_match_opcode G_UMULH):$root,
@@ -862,7 +868,7 @@ def identity_combines : GICombineGroup<[select_same_val, right_identity_zero,
                                         fneg_fneg_fold, right_identity_one]>;
 
 def const_combines : GICombineGroup<[constant_fp_op, const_ptradd_to_i2p,
-                                     overlapping_and, mulo_by_2]>;
+                                     overlapping_and, mulo_by_2, mulo_by_0]>;
 
 def known_bits_simplifications : GICombineGroup<[
   redundant_and, redundant_sext_inreg, redundant_or, urem_pow2_to_mask,

diff  --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
index d6a009744161d..fba1adabd9e08 100644
--- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
@@ -4585,6 +4585,39 @@ bool CombinerHelper::matchMulOBy2(MachineInstr &MI, BuildFnTy &MatchInfo) {
   return true;
 }
 
+bool CombinerHelper::matchMulOBy0(MachineInstr &MI, BuildFnTy &MatchInfo) {
+  // (G_*MULO x, 0) -> 0 + no carry out
+  unsigned Opc = MI.getOpcode();
+  assert(Opc == TargetOpcode::G_UMULO || Opc == TargetOpcode::G_SMULO);
+  if (!mi_match(MI.getOperand(3).getReg(), MRI, m_SpecificICstOrSplat(0)))
+    return false;
+  Register Dst = MI.getOperand(0).getReg();
+  Register Carry = MI.getOperand(1).getReg();
+  LLT DstTy = MRI.getType(Dst);
+  LLT CarryTy = MRI.getType(Carry);
+  if (DstTy.isVector()) {
+    LLT DstEltTy = DstTy.getElementType();
+    if (!isLegalOrBeforeLegalizer(
+            {TargetOpcode::G_BUILD_VECTOR, {DstTy, DstEltTy}}) ||
+        !isLegalOrBeforeLegalizer({TargetOpcode::G_CONSTANT, {DstEltTy}}))
+      return false;
+    LLT CarryEltTy = CarryTy.getElementType();
+    if (!isLegalOrBeforeLegalizer(
+            {TargetOpcode::G_BUILD_VECTOR, {CarryTy, CarryEltTy}}) ||
+        !isLegalOrBeforeLegalizer({TargetOpcode::G_CONSTANT, {CarryEltTy}}))
+      return false;
+  } else {
+    if (!isLegalOrBeforeLegalizer({TargetOpcode::G_CONSTANT, {DstTy}}) ||
+        !isLegalOrBeforeLegalizer({TargetOpcode::G_CONSTANT, {CarryTy}}))
+      return false;
+  }
+  MatchInfo = [=](MachineIRBuilder &B) {
+    B.buildConstant(Dst, 0);
+    B.buildConstant(Carry, 0);
+  };
+  return true;
+}
+
 MachineInstr *CombinerHelper::buildUDivUsingMul(MachineInstr &MI) {
   assert(MI.getOpcode() == TargetOpcode::G_UDIV);
   auto &UDiv = cast<GenericMachineInstr>(MI);

diff  --git a/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizer-combiner-mulo-zero.mir b/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizer-combiner-mulo-zero.mir
new file mode 100644
index 0000000000000..d9aaa933d95f4
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizer-combiner-mulo-zero.mir
@@ -0,0 +1,134 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple aarch64 -debugify-and-strip-all-safe -run-pass=aarch64-prelegalizer-combiner --aarch64prelegalizercombinerhelper-only-enable-rule="mulo_by_0" -global-isel -verify-machineinstrs %s -o - | FileCheck %s
+# REQUIRES: asserts
+
+# (G_*MULO x, 0) -> 0 + no carry out
+
+...
+---
+name:            umulo_zero
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1
+    ; CHECK-LABEL: name: umulo_zero
+    ; CHECK: liveins: $w0, $w1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %zero:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: %mulo:_(s32) = COPY %zero(s32)
+    ; CHECK-NEXT: %carry:_(s1) = G_CONSTANT i1 false
+    ; CHECK-NEXT: %carry_wide:_(s32) = G_ZEXT %carry(s1)
+    ; CHECK-NEXT: $w0 = COPY %mulo(s32)
+    ; CHECK-NEXT: $w1 = COPY %carry_wide(s32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %lhs:_(s32) = COPY $w0
+    %zero:_(s32) = G_CONSTANT i32 0
+    %mulo:_(s32), %carry:_(s1) = G_UMULO %lhs, %zero
+    %carry_wide:_(s32) = G_ZEXT %carry(s1)
+    $w0 = COPY %mulo(s32)
+    $w1 = COPY %carry_wide
+    RET_ReallyLR implicit $w0
+...
+---
+name:            smulo_zero
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1
+    ; CHECK-LABEL: name: smulo_zero
+    ; CHECK: liveins: $w0, $w1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %zero:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: %mulo:_(s32) = COPY %zero(s32)
+    ; CHECK-NEXT: %carry:_(s1) = G_CONSTANT i1 false
+    ; CHECK-NEXT: %carry_wide:_(s32) = G_ZEXT %carry(s1)
+    ; CHECK-NEXT: $w0 = COPY %mulo(s32)
+    ; CHECK-NEXT: $w1 = COPY %carry_wide(s32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %lhs:_(s32) = COPY $w0
+    %zero:_(s32) = G_CONSTANT i32 0
+    %mulo:_(s32), %carry:_(s1) = G_SMULO %lhs, %zero
+    %carry_wide:_(s32) = G_ZEXT %carry(s1)
+    $w0 = COPY %mulo(s32)
+    $w1 = COPY %carry_wide
+    RET_ReallyLR implicit $w0
+...
+---
+name:            wrong_cst
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w0, $w1
+    ; CHECK-LABEL: name: wrong_cst
+    ; CHECK: liveins: $w0, $w1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %lhs:_(s32) = COPY $w0
+    ; CHECK-NEXT: %not_zero:_(s32) = G_CONSTANT i32 3
+    ; CHECK-NEXT: %mulo:_(s32), %carry:_(s1) = G_UMULO %lhs, %not_zero
+    ; CHECK-NEXT: %carry_wide:_(s32) = G_ZEXT %carry(s1)
+    ; CHECK-NEXT: $w0 = COPY %mulo(s32)
+    ; CHECK-NEXT: $w1 = COPY %carry_wide(s32)
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %lhs:_(s32) = COPY $w0
+    %not_zero:_(s32) = G_CONSTANT i32 3
+    %mulo:_(s32), %carry:_(s1) = G_UMULO %lhs, %not_zero
+    %carry_wide:_(s32) = G_ZEXT %carry(s1)
+    $w0 = COPY %mulo(s32)
+    $w1 = COPY %carry_wide
+    RET_ReallyLR implicit $w0
+...
+---
+name:            umulo_vec_zero
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $q0, $x0
+    ; CHECK-LABEL: name: umulo_vec_zero
+    ; CHECK: liveins: $q0, $x0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
+    ; CHECK-NEXT: %mulo:_(<2 x s64>) = G_BUILD_VECTOR %zero(s64), %zero(s64)
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s1) = G_CONSTANT i1 false
+    ; CHECK-NEXT: %carry:_(<2 x s1>) = G_BUILD_VECTOR [[C]](s1), [[C]](s1)
+    ; CHECK-NEXT: %carry_elt_0:_(s1) = G_EXTRACT_VECTOR_ELT %carry(<2 x s1>), %zero(s64)
+    ; CHECK-NEXT: %carry_wide:_(s64) = G_ZEXT %carry_elt_0(s1)
+    ; CHECK-NEXT: $q0 = COPY %mulo(<2 x s64>)
+    ; CHECK-NEXT: $x0 = COPY %carry_wide(s64)
+    ; CHECK-NEXT: RET_ReallyLR implicit $q0
+    %lhs:_(<2 x s64>) = COPY $q0
+    %zero:_(s64) = G_CONSTANT i64 0
+    %zero_vec:_(<2 x s64>) = G_BUILD_VECTOR %zero, %zero
+    %mulo:_(<2 x s64>), %carry:_(<2 x s1>) = G_UMULO %lhs, %zero_vec
+    %carry_elt_0:_(s1) = G_EXTRACT_VECTOR_ELT %carry:_(<2 x s1>), %zero:_(s64)
+    %carry_wide:_(s64) = G_ZEXT %carry_elt_0
+    $q0 = COPY %mulo(<2 x s64>)
+    $x0 = COPY %carry_wide
+    RET_ReallyLR implicit $q0
+...
+---
+name:            smulo_vec_zero
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $q0, $x0
+    ; CHECK-LABEL: name: smulo_vec_zero
+    ; CHECK: liveins: $q0, $x0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
+    ; CHECK-NEXT: %mulo:_(<2 x s64>) = G_BUILD_VECTOR %zero(s64), %zero(s64)
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s1) = G_CONSTANT i1 false
+    ; CHECK-NEXT: %carry:_(<2 x s1>) = G_BUILD_VECTOR [[C]](s1), [[C]](s1)
+    ; CHECK-NEXT: %carry_elt_0:_(s1) = G_EXTRACT_VECTOR_ELT %carry(<2 x s1>), %zero(s64)
+    ; CHECK-NEXT: %carry_wide:_(s64) = G_ZEXT %carry_elt_0(s1)
+    ; CHECK-NEXT: $q0 = COPY %mulo(<2 x s64>)
+    ; CHECK-NEXT: $x0 = COPY %carry_wide(s64)
+    ; CHECK-NEXT: RET_ReallyLR implicit $q0
+    %lhs:_(<2 x s64>) = COPY $q0
+    %zero:_(s64) = G_CONSTANT i64 0
+    %zero_vec:_(<2 x s64>) = G_BUILD_VECTOR %zero, %zero
+    %mulo:_(<2 x s64>), %carry:_(<2 x s1>) = G_SMULO %lhs, %zero_vec
+    %carry_elt_0:_(s1) = G_EXTRACT_VECTOR_ELT %carry:_(<2 x s1>), %zero:_(s64)
+    %carry_wide:_(s64) = G_ZEXT %carry_elt_0
+    $q0 = COPY %mulo(<2 x s64>)
+    $x0 = COPY %carry_wide
+    RET_ReallyLR implicit $q0


        


More information about the llvm-commits mailing list