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 <[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
