https://github.com/rj-jesus updated 
https://github.com/llvm/llvm-project/pull/224311

>From f81fc6b57b940f55a0f935c9c182c6e8dedfeb0e Mon Sep 17 00:00:00 2001
From: Ricardo Jesus <[email protected]>
Date: Wed, 16 Sep 2026 09:07:42 -0700
Subject: [PATCH 1/2] Add tests.

---
 llvm/test/Transforms/InstCombine/mulh.ll | 458 +++++++++++++++++++++++
 1 file changed, 458 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/mulh.ll

diff --git a/llvm/test/Transforms/InstCombine/mulh.ll 
b/llvm/test/Transforms/InstCombine/mulh.ll
new file mode 100644
index 0000000000000..c0daf9b2e1579
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/mulh.ll
@@ -0,0 +1,458 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 
UTC_ARGS: --version 6
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define i16 @smulh_ashr(i8 %a, i8 %b) {
+; CHECK-LABEL: define i16 @smulh_ashr(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = sext i8 [[A]] to i16
+; CHECK-NEXT:    [[EB:%.*]] = sext i8 [[B]] to i16
+; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i16 [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHR:%.*]] = ashr i16 [[MUL]], 8
+; CHECK-NEXT:    ret i16 [[SHR]]
+;
+  %ea = sext i8 %a to i16
+  %eb = sext i8 %b to i16
+  %mul = mul i16 %ea, %eb
+  %shr = ashr i16 %mul, 8
+  ret i16 %shr
+}
+
+define i16 @smulh_lshr(i8 %a, i8 %b) {
+; CHECK-LABEL: define i16 @smulh_lshr(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = sext i8 [[A]] to i16
+; CHECK-NEXT:    [[EB:%.*]] = sext i8 [[B]] to i16
+; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i16 [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i16 [[MUL]], 8
+; CHECK-NEXT:    ret i16 [[SHR]]
+;
+  %ea = sext i8 %a to i16
+  %eb = sext i8 %b to i16
+  %mul = mul i16 %ea, %eb
+  %shr = lshr i16 %mul, 8
+  ret i16 %shr
+}
+
+define i16 @umulh_ashr(i8 %a, i8 %b) {
+; CHECK-LABEL: define i16 @umulh_ashr(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = zext i8 [[A]] to i16
+; CHECK-NEXT:    [[EB:%.*]] = zext i8 [[B]] to i16
+; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i16 [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHR:%.*]] = ashr i16 [[MUL]], 8
+; CHECK-NEXT:    ret i16 [[SHR]]
+;
+  %ea = zext i8 %a to i16
+  %eb = zext i8 %b to i16
+  %mul = mul i16 %ea, %eb
+  %shr = ashr i16 %mul, 8
+  ret i16 %shr
+}
+
+define i16 @umulh_lshr(i8 %a, i8 %b) {
+; CHECK-LABEL: define i16 @umulh_lshr(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = zext i8 [[A]] to i16
+; CHECK-NEXT:    [[EB:%.*]] = zext i8 [[B]] to i16
+; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i16 [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i16 [[MUL]], 8
+; CHECK-NEXT:    ret i16 [[SHR]]
+;
+  %ea = zext i8 %a to i16
+  %eb = zext i8 %b to i16
+  %mul = mul i16 %ea, %eb
+  %shr = lshr i16 %mul, 8
+  ret i16 %shr
+}
+
+define i8 @smulh_trunc(i8 %a, i8 %b) {
+; CHECK-LABEL: define i8 @smulh_trunc(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = sext i8 [[A]] to i16
+; CHECK-NEXT:    [[EB:%.*]] = sext i8 [[B]] to i16
+; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i16 [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i16 [[MUL]], 8
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc nuw i16 [[SHR]] to i8
+; CHECK-NEXT:    ret i8 [[TMP1]]
+;
+  %ea = sext i8 %a to i16
+  %eb = sext i8 %b to i16
+  %mul = mul i16 %ea, %eb
+  %shr = ashr i16 %mul, 8
+  %res = trunc i16 %shr to i8
+  ret i8 %res
+}
+
+define i8 @umulh_trunc(i8 %a, i8 %b) {
+; CHECK-LABEL: define i8 @umulh_trunc(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = zext i8 [[A]] to i16
+; CHECK-NEXT:    [[EB:%.*]] = zext i8 [[B]] to i16
+; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i16 [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i16 [[MUL]], 8
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc nuw i16 [[SHR]] to i8
+; CHECK-NEXT:    ret i8 [[TMP1]]
+;
+  %ea = zext i8 %a to i16
+  %eb = zext i8 %b to i16
+  %mul = mul i16 %ea, %eb
+  %shr = lshr i16 %mul, 8
+  %res = trunc i16 %shr to i8
+  ret i8 %res
+}
+
+define i64 @smulh_i64(i64 %a, i64 %b) {
+; CHECK-LABEL: define i64 @smulh_i64(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = sext i64 [[A]] to i128
+; CHECK-NEXT:    [[EB:%.*]] = sext i64 [[B]] to i128
+; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i128 [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i128 [[MUL]], 64
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc nuw i128 [[SHR]] to i64
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %ea = sext i64 %a to i128
+  %eb = sext i64 %b to i128
+  %mul = mul i128 %ea, %eb
+  %shr = ashr i128 %mul, 64
+  %res = trunc i128 %shr to i64
+  ret i64 %res
+}
+
+define i64 @umulh_i64(i64 %a, i64 %b) {
+; CHECK-LABEL: define i64 @umulh_i64(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = zext i64 [[A]] to i128
+; CHECK-NEXT:    [[EB:%.*]] = zext i64 [[B]] to i128
+; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i128 [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i128 [[MUL]], 64
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc nuw i128 [[SHR]] to i64
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %ea = zext i64 %a to i128
+  %eb = zext i64 %b to i128
+  %mul = mul i128 %ea, %eb
+  %shr = lshr i128 %mul, 64
+  %res = trunc i128 %shr to i64
+  ret i64 %res
+}
+
+define i10 @smulh_i5(i5 %a, i5 %b) {
+; CHECK-LABEL: define i10 @smulh_i5(
+; CHECK-SAME: i5 [[A:%.*]], i5 [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = sext i5 [[A]] to i10
+; CHECK-NEXT:    [[EB:%.*]] = sext i5 [[B]] to i10
+; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i10 [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i10 [[MUL]], 5
+; CHECK-NEXT:    ret i10 [[SHR]]
+;
+  %ea = sext i5 %a to i10
+  %eb = sext i5 %b to i10
+  %mul = mul i10 %ea, %eb
+  %shr = lshr i10 %mul, 5
+  ret i10 %shr
+}
+
+define i10 @umulh_i5(i5 %a, i5 %b) {
+; CHECK-LABEL: define i10 @umulh_i5(
+; CHECK-SAME: i5 [[A:%.*]], i5 [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = zext i5 [[A]] to i10
+; CHECK-NEXT:    [[EB:%.*]] = zext i5 [[B]] to i10
+; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i10 [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i10 [[MUL]], 5
+; CHECK-NEXT:    ret i10 [[SHR]]
+;
+  %ea = zext i5 %a to i10
+  %eb = zext i5 %b to i10
+  %mul = mul i10 %ea, %eb
+  %shr = lshr i10 %mul, 5
+  ret i10 %shr
+}
+
+define <4 x i32> @smulh_v4i16(<4 x i16> %a, <4 x i16> %b) {
+; CHECK-LABEL: define <4 x i32> @smulh_v4i16(
+; CHECK-SAME: <4 x i16> [[A:%.*]], <4 x i16> [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = sext <4 x i16> [[A]] to <4 x i32>
+; CHECK-NEXT:    [[EB:%.*]] = sext <4 x i16> [[B]] to <4 x i32>
+; CHECK-NEXT:    [[MUL:%.*]] = mul nsw <4 x i32> [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr <4 x i32> [[MUL]], splat (i32 16)
+; CHECK-NEXT:    ret <4 x i32> [[SHR]]
+;
+  %ea = sext <4 x i16> %a to <4 x i32>
+  %eb = sext <4 x i16> %b to <4 x i32>
+  %mul = mul <4 x i32> %ea, %eb
+  %shr = lshr <4 x i32> %mul, splat (i32 16)
+  ret <4 x i32> %shr
+}
+
+define <4 x i32> @umulh_v4i16(<4 x i16> %a, <4 x i16> %b) {
+; CHECK-LABEL: define <4 x i32> @umulh_v4i16(
+; CHECK-SAME: <4 x i16> [[A:%.*]], <4 x i16> [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = zext <4 x i16> [[A]] to <4 x i32>
+; CHECK-NEXT:    [[EB:%.*]] = zext <4 x i16> [[B]] to <4 x i32>
+; CHECK-NEXT:    [[MUL:%.*]] = mul nuw <4 x i32> [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr <4 x i32> [[MUL]], splat (i32 16)
+; CHECK-NEXT:    ret <4 x i32> [[SHR]]
+;
+  %ea = zext <4 x i16> %a to <4 x i32>
+  %eb = zext <4 x i16> %b to <4 x i32>
+  %mul = mul <4 x i32> %ea, %eb
+  %shr = lshr <4 x i32> %mul, splat (i32 16)
+  ret <4 x i32> %shr
+}
+
+define <vscale x 4 x i32> @smulh_nxv4i16(<vscale x 4 x i16> %a, <vscale x 4 x 
i16> %b) {
+; CHECK-LABEL: define <vscale x 4 x i32> @smulh_nxv4i16(
+; CHECK-SAME: <vscale x 4 x i16> [[A:%.*]], <vscale x 4 x i16> [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = sext <vscale x 4 x i16> [[A]] to <vscale x 4 x 
i32>
+; CHECK-NEXT:    [[EB:%.*]] = sext <vscale x 4 x i16> [[B]] to <vscale x 4 x 
i32>
+; CHECK-NEXT:    [[MUL:%.*]] = mul nsw <vscale x 4 x i32> [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr <vscale x 4 x i32> [[MUL]], splat (i32 16)
+; CHECK-NEXT:    ret <vscale x 4 x i32> [[SHR]]
+;
+  %ea = sext <vscale x 4 x i16> %a to <vscale x 4 x i32>
+  %eb = sext <vscale x 4 x i16> %b to <vscale x 4 x i32>
+  %mul = mul <vscale x 4 x i32> %ea, %eb
+  %shr = lshr <vscale x 4 x i32> %mul, splat (i32 16)
+  ret <vscale x 4 x i32> %shr
+}
+
+define <vscale x 4 x i32> @umulh_nxv4i16(<vscale x 4 x i16> %a, <vscale x 4 x 
i16> %b) {
+; CHECK-LABEL: define <vscale x 4 x i32> @umulh_nxv4i16(
+; CHECK-SAME: <vscale x 4 x i16> [[A:%.*]], <vscale x 4 x i16> [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = zext <vscale x 4 x i16> [[A]] to <vscale x 4 x 
i32>
+; CHECK-NEXT:    [[EB:%.*]] = zext <vscale x 4 x i16> [[B]] to <vscale x 4 x 
i32>
+; CHECK-NEXT:    [[MUL:%.*]] = mul nuw <vscale x 4 x i32> [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr <vscale x 4 x i32> [[MUL]], splat (i32 16)
+; CHECK-NEXT:    ret <vscale x 4 x i32> [[SHR]]
+;
+  %ea = zext <vscale x 4 x i16> %a to <vscale x 4 x i32>
+  %eb = zext <vscale x 4 x i16> %b to <vscale x 4 x i32>
+  %mul = mul <vscale x 4 x i32> %ea, %eb
+  %shr = lshr <vscale x 4 x i32> %mul, splat (i32 16)
+  ret <vscale x 4 x i32> %shr
+}
+
+define <4 x i32> @smulh_v4i16_poison_lane(<4 x i16> %a, <4 x i16> %b) {
+; CHECK-LABEL: define <4 x i32> @smulh_v4i16_poison_lane(
+; CHECK-SAME: <4 x i16> [[A:%.*]], <4 x i16> [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = sext <4 x i16> [[A]] to <4 x i32>
+; CHECK-NEXT:    [[EB:%.*]] = sext <4 x i16> [[B]] to <4 x i32>
+; CHECK-NEXT:    [[MUL:%.*]] = mul nsw <4 x i32> [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr <4 x i32> [[MUL]], <i32 16, i32 poison, 
i32 16, i32 16>
+; CHECK-NEXT:    ret <4 x i32> [[SHR]]
+;
+  %ea = sext <4 x i16> %a to <4 x i32>
+  %eb = sext <4 x i16> %b to <4 x i32>
+  %mul = mul <4 x i32> %ea, %eb
+  %shr = lshr <4 x i32> %mul, <i32 16, i32 poison, i32 16, i32 16>
+  ret <4 x i32> %shr
+}
+
+define <4 x i32> @umulh_v4i16_poison_lane(<4 x i16> %a, <4 x i16> %b) {
+; CHECK-LABEL: define <4 x i32> @umulh_v4i16_poison_lane(
+; CHECK-SAME: <4 x i16> [[A:%.*]], <4 x i16> [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = zext <4 x i16> [[A]] to <4 x i32>
+; CHECK-NEXT:    [[EB:%.*]] = zext <4 x i16> [[B]] to <4 x i32>
+; CHECK-NEXT:    [[MUL:%.*]] = mul nuw <4 x i32> [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr <4 x i32> [[MUL]], <i32 16, i32 poison, 
i32 16, i32 16>
+; CHECK-NEXT:    ret <4 x i32> [[SHR]]
+;
+  %ea = zext <4 x i16> %a to <4 x i32>
+  %eb = zext <4 x i16> %b to <4 x i32>
+  %mul = mul <4 x i32> %ea, %eb
+  %shr = lshr <4 x i32> %mul, <i32 16, i32 poison, i32 16, i32 16>
+  ret <4 x i32> %shr
+}
+
+define i16 @operands_multiuse(i8 %a, i8 %b) {
+; CHECK-LABEL: define i16 @operands_multiuse(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = zext i8 [[A]] to i16
+; CHECK-NEXT:    [[EB:%.*]] = zext i8 [[B]] to i16
+; CHECK-NEXT:    call void (...) @llvm.fake.use(i16 [[EA]])
+; CHECK-NEXT:    call void (...) @llvm.fake.use(i16 [[EB]])
+; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i16 [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i16 [[MUL]], 8
+; CHECK-NEXT:    ret i16 [[SHR]]
+;
+  %ea = zext i8 %a to i16
+  %eb = zext i8 %b to i16
+  call void (...) @llvm.fake.use(i16 %ea)
+  call void (...) @llvm.fake.use(i16 %eb)
+  %mul = mul i16 %ea, %eb
+  %shr = lshr i16 %mul, 8
+  ret i16 %shr
+}
+
+define i16 @todo_constant_operand_signed(i8 %a) {
+; CHECK-LABEL: define i16 @todo_constant_operand_signed(
+; CHECK-SAME: i8 [[A:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = sext i8 [[A]] to i16
+; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i16 [[EA]], -100
+; CHECK-NEXT:    [[SHR:%.*]] = ashr i16 [[MUL]], 8
+; CHECK-NEXT:    ret i16 [[SHR]]
+;
+  %ea = sext i8 %a to i16
+  %mul = mul i16 %ea, -100
+  %shr = ashr i16 %mul, 8
+  ret i16 %shr
+}
+
+define i16 @todo_constant_operand_unsigned(i8 %a) {
+; CHECK-LABEL: define i16 @todo_constant_operand_unsigned(
+; CHECK-SAME: i8 [[A:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = zext i8 [[A]] to i16
+; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i16 [[EA]], 200
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i16 [[MUL]], 8
+; CHECK-NEXT:    ret i16 [[SHR]]
+;
+  %ea = zext i8 %a to i16
+  %mul = mul i16 %ea, 200
+  %shr = lshr i16 %mul, 8
+  ret i16 %shr
+}
+
+; Negative tests.
+
+define i16 @mixed_extends(i8 %a, i8 %b) {
+; CHECK-LABEL: define i16 @mixed_extends(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = zext i8 [[A]] to i16
+; CHECK-NEXT:    [[EB:%.*]] = sext i8 [[B]] to i16
+; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i16 [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i16 [[MUL]], 8
+; CHECK-NEXT:    ret i16 [[SHR]]
+;
+  %ea = zext i8 %a to i16
+  %eb = sext i8 %b to i16
+  %mul = mul i16 %ea, %eb
+  %shr = lshr i16 %mul, 8
+  ret i16 %shr
+}
+
+define i16 @wrong_shift_amount(i8 %a, i8 %b) {
+; CHECK-LABEL: define i16 @wrong_shift_amount(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = zext i8 [[A]] to i16
+; CHECK-NEXT:    [[EB:%.*]] = zext i8 [[B]] to i16
+; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i16 [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i16 [[MUL]], 7
+; CHECK-NEXT:    ret i16 [[SHR]]
+;
+  %ea = zext i8 %a to i16
+  %eb = zext i8 %b to i16
+  %mul = mul i16 %ea, %eb
+  %shr = lshr i16 %mul, 7
+  ret i16 %shr
+}
+
+define i32 @not_half_source_width(i12 %a, i12 %b) {
+; CHECK-LABEL: define i32 @not_half_source_width(
+; CHECK-SAME: i12 [[A:%.*]], i12 [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = zext i12 [[A]] to i32
+; CHECK-NEXT:    [[EB:%.*]] = zext i12 [[B]] to i32
+; CHECK-NEXT:    [[MUL:%.*]] = mul nuw nsw i32 [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[MUL]], 16
+; CHECK-NEXT:    ret i32 [[SHR]]
+;
+  %ea = zext i12 %a to i32
+  %eb = zext i12 %b to i32
+  %mul = mul i32 %ea, %eb
+  %shr = lshr i32 %mul, 16
+  ret i32 %shr
+}
+
+define i16 @different_source_widths(i8 %a, i4 %b) {
+; CHECK-LABEL: define i16 @different_source_widths(
+; CHECK-SAME: i8 [[A:%.*]], i4 [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = zext i8 [[A]] to i16
+; CHECK-NEXT:    [[EB:%.*]] = zext i4 [[B]] to i16
+; CHECK-NEXT:    [[MUL:%.*]] = mul nuw nsw i16 [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i16 [[MUL]], 8
+; CHECK-NEXT:    ret i16 [[SHR]]
+;
+  %ea = zext i8 %a to i16
+  %eb = zext i4 %b to i16
+  %mul = mul i16 %ea, %eb
+  %shr = lshr i16 %mul, 8
+  ret i16 %shr
+}
+
+define i16 @mul_multiuse(i8 %a, i8 %b) {
+; CHECK-LABEL: define i16 @mul_multiuse(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = zext i8 [[A]] to i16
+; CHECK-NEXT:    [[EB:%.*]] = zext i8 [[B]] to i16
+; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i16 [[EA]], [[EB]]
+; CHECK-NEXT:    call void (...) @llvm.fake.use(i16 [[MUL]])
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i16 [[MUL]], 8
+; CHECK-NEXT:    ret i16 [[SHR]]
+;
+  %ea = zext i8 %a to i16
+  %eb = zext i8 %b to i16
+  %mul = mul i16 %ea, %eb
+  call void (...) @llvm.fake.use(i16 %mul)
+  %shr = lshr i16 %mul, 8
+  ret i16 %shr
+}
+
+define i16 @not_shift_right(i8 %a, i8 %b) {
+; CHECK-LABEL: define i16 @not_shift_right(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = zext i8 [[A]] to i16
+; CHECK-NEXT:    [[EB:%.*]] = zext i8 [[B]] to i16
+; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i16 [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHL:%.*]] = shl i16 [[MUL]], 8
+; CHECK-NEXT:    ret i16 [[SHL]]
+;
+  %ea = zext i8 %a to i16
+  %eb = zext i8 %b to i16
+  %mul = mul i16 %ea, %eb
+  %shl = shl i16 %mul, 8
+  ret i16 %shl
+}
+
+define <4 x i32> @not_splat_shift_amount(<4 x i16> %a, <4 x i16> %b) {
+; CHECK-LABEL: define <4 x i32> @not_splat_shift_amount(
+; CHECK-SAME: <4 x i16> [[A:%.*]], <4 x i16> [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = zext <4 x i16> [[A]] to <4 x i32>
+; CHECK-NEXT:    [[EB:%.*]] = zext <4 x i16> [[B]] to <4 x i32>
+; CHECK-NEXT:    [[MUL:%.*]] = mul nuw <4 x i32> [[EA]], [[EB]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr <4 x i32> [[MUL]], <i32 16, i32 16, i32 
16, i32 15>
+; CHECK-NEXT:    ret <4 x i32> [[SHR]]
+;
+  %ea = zext <4 x i16> %a to <4 x i32>
+  %eb = zext <4 x i16> %b to <4 x i32>
+  %mul = mul <4 x i32> %ea, %eb
+  %shr = lshr <4 x i32> %mul, <i32 16, i32 16, i32 16, i32 15>
+  ret <4 x i32> %shr
+}
+
+define i16 @operand_not_extended(i8 %a, i16 %b) {
+; CHECK-LABEL: define i16 @operand_not_extended(
+; CHECK-SAME: i8 [[A:%.*]], i16 [[B:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = zext i8 [[A]] to i16
+; CHECK-NEXT:    [[MUL:%.*]] = mul i16 [[B]], [[EA]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i16 [[MUL]], 8
+; CHECK-NEXT:    ret i16 [[SHR]]
+;
+  %ea = zext i8 %a to i16
+  %mul = mul i16 %ea, %b
+  %shr = lshr i16 %mul, 8
+  ret i16 %shr
+}
+
+define i16 @constant_operand_too_wide(i8 %a) {
+; CHECK-LABEL: define i16 @constant_operand_too_wide(
+; CHECK-SAME: i8 [[A:%.*]]) {
+; CHECK-NEXT:    [[EA:%.*]] = zext i8 [[A]] to i16
+; CHECK-NEXT:    [[MUL:%.*]] = mul i16 [[EA]], 300
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i16 [[MUL]], 8
+; CHECK-NEXT:    ret i16 [[SHR]]
+;
+  %ea = zext i8 %a to i16
+  %mul = mul i16 %ea, 300
+  %shr = lshr i16 %mul, 8
+  ret i16 %shr
+}

>From 8c0c9ed06f70929d29f1b0f887f98614b4c994fe Mon Sep 17 00:00:00 2001
From: Ricardo Jesus <[email protected]>
Date: Sat, 22 Aug 2026 01:56:00 -0700
Subject: [PATCH 2/2] [InstCombine] Combine ((ext(A) * ext(B)) >> N) ->
 ext(mulh(A, B)).

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.
---
 clang/test/CodeGen/X86/ms-x86-intrinsics.c    |   4 +-
 .../InstCombine/InstCombineShifts.cpp         |  19 ++++
 .../AggressiveInstCombine/umulh_carry.ll      |  42 ++------
 .../AggressiveInstCombine/umulh_carry4.ll     |  96 +++--------------
 .../AggressiveInstCombine/umulh_ladder.ll     |  60 ++---------
 .../AggressiveInstCombine/umulh_ladder4.ll    |  30 +-----
 llvm/test/Transforms/InstCombine/mulh.ll      | 100 ++++++------------
 .../InstCombine/trunc-inseltpoison.ll         |   8 +-
 llvm/test/Transforms/InstCombine/trunc.ll     |   8 +-
 9 files changed, 95 insertions(+), 272 deletions(-)

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-NEXT:    [[TMP2:%.*]] = zext i64 [[X]] 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 [[Y]], i64 [[X]])
 ; CHECK-NEXT:    ret i64 [[TMP5]]
 ;
   %x_lo = and i64 %x, 4294967295
@@ -37,11 +33,7 @@ define i64 @umulh_variant(i64 %x, i64 %y) {
 define i32 @umulh_variant_i32(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i32 @umulh_variant_i32(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = zext i32 [[Y]] to i64
-; CHECK-NEXT:    [[TMP2:%.*]] = zext i32 [[X]] to i64
-; CHECK-NEXT:    [[TMP3:%.*]] = mul nuw i64 [[TMP1]], [[TMP2]]
-; CHECK-NEXT:    [[TMP4:%.*]] = lshr i64 [[TMP3]], 32
-; CHECK-NEXT:    [[HW64:%.*]] = trunc nuw i64 [[TMP4]] to i32
+; CHECK-NEXT:    [[HW64:%.*]] = call i32 @llvm.umulh.i32(i32 [[Y]], i32 [[X]])
 ; CHECK-NEXT:    ret i32 [[HW64]]
 ;
   %x_lo = and i32 %x, u0xffff
@@ -69,11 +61,7 @@ define i32 @umulh_variant_i32(i32 %x, i32 %y) {
 define <2 x i32> @umulh_variant_v2i32(<2 x i32> %x, <2 x i32> %y) {
 ; CHECK-LABEL: define <2 x i32> @umulh_variant_v2i32(
 ; CHECK-SAME: <2 x i32> [[X:%.*]], <2 x i32> [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = zext <2 x i32> [[Y]] to <2 x i64>
-; CHECK-NEXT:    [[TMP2:%.*]] = zext <2 x i32> [[X]] 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> 
[[Y]], <2 x i32> [[X]])
 ; CHECK-NEXT:    ret <2 x i32> [[HW64]]
 ;
   %x_lo = and <2 x i32> %x, <i32 u0xffff, i32 u0xffff>
@@ -101,11 +89,7 @@ define <2 x i32> @umulh_variant_v2i32(<2 x i32> %x, <2 x 
i32> %y) {
 define i128 @umulh_variant_i128(i128 %x, i128 %y) {
 ; CHECK-LABEL: define i128 @umulh_variant_i128(
 ; CHECK-SAME: i128 [[X:%.*]], i128 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = zext i128 [[Y]] to i256
-; CHECK-NEXT:    [[TMP2:%.*]] = zext i128 [[X]] 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 [[Y]], i128 
[[X]])
 ; CHECK-NEXT:    ret i128 [[HW64]]
 ;
   %x_lo = and i128 %x, u0xffffffffffffffff
@@ -133,11 +117,7 @@ define i128 @umulh_variant_i128(i128 %x, i128 %y) {
 define i64 @umulh_variant_commuted(i64 %x, i64 %y) {
 ; CHECK-LABEL: define i64 @umulh_variant_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:    [[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]]
 ;
   %x_lo = and i64 %x, 4294967295
@@ -350,11 +330,7 @@ define i64 @umulh_variant__mul_use__t0(i64 %x, i64 %y) {
 ; CHECK-NEXT:    [[Y_LO:%.*]] = and i64 [[Y]], 4294967295
 ; CHECK-NEXT:    [[T0:%.*]] = mul nuw i64 [[Y_LO]], [[X_LO]]
 ; CHECK-NEXT:    call void (...) @llvm.fake.use(i64 [[T0]])
-; CHECK-NEXT:    [[TMP1:%.*]] = zext i64 [[Y]] to i128
-; CHECK-NEXT:    [[TMP2:%.*]] = zext i64 [[X]] 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 [[Y]], i64 [[X]])
 ; CHECK-NEXT:    ret i64 [[HW64]]
 ;
   %x_lo = and i64 %x, 4294967295
@@ -388,11 +364,7 @@ define i64 @umulh_variant__mul_use__t1(i64 %x, i64 %y) {
 ; CHECK-NEXT:    [[X_HI:%.*]] = lshr i64 [[X]], 32
 ; CHECK-NEXT:    [[T1:%.*]] = mul nuw i64 [[Y_LO]], [[X_HI]]
 ; CHECK-NEXT:    call void (...) @llvm.fake.use(i64 [[T1]])
-; CHECK-NEXT:    [[TMP1:%.*]] = zext i64 [[Y]] to i128
-; CHECK-NEXT:    [[TMP2:%.*]] = zext i64 [[X]] 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 [[Y]], i64 [[X]])
 ; CHECK-NEXT:    ret i64 [[HW64]]
 ;
   %x_lo = and i64 %x, 4294967295
@@ -426,11 +398,7 @@ define i64 @umulh_variant__mul_use__t2(i64 %x, i64 %y) {
 ; CHECK-NEXT:    [[Y_HI:%.*]] = lshr i64 [[Y]], 32
 ; CHECK-NEXT:    [[T2:%.*]] = mul nuw i64 [[Y_HI]], [[X_LO]]
 ; CHECK-NEXT:    call void (...) @llvm.fake.use(i64 [[T2]])
-; CHECK-NEXT:    [[TMP1:%.*]] = zext i64 [[Y]] to i128
-; CHECK-NEXT:    [[TMP2:%.*]] = zext i64 [[X]] 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 [[Y]], i64 [[X]])
 ; CHECK-NEXT:    ret i64 [[HW64]]
 ;
   %x_lo = and i64 %x, 4294967295
@@ -511,11 +479,7 @@ define i64 @umulh_variant__mul_use__t0_hi(i64 %x, i64 %y) {
 ; CHECK-NEXT:    [[T0:%.*]] = mul nuw i64 [[Y_LO]], [[X_LO]]
 ; CHECK-NEXT:    [[T0_HI:%.*]] = lshr i64 [[T0]], 32
 ; CHECK-NEXT:    call void (...) @llvm.fake.use(i64 [[T0_HI]])
-; CHECK-NEXT:    [[TMP1:%.*]] = zext i64 [[Y]] to i128
-; CHECK-NEXT:    [[TMP2:%.*]] = zext i64 [[X]] 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 [[Y]], i64 [[X]])
 ; CHECK-NEXT:    ret i64 [[HW64]]
 ;
   %x_lo = and i64 %x, 4294967295
@@ -821,11 +785,7 @@ define [2 x i64] @XXH_mult64to128(i64 noundef %lhs, i64 
noundef %rhs) {
 ; CHECK-LABEL: define [2 x i64] @XXH_mult64to128(
 ; CHECK-SAME: i64 noundef [[LHS:%.*]], i64 noundef [[RHS:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[TMP0:%.*]] = zext i64 [[RHS]] to i128
-; CHECK-NEXT:    [[TMP1:%.*]] = zext i64 [[LHS]] to i128
-; CHECK-NEXT:    [[TMP2:%.*]] = mul nuw i128 [[TMP0]], [[TMP1]]
-; CHECK-NEXT:    [[TMP3:%.*]] = lshr i128 [[TMP2]], 64
-; CHECK-NEXT:    [[ADD16:%.*]] = trunc nuw i128 [[TMP3]] to i64
+; CHECK-NEXT:    [[ADD16:%.*]] = call i64 @llvm.umulh.i64(i64 [[RHS]], i64 
[[LHS]])
 ; CHECK-NEXT:    [[SHR102:%.*]] = mul i64 [[LHS]], [[RHS]]
 ; CHECK-NEXT:    [[DOTFCA_0_INSERT:%.*]] = insertvalue [2 x i64] poison, i64 
[[SHR102]], 0
 ; CHECK-NEXT:    [[DOTFCA_1_INSERT:%.*]] = insertvalue [2 x i64] 
[[DOTFCA_0_INSERT]], i64 [[ADD16]], 1
diff --git a/llvm/test/Transforms/AggressiveInstCombine/umulh_ladder4.ll 
b/llvm/test/Transforms/AggressiveInstCombine/umulh_ladder4.ll
index 307fc62a6b4ba..57f30b3ce59c0 100644
--- a/llvm/test/Transforms/AggressiveInstCombine/umulh_ladder4.ll
+++ b/llvm/test/Transforms/AggressiveInstCombine/umulh_ladder4.ll
@@ -6,11 +6,7 @@ define i32 @mul_ladder4(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i32 @mul_ladder4(
 ; 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:    [[ADD19:%.*]] = trunc nuw i64 [[TMP3]] to i32
+; CHECK-NEXT:    [[ADD19:%.*]] = call i32 @llvm.umulh.i32(i32 [[X]], i32 [[Y]])
 ; CHECK-NEXT:    ret i32 [[ADD19]]
 ;
 entry:
@@ -40,11 +36,7 @@ define <2 x i32> @mul_ladder4_v2i32(<2 x i32> %x, <2 x i32> 
%y) {
 ; CHECK-LABEL: define <2 x i32> @mul_ladder4_v2i32(
 ; CHECK-SAME: <2 x i32> [[X:%.*]], <2 x i32> [[Y:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[TMP0:%.*]] = zext <2 x i32> [[X]] to <2 x i64>
-; CHECK-NEXT:    [[TMP1:%.*]] = zext <2 x i32> [[Y]] to <2 x i64>
-; CHECK-NEXT:    [[TMP2:%.*]] = mul nuw <2 x i64> [[TMP0]], [[TMP1]]
-; CHECK-NEXT:    [[TMP3:%.*]] = lshr <2 x i64> [[TMP2]], splat (i64 32)
-; CHECK-NEXT:    [[ADD19:%.*]] = trunc nuw <2 x i64> [[TMP3]] to <2 x i32>
+; CHECK-NEXT:    [[ADD19:%.*]] = call <2 x i32> @llvm.umulh.v2i32(<2 x i32> 
[[X]], <2 x i32> [[Y]])
 ; CHECK-NEXT:    ret <2 x i32> [[ADD19]]
 ;
 entry:
@@ -74,11 +66,7 @@ define i128 @mul_ladder4_i128(i128 %x, i128 %y) {
 ; CHECK-LABEL: define i128 @mul_ladder4_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:    [[ADD19:%.*]] = trunc nuw i256 [[TMP3]] to i128
+; CHECK-NEXT:    [[ADD19:%.*]] = call i128 @llvm.umulh.i128(i128 [[X]], i128 
[[Y]])
 ; CHECK-NEXT:    ret i128 [[ADD19]]
 ;
 entry:
@@ -108,11 +96,7 @@ define i32 @mul_ladder4_commutted(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i32 @mul_ladder4_commutted(
 ; 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:    [[ADD19:%.*]] = trunc nuw i64 [[TMP3]] to i32
+; CHECK-NEXT:    [[ADD19:%.*]] = call i32 @llvm.umulh.i32(i32 [[Y]], i32 [[X]])
 ; CHECK-NEXT:    ret i32 [[ADD19]]
 ;
 entry:
@@ -142,11 +126,7 @@ define i32 @mul_ladder4_swap_hl_lh(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i32 @mul_ladder4_swap_hl_lh(
 ; 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:    [[ADD19:%.*]] = trunc nuw i64 [[TMP3]] to i32
+; CHECK-NEXT:    [[ADD19:%.*]] = call i32 @llvm.umulh.i32(i32 [[X]], i32 [[Y]])
 ; CHECK-NEXT:    ret i32 [[ADD19]]
 ;
 entry:
diff --git a/llvm/test/Transforms/InstCombine/mulh.ll 
b/llvm/test/Transforms/InstCombine/mulh.ll
index c0daf9b2e1579..e7a3012e9dda5 100644
--- a/llvm/test/Transforms/InstCombine/mulh.ll
+++ b/llvm/test/Transforms/InstCombine/mulh.ll
@@ -4,10 +4,8 @@
 define i16 @smulh_ashr(i8 %a, i8 %b) {
 ; CHECK-LABEL: define i16 @smulh_ashr(
 ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
-; CHECK-NEXT:    [[EA:%.*]] = sext i8 [[A]] to i16
-; CHECK-NEXT:    [[EB:%.*]] = sext i8 [[B]] to i16
-; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i16 [[EA]], [[EB]]
-; CHECK-NEXT:    [[SHR:%.*]] = ashr i16 [[MUL]], 8
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.smulh.i8(i8 [[A]], i8 [[B]])
+; CHECK-NEXT:    [[SHR:%.*]] = sext i8 [[TMP1]] to i16
 ; CHECK-NEXT:    ret i16 [[SHR]]
 ;
   %ea = sext i8 %a to i16
@@ -20,10 +18,8 @@ define i16 @smulh_ashr(i8 %a, i8 %b) {
 define i16 @smulh_lshr(i8 %a, i8 %b) {
 ; CHECK-LABEL: define i16 @smulh_lshr(
 ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
-; CHECK-NEXT:    [[EA:%.*]] = sext i8 [[A]] to i16
-; CHECK-NEXT:    [[EB:%.*]] = sext i8 [[B]] to i16
-; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i16 [[EA]], [[EB]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr i16 [[MUL]], 8
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.smulh.i8(i8 [[A]], i8 [[B]])
+; CHECK-NEXT:    [[SHR:%.*]] = zext i8 [[TMP1]] to i16
 ; CHECK-NEXT:    ret i16 [[SHR]]
 ;
   %ea = sext i8 %a to i16
@@ -36,10 +32,8 @@ define i16 @smulh_lshr(i8 %a, i8 %b) {
 define i16 @umulh_ashr(i8 %a, i8 %b) {
 ; CHECK-LABEL: define i16 @umulh_ashr(
 ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
-; CHECK-NEXT:    [[EA:%.*]] = zext i8 [[A]] to i16
-; CHECK-NEXT:    [[EB:%.*]] = zext i8 [[B]] to i16
-; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i16 [[EA]], [[EB]]
-; CHECK-NEXT:    [[SHR:%.*]] = ashr i16 [[MUL]], 8
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.umulh.i8(i8 [[A]], i8 [[B]])
+; CHECK-NEXT:    [[SHR:%.*]] = sext i8 [[TMP1]] to i16
 ; CHECK-NEXT:    ret i16 [[SHR]]
 ;
   %ea = zext i8 %a to i16
@@ -52,10 +46,8 @@ define i16 @umulh_ashr(i8 %a, i8 %b) {
 define i16 @umulh_lshr(i8 %a, i8 %b) {
 ; CHECK-LABEL: define i16 @umulh_lshr(
 ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
-; CHECK-NEXT:    [[EA:%.*]] = zext i8 [[A]] to i16
-; CHECK-NEXT:    [[EB:%.*]] = zext i8 [[B]] to i16
-; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i16 [[EA]], [[EB]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr i16 [[MUL]], 8
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.umulh.i8(i8 [[A]], i8 [[B]])
+; CHECK-NEXT:    [[SHR:%.*]] = zext i8 [[TMP1]] to i16
 ; CHECK-NEXT:    ret i16 [[SHR]]
 ;
   %ea = zext i8 %a to i16
@@ -68,11 +60,7 @@ define i16 @umulh_lshr(i8 %a, i8 %b) {
 define i8 @smulh_trunc(i8 %a, i8 %b) {
 ; CHECK-LABEL: define i8 @smulh_trunc(
 ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
-; CHECK-NEXT:    [[EA:%.*]] = sext i8 [[A]] to i16
-; CHECK-NEXT:    [[EB:%.*]] = sext i8 [[B]] to i16
-; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i16 [[EA]], [[EB]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr i16 [[MUL]], 8
-; CHECK-NEXT:    [[TMP1:%.*]] = trunc nuw i16 [[SHR]] to i8
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.smulh.i8(i8 [[A]], i8 [[B]])
 ; CHECK-NEXT:    ret i8 [[TMP1]]
 ;
   %ea = sext i8 %a to i16
@@ -86,11 +74,7 @@ define i8 @smulh_trunc(i8 %a, i8 %b) {
 define i8 @umulh_trunc(i8 %a, i8 %b) {
 ; CHECK-LABEL: define i8 @umulh_trunc(
 ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
-; CHECK-NEXT:    [[EA:%.*]] = zext i8 [[A]] to i16
-; CHECK-NEXT:    [[EB:%.*]] = zext i8 [[B]] to i16
-; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i16 [[EA]], [[EB]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr i16 [[MUL]], 8
-; CHECK-NEXT:    [[TMP1:%.*]] = trunc nuw i16 [[SHR]] to i8
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.umulh.i8(i8 [[A]], i8 [[B]])
 ; CHECK-NEXT:    ret i8 [[TMP1]]
 ;
   %ea = zext i8 %a to i16
@@ -104,11 +88,7 @@ define i8 @umulh_trunc(i8 %a, i8 %b) {
 define i64 @smulh_i64(i64 %a, i64 %b) {
 ; CHECK-LABEL: define i64 @smulh_i64(
 ; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
-; CHECK-NEXT:    [[EA:%.*]] = sext i64 [[A]] to i128
-; CHECK-NEXT:    [[EB:%.*]] = sext i64 [[B]] to i128
-; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i128 [[EA]], [[EB]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr i128 [[MUL]], 64
-; CHECK-NEXT:    [[TMP1:%.*]] = trunc nuw i128 [[SHR]] to i64
+; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.smulh.i64(i64 [[A]], i64 [[B]])
 ; CHECK-NEXT:    ret i64 [[TMP1]]
 ;
   %ea = sext i64 %a to i128
@@ -122,11 +102,7 @@ define i64 @smulh_i64(i64 %a, i64 %b) {
 define i64 @umulh_i64(i64 %a, i64 %b) {
 ; CHECK-LABEL: define i64 @umulh_i64(
 ; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
-; CHECK-NEXT:    [[EA:%.*]] = zext i64 [[A]] to i128
-; CHECK-NEXT:    [[EB:%.*]] = zext i64 [[B]] to i128
-; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i128 [[EA]], [[EB]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr i128 [[MUL]], 64
-; CHECK-NEXT:    [[TMP1:%.*]] = trunc nuw i128 [[SHR]] to i64
+; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.umulh.i64(i64 [[A]], i64 [[B]])
 ; CHECK-NEXT:    ret i64 [[TMP1]]
 ;
   %ea = zext i64 %a to i128
@@ -140,10 +116,8 @@ define i64 @umulh_i64(i64 %a, i64 %b) {
 define i10 @smulh_i5(i5 %a, i5 %b) {
 ; CHECK-LABEL: define i10 @smulh_i5(
 ; CHECK-SAME: i5 [[A:%.*]], i5 [[B:%.*]]) {
-; CHECK-NEXT:    [[EA:%.*]] = sext i5 [[A]] to i10
-; CHECK-NEXT:    [[EB:%.*]] = sext i5 [[B]] to i10
-; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i10 [[EA]], [[EB]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr i10 [[MUL]], 5
+; CHECK-NEXT:    [[TMP1:%.*]] = call i5 @llvm.smulh.i5(i5 [[A]], i5 [[B]])
+; CHECK-NEXT:    [[SHR:%.*]] = zext i5 [[TMP1]] to i10
 ; CHECK-NEXT:    ret i10 [[SHR]]
 ;
   %ea = sext i5 %a to i10
@@ -156,10 +130,8 @@ define i10 @smulh_i5(i5 %a, i5 %b) {
 define i10 @umulh_i5(i5 %a, i5 %b) {
 ; CHECK-LABEL: define i10 @umulh_i5(
 ; CHECK-SAME: i5 [[A:%.*]], i5 [[B:%.*]]) {
-; CHECK-NEXT:    [[EA:%.*]] = zext i5 [[A]] to i10
-; CHECK-NEXT:    [[EB:%.*]] = zext i5 [[B]] to i10
-; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i10 [[EA]], [[EB]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr i10 [[MUL]], 5
+; CHECK-NEXT:    [[TMP1:%.*]] = call i5 @llvm.umulh.i5(i5 [[A]], i5 [[B]])
+; CHECK-NEXT:    [[SHR:%.*]] = zext i5 [[TMP1]] to i10
 ; CHECK-NEXT:    ret i10 [[SHR]]
 ;
   %ea = zext i5 %a to i10
@@ -172,10 +144,8 @@ define i10 @umulh_i5(i5 %a, i5 %b) {
 define <4 x i32> @smulh_v4i16(<4 x i16> %a, <4 x i16> %b) {
 ; CHECK-LABEL: define <4 x i32> @smulh_v4i16(
 ; CHECK-SAME: <4 x i16> [[A:%.*]], <4 x i16> [[B:%.*]]) {
-; CHECK-NEXT:    [[EA:%.*]] = sext <4 x i16> [[A]] to <4 x i32>
-; CHECK-NEXT:    [[EB:%.*]] = sext <4 x i16> [[B]] to <4 x i32>
-; CHECK-NEXT:    [[MUL:%.*]] = mul nsw <4 x i32> [[EA]], [[EB]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr <4 x i32> [[MUL]], splat (i32 16)
+; CHECK-NEXT:    [[TMP1:%.*]] = call <4 x i16> @llvm.smulh.v4i16(<4 x i16> 
[[A]], <4 x i16> [[B]])
+; CHECK-NEXT:    [[SHR:%.*]] = zext <4 x i16> [[TMP1]] to <4 x i32>
 ; CHECK-NEXT:    ret <4 x i32> [[SHR]]
 ;
   %ea = sext <4 x i16> %a to <4 x i32>
@@ -188,10 +158,8 @@ define <4 x i32> @smulh_v4i16(<4 x i16> %a, <4 x i16> %b) {
 define <4 x i32> @umulh_v4i16(<4 x i16> %a, <4 x i16> %b) {
 ; CHECK-LABEL: define <4 x i32> @umulh_v4i16(
 ; CHECK-SAME: <4 x i16> [[A:%.*]], <4 x i16> [[B:%.*]]) {
-; CHECK-NEXT:    [[EA:%.*]] = zext <4 x i16> [[A]] to <4 x i32>
-; CHECK-NEXT:    [[EB:%.*]] = zext <4 x i16> [[B]] to <4 x i32>
-; CHECK-NEXT:    [[MUL:%.*]] = mul nuw <4 x i32> [[EA]], [[EB]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr <4 x i32> [[MUL]], splat (i32 16)
+; CHECK-NEXT:    [[TMP1:%.*]] = call <4 x i16> @llvm.umulh.v4i16(<4 x i16> 
[[A]], <4 x i16> [[B]])
+; CHECK-NEXT:    [[SHR:%.*]] = zext <4 x i16> [[TMP1]] to <4 x i32>
 ; CHECK-NEXT:    ret <4 x i32> [[SHR]]
 ;
   %ea = zext <4 x i16> %a to <4 x i32>
@@ -204,10 +172,8 @@ define <4 x i32> @umulh_v4i16(<4 x i16> %a, <4 x i16> %b) {
 define <vscale x 4 x i32> @smulh_nxv4i16(<vscale x 4 x i16> %a, <vscale x 4 x 
i16> %b) {
 ; CHECK-LABEL: define <vscale x 4 x i32> @smulh_nxv4i16(
 ; CHECK-SAME: <vscale x 4 x i16> [[A:%.*]], <vscale x 4 x i16> [[B:%.*]]) {
-; CHECK-NEXT:    [[EA:%.*]] = sext <vscale x 4 x i16> [[A]] to <vscale x 4 x 
i32>
-; CHECK-NEXT:    [[EB:%.*]] = sext <vscale x 4 x i16> [[B]] to <vscale x 4 x 
i32>
-; CHECK-NEXT:    [[MUL:%.*]] = mul nsw <vscale x 4 x i32> [[EA]], [[EB]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr <vscale x 4 x i32> [[MUL]], splat (i32 16)
+; CHECK-NEXT:    [[TMP1:%.*]] = call <vscale x 4 x i16> 
@llvm.smulh.nxv4i16(<vscale x 4 x i16> [[A]], <vscale x 4 x i16> [[B]])
+; CHECK-NEXT:    [[SHR:%.*]] = zext <vscale x 4 x i16> [[TMP1]] to <vscale x 4 
x i32>
 ; CHECK-NEXT:    ret <vscale x 4 x i32> [[SHR]]
 ;
   %ea = sext <vscale x 4 x i16> %a to <vscale x 4 x i32>
@@ -220,10 +186,8 @@ define <vscale x 4 x i32> @smulh_nxv4i16(<vscale x 4 x 
i16> %a, <vscale x 4 x i1
 define <vscale x 4 x i32> @umulh_nxv4i16(<vscale x 4 x i16> %a, <vscale x 4 x 
i16> %b) {
 ; CHECK-LABEL: define <vscale x 4 x i32> @umulh_nxv4i16(
 ; CHECK-SAME: <vscale x 4 x i16> [[A:%.*]], <vscale x 4 x i16> [[B:%.*]]) {
-; CHECK-NEXT:    [[EA:%.*]] = zext <vscale x 4 x i16> [[A]] to <vscale x 4 x 
i32>
-; CHECK-NEXT:    [[EB:%.*]] = zext <vscale x 4 x i16> [[B]] to <vscale x 4 x 
i32>
-; CHECK-NEXT:    [[MUL:%.*]] = mul nuw <vscale x 4 x i32> [[EA]], [[EB]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr <vscale x 4 x i32> [[MUL]], splat (i32 16)
+; CHECK-NEXT:    [[TMP1:%.*]] = call <vscale x 4 x i16> 
@llvm.umulh.nxv4i16(<vscale x 4 x i16> [[A]], <vscale x 4 x i16> [[B]])
+; CHECK-NEXT:    [[SHR:%.*]] = zext <vscale x 4 x i16> [[TMP1]] to <vscale x 4 
x i32>
 ; CHECK-NEXT:    ret <vscale x 4 x i32> [[SHR]]
 ;
   %ea = zext <vscale x 4 x i16> %a to <vscale x 4 x i32>
@@ -236,10 +200,8 @@ define <vscale x 4 x i32> @umulh_nxv4i16(<vscale x 4 x 
i16> %a, <vscale x 4 x i1
 define <4 x i32> @smulh_v4i16_poison_lane(<4 x i16> %a, <4 x i16> %b) {
 ; CHECK-LABEL: define <4 x i32> @smulh_v4i16_poison_lane(
 ; CHECK-SAME: <4 x i16> [[A:%.*]], <4 x i16> [[B:%.*]]) {
-; CHECK-NEXT:    [[EA:%.*]] = sext <4 x i16> [[A]] to <4 x i32>
-; CHECK-NEXT:    [[EB:%.*]] = sext <4 x i16> [[B]] to <4 x i32>
-; CHECK-NEXT:    [[MUL:%.*]] = mul nsw <4 x i32> [[EA]], [[EB]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr <4 x i32> [[MUL]], <i32 16, i32 poison, 
i32 16, i32 16>
+; CHECK-NEXT:    [[TMP1:%.*]] = call <4 x i16> @llvm.smulh.v4i16(<4 x i16> 
[[A]], <4 x i16> [[B]])
+; CHECK-NEXT:    [[SHR:%.*]] = zext <4 x i16> [[TMP1]] to <4 x i32>
 ; CHECK-NEXT:    ret <4 x i32> [[SHR]]
 ;
   %ea = sext <4 x i16> %a to <4 x i32>
@@ -252,10 +214,8 @@ define <4 x i32> @smulh_v4i16_poison_lane(<4 x i16> %a, <4 
x i16> %b) {
 define <4 x i32> @umulh_v4i16_poison_lane(<4 x i16> %a, <4 x i16> %b) {
 ; CHECK-LABEL: define <4 x i32> @umulh_v4i16_poison_lane(
 ; CHECK-SAME: <4 x i16> [[A:%.*]], <4 x i16> [[B:%.*]]) {
-; CHECK-NEXT:    [[EA:%.*]] = zext <4 x i16> [[A]] to <4 x i32>
-; CHECK-NEXT:    [[EB:%.*]] = zext <4 x i16> [[B]] to <4 x i32>
-; CHECK-NEXT:    [[MUL:%.*]] = mul nuw <4 x i32> [[EA]], [[EB]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr <4 x i32> [[MUL]], <i32 16, i32 poison, 
i32 16, i32 16>
+; CHECK-NEXT:    [[TMP1:%.*]] = call <4 x i16> @llvm.umulh.v4i16(<4 x i16> 
[[A]], <4 x i16> [[B]])
+; CHECK-NEXT:    [[SHR:%.*]] = zext <4 x i16> [[TMP1]] to <4 x i32>
 ; CHECK-NEXT:    ret <4 x i32> [[SHR]]
 ;
   %ea = zext <4 x i16> %a to <4 x i32>
@@ -272,8 +232,8 @@ define i16 @operands_multiuse(i8 %a, i8 %b) {
 ; CHECK-NEXT:    [[EB:%.*]] = zext i8 [[B]] to i16
 ; CHECK-NEXT:    call void (...) @llvm.fake.use(i16 [[EA]])
 ; CHECK-NEXT:    call void (...) @llvm.fake.use(i16 [[EB]])
-; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i16 [[EA]], [[EB]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr i16 [[MUL]], 8
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.umulh.i8(i8 [[A]], i8 [[B]])
+; CHECK-NEXT:    [[SHR:%.*]] = zext i8 [[TMP1]] to i16
 ; CHECK-NEXT:    ret i16 [[SHR]]
 ;
   %ea = zext i8 %a to i16
diff --git a/llvm/test/Transforms/InstCombine/trunc-inseltpoison.ll 
b/llvm/test/Transforms/InstCombine/trunc-inseltpoison.ll
index f83352c94ad89..3e2351da46d62 100644
--- a/llvm/test/Transforms/InstCombine/trunc-inseltpoison.ll
+++ b/llvm/test/Transforms/InstCombine/trunc-inseltpoison.ll
@@ -200,11 +200,9 @@ define i16 @ashr_mul_sign_bits(i8 %X, i8 %Y) {
 
 define i16 @ashr_mul(i8 %X, i8 %Y) {
 ; CHECK-LABEL: @ashr_mul(
-; CHECK-NEXT:    [[A:%.*]] = sext i8 [[X:%.*]] to i16
-; CHECK-NEXT:    [[B:%.*]] = sext i8 [[Y:%.*]] to i16
-; CHECK-NEXT:    [[C:%.*]] = mul nsw i16 [[A]], [[B]]
-; CHECK-NEXT:    [[D:%.*]] = ashr i16 [[C]], 8
-; CHECK-NEXT:    ret i16 [[D]]
+; CHECK-NEXT:    [[Y:%.*]] = call i8 @llvm.smulh.i8(i8 [[X:%.*]], i8 
[[Y1:%.*]])
+; CHECK-NEXT:    [[B:%.*]] = sext i8 [[Y]] to i16
+; CHECK-NEXT:    ret i16 [[B]]
 ;
   %A = sext i8 %X to i20
   %B = sext i8 %Y to i20
diff --git a/llvm/test/Transforms/InstCombine/trunc.ll 
b/llvm/test/Transforms/InstCombine/trunc.ll
index 91f637e89069f..ea6c22d29f67f 100644
--- a/llvm/test/Transforms/InstCombine/trunc.ll
+++ b/llvm/test/Transforms/InstCombine/trunc.ll
@@ -201,11 +201,9 @@ define i16 @ashr_mul_sign_bits(i8 %X, i8 %Y) {
 
 define i16 @ashr_mul(i8 %X, i8 %Y) {
 ; CHECK-LABEL: @ashr_mul(
-; CHECK-NEXT:    [[A:%.*]] = sext i8 [[X:%.*]] to i16
-; CHECK-NEXT:    [[B:%.*]] = sext i8 [[Y:%.*]] to i16
-; CHECK-NEXT:    [[C:%.*]] = mul nsw i16 [[A]], [[B]]
-; CHECK-NEXT:    [[D:%.*]] = ashr i16 [[C]], 8
-; CHECK-NEXT:    ret i16 [[D]]
+; CHECK-NEXT:    [[Y:%.*]] = call i8 @llvm.smulh.i8(i8 [[X:%.*]], i8 
[[Y1:%.*]])
+; CHECK-NEXT:    [[B:%.*]] = sext i8 [[Y]] to i16
+; CHECK-NEXT:    ret i16 [[B]]
 ;
   %A = sext i8 %X to i20
   %B = sext i8 %Y to i20

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to