[llvm] [AArch64][GlobalISel] Add lowering for s/umul.fix.sat (PR #217221)

via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 18 23:25:35 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-aarch64

Author: David Green (davemgreen)

<details>
<summary>Changes</summary>

This extends the existing s/umul.fix lowering to handle the saturating versions of the instructions. They use a TruncSSatS or TruncUSatU instead of the trunc, keeping the implementation simple. That does require truncsat lowering to be added to allow those operations to subsequently lower if needed.

---

Patch is 82.98 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/217221.diff


6 Files Affected:

- (modified) llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h (+1) 
- (modified) llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp (+59-8) 
- (modified) llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp (+5-2) 
- (modified) llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir (+12-10) 
- (modified) llvm/test/CodeGen/AArch64/smul_fix_sat.ll (+745-344) 
- (modified) llvm/test/CodeGen/AArch64/umul_fix_sat.ll (+455-233) 


``````````diff
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
index ce7bf3c49712f..de00cf8966970 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
@@ -575,6 +575,7 @@ class LegalizerHelper {
   LLVM_ABI LegalizeResult lowerAddSubSatToMinMax(MachineInstr &MI);
   LLVM_ABI LegalizeResult lowerAddSubSatToAddoSubo(MachineInstr &MI);
   LLVM_ABI LegalizeResult lowerShlSat(MachineInstr &MI);
+  LLVM_ABI LegalizeResult lowerTruncSat(MachineInstr &MI);
   LLVM_ABI LegalizeResult lowerBswap(MachineInstr &MI);
   LLVM_ABI LegalizeResult lowerBitreverse(MachineInstr &MI);
   LLVM_ABI LegalizeResult lowerReadWriteRegister(MachineInstr &MI);
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 6f85390fd4ede..3a9de29c55224 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -5058,6 +5058,10 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
   case G_SSHLSAT:
   case G_USHLSAT:
     return lowerShlSat(MI);
+  case G_TRUNC_SSAT_S:
+  case G_TRUNC_USAT_U:
+  case G_TRUNC_SSAT_U:
+    return lowerTruncSat(MI);
   case G_ABS:
     return lowerAbsToAddXor(MI);
   case G_ABDS:
@@ -5113,6 +5117,8 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
   }
   case G_SMULFIX:
   case G_UMULFIX:
+  case G_SMULFIXSAT:
+  case G_UMULFIXSAT:
     return lowerMulfix(MI);
   }
 }
@@ -10297,6 +10303,39 @@ LegalizerHelper::lowerShlSat(MachineInstr &MI) {
   return Legalized;
 }
 
+LegalizerHelper::LegalizeResult
+LegalizerHelper::lowerTruncSat(MachineInstr &MI) {
+  unsigned Opc = MI.getOpcode();
+  auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
+  unsigned DstSize = DstTy.getScalarSizeInBits();
+  unsigned SrcSize = SrcTy.getScalarSizeInBits();
+
+  if (Opc == TargetOpcode::G_TRUNC_SSAT_S) {
+    auto Max = MIRBuilder.buildConstant(
+        SrcTy, APInt::getSignedMaxValue(DstSize).sext(SrcSize));
+    Src = MIRBuilder.buildSMin(SrcTy, Src, Max).getReg(0);
+    auto Min = MIRBuilder.buildConstant(
+        SrcTy, APInt::getSignedMinValue(DstSize).sext(SrcSize));
+    Src = MIRBuilder.buildSMax(SrcTy, Src, Min).getReg(0);
+  } else if (Opc == TargetOpcode::G_TRUNC_USAT_U) {
+    auto Max = MIRBuilder.buildConstant(
+        SrcTy, APInt::getAllOnes(DstSize).zext(SrcSize));
+    Src = MIRBuilder.buildUMin(SrcTy, Src, Max).getReg(0);
+  } else if (Opc == TargetOpcode::G_TRUNC_SSAT_U) {
+    auto Max = MIRBuilder.buildConstant(
+        SrcTy, APInt::getAllOnes(DstSize).zext(SrcSize));
+    Src = MIRBuilder.buildSMin(SrcTy, Src, Max).getReg(0);
+    auto Min = MIRBuilder.buildConstant(SrcTy, APInt::getZero(SrcSize));
+    Src = MIRBuilder.buildSMax(SrcTy, Src, Min).getReg(0);
+  } else {
+    llvm_unreachable("Expected truncsat opcode!");
+  }
+
+  MIRBuilder.buildTrunc(Dst, Src);
+  MI.eraseFromParent();
+  return Legalized;
+}
+
 LegalizerHelper::LegalizeResult LegalizerHelper::lowerBswap(MachineInstr &MI) {
   auto [Dst, Src] = MI.getFirst2Regs();
   const LLT Ty = MRI.getType(Src);
@@ -10933,25 +10972,32 @@ LegalizerHelper::LegalizeResult LegalizerHelper::lowerVAArg(MachineInstr &MI) {
 }
 
 LegalizerHelper::LegalizeResult LegalizerHelper::lowerMulfix(MachineInstr &MI) {
-  [[maybe_unused]] unsigned OpCode = MI.getOpcode();
+  unsigned OpCode = MI.getOpcode();
   assert((OpCode == TargetOpcode::G_SMULFIX ||
-          OpCode == TargetOpcode::G_UMULFIX) &&
-         "Operator must be either G_SMULFIX or G_UMULFIX!");
+          OpCode == TargetOpcode::G_UMULFIX ||
+          OpCode == TargetOpcode::G_SMULFIXSAT ||
+          OpCode == TargetOpcode::G_UMULFIXSAT) &&
+         "Operator must be either G_SMULFIX[SAT] or G_UMULFIX[SAT]!");
   auto [Dst, LHS, RHS] = MI.getFirst3Regs();
   LLT Ty = MRI.getType(Dst);
   unsigned Scale = MI.getOperand(3).getImm();
 
