[clang] [llvm] [InstCombine] Combine ((ext(A) * ext(B)) >> N) -> ext(mulh(A, B)). (PR #224311)
Ricardo Jesus via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 17 06:56:36 PDT 2026
https://github.com/rj-jesus created https://github.com/llvm/llvm-project/pull/224311
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.
>From f81fc6b57b940f55a0f935c9c182c6e8dedfeb0e Mon Sep 17 00:00:00 2001
From: Ricardo Jesus <rjj at nvidia.com>
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 <rjj at nvidia.com>
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
More information about the llvm-commits
mailing list