[clang] [llvm] [InstCombine] Combine ((ext(A) * ext(B)) >> N) -> ext(mulh(A, B)). (PR #224311)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Sep 17 06:57:20 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Ricardo Jesus (rj-jesus)
<details>
<summary>Changes</summary>
The source values must be equally extended to double their width.
The result is sign/zero-extended for an arithmetic/logical shift.
This is a simplified version of DAGCombiner's combineShiftToMULH.
---
Patch is 46.39 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/224311.diff
9 Files Affected:
- (modified) clang/test/CodeGen/X86/ms-x86-intrinsics.c (+2-2)
- (modified) llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp (+19)
- (modified) llvm/test/Transforms/AggressiveInstCombine/umulh_carry.ll (+7-35)
- (modified) llvm/test/Transforms/AggressiveInstCombine/umulh_carry4.ll (+16-80)
- (modified) llvm/test/Transforms/AggressiveInstCombine/umulh_ladder.ll (+10-50)
- (modified) llvm/test/Transforms/AggressiveInstCombine/umulh_ladder4.ll (+5-25)
- (added) llvm/test/Transforms/InstCombine/mulh.ll (+418)
- (modified) llvm/test/Transforms/InstCombine/trunc-inseltpoison.ll (+3-5)
- (modified) llvm/test/Transforms/InstCombine/trunc.ll (+3-5)
``````````diff
diff --git a/clang/test/CodeGen/X86/ms-x86-intrinsics.c b/clang/test/CodeGen/X86/ms-x86-intrinsics.c
index 34cf690e6d5da..9099b56e50d45 100644
--- a/clang/test/CodeGen/X86/ms-x86-intrinsics.c
+++ b/clang/test/CodeGen/X86/ms-x86-intrinsics.c
@@ -158,13 +158,13 @@ __int64 test__mulh(__int64 a, __int64 b) {
return __mulh(a, b);
}
// CHECK-X64-LABEL: define dso_local range(i64 -4611686018427387904, 4611686018427387905) i64 @test__mulh(i64 noundef %a, i64 noundef %b)
-// CHECK-X64: = mul nsw i128 %
+// CHECK-X64: = tail call i64 @llvm.smulh.i64(i64 %a, i64 %b)
unsigned __int64 test__umulh(unsigned __int64 a, unsigned __int64 b) {
return __umulh(a, b);
}
// CHECK-X64-LABEL: define dso_local range(i64 0, -1) i64 @test__umulh(i64 noundef %a, i64 noundef %b)
-// CHECK-X64: = mul nuw i128 %
+// CHECK-X64: = tail call i64 @llvm.umulh.i64(i64 %a, i64 %b)
__int64 test_mul128(__int64 Multiplier,
__int64 Multiplicand,
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
index 7e32abcd6e9ba..a8dc034588ecf 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
@@ -923,6 +923,25 @@ Instruction *InstCombinerImpl::FoldShiftByConstant(Value *Op0, Constant *C1,
return CastInst::Create(ExtOpcode, Cmp, Ty);
}
+ // (ext(A) * ext(B)) >> (Width / 2) --> ext([su]mulh(A, B))
+ // A and B must be equally extended to double their original width.
+ // The result is sign/zero-extended for an arithmetic/logical shift.
+ Value *A, *B;
+ Instruction *ExtA, *ExtB;
+ if (!IsLeftShift && match(C1, m_SpecificIntAllowPoison(TypeBits / 2)) &&
+ match(Op0,
+ m_OneUse(m_Mul(m_Instruction(ExtA, m_ZExtOrSExt(m_Value(A))),
+ m_Instruction(ExtB, m_ZExtOrSExt(m_Value(B)))))) &&
+ ExtA->getOpcode() == ExtB->getOpcode() && A->getType() == B->getType() &&
+ TypeBits == 2 * A->getType()->getScalarSizeInBits()) {
+ auto IID = ExtA->getOpcode() == Instruction::SExt ? Intrinsic::smulh
+ : Intrinsic::umulh;
+ Value *MulHigh = Builder.CreateBinaryIntrinsic(IID, A, B);
+ auto ExtOp = I.getOpcode() == Instruction::LShr ? Instruction::ZExt
+ : Instruction::SExt;
+ return CastInst::Create(ExtOp, MulHigh, Ty);
+ }
+
const APInt *Op1C;
if (!match(C1, m_APInt(Op1C)))
return nullptr;
diff --git a/llvm/test/Transforms/AggressiveInstCombine/umulh_carry.ll b/llvm/test/Transforms/AggressiveInstCombine/umulh_carry.ll
index b78095cac0df9..8a50435dde27a 100644
--- a/llvm/test/Transforms/AggressiveInstCombine/umulh_carry.ll
+++ b/llvm/test/Transforms/AggressiveInstCombine/umulh_carry.ll
@@ -6,11 +6,7 @@ define i32 @mul_carry(i32 %x, i32 %y) {
; CHECK-LABEL: define i32 @mul_carry(
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
-; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[X]] to i64
-; CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[Y]] to i64
-; CHECK-NEXT: [[TMP2:%.*]] = mul nuw i64 [[TMP0]], [[TMP1]]
-; CHECK-NEXT: [[TMP3:%.*]] = lshr i64 [[TMP2]], 32
-; CHECK-NEXT: [[ADD11:%.*]] = trunc nuw i64 [[TMP3]] to i32
+; CHECK-NEXT: [[ADD11:%.*]] = call i32 @llvm.umulh.i32(i32 [[X]], i32 [[Y]])
; CHECK-NEXT: ret i32 [[ADD11]]
;
entry:
@@ -38,11 +34,7 @@ define i128 @mul_carry_i128(i128 %x, i128 %y) {
; CHECK-LABEL: define i128 @mul_carry_i128(
; CHECK-SAME: i128 [[X:%.*]], i128 [[Y:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
-; CHECK-NEXT: [[TMP0:%.*]] = zext i128 [[X]] to i256
-; CHECK-NEXT: [[TMP1:%.*]] = zext i128 [[Y]] to i256
-; CHECK-NEXT: [[TMP2:%.*]] = mul nuw i256 [[TMP0]], [[TMP1]]
-; CHECK-NEXT: [[TMP3:%.*]] = lshr i256 [[TMP2]], 128
-; CHECK-NEXT: [[ADD11:%.*]] = trunc nuw i256 [[TMP3]] to i128
+; CHECK-NEXT: [[ADD11:%.*]] = call i128 @llvm.umulh.i128(i128 [[X]], i128 [[Y]])
; CHECK-NEXT: ret i128 [[ADD11]]
;
entry:
@@ -70,11 +62,7 @@ define <4 x i32> @mul_carry_v4i32(<4 x i32> %x, <4 x i32> %y) {
; CHECK-LABEL: define <4 x i32> @mul_carry_v4i32(
; CHECK-SAME: <4 x i32> [[X:%.*]], <4 x i32> [[Y:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
-; CHECK-NEXT: [[TMP0:%.*]] = zext <4 x i32> [[X]] to <4 x i64>
-; CHECK-NEXT: [[TMP1:%.*]] = zext <4 x i32> [[Y]] to <4 x i64>
-; CHECK-NEXT: [[TMP2:%.*]] = mul nuw <4 x i64> [[TMP0]], [[TMP1]]
-; CHECK-NEXT: [[TMP3:%.*]] = lshr <4 x i64> [[TMP2]], splat (i64 32)
-; CHECK-NEXT: [[ADD11:%.*]] = trunc nuw <4 x i64> [[TMP3]] to <4 x i32>
+; CHECK-NEXT: [[ADD11:%.*]] = call <4 x i32> @llvm.umulh.v4i32(<4 x i32> [[X]], <4 x i32> [[Y]])
; CHECK-NEXT: ret <4 x i32> [[ADD11]]
;
entry:
@@ -102,11 +90,7 @@ define i32 @mul_carry_xlyh(i32 %x, i32 %y) {
; CHECK-LABEL: define i32 @mul_carry_xlyh(
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
-; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[Y]] to i64
-; CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[X]] to i64
-; CHECK-NEXT: [[TMP2:%.*]] = mul nuw i64 [[TMP0]], [[TMP1]]
-; CHECK-NEXT: [[TMP3:%.*]] = lshr i64 [[TMP2]], 32
-; CHECK-NEXT: [[ADD11:%.*]] = trunc nuw i64 [[TMP3]] to i32
+; CHECK-NEXT: [[ADD11:%.*]] = call i32 @llvm.umulh.i32(i32 [[Y]], i32 [[X]])
; CHECK-NEXT: ret i32 [[ADD11]]
;
entry:
@@ -133,11 +117,7 @@ define i32 @mul_carry_comm(i32 %x, i32 %y) {
; CHECK-LABEL: define i32 @mul_carry_comm(
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
-; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[X]] to i64
-; CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[Y]] to i64
-; CHECK-NEXT: [[TMP2:%.*]] = mul nuw i64 [[TMP0]], [[TMP1]]
-; CHECK-NEXT: [[TMP3:%.*]] = lshr i64 [[TMP2]], 32
-; CHECK-NEXT: [[ADD11:%.*]] = trunc nuw i64 [[TMP3]] to i32
+; CHECK-NEXT: [[ADD11:%.*]] = call i32 @llvm.umulh.i32(i32 [[X]], i32 [[Y]])
; CHECK-NEXT: ret i32 [[ADD11]]
;
entry:
@@ -469,11 +449,7 @@ define i32 @mul_carry_use_llh(i32 %x, i32 %y) {
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[Y]], 65535
; CHECK-NEXT: [[ADD6:%.*]] = mul nuw i32 [[AND]], [[AND2]]
; CHECK-NEXT: [[SHR10:%.*]] = lshr i32 [[ADD6]], 16
-; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[X]] to i64
-; CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[Y]] to i64
-; CHECK-NEXT: [[TMP2:%.*]] = mul nuw i64 [[TMP0]], [[TMP1]]
-; CHECK-NEXT: [[TMP3:%.*]] = lshr i64 [[TMP2]], 32
-; CHECK-NEXT: [[ADD11:%.*]] = trunc nuw i64 [[TMP3]] to i32
+; CHECK-NEXT: [[ADD11:%.*]] = call i32 @llvm.umulh.i32(i32 [[X]], i32 [[Y]])
; CHECK-NEXT: call void (...) @llvm.fake.use(i32 [[SHR10]])
; CHECK-NEXT: ret i32 [[ADD11]]
;
@@ -505,11 +481,7 @@ define i32 @mul_carry_use_mulll(i32 %x, i32 %y) {
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], 65535
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[Y]], 65535
; CHECK-NEXT: [[MUL4:%.*]] = mul nuw i32 [[AND]], [[AND2]]
-; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[X]] to i64
-; CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[Y]] to i64
-; CHECK-NEXT: [[TMP2:%.*]] = mul nuw i64 [[TMP0]], [[TMP1]]
-; CHECK-NEXT: [[TMP3:%.*]] = lshr i64 [[TMP2]], 32
-; CHECK-NEXT: [[ADD11:%.*]] = trunc nuw i64 [[TMP3]] to i32
+; CHECK-NEXT: [[ADD11:%.*]] = call i32 @llvm.umulh.i32(i32 [[X]], i32 [[Y]])
; CHECK-NEXT: call void (...) @llvm.fake.use(i32 [[MUL4]])
; CHECK-NEXT: ret i32 [[ADD11]]
;
diff --git a/llvm/test/Transforms/AggressiveInstCombine/umulh_carry4.ll b/llvm/test/Transforms/AggressiveInstCombine/umulh_carry4.ll
index fa21721f17762..ba843073dc7d0 100644
--- a/llvm/test/Transforms/AggressiveInstCombine/umulh_carry4.ll
+++ b/llvm/test/Transforms/AggressiveInstCombine/umulh_carry4.ll
@@ -5,11 +5,7 @@
define i64 @umulh(i64 %x, i64 %y) {
; CHECK-LABEL: define i64 @umulh(
; CHECK-SAME: i64 [[X:%.*]], i64 [[Y:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = zext i64 [[X]] to i128
-; CHECK-NEXT: [[TMP2:%.*]] = zext i64 [[Y]] to i128
-; CHECK-NEXT: [[TMP3:%.*]] = mul nuw i128 [[TMP1]], [[TMP2]]
-; CHECK-NEXT: [[TMP5:%.*]] = lshr i128 [[TMP3]], 64
-; CHECK-NEXT: [[TMP4:%.*]] = trunc nuw i128 [[TMP5]] to i64
+; CHECK-NEXT: [[TMP4:%.*]] = call i64 @llvm.umulh.i64(i64 [[X]], i64 [[Y]])
; CHECK-NEXT: ret i64 [[TMP4]]
;
; Extract low and high 32 bits
@@ -56,11 +52,7 @@ define i64 @umulh(i64 %x, i64 %y) {
define i64 @umulh__commuted(i64 %x, i64 %y) {
; CHECK-LABEL: define i64 @umulh__commuted(
; CHECK-SAME: i64 [[X:%.*]], i64 [[Y:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = zext i64 [[X]] to i128
-; CHECK-NEXT: [[TMP2:%.*]] = zext i64 [[Y]] to i128
-; CHECK-NEXT: [[TMP3:%.*]] = mul nuw i128 [[TMP1]], [[TMP2]]
-; CHECK-NEXT: [[TMP5:%.*]] = lshr i128 [[TMP3]], 64
-; CHECK-NEXT: [[TMP4:%.*]] = trunc nuw i128 [[TMP5]] to i64
+; CHECK-NEXT: [[TMP4:%.*]] = call i64 @llvm.umulh.i64(i64 [[X]], i64 [[Y]])
; CHECK-NEXT: ret i64 [[TMP4]]
;
; Extract low and high 32 bits
@@ -104,11 +96,7 @@ define i32 @mulh_src32(i32 %x, i32 %y) {
; Extract low and high 16 bits
; CHECK-LABEL: define i32 @mulh_src32(
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[X]] to i64
-; CHECK-NEXT: [[TMP2:%.*]] = zext i32 [[Y]] to i64
-; CHECK-NEXT: [[TMP3:%.*]] = mul nuw i64 [[TMP1]], [[TMP2]]
-; CHECK-NEXT: [[TMP4:%.*]] = lshr i64 [[TMP3]], 32
-; CHECK-NEXT: [[TMP5:%.*]] = trunc nuw i64 [[TMP4]] to i32
+; CHECK-NEXT: [[TMP5:%.*]] = call i32 @llvm.umulh.i32(i32 [[X]], i32 [[Y]])
; CHECK-NEXT: ret i32 [[TMP5]]
;
%x_lo = and i32 %x, u0xffff ; x & 0xffffffff
@@ -151,11 +139,7 @@ define i128 @mulh_src128(i128 %x, i128 %y) {
; Extract low and high 64 bits
; CHECK-LABEL: define i128 @mulh_src128(
; CHECK-SAME: i128 [[X:%.*]], i128 [[Y:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = zext i128 [[X]] to i256
-; CHECK-NEXT: [[TMP2:%.*]] = zext i128 [[Y]] to i256
-; CHECK-NEXT: [[TMP3:%.*]] = mul nuw i256 [[TMP1]], [[TMP2]]
-; CHECK-NEXT: [[TMP4:%.*]] = lshr i256 [[TMP3]], 128
-; CHECK-NEXT: [[HW64:%.*]] = trunc nuw i256 [[TMP4]] to i128
+; CHECK-NEXT: [[HW64:%.*]] = call i128 @llvm.umulh.i128(i128 [[X]], i128 [[Y]])
; CHECK-NEXT: ret i128 [[HW64]]
;
%x_lo = and i128 %x, u0xffffffffffffffff ; x & 0xffffffff
@@ -198,11 +182,7 @@ define <2 x i32> @mulh_v2i32(<2 x i32> %x, <2 x i32> %y) {
; Extract low and high 16 bits
; CHECK-LABEL: define <2 x i32> @mulh_v2i32(
; CHECK-SAME: <2 x i32> [[X:%.*]], <2 x i32> [[Y:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = zext <2 x i32> [[X]] to <2 x i64>
-; CHECK-NEXT: [[TMP2:%.*]] = zext <2 x i32> [[Y]] to <2 x i64>
-; CHECK-NEXT: [[TMP3:%.*]] = mul nuw <2 x i64> [[TMP1]], [[TMP2]]
-; CHECK-NEXT: [[TMP4:%.*]] = lshr <2 x i64> [[TMP3]], splat (i64 32)
-; CHECK-NEXT: [[HW64:%.*]] = trunc nuw <2 x i64> [[TMP4]] to <2 x i32>
+; CHECK-NEXT: [[HW64:%.*]] = call <2 x i32> @llvm.umulh.v2i32(<2 x i32> [[X]], <2 x i32> [[Y]])
; CHECK-NEXT: ret <2 x i32> [[HW64]]
;
%x_lo = and <2 x i32> %x, <i32 u0xffff, i32 u0xffff>
@@ -245,11 +225,7 @@ define <2 x i32> @mulh_v2i32(<2 x i32> %x, <2 x i32> %y) {
define void @full_mul_int128(i64 %x, i64 %y, ptr %p) {
; CHECK-LABEL: define void @full_mul_int128(
; CHECK-SAME: i64 [[X:%.*]], i64 [[Y:%.*]], ptr [[P:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = zext i64 [[X]] to i128
-; CHECK-NEXT: [[TMP2:%.*]] = zext i64 [[Y]] to i128
-; CHECK-NEXT: [[TMP3:%.*]] = mul nuw i128 [[TMP1]], [[TMP2]]
-; CHECK-NEXT: [[TMP5:%.*]] = lshr i128 [[TMP3]], 64
-; CHECK-NEXT: [[TMP4:%.*]] = trunc nuw i128 [[TMP5]] to i64
+; CHECK-NEXT: [[TMP4:%.*]] = call i64 @llvm.umulh.i64(i64 [[X]], i64 [[Y]])
; CHECK-NEXT: [[HI_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8
; CHECK-NEXT: store i64 [[TMP4]], ptr [[HI_PTR]], align 8
; CHECK-NEXT: [[TMP8:%.*]] = mul i64 [[X]], [[Y]]
@@ -745,11 +721,7 @@ define i64 @umulh__mul_use__x_lo(i64 %x, i64 %y) {
; CHECK-SAME: i64 [[X:%.*]], i64 [[Y:%.*]]) {
; CHECK-NEXT: [[X_LO:%.*]] = and i64 [[X]], 4294967295
; CHECK-NEXT: call void (...) @llvm.fake.use(i64 [[X_LO]])
-; CHECK-NEXT: [[TMP1:%.*]] = zext i64 [[X]] to i128
-; CHECK-NEXT: [[TMP2:%.*]] = zext i64 [[Y]] to i128
-; CHECK-NEXT: [[TMP3:%.*]] = mul nuw i128 [[TMP1]], [[TMP2]]
-; CHECK-NEXT: [[TMP4:%.*]] = lshr i128 [[TMP3]], 64
-; CHECK-NEXT: [[HW64:%.*]] = trunc nuw i128 [[TMP4]] to i64
+; CHECK-NEXT: [[HW64:%.*]] = call i64 @llvm.umulh.i64(i64 [[X]], i64 [[Y]])
; CHECK-NEXT: ret i64 [[HW64]]
;
; Extract low and high 32 bits
@@ -796,11 +768,7 @@ define i64 @umulh__mul_use__y_hi(i64 %x, i64 %y) {
; CHECK-SAME: i64 [[X:%.*]], i64 [[Y:%.*]]) {
; CHECK-NEXT: [[Y_HI:%.*]] = lshr i64 [[Y]], 32
; CHECK-NEXT: call void (...) @llvm.fake.use(i64 [[Y_HI]])
-; CHECK-NEXT: [[TMP1:%.*]] = zext i64 [[X]] to i128
-; CHECK-NEXT: [[TMP2:%.*]] = zext i64 [[Y]] to i128
-; CHECK-NEXT: [[TMP3:%.*]] = mul nuw i128 [[TMP1]], [[TMP2]]
-; CHECK-NEXT: [[TMP4:%.*]] = lshr i128 [[TMP3]], 64
-; CHECK-NEXT: [[HW64:%.*]] = trunc nuw i128 [[TMP4]] to i64
+; CHECK-NEXT: [[HW64:%.*]] = call i64 @llvm.umulh.i64(i64 [[X]], i64 [[Y]])
; CHECK-NEXT: ret i64 [[HW64]]
;
; Extract low and high 32 bits
@@ -1044,11 +1012,7 @@ define i64 @umulh__mul_use__y_lo_x_lo(i64 %x, i64 %y) {
; CHECK-NEXT: [[Y_LO:%.*]] = and i64 [[Y]], 4294967295
; CHECK-NEXT: [[Y_LO_X_LO:%.*]] = mul nuw i64 [[Y_LO]], [[X_LO]]
; CHECK-NEXT: call void (...) @llvm.fake.use(i64 [[Y_LO_X_LO]])
-; CHECK-NEXT: [[TMP1:%.*]] = zext i64 [[X]] to i128
-; CHECK-NEXT: [[TMP2:%.*]] = zext i64 [[Y]] to i128
-; CHECK-NEXT: [[TMP3:%.*]] = mul nuw i128 [[TMP1]], [[TMP2]]
-; CHECK-NEXT: [[TMP4:%.*]] = lshr i128 [[TMP3]], 64
-; CHECK-NEXT: [[TMP5:%.*]] = trunc nuw i128 [[TMP4]] to i64
+; CHECK-NEXT: [[TMP5:%.*]] = call i64 @llvm.umulh.i64(i64 [[X]], i64 [[Y]])
; CHECK-NEXT: ret i64 [[TMP5]]
;
; Extract low and high 32 bits
@@ -1492,11 +1456,7 @@ define i64 @umulh__mul_use__low_accum(i64 %x, i64 %y) {
; CHECK-NEXT: [[CROSS_SUM_LO:%.*]] = and i64 [[CROSS_SUM]], 4294967295
; CHECK-NEXT: [[LOW_ACCUM:%.*]] = add nuw nsw i64 [[CROSS_SUM_LO]], [[Y_LO_X_LO_HI]]
; CHECK-NEXT: call void (...) @llvm.fake.use(i64 [[LOW_ACCUM]])
-; CHECK-NEXT: [[TMP1:%.*]] = zext i64 [[X]] to i128
-; CHECK-NEXT: [[TMP2:%.*]] = zext i64 [[Y]] to i128
-; CHECK-NEXT: [[TMP3:%.*]] = mul nuw i128 [[TMP1]], [[TMP2]]
-; CHECK-NEXT: [[TMP4:%.*]] = lshr i128 [[TMP3]], 64
-; CHECK-NEXT: [[TMP5:%.*]] = trunc nuw i128 [[TMP4]] to i64
+; CHECK-NEXT: [[TMP5:%.*]] = call i64 @llvm.umulh.i64(i64 [[X]], i64 [[Y]])
; CHECK-NEXT: ret i64 [[TMP5]]
;
; Extract low and high 32 bits
@@ -1736,11 +1696,7 @@ define void @full_mul_int128__mul_use__x_lo(i64 %x, i64 %y, ptr %p) {
; CHECK-SAME: i64 [[X:%.*]], i64 [[Y:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: [[X_LO:%.*]] = and i64 [[X]], 4294967295
; CHECK-NEXT: call void (...) @llvm.fake.use(i64 [[X_LO]])
-; CHECK-NEXT: [[TMP1:%.*]] = zext i64 [[X]] to i128
-; CHECK-NEXT: [[TMP2:%.*]] = zext i64 [[Y]] to i128
-; CHECK-NEXT: [[TMP3:%.*]] = mul nuw i128 [[TMP1]], [[TMP2]]
-; CHECK-NEXT: [[TMP4:%.*]] = lshr i128 [[TMP3]], 64
-; CHECK-NEXT: [[HW64:%.*]] = trunc nuw i128 [[TMP4]] to i64
+; CHECK-NEXT: [[HW64:%.*]] = call i64 @llvm.umulh.i64(i64 [[X]], i64 [[Y]])
; CHECK-NEXT: [[HI_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8
; CHECK-NEXT: store i64 [[HW64]], ptr [[HI_PTR]], align 8
; CHECK-NEXT: [[LW64:%.*]] = mul i64 [[X]], [[Y]]
@@ -1793,11 +1749,7 @@ define void @full_mul_int128__mul_use__y_lo(i64 %x, i64 %y, ptr %p) {
; CHECK-SAME: i64 [[X:%.*]], i64 [[Y:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: [[Y_LO:%.*]] = and i64 [[Y]], 4294967295
; CHECK-NEXT: call void (...) @llvm.fake.use(i64 [[Y_LO]])
-; CHECK-NEXT: [[TMP1:%.*]] = zext i64 [[X]] to i128
-; CHECK-NEXT: [[TMP2:%.*]] = zext i64 [[Y]] to i128
-; CHECK-NEXT: [[TMP3:%.*]] = mul nuw i128 [[TMP1]], [[TMP2]]
-; CHECK-NEXT: [[TMP4:%.*]] = lshr i128 [[TMP3]], 64
-; CHECK-NEXT: [[HW64:%.*]] = trunc nuw i128 [[TMP4]] to i64
+; CHECK-NEXT: [[HW64:%.*]] = call i64 @llvm.umulh.i64(i64 [[X]], i64 [[Y]])
; CHECK-NEXT: [[HI_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8
; CHECK-NEXT: store i64 [[HW64]], ptr [[HI_PTR]], align 8
; CHECK-NEXT: [[LW64:%.*]] = mul i64 [[X]], [[Y]]
@@ -1850,11 +1802,7 @@ define void @full_mul_int128__mul_use__x_hi(i64 %x, i64 %y, ptr %p) {
; CHECK-SAME: i64 [[X:%.*]], i64 [[Y:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: [[X_HI:%.*]] = lshr i64 [[X]], 32
; CHECK-NEXT: call void (...) @llvm.fake.use(i64 [[X_HI]])
-; CHECK-NEXT: [[TMP1:%.*]] = zext i64 [[X]] to i128
-; CHECK-NEXT: [[TMP2:%.*]] = zext i64 [[Y]] to i128
-; CHECK-NEXT: [[TMP3:%.*]] = mul nuw i128 [[TMP1]], [[TMP2]]
-; CHECK-NEXT: [[TMP4:%.*]] = lshr i128 [[TMP3]], 64
-; CHECK-NEXT: [[HW64:%.*]] = trunc nuw i128 [[TMP4]] to i64
+; CHECK-NEXT: [[HW64:%.*]] = call i64 @llvm.umulh.i64(i64 [[X]], i64 [[Y]])
; CHECK-NEXT: [[HI_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8
; CHECK-NEXT: store i64 [[HW64]], ptr [[HI_PTR]], align 8
; CHECK-NEXT: [[LW64:%.*]] = mul i64 [[X]], [[Y]]
@@ -1907,11 +1855,7 @@ define void @full_mul_int128__mul_use__y_hi(i64 %x, i64 %y, ptr %p) {
; CHECK-SAME: i64 [[X:%.*]], i64 [[Y:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: [[Y_HI:%.*]] = lshr i64 [[Y]], 32
; CHECK-NEXT: call void (...) @llvm.fake.use(i64 [[Y_HI]])
-; CHECK-NEXT: [[TMP1:%.*]] = zext i64 [[X]] to i128
-; CHECK-NEXT: [[TMP2:%.*]] = zext i64 [[Y]] to i128
-; CHECK-NEXT: [[TMP3:%.*]] = mul nuw i128 [[TMP1]], [[TMP2]]
-; CHECK-NEXT: [[TMP4:%.*]] = lshr i128 [[TMP3]], 64
-; CHECK-NEXT: [[HW64:%.*]] = trunc nuw i128 [[TMP4]] to i64
+; CHECK-NEXT: [[HW64:%.*]] = call i64 @llvm.umulh.i64(i64 [[X]], i64 [[Y]])
; CHECK-NEXT: [[HI_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8
; CHECK-NEXT: store i64 [[HW64]], ptr [[HI_PTR]], align 8
; CHECK-NEXT: [[LW64:%.*]] = mul i64 [[X]], [[Y]]
@@ -2188,11 +2132,7 @@ define void @full_mul_int128__mul_use__y_lo_x_lo(i64 %x, i64 %y, ptr %p) {
; CHECK-NEXT: [[Y_LO_X_LO:%.*]] = mul nuw i64 [[Y_LO]], [[X_LO]]
; CHECK-NEXT: call void (...) @llvm.fake.use(i64 [[Y_LO_X_LO]])
; CHECK-NEXT: [[TMP6:%.*]] = add i64 [[UPPER_MID_WITH_CROSS]], [[LOW_ACCUM_HI]]
-; CHECK-NEXT: [[TMP1:%.*]] = zext i64 [[X]] to i128
-; CHECK-NEXT: [[TMP2:%.*]] = zext i64 [[Y]] to i128
-; CHECK-NEXT: [[TMP3:%.*]] = mul nuw i128 [[TMP1]], [[TMP2]]
-; CHECK-NEXT: [[TMP4:%.*]] = lshr i128 [[TMP3]], 64
-; CHECK-NEXT: [[TMP5:%.*]] = trunc nuw i128 [[TMP4]] to i64
+; CHECK-NEXT: [[TMP5:%.*]] = call i64 @llvm.umulh.i64(i64 [[X]], i64 [[Y]])
; CHECK-NEXT: [[HI_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8
; CHECK-NEXT: store i64 [[TMP5]], ptr [[HI_PTR]], align 8
; CHECK-NEXT: [[LOW_ACCUM1:%.*]] = shl i64 [[TMP6]], 32
@@ -2964,11 +2904,7 @@ define void @full_mul_int128__mul_use__upper_mid_with_cross(i64 %x, i64 %y, ptr
define void @full_mul_int128__mul_use__low_accum_shifted(i64 %x, i64 %y, ptr %p) {
; CHECK-LABEL: define void @full_mul_int128__mul_use__low_accum_shifted(
; CHECK-SAME: i64 [[X:%.*]], i64 [[Y:%.*]], ptr [[P:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = zext i64 [[X]] to i128
-; CHECK-NEXT: [[TMP2:%.*]] = zext i64 [[Y]] to i128
-; CHECK-NEXT: [[TMP3:%.*]] = mul nuw i128 [[TMP1]], [[TMP2]]
-; CHECK-NEXT: [[TMP4:%.*]] = lshr i128 [[TMP3]], 64
-; CHECK-NEXT: [[TMP5:%.*]] = trunc nuw i128 [[TMP4]] to i64
+; CHECK-NEXT: [[TMP5:%.*]] = call i64 @llvm.umulh.i64(i64 [[X]], i64 [[Y]])
; CHECK-NEXT: [[HI_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8
; CHECK-NEXT: store i64 [[TMP5]], ptr [[HI_PTR]], align 8
; CHECK-NEXT: [[LW64:%.*]] = mul i64 [[X]], [[Y]]
diff --git a/llvm/test/Transforms/AggressiveInstCombine/umulh_ladder.ll b/llvm/test/Transforms/AggressiveInstCombine/umulh_ladder.ll
index 257cc0315c72f..3c86fa45944dd 100644
--- a/llvm/test/Transforms/AggressiveInstCombine/umulh_ladder.ll
+++ b/llvm/test/Transforms/AggressiveInstCombine/umulh_ladder.ll
@@ -5,11 +5,7 @@
define i64 @umulh_variant(i64 %x, i64 %y) {
; CHECK-LABEL: define i64 @umulh_variant(
; CHECK-SAME: i64 [[X:%.*]], i64 [[Y:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = zext i64 [[Y]] to i128
-; CHECK-N...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/224311
More information about the cfe-commits
mailing list