-  if (Scale == 0) {
+  bool Saturating = (OpCode == TargetOpcode::G_SMULFIXSAT ||
+                     OpCode == TargetOpcode::G_UMULFIXSAT);
+  bool IsSigned = (OpCode == TargetOpcode::G_SMULFIX ||
+                   OpCode == TargetOpcode::G_SMULFIXSAT);
+
+  if (!Saturating && Scale == 0) {
     MIRBuilder.buildMul(Dst, LHS, RHS);
     MI.eraseFromParent();
     return Legalized;
   }
 
-  // TODO: Port other lowerng paths from SelectionDAG.
+  // TODO: Port other lowering paths from SelectionDAG.
   LLT WideTy = Ty.changeElementSize(Ty.getScalarSizeInBits() * 2);
   auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Scale);
   MachineInstrBuilder ExtLHS{}, ExtRHS{}, Shift{};
-  if (MI.getOpcode() == TargetOpcode::G_SMULFIX) {
+  if (IsSigned) {
     ExtLHS = MIRBuilder.buildSExt(WideTy, LHS);
     ExtRHS = MIRBuilder.buildSExt(WideTy, RHS);
   } else {
@@ -10960,12 +11006,17 @@ LegalizerHelper::LegalizeResult LegalizerHelper::lowerMulfix(MachineInstr &MI) {
   }
 
   auto Mul = MIRBuilder.buildMul(WideTy, ExtLHS, ExtRHS);
-  if (MI.getOpcode() == TargetOpcode::G_SMULFIX)
+  if (IsSigned)
     Shift = MIRBuilder.buildAShr(WideTy, Mul, ShiftAmt);
   else
     Shift = MIRBuilder.buildLShr(WideTy, Mul, ShiftAmt);
 
-  MIRBuilder.buildTrunc(Dst, Shift);
+  if (!Saturating)
+    MIRBuilder.buildTrunc(Dst, Shift);
+  else if (IsSigned)
+    MIRBuilder.buildTruncSSatS(Dst, Shift);
+  else
+    MIRBuilder.buildTruncUSatU(Dst, Shift);
 
   MI.eraseFromParent();
   return Legalized;
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
index 1274aab686bae..91ad1911818f6 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
@@ -296,7 +296,9 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
       .legalFor({i64, v16i8, v8i16, v4i32})
       .lower();
 
-  getActionDefinitionsBuilder({G_SMULFIX, G_UMULFIX}).lower();
+  getActionDefinitionsBuilder(
+      {G_SMULFIX, G_UMULFIX, G_SMULFIXSAT, G_UMULFIXSAT})
+      .lower();
 
   getActionDefinitionsBuilder({G_SMIN, G_SMAX, G_UMIN, G_UMAX})
       .legalFor({v8i8, v16i8, v4i16, v8i16, v2i32, v4i32})
@@ -858,7 +860,8 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
 
   getActionDefinitionsBuilder({G_TRUNC_SSAT_S, G_TRUNC_SSAT_U, G_TRUNC_USAT_U})
       .legalFor({{v8i8, v8i16}, {v4i16, v4i32}, {v2i32, v2i64}})
-      .clampNumElements(0, v2s32, v2s32);
+      .clampNumElements(0, v2s32, v2s32)
+      .lower();
 
   getActionDefinitionsBuilder(G_SEXT_INREG)
       .legalFor({i32, i64, v8i8, v16i8, v4i16, v8i16, v2i32, v4i32, v2i64})
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
index 4a88a30d56e01..de55cc6cc5393 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
@@ -354,16 +354,16 @@
 # DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
 # DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
 # DEBUG-NEXT: G_TRUNC_SSAT_S (opcode {{[0-9]+}}): 2 type indices, 0 imm indices
-# DEBUG-NEXT: .. the first uncovered type index: 2, OK
-# DEBUG-NEXT: .. the first uncovered imm index: 0, OK
+# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
+# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
 # DEBUG-NEXT: G_TRUNC_SSAT_U (opcode {{[0-9]+}}): 2 type indices, 0 imm indices
 # DEBUG-NEXT: .. opcode {{[0-9]+}} is aliased to {{[0-9]+}}
-# DEBUG-NEXT: .. the first uncovered type index: 2, OK
-# DEBUG-NEXT: .. the first uncovered imm index: 0, OK
+# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
+# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
 # DEBUG-NEXT: G_TRUNC_USAT_U (opcode {{[0-9]+}}): 2 type indices, 0 imm indices
 # DEBUG-NEXT: .. opcode {{[0-9]+}} is aliased to {{[0-9]+}}
-# DEBUG-NEXT: .. the first uncovered type index: 2, OK
-# DEBUG-NEXT: .. the first uncovered imm index: 0, OK
+# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
+# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
 # DEBUG-NEXT: G_CONSTANT (opcode {{[0-9]+}}): 1 type index, 0 imm indices
 # DEBUG-NEXT: .. the first uncovered type index: 1, OK
 # DEBUG-NEXT: .. the first uncovered imm index: 0, OK
@@ -500,11 +500,13 @@
 # DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
 # DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
 # DEBUG-NEXT: G_SMULFIXSAT (opcode {{[0-9]+}}): 1 type index, 1 imm index
-# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
-# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
+# DEBUG-NEXT: .. opcode {{[0-9]+}} is aliased to {{[0-9]+}}
+# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
+# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
 # DEBUG-NEXT: G_UMULFIXSAT (opcode {{[0-9]+}}): 1 type index, 1 imm index
-# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
-# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
+# DEBUG-NEXT: .. opcode {{[0-9]+}} is aliased to {{[0-9]+}}
+# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
+# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
 # DEBUG-NEXT: G_SDIVFIX (opcode {{[0-9]+}}): 1 type index, 1 imm index
 # DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
 # DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
diff --git a/llvm/test/CodeGen/AArch64/smul_fix_sat.ll b/llvm/test/CodeGen/AArch64/smul_fix_sat.ll
index 0a087c949d4d3..865b11100c4f5 100644
--- a/llvm/test/CodeGen/AArch64/smul_fix_sat.ll
+++ b/llvm/test/CodeGen/AArch64/smul_fix_sat.ll
@@ -2,455 +2,856 @@
 ; RUN: llc < %s -mtriple=aarch64-linux-gnu -global-isel=0 | FileCheck %s --check-prefixes=CHECK,CHECK-SD
 ; RUN: llc < %s -mtriple=aarch64-linux-gnu -global-isel=1 -global-isel-abort=2 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-GI
 
-; CHECK-GI:       warning: Instruction selection used fallback path for func
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for func2
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for func3
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for func4
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for func5
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for func6
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for func7
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for func8
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for vec_v8i8
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for vec_v16i8
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for vec_v4i16
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for vec_v8i16
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for vec_v2i32
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for vec_v4i32
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for vec_v8i32
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for vec_v2i64
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for vec_v4i64
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for vec_sqdmulh_v8i16
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for vec_sqdmulh_v4i16
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for vec_sqdmulh_v4i32
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for vec_sqdmulh_v2i32
 
 define i32 @func(i32 %x, i32 %y) {
-; CHECK-LABEL: func:
-; CHECK:       // %bb.0:
-; CHECK-NEXT:    smull x9, w0, w1
-; CHECK-NEXT:    mov w8, #2147483647 // =0x7fffffff
-; CHECK-NEXT:    lsr x10, x9, #32
-; CHECK-NEXT:    extr w9, w10, w9, #2
-; CHECK-NEXT:    cmp w10, #1
-; CHECK-NEXT:    csel w8, w8, w9, gt
-; CHECK-NEXT:    cmn w10, #2
-; CHECK-NEXT:    mov w9, #-2147483648 // =0x80000000
-; CHECK-NEXT:    csel w0, w9, w8, lt
-; CHECK-NEXT:    ret
+; CHECK-SD-LABEL: func:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    smull x9, w0, w1
+; CHECK-SD-NEXT:    mov w8, #2147483647 // =0x7fffffff
+; CHECK-SD-NEXT:    lsr x10, x9, #32
+; CHECK-SD-NEXT:    extr w9, w10, w9, #2
+; CHECK-SD-NEXT:    cmp w10, #1
+; CHECK-SD-NEXT:    csel w8, w8, w9, gt
+; CHECK-SD-NEXT:    cmn w10, #2
+; CHECK-SD-NEXT:    mov w9, #-2147483648 // =0x80000000
+; CHECK-SD-NEXT:    csel w0, w9, w8, lt
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: func:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    smull x8, w0, w1
+; CHECK-GI-NEXT:    mov w9, #2147483647 // =0x7fffffff
+; CHECK-GI-NEXT:    asr x8, x8, #2
+; CHECK-GI-NEXT:    cmp x8, x9
+; CHECK-GI-NEXT:    csel x8, x8, x9, lt
+; CHECK-GI-NEXT:    mov x9, #-2147483648 // =0xffffffff80000000
+; CHECK-GI-NEXT:    cmp x8, x9
+; CHECK-GI-NEXT:    csel x0, x8, x9, gt
+; CHECK-GI-NEXT:    // kill: def $w0 killed $w0 killed $x0
+; CHECK-GI-NEXT:    ret
   %tmp = call i32 @llvm.smul.fix.sat.i32(i32 %x, i32 %y, i32 2)
   ret i32 %tmp
 }
 
 define i64 @func2(i64 %x, i64 %y) {
-; CHECK-LABEL: func2:
-; CHECK:       // %bb.0:
-; CHECK-NEXT:    mul x9, x0, x1
-; CHECK-NEXT:    mov x8, #9223372036854775807 // =0x7fffffffffffffff
-; CHECK-NEXT:    smulh x10, x0, x1
-; CHECK-NEXT:    extr x9, x10, x9, #2
-; CHECK-NEXT:    cmp x10, #1
-; CHECK-NEXT:    csel x8, x8, x9, gt
-; CHECK-NEXT:    cmn x10, #2
-; CHECK-NEXT:    mov x9, #-9223372036854775808 // =0x8000000000000000
-; CHECK-NEXT:    csel x0, x9, x8, lt
-; CHECK-NEXT:    ret
+; CHECK-SD-LABEL: func2:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    mul x9, x0, x1
+; CHECK-SD-NEXT:    mov x8, #9223372036854775807 // =0x7fffffffffffffff
+; CHECK-SD-NEXT:    smulh x10, x0, x1
+; CHECK-SD-NEXT:    extr x9, x10, x9, #2
+; CHECK-SD-NEXT:    cmp x10, #1
+; CHECK-SD-NEXT:    csel x8, x8, x9, gt
+; CHECK-SD-NEXT:    cmn x10, #2
+; CHECK-SD-NEXT:    mov x9, #-9223372036854775808 // =0x8000000000000000
+; CHECK-SD-NEXT:    csel x0, x9, x8, lt
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: func2:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    umulh x9, x0, x1
+; CHECK-GI-NEXT:    asr x10, x1, #63
+; CHECK-GI-NEXT:    mov x8, #9223372036854775807 // =0x7fffffffffffffff
+; CHECK-GI-NEXT:    mul x11, x0, x1
+; CHECK-GI-NEXT:    madd x9, x0, x10, x9
+; CHECK-GI-NEXT:    asr x10, x0, #63
+; CHECK-GI-NEXT:    madd x9, x10, x1, x9
+; CHECK-GI-NEXT:    extr x10, x9, x11, #2
+; CHECK-GI-NEXT:    asr x9, x9, #2
+; CHECK-GI-NEXT:    cmp x10, x8
+; CHECK-GI-NEXT:    cset w11, lo
+; CHECK-GI-NEXT:    cmp x9, #0
+; CHECK-GI-NEXT:    cset w12, mi
+; CHECK-GI-NEXT:    csel w11, w11, w12, eq
+; CHECK-GI-NEXT:    tst w11, #0x1
+; CHECK-GI-NEXT:    csel x8, x10, x8, ne
+; CHECK-GI-NEXT:    mov x10, #-9223372036854775808 // =0x8000000000000000
+; CHECK-GI-NEXT:    csel x9, x9, xzr, ne
+; CHECK-GI-NEXT:    cmp x8, x10
+; CHECK-GI-NEXT:    cset w11, hi
+; CHECK-GI-NEXT:    cmn x9, #1
+; CHECK-GI-NEXT:    cset w9, gt
+; CHECK-GI-NEXT:    csel w9, w11, w9, eq
+; CHECK-GI-NEXT:    tst w9, #0x1
+; CHECK-GI-NEXT:    csel x0, x8, x10, ne
+; CHECK-GI-NEXT:    ret
   %tmp = call i64 @llvm.smul.fix.sat.i64(i64 %x, i64 %y, i32 2)
   ret i64 %tmp
 }
 
 define i4 @func3(i4 %x, i4 %y) {
-; CHECK-LABEL: func3:
-; CHECK:       // %bb.0:
-; CHECK-NEXT:    sbfx w9, w1, #0, #4
-; CHECK-NEXT:    lsl w10, w0, #28
-; CHECK-NEXT:    mov w8, #2147483647 // =0x7fffffff
-; CHECK-NEXT:    smull x9, w10, w9
-; CHECK-NEXT:    lsr x10, x9, #32
-; CHECK-NEXT:    extr w9, w10, w9, #2
-; CHECK-NEXT:    cmp w10, #1
-; CHECK-NEXT:    csel w8, w8, w9, gt
-; CHECK-NEXT:    cmn w10, #2
-; CHECK-NEXT:    mov w9, #-2147483648 // =0x80000000
-; CHECK-NEXT:    csel w8, w9, w8, lt
-; CHECK-NEXT:    asr w0, w8, #28
-; CHECK-NEXT:    ret
+; CHECK-SD-LABEL: func3:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    sbfx w9, w1, #0, #4
+; CHECK-SD-NEXT:    lsl w10, w0, #28
+; CHECK-SD-NEXT:    mov w8, #2147483647 // =0x7fffffff
+; CHECK-SD-NEXT:    smull x9, w10, w9
+; CHECK-SD-NEXT:    lsr x10, x9, #32
+; CHECK-SD-NEXT:    extr w9, w10, w9, #2
+; CHECK-SD-NEXT:    cmp w10, #1
+; CHECK-SD-NEXT:    csel w8, w8, w9, gt
+; CHECK-SD-NEXT:    cmn w10, #2
+; CHECK-SD-NEXT:    mov w9, #-2147483648 // =0x80000000
+; CHECK-SD-NEXT:    csel w8, w9, w8, lt
+; CHECK-SD-NEXT:    asr w0, w8, #28
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: func3:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    sbfx w9, w0, #0, #4
+; CHECK-GI-NEXT:    sbfx w10, w1, #0, #4
+; CHECK-GI-NEXT:    mov w8, #7 // =0x7
+; CHECK-GI-NEXT:    mul w9, w9, w10
+; CHECK-GI-NEXT:    sbfx w9, w9, #2, #6
+; CHECK-GI-NEXT:    cmp w9, #7
+; CHECK-GI-NEXT:    csel w8, w9, w8, lt
+; CHECK-GI-NEXT:    mov w9, #-8 // =0xfffffff8
+; CHECK-GI-NEXT:    cmn w8, #8
+; CHECK-GI-NEXT:    csel w0, w8, w9, gt
+; CHECK-GI-NEXT:    ret
   %tmp = call i4 @llvm.smul.fix.sat.i4(i4 %x, i4 %y, i32 2)
   ret i4 %tmp
 }
 
 ;; These result in regular integer multiplication with a saturation check.
 define i32 @func4(i32 %x, i32 %y) {
-; CHECK-LABEL: func4:
-; CHECK:       // %bb.0:
-; CHECK-NEXT:    smull x9, w0, w1
-; CHECK-NEXT:    eor w10, w0, w1
-; CHECK-NEXT:    mov w8, #-2147483648 // =0x80000000
-; CHECK-NEXT:    cmp w10, #0
-; CHECK-NEXT:    cinv w8, w8, pl
-; CHECK-NEXT:    cmp x9, w9, sxtw
-; CHECK-NEXT:    csel w0, w8, w9, ne
-; CHECK-NEXT:    ret
+; CHECK-SD-LABEL: func4:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    smull x9, w0, w1
+; CHECK-SD-NEXT:    eor w10, w0, w1
+; CHECK-SD-NEXT:    mov w8, #-2147483648 // =0x80000000
+; CHECK-SD-NEXT:    cmp w10, #0
+; CHECK-SD-NEXT:    cinv w8, w8, pl
+; CHECK-SD-NEXT:    cmp x9, w9, sxtw
+; CHECK-SD-NEXT:    csel w0, w8, w9, ne
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: func4:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    smull x8, w0, w1
+; CHECK-GI-NEXT:    mov w9, #2147483647 // =0x7fffffff
+; CHECK-GI-NEXT:    cmp x8, x9
+; CHECK-GI-NEXT:    csel x8, x8, x9, lt
+; CHECK-GI-NEXT:    mov x9, #-2147483648 // =0xffffffff80000000
+; CHECK-GI-NEXT:    cmp x8, x9
+; CHECK-GI-NEXT:    csel x0, x8, x9, gt
+; CHECK-GI-NEXT:    // kill: def $w0 killed $w0 killed $x0
+; CHECK-GI-NEXT:    ret
   %tmp = call i32 @llvm.smul.fix.sat.i32(i32 %x, i32 %y, i32 0)
   ret i32 %tmp
 }
 
 define i64 @func5(i64 %x, i64 %y) {
-; CHECK-LABEL: func5:
-; CHECK:       // %bb.0:
-; CHECK-NEXT:    mul x9, x0, x1
-; CHECK-NEXT:    eor x11, x0, x1
-; CHECK-NEXT:    mov x8, #-9223372036854775808 // =0x8000000000000000
-; CHECK-NEXT:    cmp x11, #0
-; CHECK-NEXT:    smulh x10, x0, x1
-; CHECK-NEXT:    cinv x8, x8, pl
-; CHECK-NEXT:    cmp x10, x9, asr #63
-; CHECK-NEXT:    csel x0, x8, x9, ne
-; CHECK-NEXT:    ret
+; CHECK-SD-LABEL: func5:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    mul x9, x0, x1
+; CHECK-SD-NEXT:    eor x11, x0, x1
+; CHECK-SD-NEXT:    mov x8, #-9223372036854775808 // =0x8000000000000000
+; CHECK-SD-NEXT:    cmp x11, #0
+; CHECK-SD-NEXT:    smulh x10, x0, x1
+; CHECK-SD-NEXT:    cinv x8, x8, pl
+; CHECK-SD-NEXT:    cmp x10, x9, asr #63
+; CHECK-SD-NEXT:    csel x0, x8, x9, ne
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: func5:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    umulh x8, x0, x1
+; CHECK-GI-NEXT:    asr x9, x1, #63
+; CHECK-GI-NEXT:    mul x10, x0, x1
+; CHECK-GI-NEXT:    madd x8, x0, x9, x8
+; CHECK-GI-NEXT:    asr x9, x0, #63
+; CHECK-GI-NEXT:    madd x8, x9, x1, x8
+; CHECK-GI-NEXT:    mov x9, #9223372036854775807 // =0x7fffffffffffffff
+; CHECK-GI-NEXT:    cmp x10, x9
+; CHECK-GI-NEXT:    cset w11, lo
+; CHECK-GI-NEXT:    cmp x8, #0
+; CHECK-GI-NEXT:    cset w12, mi
+; CHECK-GI-NEXT:    csel w11, w11, w12, eq
+; CHECK-GI-NEXT:    tst w11, #0x1
+; CHECK-GI-NEXT:    csel x9, x10, x9, ne
+; CHECK-GI-NEXT:    mov x10, #-9223372036854775808 // =0x8000000000000000
+; CHECK-GI-NEXT:    csel x8, x8, xzr, ne
+; CHECK-GI-NEXT:    cmp x9...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/217221


More information about the llvm-commits mailing list