[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