[llvm] [GlobalISel][AArch64] Add lowering for G_SMULFIXSAT and G_UMULFIXSAT (PR #197400)
Gábor Spaits via llvm-commits
llvm-commits at lists.llvm.org
Wed May 13 02:51:05 PDT 2026
https://github.com/spaits created https://github.com/llvm/llvm-project/pull/197400
None
>From 7c33f4dd8a8dbaa4005d16062ab47391908fc9f0 Mon Sep 17 00:00:00 2001
From: Gabor Spaits <gaborspaits1 at gmail.com>
Date: Mon, 11 May 2026 16:30:49 +0200
Subject: [PATCH 1/6] [GlobalISel][AArch64] Add lowering for G_UMULFIX
---
.../llvm/CodeGen/GlobalISel/LegalizerHelper.h | 2 +-
.../CodeGen/GlobalISel/LegalizerHelper.cpp | 28 ++-
.../AArch64/GISel/AArch64LegalizerInfo.cpp | 2 +-
.../AArch64/GlobalISel/legalize-smulfix.mir | 24 +--
.../AArch64/GlobalISel/legalize-umulfix.mir | 179 ++++++++++++++++++
.../GlobalISel/legalizer-info-validation.mir | 5 +-
llvm/test/CodeGen/AArch64/umul_fix.ll | 169 +++++++++++------
7 files changed, 330 insertions(+), 79 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/legalize-umulfix.mir
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
index 9858f5e92de7a..3377ec71c8f0a 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
@@ -576,7 +576,7 @@ class LegalizerHelper {
LLVM_ABI LegalizeResult lowerMemCpyFamily(MachineInstr &MI,
unsigned MaxLen = 0);
LLVM_ABI LegalizeResult lowerVAArg(MachineInstr &MI);
- LLVM_ABI LegalizeResult lowerSmulfix(MachineInstr &MI);
+ LLVM_ABI LegalizeResult lowerMulfix(MachineInstr &MI);
};
} // End namespace llvm.
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 070d7ec4b963e..4b8276f9b77e0 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -37,6 +37,7 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
+#include <cassert>
#include <numeric>
#include <optional>
@@ -4969,7 +4970,8 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
return Legalized;
}
case G_SMULFIX:
- return lowerSmulfix(MI);
+ case G_UMULFIX:
+ return lowerMulfix(MI);
}
}
@@ -10656,8 +10658,11 @@ LegalizerHelper::LegalizeResult LegalizerHelper::lowerVAArg(MachineInstr &MI) {
return Legalized;
}
-LegalizerHelper::LegalizeResult
-LegalizerHelper::lowerSmulfix(MachineInstr &MI) {
+LegalizerHelper::LegalizeResult LegalizerHelper::lowerMulfix(MachineInstr &MI) {
+ unsigned OpCode = MI.getOpcode();
+ assert(OpCode == TargetOpcode::G_SMULFIX ||
+ OpCode == TargetOpcode::G_UMULFIX &&
+ "Operator must be either G_SMULFIX or G_UMULFIX!");
auto [Dst, LHS, RHS] = MI.getFirst3Regs();
LLT Ty = MRI.getType(Dst);
unsigned Scale = MI.getOperand(3).getImm();
@@ -10669,12 +10674,19 @@ LegalizerHelper::lowerSmulfix(MachineInstr &MI) {
}
LLT WideTy = Ty.changeElementSize(Ty.getScalarSizeInBits() * 2);
- auto SExtLHS = MIRBuilder.buildSExt(WideTy, LHS);
- auto SExtRHS = MIRBuilder.buildSExt(WideTy, RHS);
- auto Mul = MIRBuilder.buildMul(WideTy, SExtLHS, SExtRHS);
auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Scale);
- auto Shifted = MIRBuilder.buildAShr(WideTy, Mul, ShiftAmt);
- MIRBuilder.buildTrunc(Dst, Shifted);
+ MachineInstrBuilder ExtLHS{}, ExtRHS{};
+ if (MI.getOpcode() == TargetOpcode::G_SMULFIX) {
+ ExtLHS = MIRBuilder.buildSExt(WideTy, LHS);
+ ExtRHS = MIRBuilder.buildSExt(WideTy, RHS);
+ } else {
+ ExtLHS = MIRBuilder.buildZExt(WideTy, LHS);
+ ExtRHS = MIRBuilder.buildZExt(WideTy, RHS);
+ }
+
+ auto Mul = MIRBuilder.buildMul(WideTy, ExtLHS, ExtRHS);
+ auto Shift = MIRBuilder.buildAShr(WideTy, Mul, ShiftAmt);
+ MIRBuilder.buildTrunc(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 4c7abbfb871af..e2bff9f74360c 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
@@ -297,7 +297,7 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
.legalFor({i64, v16i8, v8i16, v4i32})
.lower();
- getActionDefinitionsBuilder(G_SMULFIX).lower();
+ getActionDefinitionsBuilder({G_SMULFIX, G_UMULFIX}).lower();
getActionDefinitionsBuilder({G_SMIN, G_SMAX, G_UMIN, G_UMAX})
.legalFor({v8i8, v16i8, v4i16, v8i16, v2i32, v4i32})
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-smulfix.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-smulfix.mir
index 2b660e5064b03..2bc0c420461be 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-smulfix.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-smulfix.mir
@@ -31,10 +31,10 @@ body: |
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(i32) = COPY $w1
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 15
; CHECK-NEXT: [[SEXT:%[0-9]+]]:_(i64) = G_SEXT [[COPY]](i32)
; CHECK-NEXT: [[SEXT1:%[0-9]+]]:_(i64) = G_SEXT [[COPY1]](i32)
; CHECK-NEXT: [[MUL:%[0-9]+]]:_(i64) = G_MUL [[SEXT]], [[SEXT1]]
- ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 15
; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(i64) = G_ASHR [[MUL]], [[C]](i64)
; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(i32) = G_TRUNC [[ASHR]](i64)
; CHECK-NEXT: $w0 = COPY [[TRUNC]](i32)
@@ -56,17 +56,17 @@ body: |
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i64) = COPY $x0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(i64) = COPY $x1
- ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 63
- ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(i64) = G_ASHR [[COPY]], [[C]](i64)
- ; CHECK-NEXT: [[ASHR1:%[0-9]+]]:_(i64) = G_ASHR [[COPY1]], [[C]](i64)
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 15
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(i64) = G_CONSTANT i64 63
+ ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(i64) = G_ASHR [[COPY]], [[C1]](i64)
+ ; CHECK-NEXT: [[ASHR1:%[0-9]+]]:_(i64) = G_ASHR [[COPY1]], [[C1]](i64)
; CHECK-NEXT: [[MUL:%[0-9]+]]:_(i64) = G_MUL [[COPY]], [[COPY1]]
; CHECK-NEXT: [[MUL1:%[0-9]+]]:_(i64) = G_MUL [[ASHR]], [[COPY1]]
; CHECK-NEXT: [[MUL2:%[0-9]+]]:_(i64) = G_MUL [[COPY]], [[ASHR1]]
; CHECK-NEXT: [[UMULH:%[0-9]+]]:_(i64) = G_UMULH [[COPY]], [[COPY1]]
; CHECK-NEXT: [[ADD:%[0-9]+]]:_(i64) = G_ADD [[MUL1]], [[MUL2]]
; CHECK-NEXT: [[ADD1:%[0-9]+]]:_(i64) = G_ADD [[ADD]], [[UMULH]]
- ; CHECK-NEXT: [[C1:%[0-9]+]]:_(i64) = G_CONSTANT i64 15
- ; CHECK-NEXT: [[LSHR:%[0-9]+]]:_(i64) = G_LSHR [[MUL]], [[C1]](i64)
+ ; CHECK-NEXT: [[LSHR:%[0-9]+]]:_(i64) = G_LSHR [[MUL]], [[C]](i64)
; CHECK-NEXT: [[C2:%[0-9]+]]:_(i64) = G_CONSTANT i64 49
; CHECK-NEXT: [[SHL:%[0-9]+]]:_(i64) = G_SHL [[ADD1]], [[C2]](i64)
; CHECK-NEXT: [[OR:%[0-9]+]]:_(i64) = G_OR [[LSHR]], [[SHL]]
@@ -89,6 +89,8 @@ body: |
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<4 x i32>) = COPY $q0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(<4 x i32>) = COPY $q1
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 2
+ ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<2 x i64>) = G_BUILD_VECTOR [[C]](i64), [[C]](i64)
; CHECK-NEXT: [[UV:%[0-9]+]]:_(<2 x i32>), [[UV1:%[0-9]+]]:_(<2 x i32>) = G_UNMERGE_VALUES [[COPY]](<4 x i32>)
; CHECK-NEXT: [[SEXT:%[0-9]+]]:_(<2 x i64>) = G_SEXT [[UV]](<2 x i32>)
; CHECK-NEXT: [[SEXT1:%[0-9]+]]:_(<2 x i64>) = G_SEXT [[UV1]](<2 x i32>)
@@ -97,8 +99,6 @@ body: |
; CHECK-NEXT: [[SEXT3:%[0-9]+]]:_(<2 x i64>) = G_SEXT [[UV3]](<2 x i32>)
; CHECK-NEXT: [[MUL:%[0-9]+]]:_(<2 x i64>) = G_MUL [[SEXT]], [[SEXT2]]
; CHECK-NEXT: [[MUL1:%[0-9]+]]:_(<2 x i64>) = G_MUL [[SEXT1]], [[SEXT3]]
- ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 2
- ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<2 x i64>) = G_BUILD_VECTOR [[C]](i64), [[C]](i64)
; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL]], [[BUILD_VECTOR]](<2 x i64>)
; CHECK-NEXT: [[ASHR1:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL1]], [[BUILD_VECTOR]](<2 x i64>)
; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(<2 x i32>) = G_TRUNC [[ASHR]](<2 x i64>)
@@ -123,6 +123,8 @@ body: |
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<4 x i32>) = COPY $q0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(<4 x i32>) = COPY $q1
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 15
+ ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<2 x i64>) = G_BUILD_VECTOR [[C]](i64), [[C]](i64)
; CHECK-NEXT: [[UV:%[0-9]+]]:_(<2 x i32>), [[UV1:%[0-9]+]]:_(<2 x i32>) = G_UNMERGE_VALUES [[COPY]](<4 x i32>)
; CHECK-NEXT: [[SEXT:%[0-9]+]]:_(<2 x i64>) = G_SEXT [[UV]](<2 x i32>)
; CHECK-NEXT: [[SEXT1:%[0-9]+]]:_(<2 x i64>) = G_SEXT [[UV1]](<2 x i32>)
@@ -131,8 +133,6 @@ body: |
; CHECK-NEXT: [[SEXT3:%[0-9]+]]:_(<2 x i64>) = G_SEXT [[UV3]](<2 x i32>)
; CHECK-NEXT: [[MUL:%[0-9]+]]:_(<2 x i64>) = G_MUL [[SEXT]], [[SEXT2]]
; CHECK-NEXT: [[MUL1:%[0-9]+]]:_(<2 x i64>) = G_MUL [[SEXT1]], [[SEXT3]]
- ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 15
- ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<2 x i64>) = G_BUILD_VECTOR [[C]](i64), [[C]](i64)
; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL]], [[BUILD_VECTOR]](<2 x i64>)
; CHECK-NEXT: [[ASHR1:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL1]], [[BUILD_VECTOR]](<2 x i64>)
; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(<2 x i32>) = G_TRUNC [[ASHR]](<2 x i64>)
@@ -156,6 +156,8 @@ body: |
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<4 x i32>) = COPY $q0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(<4 x i32>) = COPY $q1
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 31
+ ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<2 x i64>) = G_BUILD_VECTOR [[C]](i64), [[C]](i64)
; CHECK-NEXT: [[UV:%[0-9]+]]:_(<2 x i32>), [[UV1:%[0-9]+]]:_(<2 x i32>) = G_UNMERGE_VALUES [[COPY]](<4 x i32>)
; CHECK-NEXT: [[SEXT:%[0-9]+]]:_(<2 x i64>) = G_SEXT [[UV]](<2 x i32>)
; CHECK-NEXT: [[SEXT1:%[0-9]+]]:_(<2 x i64>) = G_SEXT [[UV1]](<2 x i32>)
@@ -164,8 +166,6 @@ body: |
; CHECK-NEXT: [[SEXT3:%[0-9]+]]:_(<2 x i64>) = G_SEXT [[UV3]](<2 x i32>)
; CHECK-NEXT: [[MUL:%[0-9]+]]:_(<2 x i64>) = G_MUL [[SEXT]], [[SEXT2]]
; CHECK-NEXT: [[MUL1:%[0-9]+]]:_(<2 x i64>) = G_MUL [[SEXT1]], [[SEXT3]]
- ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 31
- ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<2 x i64>) = G_BUILD_VECTOR [[C]](i64), [[C]](i64)
; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL]], [[BUILD_VECTOR]](<2 x i64>)
; CHECK-NEXT: [[ASHR1:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL1]], [[BUILD_VECTOR]](<2 x i64>)
; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(<2 x i32>) = G_TRUNC [[ASHR]](<2 x i64>)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-umulfix.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-umulfix.mir
new file mode 100644
index 0000000000000..1ad22728793b8
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-umulfix.mir
@@ -0,0 +1,179 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -global-isel -mtriple=aarch64 -run-pass=legalizer %s -o - | FileCheck %s
+---
+name: smulfix_i32_scale_0
+body: |
+ bb.1:
+ liveins: $w0, $w1
+
+ ; CHECK-LABEL: name: smulfix_i32_scale_0
+ ; CHECK: liveins: $w0, $w1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(i32) = COPY $w1
+ ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(i32) = G_MUL [[COPY]], [[COPY1]]
+ ; CHECK-NEXT: $w0 = COPY [[MUL]](i32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:_(i32) = COPY $w0
+ %1:_(i32) = COPY $w1
+ %2:_(i32) = G_UMULFIX %0, %1, 0
+ $w0 = COPY %2(i32)
+ RET_ReallyLR implicit $w0
+...
+---
+name: smulfix_i32
+body: |
+ bb.1:
+ liveins: $w0, $w1
+
+ ; CHECK-LABEL: name: smulfix_i32
+ ; CHECK: liveins: $w0, $w1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(i32) = COPY $w1
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 15
+ ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(i64) = G_ZEXT [[COPY]](i32)
+ ; CHECK-NEXT: [[ZEXT1:%[0-9]+]]:_(i64) = G_ZEXT [[COPY1]](i32)
+ ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(i64) = G_MUL [[ZEXT]], [[ZEXT1]]
+ ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(i64) = G_ASHR [[MUL]], [[C]](i64)
+ ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(i32) = G_TRUNC [[ASHR]](i64)
+ ; CHECK-NEXT: $w0 = COPY [[TRUNC]](i32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:_(i32) = COPY $w0
+ %1:_(i32) = COPY $w1
+ %2:_(i32) = G_UMULFIX %0, %1, 15
+ $w0 = COPY %2(i32)
+ RET_ReallyLR implicit $w0
+...
+---
+name: smulfix_i64
+body: |
+ bb.1:
+ liveins: $x0, $x1
+
+ ; CHECK-LABEL: name: smulfix_i64
+ ; CHECK: liveins: $x0, $x1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i64) = COPY $x0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(i64) = COPY $x1
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 15
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(i64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(i64) = G_MUL [[COPY]], [[COPY1]]
+ ; CHECK-NEXT: [[MUL1:%[0-9]+]]:_(i64) = G_MUL [[C1]], [[COPY1]]
+ ; CHECK-NEXT: [[MUL2:%[0-9]+]]:_(i64) = G_MUL [[COPY]], [[C1]]
+ ; CHECK-NEXT: [[UMULH:%[0-9]+]]:_(i64) = G_UMULH [[COPY]], [[COPY1]]
+ ; CHECK-NEXT: [[ADD:%[0-9]+]]:_(i64) = G_ADD [[MUL1]], [[MUL2]]
+ ; CHECK-NEXT: [[ADD1:%[0-9]+]]:_(i64) = G_ADD [[ADD]], [[UMULH]]
+ ; CHECK-NEXT: [[LSHR:%[0-9]+]]:_(i64) = G_LSHR [[MUL]], [[C]](i64)
+ ; CHECK-NEXT: [[C2:%[0-9]+]]:_(i64) = G_CONSTANT i64 49
+ ; CHECK-NEXT: [[SHL:%[0-9]+]]:_(i64) = G_SHL [[ADD1]], [[C2]](i64)
+ ; CHECK-NEXT: [[OR:%[0-9]+]]:_(i64) = G_OR [[LSHR]], [[SHL]]
+ ; CHECK-NEXT: $x0 = COPY [[OR]](i64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $x0
+ %0:_(i64) = COPY $x0
+ %1:_(i64) = COPY $x1
+ %2:_(i64) = G_UMULFIX %0, %1, 15
+ $x0 = COPY %2(i64)
+ RET_ReallyLR implicit $x0
+...
+---
+name: smulfix_4xi32
+body: |
+ bb.1:
+ liveins: $q0, $q1
+
+ ; CHECK-LABEL: name: smulfix_4xi32
+ ; CHECK: liveins: $q0, $q1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<4 x i32>) = COPY $q0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(<4 x i32>) = COPY $q1
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 2
+ ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<2 x i64>) = G_BUILD_VECTOR [[C]](i64), [[C]](i64)
+ ; CHECK-NEXT: [[UV:%[0-9]+]]:_(<2 x i32>), [[UV1:%[0-9]+]]:_(<2 x i32>) = G_UNMERGE_VALUES [[COPY]](<4 x i32>)
+ ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV]](<2 x i32>)
+ ; CHECK-NEXT: [[ZEXT1:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV1]](<2 x i32>)
+ ; CHECK-NEXT: [[UV2:%[0-9]+]]:_(<2 x i32>), [[UV3:%[0-9]+]]:_(<2 x i32>) = G_UNMERGE_VALUES [[COPY1]](<4 x i32>)
+ ; CHECK-NEXT: [[ZEXT2:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV2]](<2 x i32>)
+ ; CHECK-NEXT: [[ZEXT3:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV3]](<2 x i32>)
+ ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(<2 x i64>) = G_MUL [[ZEXT]], [[ZEXT2]]
+ ; CHECK-NEXT: [[MUL1:%[0-9]+]]:_(<2 x i64>) = G_MUL [[ZEXT1]], [[ZEXT3]]
+ ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[ASHR1:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL1]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(<2 x i32>) = G_TRUNC [[ASHR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(<2 x i32>) = G_TRUNC [[ASHR1]](<2 x i64>)
+ ; CHECK-NEXT: [[CONCAT_VECTORS:%[0-9]+]]:_(<4 x i32>) = G_CONCAT_VECTORS [[TRUNC]](<2 x i32>), [[TRUNC1]](<2 x i32>)
+ ; CHECK-NEXT: $q0 = COPY [[CONCAT_VECTORS]](<4 x i32>)
+ ; CHECK-NEXT: RET_ReallyLR implicit $q0
+ %0:_(<4 x i32>) = COPY $q0
+ %1:_(<4 x i32>) = COPY $q1
+ %2:_(<4 x i32>) = G_UMULFIX %0, %1, 2
+ $q0 = COPY %2(<4 x i32>)
+ RET_ReallyLR implicit $q0
+...
+---
+name: smulfix_4xi32_15
+body: |
+ bb.1:
+ liveins: $q0, $q1
+
+ ; CHECK-LABEL: name: smulfix_4xi32_15
+ ; CHECK: liveins: $q0, $q1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<4 x i32>) = COPY $q0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(<4 x i32>) = COPY $q1
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 15
+ ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<2 x i64>) = G_BUILD_VECTOR [[C]](i64), [[C]](i64)
+ ; CHECK-NEXT: [[UV:%[0-9]+]]:_(<2 x i32>), [[UV1:%[0-9]+]]:_(<2 x i32>) = G_UNMERGE_VALUES [[COPY]](<4 x i32>)
+ ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV]](<2 x i32>)
+ ; CHECK-NEXT: [[ZEXT1:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV1]](<2 x i32>)
+ ; CHECK-NEXT: [[UV2:%[0-9]+]]:_(<2 x i32>), [[UV3:%[0-9]+]]:_(<2 x i32>) = G_UNMERGE_VALUES [[COPY1]](<4 x i32>)
+ ; CHECK-NEXT: [[ZEXT2:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV2]](<2 x i32>)
+ ; CHECK-NEXT: [[ZEXT3:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV3]](<2 x i32>)
+ ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(<2 x i64>) = G_MUL [[ZEXT]], [[ZEXT2]]
+ ; CHECK-NEXT: [[MUL1:%[0-9]+]]:_(<2 x i64>) = G_MUL [[ZEXT1]], [[ZEXT3]]
+ ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[ASHR1:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL1]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(<2 x i32>) = G_TRUNC [[ASHR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(<2 x i32>) = G_TRUNC [[ASHR1]](<2 x i64>)
+ ; CHECK-NEXT: [[CONCAT_VECTORS:%[0-9]+]]:_(<4 x i32>) = G_CONCAT_VECTORS [[TRUNC]](<2 x i32>), [[TRUNC1]](<2 x i32>)
+ ; CHECK-NEXT: $q0 = COPY [[CONCAT_VECTORS]](<4 x i32>)
+ ; CHECK-NEXT: RET_ReallyLR implicit $q0
+ %0:_(<4 x i32>) = COPY $q0
+ %1:_(<4 x i32>) = COPY $q1
+ %2:_(<4 x i32>) = G_UMULFIX %0, %1, 15
+ $q0 = COPY %2(<4 x i32>)
+ RET_ReallyLR implicit $q0
+...
+---
+name: smulfix_4xi32_31
+body: |
+ bb.1:
+ liveins: $q0, $q1
+ ; CHECK-LABEL: name: smulfix_4xi32_31
+ ; CHECK: liveins: $q0, $q1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<4 x i32>) = COPY $q0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(<4 x i32>) = COPY $q1
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 31
+ ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<2 x i64>) = G_BUILD_VECTOR [[C]](i64), [[C]](i64)
+ ; CHECK-NEXT: [[UV:%[0-9]+]]:_(<2 x i32>), [[UV1:%[0-9]+]]:_(<2 x i32>) = G_UNMERGE_VALUES [[COPY]](<4 x i32>)
+ ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV]](<2 x i32>)
+ ; CHECK-NEXT: [[ZEXT1:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV1]](<2 x i32>)
+ ; CHECK-NEXT: [[UV2:%[0-9]+]]:_(<2 x i32>), [[UV3:%[0-9]+]]:_(<2 x i32>) = G_UNMERGE_VALUES [[COPY1]](<4 x i32>)
+ ; CHECK-NEXT: [[ZEXT2:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV2]](<2 x i32>)
+ ; CHECK-NEXT: [[ZEXT3:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV3]](<2 x i32>)
+ ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(<2 x i64>) = G_MUL [[ZEXT]], [[ZEXT2]]
+ ; CHECK-NEXT: [[MUL1:%[0-9]+]]:_(<2 x i64>) = G_MUL [[ZEXT1]], [[ZEXT3]]
+ ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[ASHR1:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL1]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(<2 x i32>) = G_TRUNC [[ASHR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(<2 x i32>) = G_TRUNC [[ASHR1]](<2 x i64>)
+ ; CHECK-NEXT: [[CONCAT_VECTORS:%[0-9]+]]:_(<4 x i32>) = G_CONCAT_VECTORS [[TRUNC]](<2 x i32>), [[TRUNC1]](<2 x i32>)
+ ; CHECK-NEXT: $q0 = COPY [[CONCAT_VECTORS]](<4 x i32>)
+ ; CHECK-NEXT: RET_ReallyLR implicit $q0
+ %0:_(<4 x i32>) = COPY $q0
+ %1:_(<4 x i32>) = COPY $q1
+ %2:_(<4 x i32>) = G_UMULFIX %0, %1, 31
+ $q0 = COPY %2(<4 x i32>)
+ RET_ReallyLR implicit $q0
+...
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
index 70dbeb7d49f65..cdf28d74e82c4 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
@@ -495,8 +495,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_UMULFIX (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_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
diff --git a/llvm/test/CodeGen/AArch64/umul_fix.ll b/llvm/test/CodeGen/AArch64/umul_fix.ll
index 823f4bdecbad6..29862369b8a08 100644
--- a/llvm/test/CodeGen/AArch64/umul_fix.ll
+++ b/llvm/test/CodeGen/AArch64/umul_fix.ll
@@ -1,13 +1,21 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc < %s -mtriple=aarch64-linux-gnu | FileCheck %s
+; RUN: llc < %s -mtriple=aarch64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-SD
+; RUN: llc < %s -mtriple=aarch64-linux-gnu -global-isel | FileCheck %s --check-prefixes=CHECK,CHECK-GI
define i32 @func(i32 %x, i32 %y) nounwind {
-; CHECK-LABEL: func:
-; CHECK: // %bb.0:
-; CHECK-NEXT: umull x8, w0, w1
-; CHECK-NEXT: lsr x9, x8, #32
-; CHECK-NEXT: extr w0, w9, w8, #2
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: func:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: umull x8, w0, w1
+; CHECK-SD-NEXT: lsr x9, x8, #32
+; CHECK-SD-NEXT: extr w0, w9, w8, #2
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: func:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: umull x8, w0, w1
+; CHECK-GI-NEXT: asr x0, x8, #2
+; CHECK-GI-NEXT: // kill: def $w0 killed $w0 killed $x0
+; CHECK-GI-NEXT: ret
%tmp = call i32 @llvm.umul.fix.i32(i32 %x, i32 %y, i32 2)
ret i32 %tmp
}
@@ -24,13 +32,21 @@ define i64 @func2(i64 %x, i64 %y) nounwind {
}
define i4 @func3(i4 %x, i4 %y) nounwind {
-; CHECK-LABEL: func3:
-; CHECK: // %bb.0:
-; CHECK-NEXT: and w8, w1, #0xf
-; CHECK-NEXT: and w9, w0, #0xf
-; CHECK-NEXT: mul w8, w9, w8
-; CHECK-NEXT: lsr w0, w8, #2
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: func3:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: and w8, w1, #0xf
+; CHECK-SD-NEXT: and w9, w0, #0xf
+; CHECK-SD-NEXT: mul w8, w9, w8
+; CHECK-SD-NEXT: lsr w0, w8, #2
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: func3:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: and w8, w0, #0xf
+; CHECK-GI-NEXT: and w9, w1, #0xf
+; CHECK-GI-NEXT: mul w8, w8, w9
+; CHECK-GI-NEXT: sbfx w0, w8, #2, #6
+; CHECK-GI-NEXT: ret
%tmp = call i4 @llvm.umul.fix.i4(i4 %x, i4 %y, i32 2)
ret i4 %tmp
}
@@ -55,12 +71,17 @@ define i64 @func5(i64 %x, i64 %y) nounwind {
}
define i4 @func6(i4 %x, i4 %y) nounwind {
-; CHECK-LABEL: func6:
-; CHECK: // %bb.0:
-; CHECK-NEXT: and w8, w1, #0xf
-; CHECK-NEXT: and w9, w0, #0xf
-; CHECK-NEXT: mul w0, w9, w8
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: func6:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: and w8, w1, #0xf
+; CHECK-SD-NEXT: and w9, w0, #0xf
+; CHECK-SD-NEXT: mul w0, w9, w8
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: func6:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: mul w0, w0, w1
+; CHECK-GI-NEXT: ret
%tmp = call i4 @llvm.umul.fix.i4(i4 %x, i4 %y, i32 0)
ret i4 %tmp
}
@@ -115,46 +136,84 @@ define <4 x i32> @vec2(<4 x i32> %x, <4 x i32> %y) nounwind {
}
define <4 x i64> @vec3(<4 x i64> %x, <4 x i64> %y) nounwind {
-; CHECK-LABEL: vec3:
-; CHECK: // %bb.0:
-; CHECK-NEXT: mov x8, v2.d[1]
-; CHECK-NEXT: mov x9, v0.d[1]
-; CHECK-NEXT: fmov x10, d2
-; CHECK-NEXT: fmov x11, d0
-; CHECK-NEXT: mov x14, v3.d[1]
-; CHECK-NEXT: mov x15, v1.d[1]
-; CHECK-NEXT: mul x12, x11, x10
-; CHECK-NEXT: mul x13, x9, x8
-; CHECK-NEXT: umulh x8, x9, x8
-; CHECK-NEXT: umulh x9, x11, x10
-; CHECK-NEXT: fmov x10, d3
-; CHECK-NEXT: fmov x11, d1
-; CHECK-NEXT: mul x16, x11, x10
-; CHECK-NEXT: extr x8, x8, x13, #32
-; CHECK-NEXT: umulh x10, x11, x10
-; CHECK-NEXT: extr x9, x9, x12, #32
-; CHECK-NEXT: mul x11, x15, x14
-; CHECK-NEXT: fmov d0, x9
-; CHECK-NEXT: umulh x14, x15, x14
-; CHECK-NEXT: extr x10, x10, x16, #32
-; CHECK-NEXT: mov v0.d[1], x8
-; CHECK-NEXT: fmov d1, x10
-; CHECK-NEXT: extr x11, x14, x11, #32
-; CHECK-NEXT: mov v1.d[1], x11
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: vec3:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: mov x8, v2.d[1]
+; CHECK-SD-NEXT: mov x9, v0.d[1]
+; CHECK-SD-NEXT: fmov x10, d2
+; CHECK-SD-NEXT: fmov x11, d0
+; CHECK-SD-NEXT: mov x14, v3.d[1]
+; CHECK-SD-NEXT: mov x15, v1.d[1]
+; CHECK-SD-NEXT: mul x12, x11, x10
+; CHECK-SD-NEXT: mul x13, x9, x8
+; CHECK-SD-NEXT: umulh x8, x9, x8
+; CHECK-SD-NEXT: umulh x9, x11, x10
+; CHECK-SD-NEXT: fmov x10, d3
+; CHECK-SD-NEXT: fmov x11, d1
+; CHECK-SD-NEXT: mul x16, x11, x10
+; CHECK-SD-NEXT: extr x8, x8, x13, #32
+; CHECK-SD-NEXT: umulh x10, x11, x10
+; CHECK-SD-NEXT: extr x9, x9, x12, #32
+; CHECK-SD-NEXT: mul x11, x15, x14
+; CHECK-SD-NEXT: fmov d0, x9
+; CHECK-SD-NEXT: umulh x14, x15, x14
+; CHECK-SD-NEXT: extr x10, x10, x16, #32
+; CHECK-SD-NEXT: mov v0.d[1], x8
+; CHECK-SD-NEXT: fmov d1, x10
+; CHECK-SD-NEXT: extr x11, x14, x11, #32
+; CHECK-SD-NEXT: mov v1.d[1], x11
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: vec3:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: mov d4, v0.d[1]
+; CHECK-GI-NEXT: mov d5, v2.d[1]
+; CHECK-GI-NEXT: fmov x8, d0
+; CHECK-GI-NEXT: fmov x9, d2
+; CHECK-GI-NEXT: mov d0, v1.d[1]
+; CHECK-GI-NEXT: mov d2, v3.d[1]
+; CHECK-GI-NEXT: fmov x13, d3
+; CHECK-GI-NEXT: mul x10, x8, x9
+; CHECK-GI-NEXT: fmov x11, d5
+; CHECK-GI-NEXT: fmov x15, d2
+; CHECK-GI-NEXT: umulh x8, x8, x9
+; CHECK-GI-NEXT: fmov x9, d4
+; CHECK-GI-NEXT: mul x12, x9, x11
+; CHECK-GI-NEXT: umulh x9, x9, x11
+; CHECK-GI-NEXT: fmov x11, d1
+; CHECK-GI-NEXT: extr x8, x8, x10, #32
+; CHECK-GI-NEXT: mul x14, x11, x13
+; CHECK-GI-NEXT: umulh x11, x11, x13
+; CHECK-GI-NEXT: fmov x13, d0
+; CHECK-GI-NEXT: fmov d0, x8
+; CHECK-GI-NEXT: extr x9, x9, x12, #32
+; CHECK-GI-NEXT: mul x16, x13, x15
+; CHECK-GI-NEXT: mov v0.d[1], x9
+; CHECK-GI-NEXT: umulh x13, x13, x15
+; CHECK-GI-NEXT: extr x10, x11, x14, #32
+; CHECK-GI-NEXT: fmov d1, x10
+; CHECK-GI-NEXT: extr x11, x13, x16, #32
+; CHECK-GI-NEXT: mov v1.d[1], x11
+; CHECK-GI-NEXT: ret
%tmp = call <4 x i64> @llvm.umul.fix.v4i64(<4 x i64> %x, <4 x i64> %y, i32 32)
ret <4 x i64> %tmp
}
define <4 x i16> @widemul(<4 x i16> %x, <4 x i16> %y) nounwind {
-; CHECK-LABEL: widemul:
-; CHECK: // %bb.0:
-; CHECK-NEXT: umull v0.4s, v0.4h, v1.4h
-; CHECK-NEXT: shrn v1.4h, v0.4s, #16
-; CHECK-NEXT: xtn v2.4h, v0.4s
-; CHECK-NEXT: shl v0.4h, v1.4h, #12
-; CHECK-NEXT: usra v0.4h, v2.4h, #4
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: widemul:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: umull v0.4s, v0.4h, v1.4h
+; CHECK-SD-NEXT: shrn v1.4h, v0.4s, #16
+; CHECK-SD-NEXT: xtn v2.4h, v0.4s
+; CHECK-SD-NEXT: shl v0.4h, v1.4h, #12
+; CHECK-SD-NEXT: usra v0.4h, v2.4h, #4
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: widemul:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: umull v0.4s, v0.4h, v1.4h
+; CHECK-GI-NEXT: shrn v0.4h, v0.4s, #4
+; CHECK-GI-NEXT: ret
%tmp = call <4 x i16> @llvm.umul.fix.v4i16(<4 x i16> %x, <4 x i16> %y, i32 4)
ret <4 x i16> %tmp
}
>From 3650f40129c6edbe3d84e00217e77a90380a007e Mon Sep 17 00:00:00 2001
From: Gabor Spaits <gaborspaits1 at gmail.com>
Date: Mon, 11 May 2026 23:01:56 +0200
Subject: [PATCH 2/6] Test flags
---
llvm/test/CodeGen/AArch64/GlobalISel/legalize-umulfix.mir | 2 +-
llvm/test/CodeGen/AArch64/umul_fix.ll | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-umulfix.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-umulfix.mir
index 1ad22728793b8..d27fba2cc4091 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-umulfix.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-umulfix.mir
@@ -1,5 +1,5 @@
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
-# RUN: llc -global-isel -mtriple=aarch64 -run-pass=legalizer %s -o - | FileCheck %s
+# RUN: llc -mtriple=aarch64 -run-pass=legalizer %s -o - | FileCheck %s
---
name: smulfix_i32_scale_0
body: |
diff --git a/llvm/test/CodeGen/AArch64/umul_fix.ll b/llvm/test/CodeGen/AArch64/umul_fix.ll
index 29862369b8a08..986dc40a744fe 100644
--- a/llvm/test/CodeGen/AArch64/umul_fix.ll
+++ b/llvm/test/CodeGen/AArch64/umul_fix.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc < %s -mtriple=aarch64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-SD
+; 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 | FileCheck %s --check-prefixes=CHECK,CHECK-GI
define i32 @func(i32 %x, i32 %y) nounwind {
>From 6bf548bac521b1c861f7dc1e114bae393b8fcc26 Mon Sep 17 00:00:00 2001
From: Gabor Spaits <gaborspaits1 at gmail.com>
Date: Tue, 12 May 2026 09:29:28 +0200
Subject: [PATCH 3/6] Use logical shift right for unsigned case
---
.../CodeGen/GlobalISel/LegalizerHelper.cpp | 8 ++++--
.../AArch64/GlobalISel/legalize-umulfix.mir | 28 +++++++++----------
llvm/test/CodeGen/AArch64/umul_fix.ll | 4 +--
3 files changed, 22 insertions(+), 18 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 4b8276f9b77e0..e6e385b81fa7a 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -10675,7 +10675,7 @@ LegalizerHelper::LegalizeResult LegalizerHelper::lowerMulfix(MachineInstr &MI) {
LLT WideTy = Ty.changeElementSize(Ty.getScalarSizeInBits() * 2);
auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Scale);
- MachineInstrBuilder ExtLHS{}, ExtRHS{};
+ MachineInstrBuilder ExtLHS{}, ExtRHS{}, Shift{};
if (MI.getOpcode() == TargetOpcode::G_SMULFIX) {
ExtLHS = MIRBuilder.buildSExt(WideTy, LHS);
ExtRHS = MIRBuilder.buildSExt(WideTy, RHS);
@@ -10685,7 +10685,11 @@ LegalizerHelper::LegalizeResult LegalizerHelper::lowerMulfix(MachineInstr &MI) {
}
auto Mul = MIRBuilder.buildMul(WideTy, ExtLHS, ExtRHS);
- auto Shift = MIRBuilder.buildAShr(WideTy, Mul, ShiftAmt);
+ if (MI.getOpcode() == TargetOpcode::G_SMULFIX)
+ Shift = MIRBuilder.buildAShr(WideTy, Mul, ShiftAmt);
+ else
+ Shift = MIRBuilder.buildLShr(WideTy, Mul, ShiftAmt);
+
MIRBuilder.buildTrunc(Dst, Shift);
MI.eraseFromParent();
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-umulfix.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-umulfix.mir
index d27fba2cc4091..5d57177816db1 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-umulfix.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-umulfix.mir
@@ -35,8 +35,8 @@ body: |
; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(i64) = G_ZEXT [[COPY]](i32)
; CHECK-NEXT: [[ZEXT1:%[0-9]+]]:_(i64) = G_ZEXT [[COPY1]](i32)
; CHECK-NEXT: [[MUL:%[0-9]+]]:_(i64) = G_MUL [[ZEXT]], [[ZEXT1]]
- ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(i64) = G_ASHR [[MUL]], [[C]](i64)
- ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(i32) = G_TRUNC [[ASHR]](i64)
+ ; CHECK-NEXT: [[LSHR:%[0-9]+]]:_(i64) = G_LSHR [[MUL]], [[C]](i64)
+ ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(i32) = G_TRUNC [[LSHR]](i64)
; CHECK-NEXT: $w0 = COPY [[TRUNC]](i32)
; CHECK-NEXT: RET_ReallyLR implicit $w0
%0:_(i32) = COPY $w0
@@ -97,10 +97,10 @@ body: |
; CHECK-NEXT: [[ZEXT3:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV3]](<2 x i32>)
; CHECK-NEXT: [[MUL:%[0-9]+]]:_(<2 x i64>) = G_MUL [[ZEXT]], [[ZEXT2]]
; CHECK-NEXT: [[MUL1:%[0-9]+]]:_(<2 x i64>) = G_MUL [[ZEXT1]], [[ZEXT3]]
- ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL]], [[BUILD_VECTOR]](<2 x i64>)
- ; CHECK-NEXT: [[ASHR1:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL1]], [[BUILD_VECTOR]](<2 x i64>)
- ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(<2 x i32>) = G_TRUNC [[ASHR]](<2 x i64>)
- ; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(<2 x i32>) = G_TRUNC [[ASHR1]](<2 x i64>)
+ ; CHECK-NEXT: [[LSHR:%[0-9]+]]:_(<2 x i64>) = G_LSHR [[MUL]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[LSHR1:%[0-9]+]]:_(<2 x i64>) = G_LSHR [[MUL1]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(<2 x i32>) = G_TRUNC [[LSHR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(<2 x i32>) = G_TRUNC [[LSHR1]](<2 x i64>)
; CHECK-NEXT: [[CONCAT_VECTORS:%[0-9]+]]:_(<4 x i32>) = G_CONCAT_VECTORS [[TRUNC]](<2 x i32>), [[TRUNC1]](<2 x i32>)
; CHECK-NEXT: $q0 = COPY [[CONCAT_VECTORS]](<4 x i32>)
; CHECK-NEXT: RET_ReallyLR implicit $q0
@@ -131,10 +131,10 @@ body: |
; CHECK-NEXT: [[ZEXT3:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV3]](<2 x i32>)
; CHECK-NEXT: [[MUL:%[0-9]+]]:_(<2 x i64>) = G_MUL [[ZEXT]], [[ZEXT2]]
; CHECK-NEXT: [[MUL1:%[0-9]+]]:_(<2 x i64>) = G_MUL [[ZEXT1]], [[ZEXT3]]
- ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL]], [[BUILD_VECTOR]](<2 x i64>)
- ; CHECK-NEXT: [[ASHR1:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL1]], [[BUILD_VECTOR]](<2 x i64>)
- ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(<2 x i32>) = G_TRUNC [[ASHR]](<2 x i64>)
- ; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(<2 x i32>) = G_TRUNC [[ASHR1]](<2 x i64>)
+ ; CHECK-NEXT: [[LSHR:%[0-9]+]]:_(<2 x i64>) = G_LSHR [[MUL]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[LSHR1:%[0-9]+]]:_(<2 x i64>) = G_LSHR [[MUL1]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(<2 x i32>) = G_TRUNC [[LSHR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(<2 x i32>) = G_TRUNC [[LSHR1]](<2 x i64>)
; CHECK-NEXT: [[CONCAT_VECTORS:%[0-9]+]]:_(<4 x i32>) = G_CONCAT_VECTORS [[TRUNC]](<2 x i32>), [[TRUNC1]](<2 x i32>)
; CHECK-NEXT: $q0 = COPY [[CONCAT_VECTORS]](<4 x i32>)
; CHECK-NEXT: RET_ReallyLR implicit $q0
@@ -164,10 +164,10 @@ body: |
; CHECK-NEXT: [[ZEXT3:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV3]](<2 x i32>)
; CHECK-NEXT: [[MUL:%[0-9]+]]:_(<2 x i64>) = G_MUL [[ZEXT]], [[ZEXT2]]
; CHECK-NEXT: [[MUL1:%[0-9]+]]:_(<2 x i64>) = G_MUL [[ZEXT1]], [[ZEXT3]]
- ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL]], [[BUILD_VECTOR]](<2 x i64>)
- ; CHECK-NEXT: [[ASHR1:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL1]], [[BUILD_VECTOR]](<2 x i64>)
- ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(<2 x i32>) = G_TRUNC [[ASHR]](<2 x i64>)
- ; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(<2 x i32>) = G_TRUNC [[ASHR1]](<2 x i64>)
+ ; CHECK-NEXT: [[LSHR:%[0-9]+]]:_(<2 x i64>) = G_LSHR [[MUL]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[LSHR1:%[0-9]+]]:_(<2 x i64>) = G_LSHR [[MUL1]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(<2 x i32>) = G_TRUNC [[LSHR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(<2 x i32>) = G_TRUNC [[LSHR1]](<2 x i64>)
; CHECK-NEXT: [[CONCAT_VECTORS:%[0-9]+]]:_(<4 x i32>) = G_CONCAT_VECTORS [[TRUNC]](<2 x i32>), [[TRUNC1]](<2 x i32>)
; CHECK-NEXT: $q0 = COPY [[CONCAT_VECTORS]](<4 x i32>)
; CHECK-NEXT: RET_ReallyLR implicit $q0
diff --git a/llvm/test/CodeGen/AArch64/umul_fix.ll b/llvm/test/CodeGen/AArch64/umul_fix.ll
index 986dc40a744fe..0656f5e17b30e 100644
--- a/llvm/test/CodeGen/AArch64/umul_fix.ll
+++ b/llvm/test/CodeGen/AArch64/umul_fix.ll
@@ -13,7 +13,7 @@ define i32 @func(i32 %x, i32 %y) nounwind {
; CHECK-GI-LABEL: func:
; CHECK-GI: // %bb.0:
; CHECK-GI-NEXT: umull x8, w0, w1
-; CHECK-GI-NEXT: asr x0, x8, #2
+; CHECK-GI-NEXT: lsr x0, x8, #2
; CHECK-GI-NEXT: // kill: def $w0 killed $w0 killed $x0
; CHECK-GI-NEXT: ret
%tmp = call i32 @llvm.umul.fix.i32(i32 %x, i32 %y, i32 2)
@@ -45,7 +45,7 @@ define i4 @func3(i4 %x, i4 %y) nounwind {
; CHECK-GI-NEXT: and w8, w0, #0xf
; CHECK-GI-NEXT: and w9, w1, #0xf
; CHECK-GI-NEXT: mul w8, w8, w9
-; CHECK-GI-NEXT: sbfx w0, w8, #2, #6
+; CHECK-GI-NEXT: lsr w0, w8, #2
; CHECK-GI-NEXT: ret
%tmp = call i4 @llvm.umul.fix.i4(i4 %x, i4 %y, i32 2)
ret i4 %tmp
>From 6313c407788e3bfc972bd41c7276aaa560f8a2ec Mon Sep 17 00:00:00 2001
From: Gabor Spaits <gaborspaits1 at gmail.com>
Date: Tue, 12 May 2026 14:08:22 +0200
Subject: [PATCH 4/6] Add TODO
---
llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index e6e385b81fa7a..3e31408d0812f 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -10673,6 +10673,7 @@ LegalizerHelper::LegalizeResult LegalizerHelper::lowerMulfix(MachineInstr &MI) {
return Legalized;
}
+ // TODO: Port other lowerng paths from SelectionDAG.
LLT WideTy = Ty.changeElementSize(Ty.getScalarSizeInBits() * 2);
auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Scale);
MachineInstrBuilder ExtLHS{}, ExtRHS{}, Shift{};
>From 59de62aceedb6786bb5189d777697ba7b2182c9f Mon Sep 17 00:00:00 2001
From: Gabor Spaits <gaborspaits1 at gmail.com>
Date: Tue, 12 May 2026 16:15:05 +0200
Subject: [PATCH 5/6] [GlobalISel][AArch64] Lower G_TRUNC_SSAT_S,
G_TRUNC_SSAT_U and G_TRUNC_USAT_U
---
.../llvm/CodeGen/GlobalISel/LegalizerHelper.h | 1 +
.../CodeGen/GlobalISel/LegalizerHelper.cpp | 50 +++++++++++
.../AArch64/GISel/AArch64LegalizerInfo.cpp | 3 +-
.../GlobalISel/legalize-trunc_ssat_s.mir | 85 +++++++++++++++++++
.../GlobalISel/legalize-trunc_ssat_u.mir | 83 ++++++++++++++++++
.../GlobalISel/legalize-trunc_usat_u.mir | 74 ++++++++++++++++
.../GlobalISel/legalizer-info-validation.mir | 12 +--
7 files changed, 301 insertions(+), 7 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/legalize-trunc_ssat_s.mir
create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/legalize-trunc_ssat_u.mir
create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/legalize-trunc_usat_u.mir
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
index 3377ec71c8f0a..cdda05db6db9b 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
@@ -577,6 +577,7 @@ class LegalizerHelper {
unsigned MaxLen = 0);
LLVM_ABI LegalizeResult lowerVAArg(MachineInstr &MI);
LLVM_ABI LegalizeResult lowerMulfix(MachineInstr &MI);
+ LLVM_ABI LegalizeResult lowerTruncSat(MachineInstr &MI);
};
} // End namespace llvm.
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 3e31408d0812f..64faaa0de3ed4 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
+#include "llvm/ADT/APInt.h"
#include "llvm/CodeGen/GlobalISel/CallLowering.h"
#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
#include "llvm/CodeGen/GlobalISel/GISelValueTracking.h"
@@ -4972,6 +4973,10 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
case G_SMULFIX:
case G_UMULFIX:
return lowerMulfix(MI);
+ case G_TRUNC_SSAT_S:
+ case G_TRUNC_SSAT_U:
+ case G_TRUNC_USAT_U:
+ return lowerTruncSat(MI);
}
}
@@ -10697,6 +10702,51 @@ LegalizerHelper::LegalizeResult LegalizerHelper::lowerMulfix(MachineInstr &MI) {
return Legalized;
}
+LegalizerHelper::LegalizeResult
+LegalizerHelper::lowerTruncSat(MachineInstr &MI) {
+ unsigned OpCode = MI.getOpcode();
+ assert((OpCode == TargetOpcode::G_TRUNC_SSAT_S ||
+ OpCode == TargetOpcode::G_TRUNC_SSAT_U ||
+ OpCode == TargetOpcode::G_TRUNC_USAT_U) &&
+ "Operator must be either G_TRUNC_SSAT_S or G_TRUNC_SSAT_U or "
+ "G_TRUNC_USAT_U!");
+
+ auto [NarrowTy, WideTy] = MI.getFirst2LLTs();
+ auto [Dst, Src] = MI.getFirst2Regs();
+
+ bool IsSignedInput = OpCode == TargetOpcode::G_TRUNC_SSAT_S ||
+ OpCode == TargetOpcode::G_TRUNC_SSAT_U;
+ bool IsSignedOutput = OpCode == TargetOpcode::G_TRUNC_SSAT_S;
+
+ APInt MaxValue{}, MinValue{};
+ unsigned NarrowSize = NarrowTy.getScalarSizeInBits();
+ unsigned WideSize = WideTy.getScalarSizeInBits();
+ if (IsSignedOutput) {
+ MaxValue = APInt::getSignedMaxValue(NarrowSize).sext(WideSize);
+ MinValue = APInt::getSignedMinValue(NarrowSize).sext(WideSize);
+ } else {
+ MaxValue = APInt::getMaxValue(NarrowSize).zext(WideSize);
+ MinValue = APInt::getZero(WideSize);
+ }
+
+ MachineInstrBuilder LTmax{};
+ if (IsSignedInput) {
+ auto MaxValueConstant = MIRBuilder.buildConstant(WideTy, MaxValue);
+ auto MinValueConstant = MIRBuilder.buildConstant(WideTy, MinValue);
+
+ auto GTMin = MIRBuilder.buildSMax(WideTy, MinValueConstant, Src);
+ LTmax = MIRBuilder.buildSMin(WideTy, GTMin, MaxValueConstant);
+ } else {
+ auto MaxValueConstant = MIRBuilder.buildConstant(WideTy, MaxValue);
+ LTmax = MIRBuilder.buildUMin(WideTy, MaxValueConstant, Src);
+ }
+
+ MIRBuilder.buildTrunc(Dst, LTmax);
+
+ MI.eraseFromParent();
+ return Legalized;
+}
+
static bool shouldLowerMemFuncForSize(const MachineFunction &MF) {
// On Darwin, -Os means optimize for size without hurting performance, so
// only really optimize for size when -Oz (MinSize) is used.
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
index e2bff9f74360c..041085021374c 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
@@ -863,7 +863,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/legalize-trunc_ssat_s.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-trunc_ssat_s.mir
new file mode 100644
index 0000000000000..9bc1639dd39a1
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-trunc_ssat_s.mir
@@ -0,0 +1,85 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc %s -verify-machineinstrs -O0 -run-pass=legalizer -mtriple aarch64-unknown-unknown -o - | FileCheck %s
+...
+---
+name: trunc_ssat_s_i32_to_i8
+alignment: 4
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0
+
+ ; CHECK-LABEL: name: trunc_ssat_s_i32_to_i8
+ ; CHECK: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i32) = G_CONSTANT i32 127
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(i32) = G_CONSTANT i32 -128
+ ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(i32) = G_ICMP intpred(sgt), [[C1]](i32), [[COPY]]
+ ; CHECK-NEXT: [[SELECT:%[0-9]+]]:_(i32) = G_SELECT [[ICMP]](i32), [[C1]], [[COPY]]
+ ; CHECK-NEXT: [[ICMP1:%[0-9]+]]:_(i32) = G_ICMP intpred(slt), [[SELECT]](i32), [[C]]
+ ; CHECK-NEXT: [[SELECT1:%[0-9]+]]:_(i32) = G_SELECT [[ICMP1]](i32), [[SELECT]], [[C]]
+ ; CHECK-NEXT: [[C2:%[0-9]+]]:_(i32) = G_CONSTANT i32 255
+ ; CHECK-NEXT: [[AND:%[0-9]+]]:_(i32) = G_AND [[SELECT1]], [[C2]]
+ ; CHECK-NEXT: $w0 = COPY [[AND]](i32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:_(i32) = COPY $w0
+ %4:_(i8) = G_TRUNC_SSAT_S %0(i32)
+ %5:_(i32) = G_ZEXT %4(i8)
+ $w0 = COPY %5(i32)
+ RET_ReallyLR implicit $w0
+...
+---
+name: trunc_ssat_s_i32_to_i16
+alignment: 4
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0
+
+ ; CHECK-LABEL: name: trunc_ssat_s_i32_to_i16
+ ; CHECK: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i32) = G_CONSTANT i32 32767
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(i32) = G_CONSTANT i32 -32768
+ ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(i32) = G_ICMP intpred(sgt), [[C1]](i32), [[COPY]]
+ ; CHECK-NEXT: [[SELECT:%[0-9]+]]:_(i32) = G_SELECT [[ICMP]](i32), [[C1]], [[COPY]]
+ ; CHECK-NEXT: [[ICMP1:%[0-9]+]]:_(i32) = G_ICMP intpred(slt), [[SELECT]](i32), [[C]]
+ ; CHECK-NEXT: [[SELECT1:%[0-9]+]]:_(i32) = G_SELECT [[ICMP1]](i32), [[SELECT]], [[C]]
+ ; CHECK-NEXT: [[C2:%[0-9]+]]:_(i32) = G_CONSTANT i32 65535
+ ; CHECK-NEXT: [[AND:%[0-9]+]]:_(i32) = G_AND [[SELECT1]], [[C2]]
+ ; CHECK-NEXT: $w0 = COPY [[AND]](i32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:_(i32) = COPY $w0
+ %4:_(i16) = G_TRUNC_SSAT_S %0(i32)
+ %5:_(i32) = G_ZEXT %4(i16)
+ $w0 = COPY %5(i32)
+ RET_ReallyLR implicit $w0
+...
+---
+name: trunc_ssat_s_i64_to_i32
+alignment: 4
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+
+ ; CHECK-LABEL: name: trunc_ssat_s_i64_to_i32
+ ; CHECK: liveins: $x0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i64) = COPY $x0
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 2147483647
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(i64) = G_CONSTANT i64 -2147483648
+ ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(i32) = G_ICMP intpred(sgt), [[C1]](i64), [[COPY]]
+ ; CHECK-NEXT: [[SELECT:%[0-9]+]]:_(i64) = G_SELECT [[ICMP]](i32), [[C1]], [[COPY]]
+ ; CHECK-NEXT: [[ICMP1:%[0-9]+]]:_(i32) = G_ICMP intpred(slt), [[SELECT]](i64), [[C]]
+ ; CHECK-NEXT: [[SELECT1:%[0-9]+]]:_(i64) = G_SELECT [[ICMP1]](i32), [[SELECT]], [[C]]
+ ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(i32) = G_TRUNC [[SELECT1]](i64)
+ ; CHECK-NEXT: $w0 = COPY [[TRUNC]](i32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:_(i64) = COPY $x0
+ %4:_(i32) = G_TRUNC_SSAT_S %0(i64)
+ $w0 = COPY %4(i32)
+ RET_ReallyLR implicit $w0
+...
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-trunc_ssat_u.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-trunc_ssat_u.mir
new file mode 100644
index 0000000000000..da97e15770ca8
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-trunc_ssat_u.mir
@@ -0,0 +1,83 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc %s -verify-machineinstrs -O0 -run-pass=legalizer -mtriple aarch64-unknown-unknown -o - | FileCheck %s
+...
+---
+name: trunc_ssat_u_i32_to_i8
+alignment: 4
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0
+
+ ; CHECK-LABEL: name: trunc_ssat_u_i32_to_i8
+ ; CHECK: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i32) = G_CONSTANT i32 255
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(i32) = G_CONSTANT i32 0
+ ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(i32) = G_ICMP intpred(sgt), [[C1]](i32), [[COPY]]
+ ; CHECK-NEXT: [[SELECT:%[0-9]+]]:_(i32) = G_SELECT [[ICMP]](i32), [[C1]], [[COPY]]
+ ; CHECK-NEXT: [[ICMP1:%[0-9]+]]:_(i32) = G_ICMP intpred(slt), [[SELECT]](i32), [[C]]
+ ; CHECK-NEXT: [[SELECT1:%[0-9]+]]:_(i32) = G_SELECT [[ICMP1]](i32), [[SELECT]], [[C]]
+ ; CHECK-NEXT: [[AND:%[0-9]+]]:_(i32) = G_AND [[SELECT1]], [[C]]
+ ; CHECK-NEXT: $w0 = COPY [[AND]](i32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:_(i32) = COPY $w0
+ %4:_(i8) = G_TRUNC_SSAT_U %0(i32)
+ %5:_(i32) = G_ZEXT %4(i8)
+ $w0 = COPY %5(i32)
+ RET_ReallyLR implicit $w0
+...
+---
+name: trunc_ssat_u_i32_to_i16
+alignment: 4
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0
+
+ ; CHECK-LABEL: name: trunc_ssat_u_i32_to_i16
+ ; CHECK: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i32) = G_CONSTANT i32 65535
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(i32) = G_CONSTANT i32 0
+ ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(i32) = G_ICMP intpred(sgt), [[C1]](i32), [[COPY]]
+ ; CHECK-NEXT: [[SELECT:%[0-9]+]]:_(i32) = G_SELECT [[ICMP]](i32), [[C1]], [[COPY]]
+ ; CHECK-NEXT: [[ICMP1:%[0-9]+]]:_(i32) = G_ICMP intpred(slt), [[SELECT]](i32), [[C]]
+ ; CHECK-NEXT: [[SELECT1:%[0-9]+]]:_(i32) = G_SELECT [[ICMP1]](i32), [[SELECT]], [[C]]
+ ; CHECK-NEXT: [[AND:%[0-9]+]]:_(i32) = G_AND [[SELECT1]], [[C]]
+ ; CHECK-NEXT: $w0 = COPY [[AND]](i32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:_(i32) = COPY $w0
+ %4:_(i16) = G_TRUNC_SSAT_U %0(i32)
+ %5:_(i32) = G_ZEXT %4(i16)
+ $w0 = COPY %5(i32)
+ RET_ReallyLR implicit $w0
+...
+---
+name: trunc_ssat_u_i64_to_i32
+alignment: 4
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+
+ ; CHECK-LABEL: name: trunc_ssat_u_i64_to_i32
+ ; CHECK: liveins: $x0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i64) = COPY $x0
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 4294967295
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(i64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(i32) = G_ICMP intpred(sgt), [[C1]](i64), [[COPY]]
+ ; CHECK-NEXT: [[SELECT:%[0-9]+]]:_(i64) = G_SELECT [[ICMP]](i32), [[C1]], [[COPY]]
+ ; CHECK-NEXT: [[ICMP1:%[0-9]+]]:_(i32) = G_ICMP intpred(slt), [[SELECT]](i64), [[C]]
+ ; CHECK-NEXT: [[SELECT1:%[0-9]+]]:_(i64) = G_SELECT [[ICMP1]](i32), [[SELECT]], [[C]]
+ ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(i32) = G_TRUNC [[SELECT1]](i64)
+ ; CHECK-NEXT: $w0 = COPY [[TRUNC]](i32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:_(i64) = COPY $x0
+ %4:_(i32) = G_TRUNC_SSAT_U %0(i64)
+ $w0 = COPY %4(i32)
+ RET_ReallyLR implicit $w0
+...
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-trunc_usat_u.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-trunc_usat_u.mir
new file mode 100644
index 0000000000000..cea0443e696fa
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-trunc_usat_u.mir
@@ -0,0 +1,74 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc %s -verify-machineinstrs -O0 -run-pass=legalizer -mtriple aarch64-unknown-unknown -o - | FileCheck %s
+...
+---
+name: trunc_usat_u_i32_to_i8
+alignment: 4
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0
+
+ ; CHECK-LABEL: name: trunc_usat_u_i32_to_i8
+ ; CHECK: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i32) = G_CONSTANT i32 255
+ ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(i32) = G_ICMP intpred(ult), [[C]](i32), [[COPY]]
+ ; CHECK-NEXT: [[SELECT:%[0-9]+]]:_(i32) = G_SELECT [[ICMP]](i32), [[C]], [[COPY]]
+ ; CHECK-NEXT: [[AND:%[0-9]+]]:_(i32) = G_AND [[SELECT]], [[C]]
+ ; CHECK-NEXT: $w0 = COPY [[AND]](i32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:_(i32) = COPY $w0
+ %4:_(i8) = G_TRUNC_USAT_U %0(i32)
+ %5:_(i32) = G_ZEXT %4(i8)
+ $w0 = COPY %5(i32)
+ RET_ReallyLR implicit $w0
+...
+---
+name: trunc_usat_u_i32_to_i16
+alignment: 4
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0
+
+ ; CHECK-LABEL: name: trunc_usat_u_i32_to_i16
+ ; CHECK: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i32) = G_CONSTANT i32 65535
+ ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(i32) = G_ICMP intpred(ult), [[C]](i32), [[COPY]]
+ ; CHECK-NEXT: [[SELECT:%[0-9]+]]:_(i32) = G_SELECT [[ICMP]](i32), [[C]], [[COPY]]
+ ; CHECK-NEXT: [[AND:%[0-9]+]]:_(i32) = G_AND [[SELECT]], [[C]]
+ ; CHECK-NEXT: $w0 = COPY [[AND]](i32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:_(i32) = COPY $w0
+ %4:_(i16) = G_TRUNC_USAT_U %0(i32)
+ %5:_(i32) = G_ZEXT %4(i16)
+ $w0 = COPY %5(i32)
+ RET_ReallyLR implicit $w0
+...
+---
+name: trunc_usat_u_i64_to_i32
+alignment: 4
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+
+ ; CHECK-LABEL: name: trunc_usat_u_i64_to_i32
+ ; CHECK: liveins: $x0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i64) = COPY $x0
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 4294967295
+ ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(i32) = G_ICMP intpred(ult), [[C]](i64), [[COPY]]
+ ; CHECK-NEXT: [[SELECT:%[0-9]+]]:_(i64) = G_SELECT [[ICMP]](i32), [[C]], [[COPY]]
+ ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(i32) = G_TRUNC [[SELECT]](i64)
+ ; CHECK-NEXT: $w0 = COPY [[TRUNC]](i32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:_(i64) = COPY $x0
+ %4:_(i32) = G_TRUNC_USAT_U %0(i64)
+ $w0 = COPY %4(i32)
+ RET_ReallyLR implicit $w0
+...
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
index cdf28d74e82c4..0b60b8eb69fe7 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
@@ -353,16 +353,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
>From bf57767d42d9df660b7ee79f5f479d30f819e8ca Mon Sep 17 00:00:00 2001
From: Gabor Spaits <gaborspaits1 at gmail.com>
Date: Tue, 12 May 2026 16:32:48 +0200
Subject: [PATCH 6/6] [GlobalISel][AArch64] Add lowering for G_SMULFIXSAT and
G_UMULFIXSAT
---
.../CodeGen/GlobalISel/LegalizerHelper.cpp | 24 +-
.../AArch64/GISel/AArch64LegalizerInfo.cpp | 4 +-
.../GlobalISel/legalize-smulfixsat.mir | 214 +++++
.../GlobalISel/legalize-umulfixsat.mir | 197 +++++
.../GlobalISel/legalizer-info-validation.mir | 10 +-
llvm/test/CodeGen/AArch64/smul_fix_sat.ll | 739 +++++++++++++-----
llvm/test/CodeGen/AArch64/umul_fix_sat.ll | 482 ++++++++----
7 files changed, 1297 insertions(+), 373 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/legalize-smulfixsat.mir
create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/legalize-umulfixsat.mir
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 64faaa0de3ed4..4aeee96a17228 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -4972,6 +4972,8 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
}
case G_SMULFIX:
case G_UMULFIX:
+ case G_SMULFIXSAT:
+ case G_UMULFIXSAT:
return lowerMulfix(MI);
case G_TRUNC_SSAT_S:
case G_TRUNC_SSAT_U:
@@ -10666,13 +10668,19 @@ LegalizerHelper::LegalizeResult LegalizerHelper::lowerVAArg(MachineInstr &MI) {
LegalizerHelper::LegalizeResult LegalizerHelper::lowerMulfix(MachineInstr &MI) {
unsigned OpCode = MI.getOpcode();
assert(OpCode == TargetOpcode::G_SMULFIX ||
- OpCode == TargetOpcode::G_UMULFIX &&
+ OpCode == TargetOpcode::G_UMULFIX ||
+ OpCode == TargetOpcode::G_SMULFIXSAT ||
+ OpCode == TargetOpcode::G_UMULFIXSAT &&
"Operator must be either G_SMULFIX or G_UMULFIX!");
auto [Dst, LHS, RHS] = MI.getFirst3Regs();
LLT Ty = MRI.getType(Dst);
unsigned Scale = MI.getOperand(3).getImm();
+ bool IsSigned =
+ OpCode == TargetOpcode::G_SMULFIX || OpCode == TargetOpcode::G_SMULFIXSAT;
+ bool IsSaturating = OpCode == TargetOpcode::G_SMULFIXSAT ||
+ OpCode == TargetOpcode::G_UMULFIXSAT;
- if (Scale == 0) {
+ if (Scale == 0 && !IsSaturating) {
MIRBuilder.buildMul(Dst, LHS, RHS);
MI.eraseFromParent();
return Legalized;
@@ -10682,7 +10690,7 @@ LegalizerHelper::LegalizeResult LegalizerHelper::lowerMulfix(MachineInstr &MI) {
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 {
@@ -10691,12 +10699,18 @@ 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 (IsSaturating)
+ if (IsSigned)
+ MIRBuilder.buildTruncSSatS(Dst, Shift);
+ else
+ MIRBuilder.buildTruncUSatU(Dst, Shift);
+ else
+ MIRBuilder.buildTrunc(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 041085021374c..88b0f4384f78e 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
@@ -297,7 +297,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})
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-smulfixsat.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-smulfixsat.mir
new file mode 100644
index 0000000000000..83d355950bd28
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-smulfixsat.mir
@@ -0,0 +1,214 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=aarch64 -run-pass=legalizer %s -o - | FileCheck %s
+---
+name: smulfixsat_i32_scale_0
+body: |
+ bb.1:
+ liveins: $w0, $w1
+
+ ; CHECK-LABEL: name: smulfixsat_i32_scale_0
+ ; CHECK: liveins: $w0, $w1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(i32) = COPY $w1
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: [[SEXT:%[0-9]+]]:_(i64) = G_SEXT [[COPY]](i32)
+ ; CHECK-NEXT: [[SEXT1:%[0-9]+]]:_(i64) = G_SEXT [[COPY1]](i32)
+ ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(i64) = G_MUL [[SEXT]], [[SEXT1]]
+ ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(i64) = G_ASHR [[MUL]], [[C]](i64)
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(i64) = G_CONSTANT i64 2147483647
+ ; CHECK-NEXT: [[C2:%[0-9]+]]:_(i64) = G_CONSTANT i64 -2147483648
+ ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(i32) = G_ICMP intpred(sgt), [[C2]](i64), [[ASHR]]
+ ; CHECK-NEXT: [[SELECT:%[0-9]+]]:_(i64) = G_SELECT [[ICMP]](i32), [[C2]], [[ASHR]]
+ ; CHECK-NEXT: [[ICMP1:%[0-9]+]]:_(i32) = G_ICMP intpred(slt), [[SELECT]](i64), [[C1]]
+ ; CHECK-NEXT: [[SELECT1:%[0-9]+]]:_(i64) = G_SELECT [[ICMP1]](i32), [[SELECT]], [[C1]]
+ ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(i32) = G_TRUNC [[SELECT1]](i64)
+ ; CHECK-NEXT: $w0 = COPY [[TRUNC]](i32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:_(i32) = COPY $w0
+ %1:_(i32) = COPY $w1
+ %2:_(i32) = G_SMULFIXSAT %0, %1, 0
+ $w0 = COPY %2(i32)
+ RET_ReallyLR implicit $w0
+...
+---
+name: smulfixsat_i32
+body: |
+ bb.1:
+ liveins: $w0, $w1
+
+ ; CHECK-LABEL: name: smulfixsat_i32
+ ; CHECK: liveins: $w0, $w1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(i32) = COPY $w1
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 15
+ ; CHECK-NEXT: [[SEXT:%[0-9]+]]:_(i64) = G_SEXT [[COPY]](i32)
+ ; CHECK-NEXT: [[SEXT1:%[0-9]+]]:_(i64) = G_SEXT [[COPY1]](i32)
+ ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(i64) = G_MUL [[SEXT]], [[SEXT1]]
+ ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(i64) = G_ASHR [[MUL]], [[C]](i64)
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(i64) = G_CONSTANT i64 2147483647
+ ; CHECK-NEXT: [[C2:%[0-9]+]]:_(i64) = G_CONSTANT i64 -2147483648
+ ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(i32) = G_ICMP intpred(sgt), [[C2]](i64), [[ASHR]]
+ ; CHECK-NEXT: [[SELECT:%[0-9]+]]:_(i64) = G_SELECT [[ICMP]](i32), [[C2]], [[ASHR]]
+ ; CHECK-NEXT: [[ICMP1:%[0-9]+]]:_(i32) = G_ICMP intpred(slt), [[SELECT]](i64), [[C1]]
+ ; CHECK-NEXT: [[SELECT1:%[0-9]+]]:_(i64) = G_SELECT [[ICMP1]](i32), [[SELECT]], [[C1]]
+ ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(i32) = G_TRUNC [[SELECT1]](i64)
+ ; CHECK-NEXT: $w0 = COPY [[TRUNC]](i32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:_(i32) = COPY $w0
+ %1:_(i32) = COPY $w1
+ %2:_(i32) = G_SMULFIXSAT %0, %1, 15
+ $w0 = COPY %2(i32)
+ RET_ReallyLR implicit $w0
+...
+---
+name: smulfixsat_i64
+body: |
+ bb.1:
+ liveins: $x0, $x1
+
+ ; CHECK-LABEL: name: smulfixsat_i64
+ ; CHECK: liveins: $x0, $x1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i64) = COPY $x0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(i64) = COPY $x1
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 15
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(i64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: [[C2:%[0-9]+]]:_(i64) = G_CONSTANT i64 63
+ ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(i64) = G_ASHR [[COPY]], [[C2]](i64)
+ ; CHECK-NEXT: [[ASHR1:%[0-9]+]]:_(i64) = G_ASHR [[COPY1]], [[C2]](i64)
+ ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(i64) = G_MUL [[COPY]], [[COPY1]]
+ ; CHECK-NEXT: [[MUL1:%[0-9]+]]:_(i64) = G_MUL [[ASHR]], [[COPY1]]
+ ; CHECK-NEXT: [[MUL2:%[0-9]+]]:_(i64) = G_MUL [[COPY]], [[ASHR1]]
+ ; CHECK-NEXT: [[UMULH:%[0-9]+]]:_(i64) = G_UMULH [[COPY]], [[COPY1]]
+ ; CHECK-NEXT: [[ADD:%[0-9]+]]:_(i64) = G_ADD [[MUL1]], [[MUL2]]
+ ; CHECK-NEXT: [[ADD1:%[0-9]+]]:_(i64) = G_ADD [[ADD]], [[UMULH]]
+ ; CHECK-NEXT: [[LSHR:%[0-9]+]]:_(i64) = G_LSHR [[MUL]], [[C]](i64)
+ ; CHECK-NEXT: [[C3:%[0-9]+]]:_(i64) = G_CONSTANT i64 49
+ ; CHECK-NEXT: [[SHL:%[0-9]+]]:_(i64) = G_SHL [[ADD1]], [[C3]](i64)
+ ; CHECK-NEXT: [[OR:%[0-9]+]]:_(i64) = G_OR [[LSHR]], [[SHL]]
+ ; CHECK-NEXT: [[ASHR2:%[0-9]+]]:_(i64) = G_ASHR [[ADD1]], [[C]](i64)
+ ; CHECK-NEXT: [[C4:%[0-9]+]]:_(i64) = G_CONSTANT i64 9223372036854775807
+ ; CHECK-NEXT: [[C5:%[0-9]+]]:_(i64) = G_CONSTANT i64 -9223372036854775808
+ ; CHECK-NEXT: [[C6:%[0-9]+]]:_(i64) = G_CONSTANT i64 -1
+ ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(i32) = G_ICMP intpred(ugt), [[C5]](i64), [[OR]]
+ ; CHECK-NEXT: [[ICMP1:%[0-9]+]]:_(i32) = G_ICMP intpred(sgt), [[C6]](i64), [[ASHR2]]
+ ; CHECK-NEXT: [[ICMP2:%[0-9]+]]:_(i32) = G_ICMP intpred(eq), [[C6]](i64), [[ASHR2]]
+ ; CHECK-NEXT: [[SELECT:%[0-9]+]]:_(i32) = G_SELECT [[ICMP2]](i32), [[ICMP]], [[ICMP1]]
+ ; CHECK-NEXT: [[SELECT1:%[0-9]+]]:_(i64) = G_SELECT [[SELECT]](i32), [[C5]], [[OR]]
+ ; CHECK-NEXT: [[SELECT2:%[0-9]+]]:_(i64) = G_SELECT [[SELECT]](i32), [[C6]], [[ASHR2]]
+ ; CHECK-NEXT: [[ICMP3:%[0-9]+]]:_(i32) = G_ICMP intpred(ult), [[SELECT1]](i64), [[C4]]
+ ; CHECK-NEXT: [[ICMP4:%[0-9]+]]:_(i32) = G_ICMP intpred(slt), [[SELECT2]](i64), [[C1]]
+ ; CHECK-NEXT: [[ICMP5:%[0-9]+]]:_(i32) = G_ICMP intpred(eq), [[SELECT2]](i64), [[C1]]
+ ; CHECK-NEXT: [[SELECT3:%[0-9]+]]:_(i32) = G_SELECT [[ICMP5]](i32), [[ICMP3]], [[ICMP4]]
+ ; CHECK-NEXT: [[SELECT4:%[0-9]+]]:_(i64) = G_SELECT [[SELECT3]](i32), [[SELECT1]], [[C4]]
+ ; CHECK-NEXT: $x0 = COPY [[SELECT4]](i64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $x0
+ %0:_(i64) = COPY $x0
+ %1:_(i64) = COPY $x1
+ %2:_(i64) = G_SMULFIXSAT %0, %1, 15
+ $x0 = COPY %2(i64)
+ RET_ReallyLR implicit $x0
+...
+---
+name: smulfixsat_4xi32
+body: |
+ bb.1:
+ liveins: $q0, $q1
+
+ ; CHECK-LABEL: name: smulfixsat_4xi32
+ ; CHECK: liveins: $q0, $q1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<4 x i32>) = COPY $q0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(<4 x i32>) = COPY $q1
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 2
+ ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<2 x i64>) = G_BUILD_VECTOR [[C]](i64), [[C]](i64)
+ ; CHECK-NEXT: [[UV:%[0-9]+]]:_(<2 x i32>), [[UV1:%[0-9]+]]:_(<2 x i32>) = G_UNMERGE_VALUES [[COPY]](<4 x i32>)
+ ; CHECK-NEXT: [[SEXT:%[0-9]+]]:_(<2 x i64>) = G_SEXT [[UV]](<2 x i32>)
+ ; CHECK-NEXT: [[SEXT1:%[0-9]+]]:_(<2 x i64>) = G_SEXT [[UV1]](<2 x i32>)
+ ; CHECK-NEXT: [[UV2:%[0-9]+]]:_(<2 x i32>), [[UV3:%[0-9]+]]:_(<2 x i32>) = G_UNMERGE_VALUES [[COPY1]](<4 x i32>)
+ ; CHECK-NEXT: [[SEXT2:%[0-9]+]]:_(<2 x i64>) = G_SEXT [[UV2]](<2 x i32>)
+ ; CHECK-NEXT: [[SEXT3:%[0-9]+]]:_(<2 x i64>) = G_SEXT [[UV3]](<2 x i32>)
+ ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(<2 x i64>) = G_MUL [[SEXT]], [[SEXT2]]
+ ; CHECK-NEXT: [[MUL1:%[0-9]+]]:_(<2 x i64>) = G_MUL [[SEXT1]], [[SEXT3]]
+ ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[ASHR1:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL1]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC_SSAT_S:%[0-9]+]]:_(<2 x i32>) = G_TRUNC_SSAT_S [[ASHR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC_SSAT_S1:%[0-9]+]]:_(<2 x i32>) = G_TRUNC_SSAT_S [[ASHR1]](<2 x i64>)
+ ; CHECK-NEXT: [[CONCAT_VECTORS:%[0-9]+]]:_(<4 x i32>) = G_CONCAT_VECTORS [[TRUNC_SSAT_S]](<2 x i32>), [[TRUNC_SSAT_S1]](<2 x i32>)
+ ; CHECK-NEXT: $q0 = COPY [[CONCAT_VECTORS]](<4 x i32>)
+ ; CHECK-NEXT: RET_ReallyLR implicit $q0
+ %0:_(<4 x i32>) = COPY $q0
+ %1:_(<4 x i32>) = COPY $q1
+ %2:_(<4 x i32>) = G_SMULFIXSAT %0, %1, 2
+ $q0 = COPY %2(<4 x i32>)
+ RET_ReallyLR implicit $q0
+...
+---
+name: smulfixsat_4xi32_15
+body: |
+ bb.1:
+ liveins: $q0, $q1
+
+ ; CHECK-LABEL: name: smulfixsat_4xi32_15
+ ; CHECK: liveins: $q0, $q1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<4 x i32>) = COPY $q0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(<4 x i32>) = COPY $q1
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 15
+ ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<2 x i64>) = G_BUILD_VECTOR [[C]](i64), [[C]](i64)
+ ; CHECK-NEXT: [[UV:%[0-9]+]]:_(<2 x i32>), [[UV1:%[0-9]+]]:_(<2 x i32>) = G_UNMERGE_VALUES [[COPY]](<4 x i32>)
+ ; CHECK-NEXT: [[SEXT:%[0-9]+]]:_(<2 x i64>) = G_SEXT [[UV]](<2 x i32>)
+ ; CHECK-NEXT: [[SEXT1:%[0-9]+]]:_(<2 x i64>) = G_SEXT [[UV1]](<2 x i32>)
+ ; CHECK-NEXT: [[UV2:%[0-9]+]]:_(<2 x i32>), [[UV3:%[0-9]+]]:_(<2 x i32>) = G_UNMERGE_VALUES [[COPY1]](<4 x i32>)
+ ; CHECK-NEXT: [[SEXT2:%[0-9]+]]:_(<2 x i64>) = G_SEXT [[UV2]](<2 x i32>)
+ ; CHECK-NEXT: [[SEXT3:%[0-9]+]]:_(<2 x i64>) = G_SEXT [[UV3]](<2 x i32>)
+ ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(<2 x i64>) = G_MUL [[SEXT]], [[SEXT2]]
+ ; CHECK-NEXT: [[MUL1:%[0-9]+]]:_(<2 x i64>) = G_MUL [[SEXT1]], [[SEXT3]]
+ ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[ASHR1:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL1]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC_SSAT_S:%[0-9]+]]:_(<2 x i32>) = G_TRUNC_SSAT_S [[ASHR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC_SSAT_S1:%[0-9]+]]:_(<2 x i32>) = G_TRUNC_SSAT_S [[ASHR1]](<2 x i64>)
+ ; CHECK-NEXT: [[CONCAT_VECTORS:%[0-9]+]]:_(<4 x i32>) = G_CONCAT_VECTORS [[TRUNC_SSAT_S]](<2 x i32>), [[TRUNC_SSAT_S1]](<2 x i32>)
+ ; CHECK-NEXT: $q0 = COPY [[CONCAT_VECTORS]](<4 x i32>)
+ ; CHECK-NEXT: RET_ReallyLR implicit $q0
+ %0:_(<4 x i32>) = COPY $q0
+ %1:_(<4 x i32>) = COPY $q1
+ %2:_(<4 x i32>) = G_SMULFIXSAT %0, %1, 15
+ $q0 = COPY %2(<4 x i32>)
+ RET_ReallyLR implicit $q0
+...
+---
+name: smulfixsat_4xi32_31
+body: |
+ bb.1:
+ liveins: $q0, $q1
+ ; CHECK-LABEL: name: smulfixsat_4xi32_31
+ ; CHECK: liveins: $q0, $q1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<4 x i32>) = COPY $q0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(<4 x i32>) = COPY $q1
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 31
+ ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<2 x i64>) = G_BUILD_VECTOR [[C]](i64), [[C]](i64)
+ ; CHECK-NEXT: [[UV:%[0-9]+]]:_(<2 x i32>), [[UV1:%[0-9]+]]:_(<2 x i32>) = G_UNMERGE_VALUES [[COPY]](<4 x i32>)
+ ; CHECK-NEXT: [[SEXT:%[0-9]+]]:_(<2 x i64>) = G_SEXT [[UV]](<2 x i32>)
+ ; CHECK-NEXT: [[SEXT1:%[0-9]+]]:_(<2 x i64>) = G_SEXT [[UV1]](<2 x i32>)
+ ; CHECK-NEXT: [[UV2:%[0-9]+]]:_(<2 x i32>), [[UV3:%[0-9]+]]:_(<2 x i32>) = G_UNMERGE_VALUES [[COPY1]](<4 x i32>)
+ ; CHECK-NEXT: [[SEXT2:%[0-9]+]]:_(<2 x i64>) = G_SEXT [[UV2]](<2 x i32>)
+ ; CHECK-NEXT: [[SEXT3:%[0-9]+]]:_(<2 x i64>) = G_SEXT [[UV3]](<2 x i32>)
+ ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(<2 x i64>) = G_MUL [[SEXT]], [[SEXT2]]
+ ; CHECK-NEXT: [[MUL1:%[0-9]+]]:_(<2 x i64>) = G_MUL [[SEXT1]], [[SEXT3]]
+ ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[ASHR1:%[0-9]+]]:_(<2 x i64>) = G_ASHR [[MUL1]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC_SSAT_S:%[0-9]+]]:_(<2 x i32>) = G_TRUNC_SSAT_S [[ASHR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC_SSAT_S1:%[0-9]+]]:_(<2 x i32>) = G_TRUNC_SSAT_S [[ASHR1]](<2 x i64>)
+ ; CHECK-NEXT: [[CONCAT_VECTORS:%[0-9]+]]:_(<4 x i32>) = G_CONCAT_VECTORS [[TRUNC_SSAT_S]](<2 x i32>), [[TRUNC_SSAT_S1]](<2 x i32>)
+ ; CHECK-NEXT: $q0 = COPY [[CONCAT_VECTORS]](<4 x i32>)
+ ; CHECK-NEXT: RET_ReallyLR implicit $q0
+ %0:_(<4 x i32>) = COPY $q0
+ %1:_(<4 x i32>) = COPY $q1
+ %2:_(<4 x i32>) = G_SMULFIXSAT %0, %1, 31
+ $q0 = COPY %2(<4 x i32>)
+ RET_ReallyLR implicit $q0
+...
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-umulfixsat.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-umulfixsat.mir
new file mode 100644
index 0000000000000..7c264b853a807
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-umulfixsat.mir
@@ -0,0 +1,197 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=aarch64 -run-pass=legalizer %s -o - | FileCheck %s
+---
+name: umulfixsat_i32_scale_0
+body: |
+ bb.1:
+ liveins: $w0, $w1
+
+ ; CHECK-LABEL: name: umulfixsat_i32_scale_0
+ ; CHECK: liveins: $w0, $w1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(i32) = COPY $w1
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(i64) = G_ZEXT [[COPY]](i32)
+ ; CHECK-NEXT: [[ZEXT1:%[0-9]+]]:_(i64) = G_ZEXT [[COPY1]](i32)
+ ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(i64) = G_MUL [[ZEXT]], [[ZEXT1]]
+ ; CHECK-NEXT: [[LSHR:%[0-9]+]]:_(i64) = G_LSHR [[MUL]], [[C]](i64)
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(i64) = G_CONSTANT i64 4294967295
+ ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(i32) = G_ICMP intpred(ult), [[C1]](i64), [[LSHR]]
+ ; CHECK-NEXT: [[SELECT:%[0-9]+]]:_(i64) = G_SELECT [[ICMP]](i32), [[C1]], [[LSHR]]
+ ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(i32) = G_TRUNC [[SELECT]](i64)
+ ; CHECK-NEXT: $w0 = COPY [[TRUNC]](i32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:_(i32) = COPY $w0
+ %1:_(i32) = COPY $w1
+ %2:_(i32) = G_UMULFIXSAT %0, %1, 0
+ $w0 = COPY %2(i32)
+ RET_ReallyLR implicit $w0
+...
+---
+name: umulfixsat_i32
+body: |
+ bb.1:
+ liveins: $w0, $w1
+
+ ; CHECK-LABEL: name: umulfixsat_i32
+ ; CHECK: liveins: $w0, $w1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(i32) = COPY $w1
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 15
+ ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(i64) = G_ZEXT [[COPY]](i32)
+ ; CHECK-NEXT: [[ZEXT1:%[0-9]+]]:_(i64) = G_ZEXT [[COPY1]](i32)
+ ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(i64) = G_MUL [[ZEXT]], [[ZEXT1]]
+ ; CHECK-NEXT: [[LSHR:%[0-9]+]]:_(i64) = G_LSHR [[MUL]], [[C]](i64)
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(i64) = G_CONSTANT i64 4294967295
+ ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(i32) = G_ICMP intpred(ult), [[C1]](i64), [[LSHR]]
+ ; CHECK-NEXT: [[SELECT:%[0-9]+]]:_(i64) = G_SELECT [[ICMP]](i32), [[C1]], [[LSHR]]
+ ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(i32) = G_TRUNC [[SELECT]](i64)
+ ; CHECK-NEXT: $w0 = COPY [[TRUNC]](i32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:_(i32) = COPY $w0
+ %1:_(i32) = COPY $w1
+ %2:_(i32) = G_UMULFIXSAT %0, %1, 15
+ $w0 = COPY %2(i32)
+ RET_ReallyLR implicit $w0
+...
+---
+name: umulfixsat_i64
+body: |
+ bb.1:
+ liveins: $x0, $x1
+
+ ; CHECK-LABEL: name: umulfixsat_i64
+ ; CHECK: liveins: $x0, $x1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i64) = COPY $x0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(i64) = COPY $x1
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 15
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(i64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(i64) = G_MUL [[COPY]], [[COPY1]]
+ ; CHECK-NEXT: [[MUL1:%[0-9]+]]:_(i64) = G_MUL [[C1]], [[COPY1]]
+ ; CHECK-NEXT: [[MUL2:%[0-9]+]]:_(i64) = G_MUL [[COPY]], [[C1]]
+ ; CHECK-NEXT: [[UMULH:%[0-9]+]]:_(i64) = G_UMULH [[COPY]], [[COPY1]]
+ ; CHECK-NEXT: [[ADD:%[0-9]+]]:_(i64) = G_ADD [[MUL1]], [[MUL2]]
+ ; CHECK-NEXT: [[ADD1:%[0-9]+]]:_(i64) = G_ADD [[ADD]], [[UMULH]]
+ ; CHECK-NEXT: [[LSHR:%[0-9]+]]:_(i64) = G_LSHR [[MUL]], [[C]](i64)
+ ; CHECK-NEXT: [[C2:%[0-9]+]]:_(i64) = G_CONSTANT i64 49
+ ; CHECK-NEXT: [[SHL:%[0-9]+]]:_(i64) = G_SHL [[ADD1]], [[C2]](i64)
+ ; CHECK-NEXT: [[OR:%[0-9]+]]:_(i64) = G_OR [[LSHR]], [[SHL]]
+ ; CHECK-NEXT: [[LSHR1:%[0-9]+]]:_(i64) = G_LSHR [[ADD1]], [[C]](i64)
+ ; CHECK-NEXT: [[C3:%[0-9]+]]:_(i64) = G_CONSTANT i64 -1
+ ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(i32) = G_ICMP intpred(ult), [[C3]](i64), [[OR]]
+ ; CHECK-NEXT: [[ICMP1:%[0-9]+]]:_(i32) = G_ICMP intpred(ult), [[C1]](i64), [[LSHR1]]
+ ; CHECK-NEXT: [[ICMP2:%[0-9]+]]:_(i32) = G_ICMP intpred(eq), [[C1]](i64), [[LSHR1]]
+ ; CHECK-NEXT: [[SELECT:%[0-9]+]]:_(i32) = G_SELECT [[ICMP2]](i32), [[ICMP]], [[ICMP1]]
+ ; CHECK-NEXT: [[SELECT1:%[0-9]+]]:_(i64) = G_SELECT [[SELECT]](i32), [[C3]], [[OR]]
+ ; CHECK-NEXT: $x0 = COPY [[SELECT1]](i64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $x0
+ %0:_(i64) = COPY $x0
+ %1:_(i64) = COPY $x1
+ %2:_(i64) = G_UMULFIXSAT %0, %1, 15
+ $x0 = COPY %2(i64)
+ RET_ReallyLR implicit $x0
+...
+---
+name: umulfixsat_4xi32
+body: |
+ bb.1:
+ liveins: $q0, $q1
+
+ ; CHECK-LABEL: name: umulfixsat_4xi32
+ ; CHECK: liveins: $q0, $q1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<4 x i32>) = COPY $q0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(<4 x i32>) = COPY $q1
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 2
+ ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<2 x i64>) = G_BUILD_VECTOR [[C]](i64), [[C]](i64)
+ ; CHECK-NEXT: [[UV:%[0-9]+]]:_(<2 x i32>), [[UV1:%[0-9]+]]:_(<2 x i32>) = G_UNMERGE_VALUES [[COPY]](<4 x i32>)
+ ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV]](<2 x i32>)
+ ; CHECK-NEXT: [[ZEXT1:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV1]](<2 x i32>)
+ ; CHECK-NEXT: [[UV2:%[0-9]+]]:_(<2 x i32>), [[UV3:%[0-9]+]]:_(<2 x i32>) = G_UNMERGE_VALUES [[COPY1]](<4 x i32>)
+ ; CHECK-NEXT: [[ZEXT2:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV2]](<2 x i32>)
+ ; CHECK-NEXT: [[ZEXT3:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV3]](<2 x i32>)
+ ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(<2 x i64>) = G_MUL [[ZEXT]], [[ZEXT2]]
+ ; CHECK-NEXT: [[MUL1:%[0-9]+]]:_(<2 x i64>) = G_MUL [[ZEXT1]], [[ZEXT3]]
+ ; CHECK-NEXT: [[LSHR:%[0-9]+]]:_(<2 x i64>) = G_LSHR [[MUL]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[LSHR1:%[0-9]+]]:_(<2 x i64>) = G_LSHR [[MUL1]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC_USAT_U:%[0-9]+]]:_(<2 x i32>) = G_TRUNC_USAT_U [[LSHR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC_USAT_U1:%[0-9]+]]:_(<2 x i32>) = G_TRUNC_USAT_U [[LSHR1]](<2 x i64>)
+ ; CHECK-NEXT: [[CONCAT_VECTORS:%[0-9]+]]:_(<4 x i32>) = G_CONCAT_VECTORS [[TRUNC_USAT_U]](<2 x i32>), [[TRUNC_USAT_U1]](<2 x i32>)
+ ; CHECK-NEXT: $q0 = COPY [[CONCAT_VECTORS]](<4 x i32>)
+ ; CHECK-NEXT: RET_ReallyLR implicit $q0
+ %0:_(<4 x i32>) = COPY $q0
+ %1:_(<4 x i32>) = COPY $q1
+ %2:_(<4 x i32>) = G_UMULFIXSAT %0, %1, 2
+ $q0 = COPY %2(<4 x i32>)
+ RET_ReallyLR implicit $q0
+...
+---
+name: umulfixsat_4xi32_15
+body: |
+ bb.1:
+ liveins: $q0, $q1
+
+ ; CHECK-LABEL: name: umulfixsat_4xi32_15
+ ; CHECK: liveins: $q0, $q1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<4 x i32>) = COPY $q0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(<4 x i32>) = COPY $q1
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 15
+ ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<2 x i64>) = G_BUILD_VECTOR [[C]](i64), [[C]](i64)
+ ; CHECK-NEXT: [[UV:%[0-9]+]]:_(<2 x i32>), [[UV1:%[0-9]+]]:_(<2 x i32>) = G_UNMERGE_VALUES [[COPY]](<4 x i32>)
+ ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV]](<2 x i32>)
+ ; CHECK-NEXT: [[ZEXT1:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV1]](<2 x i32>)
+ ; CHECK-NEXT: [[UV2:%[0-9]+]]:_(<2 x i32>), [[UV3:%[0-9]+]]:_(<2 x i32>) = G_UNMERGE_VALUES [[COPY1]](<4 x i32>)
+ ; CHECK-NEXT: [[ZEXT2:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV2]](<2 x i32>)
+ ; CHECK-NEXT: [[ZEXT3:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV3]](<2 x i32>)
+ ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(<2 x i64>) = G_MUL [[ZEXT]], [[ZEXT2]]
+ ; CHECK-NEXT: [[MUL1:%[0-9]+]]:_(<2 x i64>) = G_MUL [[ZEXT1]], [[ZEXT3]]
+ ; CHECK-NEXT: [[LSHR:%[0-9]+]]:_(<2 x i64>) = G_LSHR [[MUL]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[LSHR1:%[0-9]+]]:_(<2 x i64>) = G_LSHR [[MUL1]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC_USAT_U:%[0-9]+]]:_(<2 x i32>) = G_TRUNC_USAT_U [[LSHR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC_USAT_U1:%[0-9]+]]:_(<2 x i32>) = G_TRUNC_USAT_U [[LSHR1]](<2 x i64>)
+ ; CHECK-NEXT: [[CONCAT_VECTORS:%[0-9]+]]:_(<4 x i32>) = G_CONCAT_VECTORS [[TRUNC_USAT_U]](<2 x i32>), [[TRUNC_USAT_U1]](<2 x i32>)
+ ; CHECK-NEXT: $q0 = COPY [[CONCAT_VECTORS]](<4 x i32>)
+ ; CHECK-NEXT: RET_ReallyLR implicit $q0
+ %0:_(<4 x i32>) = COPY $q0
+ %1:_(<4 x i32>) = COPY $q1
+ %2:_(<4 x i32>) = G_UMULFIXSAT %0, %1, 15
+ $q0 = COPY %2(<4 x i32>)
+ RET_ReallyLR implicit $q0
+...
+---
+name: umulfixsat_4xi32_31
+body: |
+ bb.1:
+ liveins: $q0, $q1
+ ; CHECK-LABEL: name: umulfixsat_4xi32_31
+ ; CHECK: liveins: $q0, $q1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<4 x i32>) = COPY $q0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(<4 x i32>) = COPY $q1
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 31
+ ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<2 x i64>) = G_BUILD_VECTOR [[C]](i64), [[C]](i64)
+ ; CHECK-NEXT: [[UV:%[0-9]+]]:_(<2 x i32>), [[UV1:%[0-9]+]]:_(<2 x i32>) = G_UNMERGE_VALUES [[COPY]](<4 x i32>)
+ ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV]](<2 x i32>)
+ ; CHECK-NEXT: [[ZEXT1:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV1]](<2 x i32>)
+ ; CHECK-NEXT: [[UV2:%[0-9]+]]:_(<2 x i32>), [[UV3:%[0-9]+]]:_(<2 x i32>) = G_UNMERGE_VALUES [[COPY1]](<4 x i32>)
+ ; CHECK-NEXT: [[ZEXT2:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV2]](<2 x i32>)
+ ; CHECK-NEXT: [[ZEXT3:%[0-9]+]]:_(<2 x i64>) = G_ZEXT [[UV3]](<2 x i32>)
+ ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(<2 x i64>) = G_MUL [[ZEXT]], [[ZEXT2]]
+ ; CHECK-NEXT: [[MUL1:%[0-9]+]]:_(<2 x i64>) = G_MUL [[ZEXT1]], [[ZEXT3]]
+ ; CHECK-NEXT: [[LSHR:%[0-9]+]]:_(<2 x i64>) = G_LSHR [[MUL]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[LSHR1:%[0-9]+]]:_(<2 x i64>) = G_LSHR [[MUL1]], [[BUILD_VECTOR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC_USAT_U:%[0-9]+]]:_(<2 x i32>) = G_TRUNC_USAT_U [[LSHR]](<2 x i64>)
+ ; CHECK-NEXT: [[TRUNC_USAT_U1:%[0-9]+]]:_(<2 x i32>) = G_TRUNC_USAT_U [[LSHR1]](<2 x i64>)
+ ; CHECK-NEXT: [[CONCAT_VECTORS:%[0-9]+]]:_(<4 x i32>) = G_CONCAT_VECTORS [[TRUNC_USAT_U]](<2 x i32>), [[TRUNC_USAT_U1]](<2 x i32>)
+ ; CHECK-NEXT: $q0 = COPY [[CONCAT_VECTORS]](<4 x i32>)
+ ; CHECK-NEXT: RET_ReallyLR implicit $q0
+ %0:_(<4 x i32>) = COPY $q0
+ %1:_(<4 x i32>) = COPY $q1
+ %2:_(<4 x i32>) = G_UMULFIXSAT %0, %1, 31
+ $q0 = COPY %2(<4 x i32>)
+ RET_ReallyLR implicit $q0
+...
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
index 0b60b8eb69fe7..c748f5fc925c5 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
@@ -499,11 +499,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 7cb680b8449cf..29f6f34cf8bfa 100644
--- a/llvm/test/CodeGen/AArch64/smul_fix_sat.ll
+++ b/llvm/test/CodeGen/AArch64/smul_fix_sat.ll
@@ -1,271 +1,582 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc < %s -mtriple=aarch64-linux-gnu | FileCheck %s
+; 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 | FileCheck %s --check-prefixes=CHECK,CHECK-GI
define i32 @func(i32 %x, i32 %y) nounwind {
-; 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 x9, #-2147483648 // =0xffffffff80000000
+; CHECK-GI-NEXT: mov w10, #2147483647 // =0x7fffffff
+; CHECK-GI-NEXT: asr x8, x8, #2
+; CHECK-GI-NEXT: cmp x9, x8
+; CHECK-GI-NEXT: csel x8, x9, x8, gt
+; CHECK-GI-NEXT: cmp x8, x10
+; CHECK-GI-NEXT: csel x0, x8, x10, lt
+; 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) nounwind {
-; 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: asr x9, x1, #63
+; CHECK-GI-NEXT: asr x10, x0, #63
+; CHECK-GI-NEXT: umulh x11, x0, x1
+; CHECK-GI-NEXT: mov x8, #-9223372036854775808 // =0x8000000000000000
+; CHECK-GI-NEXT: mul x9, x0, x9
+; CHECK-GI-NEXT: madd x9, x10, x1, x9
+; CHECK-GI-NEXT: mul x10, x0, x1
+; CHECK-GI-NEXT: add x9, x9, x11
+; CHECK-GI-NEXT: mov x11, #-1 // =0xffffffffffffffff
+; CHECK-GI-NEXT: extr x10, x9, x10, #2
+; CHECK-GI-NEXT: asr x9, x9, #2
+; CHECK-GI-NEXT: cmp x8, x10
+; CHECK-GI-NEXT: cset w12, hi
+; CHECK-GI-NEXT: cmp x11, x9
+; CHECK-GI-NEXT: cset w11, gt
+; CHECK-GI-NEXT: csel w11, w12, w11, eq
+; CHECK-GI-NEXT: tst w11, #0x1
+; CHECK-GI-NEXT: mov x11, #9223372036854775807 // =0x7fffffffffffffff
+; CHECK-GI-NEXT: csel x8, x8, x10, ne
+; CHECK-GI-NEXT: csinv x9, x9, xzr, eq
+; CHECK-GI-NEXT: cmp x8, x11
+; CHECK-GI-NEXT: cset w10, lo
+; CHECK-GI-NEXT: cmp x9, #0
+; CHECK-GI-NEXT: cset w9, mi
+; CHECK-GI-NEXT: csel w9, w10, w9, eq
+; CHECK-GI-NEXT: tst w9, #0x1
+; CHECK-GI-NEXT: csel x0, x8, x11, 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) nounwind {
-; 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 w8, w0, #0, #4
+; CHECK-GI-NEXT: sbfx w9, w1, #0, #4
+; CHECK-GI-NEXT: mul w8, w8, w9
+; CHECK-GI-NEXT: mov w9, #-8 // =0xfffffff8
+; CHECK-GI-NEXT: sbfx w8, w8, #2, #6
+; CHECK-GI-NEXT: cmp w9, w8
+; CHECK-GI-NEXT: csel w8, w9, w8, gt
+; CHECK-GI-NEXT: mov w9, #7 // =0x7
+; CHECK-GI-NEXT: cmp w8, #7
+; CHECK-GI-NEXT: csel w0, w8, w9, lt
+; 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) nounwind {
-; 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 x9, #-2147483648 // =0xffffffff80000000
+; CHECK-GI-NEXT: mov w10, #2147483647 // =0x7fffffff
+; CHECK-GI-NEXT: cmp x9, x8
+; CHECK-GI-NEXT: csel x8, x9, x8, gt
+; CHECK-GI-NEXT: cmp x8, x10
+; CHECK-GI-NEXT: csel x0, x8, x10, lt
+; 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: asr x8, x1, #63
+; CHECK-GI-NEXT: asr x10, x0, #63
+; CHECK-GI-NEXT: mul x9, x0, x1
+; CHECK-GI-NEXT: mul x8, x0, x8
+; CHECK-GI-NEXT: umulh x11, x0, x1
+; CHECK-GI-NEXT: madd x8, x10, x1, x8
+; CHECK-GI-NEXT: mov x10, #-9223372036854775808 // =0x8000000000000000
+; CHECK-GI-NEXT: cmp x10, x9
+; CHECK-GI-NEXT: cset w12, hi
+; CHECK-GI-NEXT: add x8, x8, x11
+; CHECK-GI-NEXT: mov x11, #-1 // =0xffffffffffffffff
+; CHECK-GI-NEXT: cmp x11, x8
+; CHECK-GI-NEXT: cset w11, gt
+; CHECK-GI-NEXT: csel w11, w12, w11, eq
+; CHECK-GI-NEXT: tst w11, #0x1
+; CHECK-GI-NEXT: mov x11, #9223372036854775807 // =0x7fffffffffffffff
+; CHECK-GI-NEXT: csel x9, x10, x9, ne
+; CHECK-GI-NEXT: csinv x8, x8, xzr, eq
+; CHECK-GI-NEXT: cmp x9, x11
+; CHECK-GI-NEXT: cset w10, lo
+; CHECK-GI-NEXT: cmp x8, #0
+; CHECK-GI-NEXT: cset w8, mi
+; CHECK-GI-NEXT: csel w8, w10, w8, eq
+; CHECK-GI-NEXT: tst w8, #0x1
+; CHECK-GI-NEXT: csel x0, x9, x11, ne
+; CHECK-GI-NEXT: ret
%tmp = call i64 @llvm.smul.fix.sat.i64(i64 %x, i64 %y, i32 0)
ret i64 %tmp
}
define i4 @func6(i4 %x, i4 %y) nounwind {
-; CHECK-LABEL: func6:
-; CHECK: // %bb.0:
-; CHECK-NEXT: sbfx w9, w1, #0, #4
-; CHECK-NEXT: lsl w10, w0, #28
-; CHECK-NEXT: mov w8, #-2147483648 // =0x80000000
-; CHECK-NEXT: smull x11, w10, w9
-; CHECK-NEXT: eor w9, w10, w9
-; CHECK-NEXT: cmp w9, #0
-; CHECK-NEXT: cinv w8, w8, pl
-; CHECK-NEXT: cmp x11, w11, sxtw
-; CHECK-NEXT: csel w8, w8, w11, ne
-; CHECK-NEXT: asr w0, w8, #28
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: func6:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: sbfx w9, w1, #0, #4
+; CHECK-SD-NEXT: lsl w10, w0, #28
+; CHECK-SD-NEXT: mov w8, #-2147483648 // =0x80000000
+; CHECK-SD-NEXT: smull x11, w10, w9
+; CHECK-SD-NEXT: eor w9, w10, w9
+; CHECK-SD-NEXT: cmp w9, #0
+; CHECK-SD-NEXT: cinv w8, w8, pl
+; CHECK-SD-NEXT: cmp x11, w11, sxtw
+; CHECK-SD-NEXT: csel w8, w8, w11, ne
+; CHECK-SD-NEXT: asr w0, w8, #28
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: func6:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: sbfx w8, w0, #0, #4
+; CHECK-GI-NEXT: sbfx w9, w1, #0, #4
+; CHECK-GI-NEXT: mul w8, w8, w9
+; CHECK-GI-NEXT: mov w9, #-8 // =0xfffffff8
+; CHECK-GI-NEXT: sxtb w8, w8
+; CHECK-GI-NEXT: cmp w9, w8
+; CHECK-GI-NEXT: csel w8, w9, w8, gt
+; CHECK-GI-NEXT: mov w9, #7 // =0x7
+; CHECK-GI-NEXT: cmp w8, #7
+; CHECK-GI-NEXT: csel w0, w8, w9, lt
+; CHECK-GI-NEXT: ret
%tmp = call i4 @llvm.smul.fix.sat.i4(i4 %x, i4 %y, i32 0)
ret i4 %tmp
}
define i64 @func7(i64 %x, i64 %y) nounwind {
-; CHECK-LABEL: func7:
-; CHECK: // %bb.0:
-; CHECK-NEXT: mul x9, x0, x1
-; CHECK-NEXT: mov w8, #2147483647 // =0x7fffffff
-; CHECK-NEXT: mov x11, #-2147483648 // =0xffffffff80000000
-; CHECK-NEXT: smulh x10, x0, x1
-; CHECK-NEXT: extr x9, x10, x9, #32
-; CHECK-NEXT: cmp x10, x8
-; CHECK-NEXT: mov x8, #9223372036854775807 // =0x7fffffffffffffff
-; CHECK-NEXT: csel x8, x8, x9, gt
-; CHECK-NEXT: cmp x10, x11
-; CHECK-NEXT: mov x9, #-9223372036854775808 // =0x8000000000000000
-; CHECK-NEXT: csel x0, x9, x8, lt
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: func7:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: mul x9, x0, x1
+; CHECK-SD-NEXT: mov w8, #2147483647 // =0x7fffffff
+; CHECK-SD-NEXT: mov x11, #-2147483648 // =0xffffffff80000000
+; CHECK-SD-NEXT: smulh x10, x0, x1
+; CHECK-SD-NEXT: extr x9, x10, x9, #32
+; CHECK-SD-NEXT: cmp x10, x8
+; CHECK-SD-NEXT: mov x8, #9223372036854775807 // =0x7fffffffffffffff
+; CHECK-SD-NEXT: csel x8, x8, x9, gt
+; CHECK-SD-NEXT: cmp x10, x11
+; CHECK-SD-NEXT: mov x9, #-9223372036854775808 // =0x8000000000000000
+; CHECK-SD-NEXT: csel x0, x9, x8, lt
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: func7:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: asr x9, x1, #63
+; CHECK-GI-NEXT: asr x10, x0, #63
+; CHECK-GI-NEXT: umulh x11, x0, x1
+; CHECK-GI-NEXT: mov x8, #-9223372036854775808 // =0x8000000000000000
+; CHECK-GI-NEXT: mul x9, x0, x9
+; CHECK-GI-NEXT: madd x9, x10, x1, x9
+; CHECK-GI-NEXT: mul x10, x0, x1
+; CHECK-GI-NEXT: add x9, x9, x11
+; CHECK-GI-NEXT: mov x11, #-1 // =0xffffffffffffffff
+; CHECK-GI-NEXT: extr x10, x9, x10, #32
+; CHECK-GI-NEXT: asr x9, x9, #32
+; CHECK-GI-NEXT: cmp x8, x10
+; CHECK-GI-NEXT: cset w12, hi
+; CHECK-GI-NEXT: cmp x11, x9
+; CHECK-GI-NEXT: cset w11, gt
+; CHECK-GI-NEXT: csel w11, w12, w11, eq
+; CHECK-GI-NEXT: tst w11, #0x1
+; CHECK-GI-NEXT: mov x11, #9223372036854775807 // =0x7fffffffffffffff
+; CHECK-GI-NEXT: csel x8, x8, x10, ne
+; CHECK-GI-NEXT: csinv x9, x9, xzr, eq
+; CHECK-GI-NEXT: cmp x8, x11
+; CHECK-GI-NEXT: cset w10, lo
+; CHECK-GI-NEXT: cmp x9, #0
+; CHECK-GI-NEXT: cset w9, mi
+; CHECK-GI-NEXT: csel w9, w10, w9, eq
+; CHECK-GI-NEXT: tst w9, #0x1
+; CHECK-GI-NEXT: csel x0, x8, x11, ne
+; CHECK-GI-NEXT: ret
%tmp = call i64 @llvm.smul.fix.sat.i64(i64 %x, i64 %y, i32 32)
ret i64 %tmp
}
define i64 @func8(i64 %x, i64 %y) nounwind {
-; CHECK-LABEL: func8:
-; CHECK: // %bb.0:
-; CHECK-NEXT: mul x9, x0, x1
-; CHECK-NEXT: mov x8, #4611686018427387903 // =0x3fffffffffffffff
-; CHECK-NEXT: mov x11, #-4611686018427387904 // =0xc000000000000000
-; CHECK-NEXT: smulh x10, x0, x1
-; CHECK-NEXT: extr x9, x10, x9, #63
-; CHECK-NEXT: cmp x10, x8
-; CHECK-NEXT: mov x8, #9223372036854775807 // =0x7fffffffffffffff
-; CHECK-NEXT: csel x8, x8, x9, gt
-; CHECK-NEXT: cmp x10, x11
-; CHECK-NEXT: mov x9, #-9223372036854775808 // =0x8000000000000000
-; CHECK-NEXT: csel x0, x9, x8, lt
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: func8:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: mul x9, x0, x1
+; CHECK-SD-NEXT: mov x8, #4611686018427387903 // =0x3fffffffffffffff
+; CHECK-SD-NEXT: mov x11, #-4611686018427387904 // =0xc000000000000000
+; CHECK-SD-NEXT: smulh x10, x0, x1
+; CHECK-SD-NEXT: extr x9, x10, x9, #63
+; CHECK-SD-NEXT: cmp x10, x8
+; CHECK-SD-NEXT: mov x8, #9223372036854775807 // =0x7fffffffffffffff
+; CHECK-SD-NEXT: csel x8, x8, x9, gt
+; CHECK-SD-NEXT: cmp x10, x11
+; CHECK-SD-NEXT: mov x9, #-9223372036854775808 // =0x8000000000000000
+; CHECK-SD-NEXT: csel x0, x9, x8, lt
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: func8:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: asr x9, x1, #63
+; CHECK-GI-NEXT: asr x10, x0, #63
+; CHECK-GI-NEXT: umulh x11, x0, x1
+; CHECK-GI-NEXT: mov x8, #-9223372036854775808 // =0x8000000000000000
+; CHECK-GI-NEXT: mul x9, x0, x9
+; CHECK-GI-NEXT: madd x9, x10, x1, x9
+; CHECK-GI-NEXT: mul x10, x0, x1
+; CHECK-GI-NEXT: add x9, x9, x11
+; CHECK-GI-NEXT: mov x11, #-1 // =0xffffffffffffffff
+; CHECK-GI-NEXT: extr x10, x9, x10, #63
+; CHECK-GI-NEXT: asr x9, x9, #63
+; CHECK-GI-NEXT: cmp x8, x10
+; CHECK-GI-NEXT: cset w12, hi
+; CHECK-GI-NEXT: cmp x11, x9
+; CHECK-GI-NEXT: cset w11, gt
+; CHECK-GI-NEXT: csel w11, w12, w11, eq
+; CHECK-GI-NEXT: tst w11, #0x1
+; CHECK-GI-NEXT: mov x11, #9223372036854775807 // =0x7fffffffffffffff
+; CHECK-GI-NEXT: csel x8, x8, x10, ne
+; CHECK-GI-NEXT: csinv x9, x9, xzr, eq
+; CHECK-GI-NEXT: cmp x8, x11
+; CHECK-GI-NEXT: cset w10, lo
+; CHECK-GI-NEXT: cmp x9, #0
+; CHECK-GI-NEXT: cset w9, mi
+; CHECK-GI-NEXT: csel w9, w10, w9, eq
+; CHECK-GI-NEXT: tst w9, #0x1
+; CHECK-GI-NEXT: csel x0, x8, x11, ne
+; CHECK-GI-NEXT: ret
%tmp = call i64 @llvm.smul.fix.sat.i64(i64 %x, i64 %y, i32 63)
ret i64 %tmp
}
define <2 x i32> @vec(<2 x i32> %x, <2 x i32> %y) nounwind {
-; CHECK-LABEL: vec:
-; CHECK: // %bb.0:
-; CHECK-NEXT: // kill: def $d1 killed $d1 def $q1
-; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0
-; CHECK-NEXT: mov w9, v1.s[1]
-; CHECK-NEXT: mov w10, v0.s[1]
-; CHECK-NEXT: mov w8, #-2147483648 // =0x80000000
-; CHECK-NEXT: fmov w12, s0
-; CHECK-NEXT: smull x11, w10, w9
-; CHECK-NEXT: eor w9, w10, w9
-; CHECK-NEXT: fmov w10, s1
-; CHECK-NEXT: cmp w9, #0
-; CHECK-NEXT: smull x9, w12, w10
-; CHECK-NEXT: eor w10, w12, w10
-; CHECK-NEXT: cinv w12, w8, pl
-; CHECK-NEXT: cmp x11, w11, sxtw
-; CHECK-NEXT: csel w11, w12, w11, ne
-; CHECK-NEXT: cmp w10, #0
-; CHECK-NEXT: cinv w8, w8, pl
-; CHECK-NEXT: cmp x9, w9, sxtw
-; CHECK-NEXT: csel w8, w8, w9, ne
-; CHECK-NEXT: fmov s0, w8
-; CHECK-NEXT: mov v0.s[1], w11
-; CHECK-NEXT: // kill: def $d0 killed $d0 killed $q0
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: vec:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: // kill: def $d1 killed $d1 def $q1
+; CHECK-SD-NEXT: // kill: def $d0 killed $d0 def $q0
+; CHECK-SD-NEXT: mov w9, v1.s[1]
+; CHECK-SD-NEXT: mov w10, v0.s[1]
+; CHECK-SD-NEXT: mov w8, #-2147483648 // =0x80000000
+; CHECK-SD-NEXT: fmov w12, s0
+; CHECK-SD-NEXT: smull x11, w10, w9
+; CHECK-SD-NEXT: eor w9, w10, w9
+; CHECK-SD-NEXT: fmov w10, s1
+; CHECK-SD-NEXT: cmp w9, #0
+; CHECK-SD-NEXT: smull x9, w12, w10
+; CHECK-SD-NEXT: eor w10, w12, w10
+; CHECK-SD-NEXT: cinv w12, w8, pl
+; CHECK-SD-NEXT: cmp x11, w11, sxtw
+; CHECK-SD-NEXT: csel w11, w12, w11, ne
+; CHECK-SD-NEXT: cmp w10, #0
+; CHECK-SD-NEXT: cinv w8, w8, pl
+; CHECK-SD-NEXT: cmp x9, w9, sxtw
+; CHECK-SD-NEXT: csel w8, w8, w9, ne
+; CHECK-SD-NEXT: fmov s0, w8
+; CHECK-SD-NEXT: mov v0.s[1], w11
+; CHECK-SD-NEXT: // kill: def $d0 killed $d0 killed $q0
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: vec:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: smull v0.2d, v0.2s, v1.2s
+; CHECK-GI-NEXT: sqxtn v0.2s, v0.2d
+; CHECK-GI-NEXT: ret
%tmp = call <2 x i32> @llvm.smul.fix.sat.v2i32(<2 x i32> %x, <2 x i32> %y, i32 0)
ret <2 x i32> %tmp
}
define <4 x i32> @vec2(<4 x i32> %x, <4 x i32> %y) nounwind {
-; CHECK-LABEL: vec2:
-; CHECK: // %bb.0:
-; CHECK-NEXT: mov w9, v1.s[1]
-; CHECK-NEXT: mov w10, v0.s[1]
-; CHECK-NEXT: mov w8, #-2147483648 // =0x80000000
-; CHECK-NEXT: fmov w12, s1
-; CHECK-NEXT: fmov w13, s0
-; CHECK-NEXT: mov w14, v0.s[2]
-; CHECK-NEXT: eor w11, w10, w9
-; CHECK-NEXT: smull x9, w10, w9
-; CHECK-NEXT: mov w10, v1.s[2]
-; CHECK-NEXT: cmp w11, #0
-; CHECK-NEXT: smull x11, w13, w12
-; CHECK-NEXT: eor w12, w13, w12
-; CHECK-NEXT: cinv w13, w8, pl
-; CHECK-NEXT: cmp x9, w9, sxtw
-; CHECK-NEXT: csel w9, w13, w9, ne
-; CHECK-NEXT: cmp w12, #0
-; CHECK-NEXT: mov w13, v1.s[3]
-; CHECK-NEXT: cinv w12, w8, pl
-; CHECK-NEXT: cmp x11, w11, sxtw
-; CHECK-NEXT: csel w11, w12, w11, ne
-; CHECK-NEXT: mov w12, v0.s[3]
-; CHECK-NEXT: fmov s0, w11
-; CHECK-NEXT: smull x11, w14, w10
-; CHECK-NEXT: mov v0.s[1], w9
-; CHECK-NEXT: eor w9, w14, w10
-; CHECK-NEXT: smull x10, w12, w13
-; CHECK-NEXT: cmp w9, #0
-; CHECK-NEXT: cinv w9, w8, pl
-; CHECK-NEXT: cmp x11, w11, sxtw
-; CHECK-NEXT: csel w9, w9, w11, ne
-; CHECK-NEXT: mov v0.s[2], w9
-; CHECK-NEXT: eor w9, w12, w13
-; CHECK-NEXT: cmp w9, #0
-; CHECK-NEXT: cinv w8, w8, pl
-; CHECK-NEXT: cmp x10, w10, sxtw
-; CHECK-NEXT: csel w8, w8, w10, ne
-; CHECK-NEXT: mov v0.s[3], w8
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: vec2:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: mov w9, v1.s[1]
+; CHECK-SD-NEXT: mov w10, v0.s[1]
+; CHECK-SD-NEXT: mov w8, #-2147483648 // =0x80000000
+; CHECK-SD-NEXT: fmov w12, s1
+; CHECK-SD-NEXT: fmov w13, s0
+; CHECK-SD-NEXT: mov w14, v0.s[2]
+; CHECK-SD-NEXT: eor w11, w10, w9
+; CHECK-SD-NEXT: smull x9, w10, w9
+; CHECK-SD-NEXT: mov w10, v1.s[2]
+; CHECK-SD-NEXT: cmp w11, #0
+; CHECK-SD-NEXT: smull x11, w13, w12
+; CHECK-SD-NEXT: eor w12, w13, w12
+; CHECK-SD-NEXT: cinv w13, w8, pl
+; CHECK-SD-NEXT: cmp x9, w9, sxtw
+; CHECK-SD-NEXT: csel w9, w13, w9, ne
+; CHECK-SD-NEXT: cmp w12, #0
+; CHECK-SD-NEXT: mov w13, v1.s[3]
+; CHECK-SD-NEXT: cinv w12, w8, pl
+; CHECK-SD-NEXT: cmp x11, w11, sxtw
+; CHECK-SD-NEXT: csel w11, w12, w11, ne
+; CHECK-SD-NEXT: mov w12, v0.s[3]
+; CHECK-SD-NEXT: fmov s0, w11
+; CHECK-SD-NEXT: smull x11, w14, w10
+; CHECK-SD-NEXT: mov v0.s[1], w9
+; CHECK-SD-NEXT: eor w9, w14, w10
+; CHECK-SD-NEXT: smull x10, w12, w13
+; CHECK-SD-NEXT: cmp w9, #0
+; CHECK-SD-NEXT: cinv w9, w8, pl
+; CHECK-SD-NEXT: cmp x11, w11, sxtw
+; CHECK-SD-NEXT: csel w9, w9, w11, ne
+; CHECK-SD-NEXT: mov v0.s[2], w9
+; CHECK-SD-NEXT: eor w9, w12, w13
+; CHECK-SD-NEXT: cmp w9, #0
+; CHECK-SD-NEXT: cinv w8, w8, pl
+; CHECK-SD-NEXT: cmp x10, w10, sxtw
+; CHECK-SD-NEXT: csel w8, w8, w10, ne
+; CHECK-SD-NEXT: mov v0.s[3], w8
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: vec2:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: smull v2.2d, v0.2s, v1.2s
+; CHECK-GI-NEXT: smull2 v1.2d, v0.4s, v1.4s
+; CHECK-GI-NEXT: sqxtn v0.2s, v2.2d
+; CHECK-GI-NEXT: sqxtn2 v0.4s, v1.2d
+; CHECK-GI-NEXT: ret
%tmp = call <4 x i32> @llvm.smul.fix.sat.v4i32(<4 x i32> %x, <4 x i32> %y, i32 0)
ret <4 x i32> %tmp
}
define <4 x i64> @vec3(<4 x i64> %x, <4 x i64> %y) nounwind {
-; CHECK-LABEL: vec3:
-; CHECK: // %bb.0:
-; CHECK-NEXT: mov x8, v2.d[1]
-; CHECK-NEXT: mov x9, v0.d[1]
-; CHECK-NEXT: mov w16, #2147483647 // =0x7fffffff
-; CHECK-NEXT: fmov x10, d2
-; CHECK-NEXT: fmov x11, d0
-; CHECK-NEXT: mov x18, #9223372036854775807 // =0x7fffffffffffffff
-; CHECK-NEXT: mov x14, v3.d[1]
-; CHECK-NEXT: mov x15, v1.d[1]
-; CHECK-NEXT: mul x13, x9, x8
-; CHECK-NEXT: smulh x8, x9, x8
-; CHECK-NEXT: mul x12, x11, x10
-; CHECK-NEXT: smulh x9, x11, x10
-; CHECK-NEXT: extr x13, x8, x13, #32
-; CHECK-NEXT: cmp x8, x16
-; CHECK-NEXT: mul x10, x15, x14
-; CHECK-NEXT: csel x13, x18, x13, gt
-; CHECK-NEXT: smulh x11, x15, x14
-; CHECK-NEXT: fmov x14, d3
-; CHECK-NEXT: fmov x15, d1
-; CHECK-NEXT: extr x12, x9, x12, #32
-; CHECK-NEXT: mul x17, x15, x14
-; CHECK-NEXT: smulh x14, x15, x14
-; CHECK-NEXT: mov x15, #-2147483648 // =0xffffffff80000000
-; CHECK-NEXT: cmp x8, x15
-; CHECK-NEXT: mov x8, #-9223372036854775808 // =0x8000000000000000
-; CHECK-NEXT: csel x13, x8, x13, lt
-; CHECK-NEXT: cmp x9, x16
-; CHECK-NEXT: csel x12, x18, x12, gt
-; CHECK-NEXT: cmp x9, x15
-; CHECK-NEXT: extr x9, x11, x10, #32
-; CHECK-NEXT: csel x10, x8, x12, lt
-; CHECK-NEXT: cmp x11, x16
-; CHECK-NEXT: csel x9, x18, x9, gt
-; CHECK-NEXT: cmp x11, x15
-; CHECK-NEXT: extr x11, x14, x17, #32
-; CHECK-NEXT: csel x9, x8, x9, lt
-; CHECK-NEXT: cmp x14, x16
-; CHECK-NEXT: fmov d0, x10
-; CHECK-NEXT: csel x11, x18, x11, gt
-; CHECK-NEXT: cmp x14, x15
-; CHECK-NEXT: csel x8, x8, x11, lt
-; CHECK-NEXT: fmov d1, x8
-; CHECK-NEXT: mov v0.d[1], x13
-; CHECK-NEXT: mov v1.d[1], x9
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: vec3:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: mov x8, v2.d[1]
+; CHECK-SD-NEXT: mov x9, v0.d[1]
+; CHECK-SD-NEXT: mov w16, #2147483647 // =0x7fffffff
+; CHECK-SD-NEXT: fmov x10, d2
+; CHECK-SD-NEXT: fmov x11, d0
+; CHECK-SD-NEXT: mov x18, #9223372036854775807 // =0x7fffffffffffffff
+; CHECK-SD-NEXT: mov x14, v3.d[1]
+; CHECK-SD-NEXT: mov x15, v1.d[1]
+; CHECK-SD-NEXT: mul x13, x9, x8
+; CHECK-SD-NEXT: smulh x8, x9, x8
+; CHECK-SD-NEXT: mul x12, x11, x10
+; CHECK-SD-NEXT: smulh x9, x11, x10
+; CHECK-SD-NEXT: extr x13, x8, x13, #32
+; CHECK-SD-NEXT: cmp x8, x16
+; CHECK-SD-NEXT: mul x10, x15, x14
+; CHECK-SD-NEXT: csel x13, x18, x13, gt
+; CHECK-SD-NEXT: smulh x11, x15, x14
+; CHECK-SD-NEXT: fmov x14, d3
+; CHECK-SD-NEXT: fmov x15, d1
+; CHECK-SD-NEXT: extr x12, x9, x12, #32
+; CHECK-SD-NEXT: mul x17, x15, x14
+; CHECK-SD-NEXT: smulh x14, x15, x14
+; CHECK-SD-NEXT: mov x15, #-2147483648 // =0xffffffff80000000
+; CHECK-SD-NEXT: cmp x8, x15
+; CHECK-SD-NEXT: mov x8, #-9223372036854775808 // =0x8000000000000000
+; CHECK-SD-NEXT: csel x13, x8, x13, lt
+; CHECK-SD-NEXT: cmp x9, x16
+; CHECK-SD-NEXT: csel x12, x18, x12, gt
+; CHECK-SD-NEXT: cmp x9, x15
+; CHECK-SD-NEXT: extr x9, x11, x10, #32
+; CHECK-SD-NEXT: csel x10, x8, x12, lt
+; CHECK-SD-NEXT: cmp x11, x16
+; CHECK-SD-NEXT: csel x9, x18, x9, gt
+; CHECK-SD-NEXT: cmp x11, x15
+; CHECK-SD-NEXT: extr x11, x14, x17, #32
+; CHECK-SD-NEXT: csel x9, x8, x9, lt
+; CHECK-SD-NEXT: cmp x14, x16
+; CHECK-SD-NEXT: fmov d0, x10
+; CHECK-SD-NEXT: csel x11, x18, x11, gt
+; CHECK-SD-NEXT: cmp x14, x15
+; CHECK-SD-NEXT: csel x8, x8, x11, lt
+; CHECK-SD-NEXT: fmov d1, x8
+; CHECK-SD-NEXT: mov v0.d[1], x13
+; CHECK-SD-NEXT: mov v1.d[1], x9
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: vec3:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: fmov x9, d2
+; CHECK-GI-NEXT: fmov x8, d0
+; CHECK-GI-NEXT: mov x2, #-1 // =0xffffffffffffffff
+; CHECK-GI-NEXT: mov d2, v2.d[1]
+; CHECK-GI-NEXT: mov d0, v0.d[1]
+; CHECK-GI-NEXT: asr x10, x9, #63
+; CHECK-GI-NEXT: asr x12, x8, #63
+; CHECK-GI-NEXT: mul x11, x8, x9
+; CHECK-GI-NEXT: mul x10, x8, x10
+; CHECK-GI-NEXT: umulh x8, x8, x9
+; CHECK-GI-NEXT: madd x9, x12, x9, x10
+; CHECK-GI-NEXT: fmov x12, d2
+; CHECK-GI-NEXT: fmov x10, d0
+; CHECK-GI-NEXT: mov d0, v3.d[1]
+; CHECK-GI-NEXT: asr x13, x12, #63
+; CHECK-GI-NEXT: asr x15, x10, #63
+; CHECK-GI-NEXT: mul x14, x10, x12
+; CHECK-GI-NEXT: mul x13, x10, x13
+; CHECK-GI-NEXT: fmov x0, d0
+; CHECK-GI-NEXT: add x8, x9, x8
+; CHECK-GI-NEXT: extr x11, x8, x11, #32
+; CHECK-GI-NEXT: asr x8, x8, #32
+; CHECK-GI-NEXT: umulh x10, x10, x12
+; CHECK-GI-NEXT: asr x1, x0, #63
+; CHECK-GI-NEXT: madd x12, x15, x12, x13
+; CHECK-GI-NEXT: fmov x15, d3
+; CHECK-GI-NEXT: fmov x13, d1
+; CHECK-GI-NEXT: mov d1, v1.d[1]
+; CHECK-GI-NEXT: asr x16, x15, #63
+; CHECK-GI-NEXT: asr x18, x13, #63
+; CHECK-GI-NEXT: mul x17, x13, x15
+; CHECK-GI-NEXT: mul x16, x13, x16
+; CHECK-GI-NEXT: add x10, x12, x10
+; CHECK-GI-NEXT: mov x12, #-9223372036854775808 // =0x8000000000000000
+; CHECK-GI-NEXT: cmp x12, x11
+; CHECK-GI-NEXT: extr x14, x10, x14, #32
+; CHECK-GI-NEXT: asr x10, x10, #32
+; CHECK-GI-NEXT: umulh x13, x13, x15
+; CHECK-GI-NEXT: madd x15, x18, x15, x16
+; CHECK-GI-NEXT: fmov x16, d1
+; CHECK-GI-NEXT: mul x18, x16, x1
+; CHECK-GI-NEXT: asr x9, x16, #63
+; CHECK-GI-NEXT: umulh x1, x16, x0
+; CHECK-GI-NEXT: add x13, x15, x13
+; CHECK-GI-NEXT: extr x17, x13, x17, #32
+; CHECK-GI-NEXT: asr x13, x13, #32
+; CHECK-GI-NEXT: madd x9, x9, x0, x18
+; CHECK-GI-NEXT: cset w18, hi
+; CHECK-GI-NEXT: cmp x2, x8
+; CHECK-GI-NEXT: cset w3, gt
+; CHECK-GI-NEXT: mul x16, x16, x0
+; CHECK-GI-NEXT: csel w15, w18, w3, eq
+; CHECK-GI-NEXT: cmp x12, x14
+; CHECK-GI-NEXT: cset w18, hi
+; CHECK-GI-NEXT: cmp x2, x10
+; CHECK-GI-NEXT: mov x3, #9223372036854775807 // =0x7fffffffffffffff
+; CHECK-GI-NEXT: cset w0, gt
+; CHECK-GI-NEXT: add x9, x9, x1
+; CHECK-GI-NEXT: csel w18, w18, w0, eq
+; CHECK-GI-NEXT: cmp x12, x17
+; CHECK-GI-NEXT: cset w0, hi
+; CHECK-GI-NEXT: cmp x2, x13
+; CHECK-GI-NEXT: extr x16, x9, x16, #32
+; CHECK-GI-NEXT: asr x9, x9, #32
+; CHECK-GI-NEXT: cset w1, gt
+; CHECK-GI-NEXT: csel w0, w0, w1, eq
+; CHECK-GI-NEXT: cmp x12, x16
+; CHECK-GI-NEXT: cset w1, hi
+; CHECK-GI-NEXT: cmp x2, x9
+; CHECK-GI-NEXT: cset w2, gt
+; CHECK-GI-NEXT: csel w1, w1, w2, eq
+; CHECK-GI-NEXT: tst w15, #0x1
+; CHECK-GI-NEXT: csel x11, x12, x11, ne
+; CHECK-GI-NEXT: csinv x8, x8, xzr, eq
+; CHECK-GI-NEXT: tst w18, #0x1
+; CHECK-GI-NEXT: csel x14, x12, x14, ne
+; CHECK-GI-NEXT: csinv x10, x10, xzr, eq
+; CHECK-GI-NEXT: tst w0, #0x1
+; CHECK-GI-NEXT: csel x15, x12, x17, ne
+; CHECK-GI-NEXT: csinv x13, x13, xzr, eq
+; CHECK-GI-NEXT: tst w1, #0x1
+; CHECK-GI-NEXT: csel x12, x12, x16, ne
+; CHECK-GI-NEXT: csinv x9, x9, xzr, eq
+; CHECK-GI-NEXT: cmp x11, x3
+; CHECK-GI-NEXT: cset w16, lo
+; CHECK-GI-NEXT: cmp x8, #0
+; CHECK-GI-NEXT: cset w8, mi
+; CHECK-GI-NEXT: csel w8, w16, w8, eq
+; CHECK-GI-NEXT: cmp x14, x3
+; CHECK-GI-NEXT: cset w16, lo
+; CHECK-GI-NEXT: cmp x10, #0
+; CHECK-GI-NEXT: cset w10, mi
+; CHECK-GI-NEXT: csel w10, w16, w10, eq
+; CHECK-GI-NEXT: cmp x15, x3
+; CHECK-GI-NEXT: cset w16, lo
+; CHECK-GI-NEXT: cmp x13, #0
+; CHECK-GI-NEXT: cset w13, mi
+; CHECK-GI-NEXT: csel w13, w16, w13, eq
+; CHECK-GI-NEXT: cmp x12, x3
+; CHECK-GI-NEXT: cset w16, lo
+; CHECK-GI-NEXT: cmp x9, #0
+; CHECK-GI-NEXT: cset w9, mi
+; CHECK-GI-NEXT: csel w9, w16, w9, eq
+; CHECK-GI-NEXT: tst w8, #0x1
+; CHECK-GI-NEXT: csel x8, x11, x3, ne
+; CHECK-GI-NEXT: tst w10, #0x1
+; CHECK-GI-NEXT: csel x10, x14, x3, ne
+; CHECK-GI-NEXT: tst w13, #0x1
+; CHECK-GI-NEXT: fmov d0, x8
+; CHECK-GI-NEXT: csel x11, x15, x3, ne
+; CHECK-GI-NEXT: tst w9, #0x1
+; CHECK-GI-NEXT: fmov d1, x11
+; CHECK-GI-NEXT: csel x9, x12, x3, ne
+; CHECK-GI-NEXT: mov v0.d[1], x10
+; CHECK-GI-NEXT: mov v1.d[1], x9
+; CHECK-GI-NEXT: ret
%tmp = call <4 x i64> @llvm.smul.fix.sat.v4i64(<4 x i64> %x, <4 x i64> %y, i32 32)
ret <4 x i64> %tmp
}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK: {{.*}}
diff --git a/llvm/test/CodeGen/AArch64/umul_fix_sat.ll b/llvm/test/CodeGen/AArch64/umul_fix_sat.ll
index e9965fd5319b5..dc1f5c1793802 100644
--- a/llvm/test/CodeGen/AArch64/umul_fix_sat.ll
+++ b/llvm/test/CodeGen/AArch64/umul_fix_sat.ll
@@ -1,206 +1,390 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc < %s -mtriple=aarch64-linux-gnu | FileCheck %s
+; 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 | FileCheck %s --check-prefixes=CHECK,CHECK-GI
define i32 @func(i32 %x, i32 %y) nounwind {
-; CHECK-LABEL: func:
-; CHECK: // %bb.0:
-; CHECK-NEXT: umull x8, w0, w1
-; CHECK-NEXT: lsr x9, x8, #32
-; CHECK-NEXT: extr w8, w9, w8, #2
-; CHECK-NEXT: cmp w9, #3
-; CHECK-NEXT: csinv w0, w8, wzr, ls
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: func:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: umull x8, w0, w1
+; CHECK-SD-NEXT: lsr x9, x8, #32
+; CHECK-SD-NEXT: extr w8, w9, w8, #2
+; CHECK-SD-NEXT: cmp w9, #3
+; CHECK-SD-NEXT: csinv w0, w8, wzr, ls
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: func:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: umull x8, w0, w1
+; CHECK-GI-NEXT: mov w9, #-1 // =0xffffffff
+; CHECK-GI-NEXT: lsr x8, x8, #2
+; CHECK-GI-NEXT: cmp x9, x8
+; CHECK-GI-NEXT: csel x0, x9, x8, lo
+; CHECK-GI-NEXT: // kill: def $w0 killed $w0 killed $x0
+; CHECK-GI-NEXT: ret
%tmp = call i32 @llvm.umul.fix.sat.i32(i32 %x, i32 %y, i32 2)
ret i32 %tmp
}
define i64 @func2(i64 %x, i64 %y) nounwind {
-; CHECK-LABEL: func2:
-; CHECK: // %bb.0:
-; CHECK-NEXT: mul x8, x0, x1
-; CHECK-NEXT: umulh x9, x0, x1
-; CHECK-NEXT: extr x8, x9, x8, #2
-; CHECK-NEXT: cmp x9, #3
-; CHECK-NEXT: csinv x0, x8, xzr, ls
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: func2:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: mul x8, x0, x1
+; CHECK-SD-NEXT: umulh x9, x0, x1
+; CHECK-SD-NEXT: extr x8, x9, x8, #2
+; CHECK-SD-NEXT: cmp x9, #3
+; CHECK-SD-NEXT: csinv x0, x8, xzr, ls
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: func2:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: mul x9, x0, x1
+; CHECK-GI-NEXT: mov x8, #-1 // =0xffffffffffffffff
+; CHECK-GI-NEXT: umulh x10, x0, x1
+; CHECK-GI-NEXT: extr x9, x10, x9, #2
+; CHECK-GI-NEXT: lsr x10, x10, #2
+; CHECK-GI-NEXT: cmp x8, x9
+; CHECK-GI-NEXT: cset w8, lo
+; CHECK-GI-NEXT: cmp xzr, x10
+; CHECK-GI-NEXT: cset w10, lo
+; CHECK-GI-NEXT: csel w8, w8, w10, eq
+; CHECK-GI-NEXT: tst w8, #0x1
+; CHECK-GI-NEXT: csinv x0, x9, xzr, eq
+; CHECK-GI-NEXT: ret
%tmp = call i64 @llvm.umul.fix.sat.i64(i64 %x, i64 %y, i32 2)
ret i64 %tmp
}
define i4 @func3(i4 %x, i4 %y) nounwind {
-; CHECK-LABEL: func3:
-; CHECK: // %bb.0:
-; CHECK-NEXT: lsl w8, w0, #28
-; CHECK-NEXT: and w9, w1, #0xf
-; CHECK-NEXT: umull x8, w8, w9
-; CHECK-NEXT: lsr x9, x8, #32
-; CHECK-NEXT: extr w8, w9, w8, #2
-; CHECK-NEXT: cmp w9, #3
-; CHECK-NEXT: csinv w8, w8, wzr, ls
-; CHECK-NEXT: lsr w0, w8, #28
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: func3:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: lsl w8, w0, #28
+; CHECK-SD-NEXT: and w9, w1, #0xf
+; CHECK-SD-NEXT: umull x8, w8, w9
+; CHECK-SD-NEXT: lsr x9, x8, #32
+; CHECK-SD-NEXT: extr w8, w9, w8, #2
+; CHECK-SD-NEXT: cmp w9, #3
+; CHECK-SD-NEXT: csinv w8, w8, wzr, ls
+; CHECK-SD-NEXT: lsr w0, w8, #28
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: func3:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: and w8, w0, #0xf
+; CHECK-GI-NEXT: and w9, w1, #0xf
+; CHECK-GI-NEXT: mul w8, w8, w9
+; CHECK-GI-NEXT: mov w9, #15 // =0xf
+; CHECK-GI-NEXT: lsr w8, w8, #2
+; CHECK-GI-NEXT: cmp w9, w8
+; CHECK-GI-NEXT: csel w0, w9, w8, lo
+; CHECK-GI-NEXT: ret
%tmp = call i4 @llvm.umul.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) nounwind {
-; CHECK-LABEL: func4:
-; CHECK: // %bb.0:
-; CHECK-NEXT: umull x8, w0, w1
-; CHECK-NEXT: tst x8, #0xffffffff00000000
-; CHECK-NEXT: csinv w0, w8, wzr, eq
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: func4:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: umull x8, w0, w1
+; CHECK-SD-NEXT: tst x8, #0xffffffff00000000
+; CHECK-SD-NEXT: csinv w0, w8, wzr, eq
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: func4:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: umull x8, w0, w1
+; CHECK-GI-NEXT: mov w9, #-1 // =0xffffffff
+; CHECK-GI-NEXT: cmp x9, x8
+; CHECK-GI-NEXT: csel x0, x9, x8, lo
+; CHECK-GI-NEXT: // kill: def $w0 killed $w0 killed $x0
+; CHECK-GI-NEXT: ret
%tmp = call i32 @llvm.umul.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: umulh x8, x0, x1
-; CHECK-NEXT: mul x9, x0, x1
-; CHECK-NEXT: cmp xzr, x8
-; CHECK-NEXT: csinv x0, x9, xzr, eq
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: func5:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: umulh x8, x0, x1
+; CHECK-SD-NEXT: mul x9, x0, x1
+; CHECK-SD-NEXT: cmp xzr, x8
+; CHECK-SD-NEXT: csinv x0, x9, xzr, eq
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: func5:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: mul x8, x0, x1
+; CHECK-GI-NEXT: mov x10, #-1 // =0xffffffffffffffff
+; CHECK-GI-NEXT: umulh x9, x0, x1
+; CHECK-GI-NEXT: cmp x10, x8
+; CHECK-GI-NEXT: cset w10, lo
+; CHECK-GI-NEXT: cmp xzr, x9
+; CHECK-GI-NEXT: cset w9, lo
+; CHECK-GI-NEXT: csel w9, w10, w9, eq
+; CHECK-GI-NEXT: tst w9, #0x1
+; CHECK-GI-NEXT: csinv x0, x8, xzr, eq
+; CHECK-GI-NEXT: ret
%tmp = call i64 @llvm.umul.fix.sat.i64(i64 %x, i64 %y, i32 0)
ret i64 %tmp
}
define i4 @func6(i4 %x, i4 %y) nounwind {
-; CHECK-LABEL: func6:
-; CHECK: // %bb.0:
-; CHECK-NEXT: lsl w8, w0, #28
-; CHECK-NEXT: and w9, w1, #0xf
-; CHECK-NEXT: umull x8, w8, w9
-; CHECK-NEXT: tst x8, #0xffffffff00000000
-; CHECK-NEXT: csinv w8, w8, wzr, eq
-; CHECK-NEXT: lsr w0, w8, #28
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: func6:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: lsl w8, w0, #28
+; CHECK-SD-NEXT: and w9, w1, #0xf
+; CHECK-SD-NEXT: umull x8, w8, w9
+; CHECK-SD-NEXT: tst x8, #0xffffffff00000000
+; CHECK-SD-NEXT: csinv w8, w8, wzr, eq
+; CHECK-SD-NEXT: lsr w0, w8, #28
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: func6:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: and w8, w0, #0xf
+; CHECK-GI-NEXT: and w9, w1, #0xf
+; CHECK-GI-NEXT: mul w8, w8, w9
+; CHECK-GI-NEXT: mov w9, #15 // =0xf
+; CHECK-GI-NEXT: cmp w9, w8
+; CHECK-GI-NEXT: csel w0, w9, w8, lo
+; CHECK-GI-NEXT: ret
%tmp = call i4 @llvm.umul.fix.sat.i4(i4 %x, i4 %y, i32 0)
ret i4 %tmp
}
define <2 x i32> @vec(<2 x i32> %x, <2 x i32> %y) nounwind {
-; CHECK-LABEL: vec:
-; CHECK: // %bb.0:
-; CHECK-NEXT: // kill: def $d1 killed $d1 def $q1
-; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0
-; CHECK-NEXT: mov w8, v1.s[1]
-; CHECK-NEXT: mov w9, v0.s[1]
-; CHECK-NEXT: fmov w10, s0
-; CHECK-NEXT: umull x8, w9, w8
-; CHECK-NEXT: fmov w9, s1
-; CHECK-NEXT: umull x9, w10, w9
-; CHECK-NEXT: tst x8, #0xffffffff00000000
-; CHECK-NEXT: csinv w8, w8, wzr, eq
-; CHECK-NEXT: tst x9, #0xffffffff00000000
-; CHECK-NEXT: csinv w9, w9, wzr, eq
-; CHECK-NEXT: fmov s0, w9
-; CHECK-NEXT: mov v0.s[1], w8
-; CHECK-NEXT: // kill: def $d0 killed $d0 killed $q0
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: vec:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: // kill: def $d1 killed $d1 def $q1
+; CHECK-SD-NEXT: // kill: def $d0 killed $d0 def $q0
+; CHECK-SD-NEXT: mov w8, v1.s[1]
+; CHECK-SD-NEXT: mov w9, v0.s[1]
+; CHECK-SD-NEXT: fmov w10, s0
+; CHECK-SD-NEXT: umull x8, w9, w8
+; CHECK-SD-NEXT: fmov w9, s1
+; CHECK-SD-NEXT: umull x9, w10, w9
+; CHECK-SD-NEXT: tst x8, #0xffffffff00000000
+; CHECK-SD-NEXT: csinv w8, w8, wzr, eq
+; CHECK-SD-NEXT: tst x9, #0xffffffff00000000
+; CHECK-SD-NEXT: csinv w9, w9, wzr, eq
+; CHECK-SD-NEXT: fmov s0, w9
+; CHECK-SD-NEXT: mov v0.s[1], w8
+; CHECK-SD-NEXT: // kill: def $d0 killed $d0 killed $q0
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: vec:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: umull v0.2d, v0.2s, v1.2s
+; CHECK-GI-NEXT: uqxtn v0.2s, v0.2d
+; CHECK-GI-NEXT: ret
%tmp = call <2 x i32> @llvm.umul.fix.sat.v2i32(<2 x i32> %x, <2 x i32> %y, i32 0)
ret <2 x i32> %tmp
}
define <4 x i32> @vec2(<4 x i32> %x, <4 x i32> %y) nounwind {
-; CHECK-LABEL: vec2:
-; CHECK: // %bb.0:
-; CHECK-NEXT: mov w8, v1.s[1]
-; CHECK-NEXT: mov w9, v0.s[1]
-; CHECK-NEXT: fmov w10, s0
-; CHECK-NEXT: mov w11, v0.s[2]
-; CHECK-NEXT: mov w13, v0.s[3]
-; CHECK-NEXT: mov w12, v1.s[3]
-; CHECK-NEXT: umull x8, w9, w8
-; CHECK-NEXT: fmov w9, s1
-; CHECK-NEXT: umull x9, w10, w9
-; CHECK-NEXT: tst x8, #0xffffffff00000000
-; CHECK-NEXT: mov w10, v1.s[2]
-; CHECK-NEXT: csinv w8, w8, wzr, eq
-; CHECK-NEXT: tst x9, #0xffffffff00000000
-; CHECK-NEXT: csinv w9, w9, wzr, eq
-; CHECK-NEXT: fmov s0, w9
-; CHECK-NEXT: umull x9, w11, w10
-; CHECK-NEXT: mov v0.s[1], w8
-; CHECK-NEXT: tst x9, #0xffffffff00000000
-; CHECK-NEXT: csinv w8, w9, wzr, eq
-; CHECK-NEXT: umull x9, w13, w12
-; CHECK-NEXT: mov v0.s[2], w8
-; CHECK-NEXT: tst x9, #0xffffffff00000000
-; CHECK-NEXT: csinv w8, w9, wzr, eq
-; CHECK-NEXT: mov v0.s[3], w8
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: vec2:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: mov w8, v1.s[1]
+; CHECK-SD-NEXT: mov w9, v0.s[1]
+; CHECK-SD-NEXT: fmov w10, s0
+; CHECK-SD-NEXT: mov w11, v0.s[2]
+; CHECK-SD-NEXT: mov w13, v0.s[3]
+; CHECK-SD-NEXT: mov w12, v1.s[3]
+; CHECK-SD-NEXT: umull x8, w9, w8
+; CHECK-SD-NEXT: fmov w9, s1
+; CHECK-SD-NEXT: umull x9, w10, w9
+; CHECK-SD-NEXT: tst x8, #0xffffffff00000000
+; CHECK-SD-NEXT: mov w10, v1.s[2]
+; CHECK-SD-NEXT: csinv w8, w8, wzr, eq
+; CHECK-SD-NEXT: tst x9, #0xffffffff00000000
+; CHECK-SD-NEXT: csinv w9, w9, wzr, eq
+; CHECK-SD-NEXT: fmov s0, w9
+; CHECK-SD-NEXT: umull x9, w11, w10
+; CHECK-SD-NEXT: mov v0.s[1], w8
+; CHECK-SD-NEXT: tst x9, #0xffffffff00000000
+; CHECK-SD-NEXT: csinv w8, w9, wzr, eq
+; CHECK-SD-NEXT: umull x9, w13, w12
+; CHECK-SD-NEXT: mov v0.s[2], w8
+; CHECK-SD-NEXT: tst x9, #0xffffffff00000000
+; CHECK-SD-NEXT: csinv w8, w9, wzr, eq
+; CHECK-SD-NEXT: mov v0.s[3], w8
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: vec2:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: umull v2.2d, v0.2s, v1.2s
+; CHECK-GI-NEXT: umull2 v1.2d, v0.4s, v1.4s
+; CHECK-GI-NEXT: uqxtn v0.2s, v2.2d
+; CHECK-GI-NEXT: uqxtn2 v0.4s, v1.2d
+; CHECK-GI-NEXT: ret
%tmp = call <4 x i32> @llvm.umul.fix.sat.v4i32(<4 x i32> %x, <4 x i32> %y, i32 0)
ret <4 x i32> %tmp
}
define <4 x i64> @vec3(<4 x i64> %x, <4 x i64> %y) nounwind {
-; CHECK-LABEL: vec3:
-; CHECK: // %bb.0:
-; CHECK-NEXT: mov x8, v2.d[1]
-; CHECK-NEXT: mov x9, v0.d[1]
-; CHECK-NEXT: mov x14, v3.d[1]
-; CHECK-NEXT: mov x15, v1.d[1]
-; CHECK-NEXT: fmov x10, d2
-; CHECK-NEXT: fmov x11, d0
-; CHECK-NEXT: mul x12, x11, x10
-; CHECK-NEXT: mul x13, x9, x8
-; CHECK-NEXT: umulh x8, x9, x8
-; CHECK-NEXT: umulh x9, x11, x10
-; CHECK-NEXT: mul x10, x15, x14
-; CHECK-NEXT: extr x13, x8, x13, #32
-; CHECK-NEXT: umulh x11, x15, x14
-; CHECK-NEXT: fmov x14, d3
-; CHECK-NEXT: fmov x15, d1
-; CHECK-NEXT: mul x16, x15, x14
-; CHECK-NEXT: umulh x14, x15, x14
-; CHECK-NEXT: mov w15, #-1 // =0xffffffff
-; CHECK-NEXT: cmp x8, x15
-; CHECK-NEXT: extr x8, x9, x12, #32
-; CHECK-NEXT: csinv x12, x13, xzr, ls
-; CHECK-NEXT: cmp x9, x15
-; CHECK-NEXT: extr x9, x11, x10, #32
-; CHECK-NEXT: csinv x8, x8, xzr, ls
-; CHECK-NEXT: cmp x11, x15
-; CHECK-NEXT: csinv x9, x9, xzr, ls
-; CHECK-NEXT: fmov d0, x8
-; CHECK-NEXT: extr x10, x14, x16, #32
-; CHECK-NEXT: cmp x14, x15
-; CHECK-NEXT: csinv x10, x10, xzr, ls
-; CHECK-NEXT: mov v0.d[1], x12
-; CHECK-NEXT: fmov d1, x10
-; CHECK-NEXT: mov v1.d[1], x9
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: vec3:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: mov x8, v2.d[1]
+; CHECK-SD-NEXT: mov x9, v0.d[1]
+; CHECK-SD-NEXT: mov x14, v3.d[1]
+; CHECK-SD-NEXT: mov x15, v1.d[1]
+; CHECK-SD-NEXT: fmov x10, d2
+; CHECK-SD-NEXT: fmov x11, d0
+; CHECK-SD-NEXT: mul x12, x11, x10
+; CHECK-SD-NEXT: mul x13, x9, x8
+; CHECK-SD-NEXT: umulh x8, x9, x8
+; CHECK-SD-NEXT: umulh x9, x11, x10
+; CHECK-SD-NEXT: mul x10, x15, x14
+; CHECK-SD-NEXT: extr x13, x8, x13, #32
+; CHECK-SD-NEXT: umulh x11, x15, x14
+; CHECK-SD-NEXT: fmov x14, d3
+; CHECK-SD-NEXT: fmov x15, d1
+; CHECK-SD-NEXT: mul x16, x15, x14
+; CHECK-SD-NEXT: umulh x14, x15, x14
+; CHECK-SD-NEXT: mov w15, #-1 // =0xffffffff
+; CHECK-SD-NEXT: cmp x8, x15
+; CHECK-SD-NEXT: extr x8, x9, x12, #32
+; CHECK-SD-NEXT: csinv x12, x13, xzr, ls
+; CHECK-SD-NEXT: cmp x9, x15
+; CHECK-SD-NEXT: extr x9, x11, x10, #32
+; CHECK-SD-NEXT: csinv x8, x8, xzr, ls
+; CHECK-SD-NEXT: cmp x11, x15
+; CHECK-SD-NEXT: csinv x9, x9, xzr, ls
+; CHECK-SD-NEXT: fmov d0, x8
+; CHECK-SD-NEXT: extr x10, x14, x16, #32
+; CHECK-SD-NEXT: cmp x14, x15
+; CHECK-SD-NEXT: csinv x10, x10, xzr, ls
+; CHECK-SD-NEXT: mov v0.d[1], x12
+; CHECK-SD-NEXT: fmov d1, x10
+; CHECK-SD-NEXT: mov v1.d[1], x9
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: vec3:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: mov d4, v0.d[1]
+; CHECK-GI-NEXT: mov d5, v2.d[1]
+; CHECK-GI-NEXT: mov x16, #-1 // =0xffffffffffffffff
+; CHECK-GI-NEXT: fmov x8, d0
+; CHECK-GI-NEXT: fmov x9, d2
+; CHECK-GI-NEXT: mov d0, v1.d[1]
+; CHECK-GI-NEXT: mov d2, v3.d[1]
+; CHECK-GI-NEXT: fmov x13, d3
+; CHECK-GI-NEXT: mul x10, x8, x9
+; CHECK-GI-NEXT: fmov x11, d5
+; CHECK-GI-NEXT: fmov x15, d0
+; CHECK-GI-NEXT: umulh x8, x8, x9
+; CHECK-GI-NEXT: fmov x9, d4
+; CHECK-GI-NEXT: mul x12, x9, x11
+; CHECK-GI-NEXT: umulh x9, x9, x11
+; CHECK-GI-NEXT: fmov x11, d1
+; CHECK-GI-NEXT: extr x10, x8, x10, #32
+; CHECK-GI-NEXT: lsr x8, x8, #32
+; CHECK-GI-NEXT: cmp x16, x10
+; CHECK-GI-NEXT: mul x14, x11, x13
+; CHECK-GI-NEXT: cset w18, lo
+; CHECK-GI-NEXT: cmp xzr, x8
+; CHECK-GI-NEXT: umulh x11, x11, x13
+; CHECK-GI-NEXT: fmov x13, d2
+; CHECK-GI-NEXT: extr x8, x9, x12, #32
+; CHECK-GI-NEXT: lsr x9, x9, #32
+; CHECK-GI-NEXT: mul x17, x15, x13
+; CHECK-GI-NEXT: umulh x12, x15, x13
+; CHECK-GI-NEXT: cset w13, lo
+; CHECK-GI-NEXT: extr x14, x11, x14, #32
+; CHECK-GI-NEXT: csel w13, w18, w13, eq
+; CHECK-GI-NEXT: cmp x16, x8
+; CHECK-GI-NEXT: cset w15, lo
+; CHECK-GI-NEXT: cmp xzr, x9
+; CHECK-GI-NEXT: lsr x9, x11, #32
+; CHECK-GI-NEXT: cset w11, lo
+; CHECK-GI-NEXT: csel w11, w15, w11, eq
+; CHECK-GI-NEXT: cmp x16, x14
+; CHECK-GI-NEXT: extr x15, x12, x17, #32
+; CHECK-GI-NEXT: cset w17, lo
+; CHECK-GI-NEXT: cmp xzr, x9
+; CHECK-GI-NEXT: lsr x9, x12, #32
+; CHECK-GI-NEXT: cset w12, lo
+; CHECK-GI-NEXT: csel w12, w17, w12, eq
+; CHECK-GI-NEXT: cmp x16, x15
+; CHECK-GI-NEXT: cset w16, lo
+; CHECK-GI-NEXT: cmp xzr, x9
+; CHECK-GI-NEXT: cset w9, lo
+; CHECK-GI-NEXT: csel w9, w16, w9, eq
+; CHECK-GI-NEXT: tst w13, #0x1
+; CHECK-GI-NEXT: csinv x10, x10, xzr, eq
+; CHECK-GI-NEXT: tst w11, #0x1
+; CHECK-GI-NEXT: csinv x8, x8, xzr, eq
+; CHECK-GI-NEXT: tst w12, #0x1
+; CHECK-GI-NEXT: fmov d0, x10
+; CHECK-GI-NEXT: csinv x11, x14, xzr, eq
+; CHECK-GI-NEXT: tst w9, #0x1
+; CHECK-GI-NEXT: fmov d1, x11
+; CHECK-GI-NEXT: csinv x9, x15, xzr, eq
+; CHECK-GI-NEXT: mov v0.d[1], x8
+; CHECK-GI-NEXT: mov v1.d[1], x9
+; CHECK-GI-NEXT: ret
%tmp = call <4 x i64> @llvm.umul.fix.sat.v4i64(<4 x i64> %x, <4 x i64> %y, i32 32)
ret <4 x i64> %tmp
}
define i64 @func7(i64 %x, i64 %y) nounwind {
-; CHECK-LABEL: func7:
-; CHECK: // %bb.0:
-; CHECK-NEXT: mul x9, x0, x1
-; CHECK-NEXT: mov w8, #-1 // =0xffffffff
-; CHECK-NEXT: umulh x10, x0, x1
-; CHECK-NEXT: extr x9, x10, x9, #32
-; CHECK-NEXT: cmp x10, x8
-; CHECK-NEXT: csinv x0, x9, xzr, ls
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: func7:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: mul x9, x0, x1
+; CHECK-SD-NEXT: mov w8, #-1 // =0xffffffff
+; CHECK-SD-NEXT: umulh x10, x0, x1
+; CHECK-SD-NEXT: extr x9, x10, x9, #32
+; CHECK-SD-NEXT: cmp x10, x8
+; CHECK-SD-NEXT: csinv x0, x9, xzr, ls
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: func7:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: mul x9, x0, x1
+; CHECK-GI-NEXT: mov x8, #-1 // =0xffffffffffffffff
+; CHECK-GI-NEXT: umulh x10, x0, x1
+; CHECK-GI-NEXT: extr x9, x10, x9, #32
+; CHECK-GI-NEXT: lsr x10, x10, #32
+; CHECK-GI-NEXT: cmp x8, x9
+; CHECK-GI-NEXT: cset w8, lo
+; CHECK-GI-NEXT: cmp xzr, x10
+; CHECK-GI-NEXT: cset w10, lo
+; CHECK-GI-NEXT: csel w8, w8, w10, eq
+; CHECK-GI-NEXT: tst w8, #0x1
+; CHECK-GI-NEXT: csinv x0, x9, xzr, eq
+; CHECK-GI-NEXT: ret
%tmp = call i64 @llvm.umul.fix.sat.i64(i64 %x, i64 %y, i32 32)
ret i64 %tmp
}
define i64 @func8(i64 %x, i64 %y) nounwind {
-; CHECK-LABEL: func8:
-; CHECK: // %bb.0:
-; CHECK-NEXT: mul x9, x0, x1
-; CHECK-NEXT: mov x8, #9223372036854775807 // =0x7fffffffffffffff
-; CHECK-NEXT: umulh x10, x0, x1
-; CHECK-NEXT: extr x9, x10, x9, #63
-; CHECK-NEXT: cmp x10, x8
-; CHECK-NEXT: csinv x0, x9, xzr, ls
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: func8:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: mul x9, x0, x1
+; CHECK-SD-NEXT: mov x8, #9223372036854775807 // =0x7fffffffffffffff
+; CHECK-SD-NEXT: umulh x10, x0, x1
+; CHECK-SD-NEXT: extr x9, x10, x9, #63
+; CHECK-SD-NEXT: cmp x10, x8
+; CHECK-SD-NEXT: csinv x0, x9, xzr, ls
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: func8:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: mul x9, x0, x1
+; CHECK-GI-NEXT: mov x8, #-1 // =0xffffffffffffffff
+; CHECK-GI-NEXT: umulh x10, x0, x1
+; CHECK-GI-NEXT: extr x9, x10, x9, #63
+; CHECK-GI-NEXT: lsr x10, x10, #63
+; CHECK-GI-NEXT: cmp x8, x9
+; CHECK-GI-NEXT: cset w8, lo
+; CHECK-GI-NEXT: cmp xzr, x10
+; CHECK-GI-NEXT: cset w10, lo
+; CHECK-GI-NEXT: csel w8, w8, w10, eq
+; CHECK-GI-NEXT: tst w8, #0x1
+; CHECK-GI-NEXT: csinv x0, x9, xzr, eq
+; CHECK-GI-NEXT: ret
%tmp = call i64 @llvm.umul.fix.sat.i64(i64 %x, i64 %y, i32 63)
ret i64 %tmp
}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK: {{.*}}
More information about the llvm-commits
mailing list