[llvm] 86a445a - [InstCombine] Add generic smulh/umulh identity folds (#227335)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 1 03:12:22 PDT 2026
Author: Simon Pilgrim
Date: 2026-10-01T10:12:11Z
New Revision: 86a445a3f6e3ee145fd9523a6360626b1df99fd1
URL: https://github.com/llvm/llvm-project/commit/86a445a3f6e3ee145fd9523a6360626b1df99fd1
DIFF: https://github.com/llvm/llvm-project/commit/86a445a3f6e3ee145fd9523a6360626b1df99fd1.diff
LOG: [InstCombine] Add generic smulh/umulh identity folds (#227335)
Added baseline smulh/umulh tests branched from equivalent x86 pmulh/pmulhu tests
Added generic generic smulh/umulh identity folds that match the x86 pmulh (commutative) folds:
[su]mulh(x,undef) -> 0
[su]mulh(x,0) -> 0
umulh(x,1) -> 0
smulh(x,1) -> sra(x,bw-1) // signsplat
Prep work for #223627
Added:
llvm/test/Transforms/InstCombine/smulh.ll
llvm/test/Transforms/InstCombine/umulh.ll
Modified:
llvm/lib/Analysis/InstructionSimplify.cpp
llvm/lib/Analysis/ValueTracking.cpp
llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 4e91cb44c7a18..29172c96d587b 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -7130,6 +7130,21 @@ static Value *simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
break;
}
+ case Intrinsic::umulh:
+ // Multiply by one.
+ if (match(Op0, m_One()) || match(Op1, m_One()))
+ return Constant::getNullValue(ReturnType);
+ [[fallthrough]];
+ case Intrinsic::smulh:
+ // Multiply by undef -> zero (NOT undef!) as other arg could still be
+ // zero.
+ if (Q.isUndefValue(Op0) || Q.isUndefValue(Op1))
+ return Constant::getNullValue(ReturnType);
+
+ // Multiply by zero.
+ if (match(Op0, m_Zero()) || match(Op1, m_Zero()))
+ return Constant::getNullValue(ReturnType);
+ break;
case Intrinsic::usub_with_overflow:
case Intrinsic::ssub_with_overflow:
// X - X -> { 0, false }
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index f56375e4dbe73..e9c1b9fa95376 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -8486,6 +8486,8 @@ bool llvm::intrinsicPropagatesPoison(Intrinsic::ID IID) {
case Intrinsic::umax:
case Intrinsic::umin:
case Intrinsic::scmp:
+ case Intrinsic::smulh:
+ case Intrinsic::umulh:
case Intrinsic::is_fpclass:
case Intrinsic::ptrmask:
case Intrinsic::ucmp:
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 7003d23262eee..8ccccded8a5f2 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -2895,6 +2895,18 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
return &CI;
break;
}
+
+ case Intrinsic::smulh: {
+ Value *Arg0 = II->getArgOperand(0);
+ Value *Arg1 = II->getArgOperand(1);
+ unsigned BitWidth = II->getType()->getScalarSizeInBits();
+
+ // Multiply by one.
+ if (match(Arg1, m_One()))
+ return replaceInstUsesWith(CI, Builder.CreateAShr(Arg0, BitWidth - 1));
+ break;
+ }
+
case Intrinsic::uadd_with_overflow:
case Intrinsic::sadd_with_overflow: {
if (Instruction *I = foldIntrinsicWithOverflowCommon(II))
diff --git a/llvm/test/Transforms/InstCombine/smulh.ll b/llvm/test/Transforms/InstCombine/smulh.ll
new file mode 100644
index 0000000000000..a04d9faa0ddd5
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/smulh.ll
@@ -0,0 +1,220 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+;
+; UNDEF Elts
+;
+
+define i32 @undef_smulh_i32(i32 %a0) {
+; CHECK-LABEL: @undef_smulh_i32(
+; CHECK-NEXT: ret i32 0
+;
+ %1 = call i32 @llvm.smulh.i32(i32 %a0, i32 undef)
+ ret i32 %1
+}
+
+define i32 @undef_smulh_i32_commute(i32 %a0) {
+; CHECK-LABEL: @undef_smulh_i32_commute(
+; CHECK-NEXT: ret i32 0
+;
+ %1 = call i32 @llvm.smulh.i32(i32 undef, i32 %a0)
+ ret i32 %1
+}
+
+define <8 x i16> @undef_smulh_v8i16(<8 x i16> %a0) {
+; CHECK-LABEL: @undef_smulh_v8i16(
+; CHECK-NEXT: ret <8 x i16> zeroinitializer
+;
+ %1 = call <8 x i16> @llvm.smulh.v8i16(<8 x i16> %a0, <8 x i16> undef)
+ ret <8 x i16> %1
+}
+
+define <32 x i8> @undef_smulh_v32i8_commute(<32 x i8> %a0) {
+; CHECK-LABEL: @undef_smulh_v32i8_commute(
+; CHECK-NEXT: ret <32 x i8> zeroinitializer
+;
+ %1 = call <32 x i8> @llvm.smulh.v32i8(<32 x i8> undef, <32 x i8> %a0)
+ ret <32 x i8> %1
+}
+
+;
+; POISON Elts
+;
+
+define i32 @poison_smulh_i32(i32 %a0) {
+; CHECK-LABEL: @poison_smulh_i32(
+; CHECK-NEXT: ret i32 poison
+;
+ %1 = call i32 @llvm.smulh.i32(i32 %a0, i32 poison)
+ ret i32 %1
+}
+
+define i32 @poison_smulh_i32_commute(i32 %a0) {
+; CHECK-LABEL: @poison_smulh_i32_commute(
+; CHECK-NEXT: ret i32 poison
+;
+ %1 = call i32 @llvm.smulh.i32(i32 poison, i32 %a0)
+ ret i32 %1
+}
+
+define <8 x i16> @poison_smulh_v8i16(<8 x i16> %a0) {
+; CHECK-LABEL: @poison_smulh_v8i16(
+; CHECK-NEXT: ret <8 x i16> poison
+;
+ %1 = call <8 x i16> @llvm.smulh.v8i16(<8 x i16> %a0, <8 x i16> poison)
+ ret <8 x i16> %1
+}
+
+define <32 x i8> @poison_smulh_v32i8_commute(<32 x i8> %a0) {
+; CHECK-LABEL: @poison_smulh_v32i8_commute(
+; CHECK-NEXT: ret <32 x i8> poison
+;
+ %1 = call <32 x i8> @llvm.smulh.v32i8(<32 x i8> poison, <32 x i8> %a0)
+ ret <32 x i8> %1
+}
+
+;
+; Zero Elts
+;
+
+define i32 @zero_smulh_i32(i32 %a0) {
+; CHECK-LABEL: @zero_smulh_i32(
+; CHECK-NEXT: ret i32 0
+;
+ %1 = call i32 @llvm.smulh.i32(i32 %a0, i32 zeroinitializer)
+ ret i32 %1
+}
+
+define i32 @zero_smulh_i32_commute(i32 %a0) {
+; CHECK-LABEL: @zero_smulh_i32_commute(
+; CHECK-NEXT: ret i32 0
+;
+ %1 = call i32 @llvm.smulh.i32(i32 zeroinitializer, i32 %a0)
+ ret i32 %1
+}
+
+define <2 x i32> @zero_smulh_v2i32(<2 x i32> %a0) {
+; CHECK-LABEL: @zero_smulh_v2i32(
+; CHECK-NEXT: ret <2 x i32> zeroinitializer
+;
+ %1 = call <2 x i32> @llvm.smulh.v2i32(<2 x i32> %a0, <2 x i32> zeroinitializer)
+ ret <2 x i32> %1
+}
+
+define <8 x i64> @zero_smulh_v8i64_commute(<8 x i64> %a0) {
+; CHECK-LABEL: @zero_smulh_v8i64_commute(
+; CHECK-NEXT: ret <8 x i64> zeroinitializer
+;
+ %1 = call <8 x i64> @llvm.smulh.v8i64(<8 x i64> zeroinitializer, <8 x i64> %a0)
+ ret <8 x i64> %1
+}
+
+;
+; Multiply by One
+;
+
+define i32 @one_smulh_i32(i32 %a0) {
+; CHECK-LABEL: @one_smulh_i32(
+; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[A0:%.*]], 31
+; CHECK-NEXT: ret i32 [[TMP1]]
+;
+ %1 = call i32 @llvm.smulh.i32(i32 %a0, i32 1)
+ ret i32 %1
+}
+
+define i32 @one_smulh_i32_commute(i32 %a0) {
+; CHECK-LABEL: @one_smulh_i32_commute(
+; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[A0:%.*]], 31
+; CHECK-NEXT: ret i32 [[TMP1]]
+;
+ %1 = call i32 @llvm.smulh.i32(i32 1, i32 %a0)
+ ret i32 %1
+}
+
+define <8 x i8> @one_smulh_v8i8(<8 x i8> %a0) {
+; CHECK-LABEL: @one_smulh_v8i8(
+; CHECK-NEXT: [[TMP1:%.*]] = ashr <8 x i8> [[A0:%.*]], splat (i8 7)
+; CHECK-NEXT: ret <8 x i8> [[TMP1]]
+;
+ %1 = call <8 x i8> @llvm.smulh.v8i8(<8 x i8> %a0, <8 x i8> splat (i8 1))
+ ret <8 x i8> %1
+}
+
+define <16 x i16> @one_smulh_v16i16_commute(<16 x i16> %a0) {
+; CHECK-LABEL: @one_smulh_v16i16_commute(
+; CHECK-NEXT: [[TMP1:%.*]] = ashr <16 x i16> [[A0:%.*]], splat (i16 15)
+; CHECK-NEXT: ret <16 x i16> [[TMP1]]
+;
+ %1 = call <16 x i16> @llvm.smulh.v16i16(<16 x i16> splat (i16 1), <16 x i16> %a0)
+ ret <16 x i16> %1
+}
+
+;
+; Constant Folding
+;
+
+define i32 @fold_smulh_i32() {
+; CHECK-LABEL: @fold_smulh_i32(
+; CHECK-NEXT: ret i32 -1
+;
+ %1 = call i32 @llvm.smulh.v8i16(i32 2, i32 -32768)
+ ret i32 %1
+}
+
+define <8 x i16> @fold_smulh_v8i16() {
+; CHECK-LABEL: @fold_smulh_v8i16(
+; CHECK-NEXT: ret <8 x i16> <i16 0, i16 0, i16 -2, i16 -2, i16 0, i16 -1, i16 -4, i16 -4>
+;
+ %1 = call <8 x i16> @llvm.smulh.v8i16(<8 x i16> <i16 -1, i16 2, i16 3, i16 -4, i16 -5, i16 6, i16 7, i16 -8>, <8 x i16> <i16 -5, i16 7, i16 -32768, i16 32765, i16 -9, i16 -11, i16 -32763, i16 32761>)
+ ret <8 x i16> %1
+}
+
+define <16 x i16> @fold_smulh_v16i16() {
+; CHECK-LABEL: @fold_smulh_v16i16(
+; CHECK-NEXT: ret <16 x i16> <i16 0, i16 -1, i16 -1, i16 1, i16 0, i16 0, i16 -3, i16 3, i16 -1, i16 -1, i16 4, i16 5, i16 -1, i16 -1, i16 6, i16 -8>
+;
+ %1 = call <16 x i16> @llvm.smulh.v16i16(<16 x i16> <i16 0, i16 -1, i16 2, i16 3, i16 -4, i16 -5, i16 6, i16 7, i16 -8, i16 9, i16 -10, i16 11, i16 -12, i16 13, i16 -14, i16 -15>, <16 x i16> <i16 -5, i16 7, i16 -32768, i16 32766, i16 -9, i16 -11, i16 -32764, i16 32762, i16 13, i16 -15, i16 -32760, i16 32758, i16 17, i16 -19, i16 -32756, i16 32756>)
+ ret <16 x i16> %1
+}
+
+define <32 x i16> @fold_smulh_v32i16() {
+; CHECK-LABEL: @fold_smulh_v32i16(
+; CHECK-NEXT: ret <32 x i16> <i16 0, i16 -1, i16 -1, i16 1, i16 0, i16 0, i16 -3, i16 3, i16 -1, i16 -1, i16 4, i16 5, i16 -1, i16 -1, i16 6, i16 -8, i16 0, i16 -1, i16 -1, i16 1, i16 0, i16 0, i16 -3, i16 3, i16 -1, i16 -1, i16 4, i16 5, i16 -1, i16 -1, i16 6, i16 -8>
+;
+ %1 = call <32 x i16> @llvm.smulh.v32i16(<32 x i16> <i16 0, i16 -1, i16 2, i16 3, i16 -4, i16 -5, i16 6, i16 7, i16 -8, i16 9, i16 -10, i16 11, i16 -12, i16 13, i16 -14, i16 -15, i16 -5, i16 7, i16 -32768, i16 32766, i16 -9, i16 -11, i16 -32764, i16 32762, i16 13, i16 -15, i16 -32760, i16 32758, i16 17, i16 -19, i16 -32756, i16 32756>, <32 x i16> <i16 -5, i16 7, i16 -32768, i16 32766, i16 -9, i16 -11, i16 -32764, i16 32762, i16 13, i16 -15, i16 -32760, i16 32758, i16 17, i16 -19, i16 -32756, i16 32756, i16 0, i16 -1, i16 2, i16 3, i16 -4, i16 -5, i16 6, i16 7, i16 -8, i16 9, i16 -10, i16 11, i16 -12, i16 13, i16 -14, i16 -15>)
+ ret <32 x i16> %1
+}
+
+;
+; Demanded Elts
+;
+
+define <8 x i64> @elts_smulh_v8i64(<8 x i64> %a0, <8 x i64> %a1) {
+; CHECK-LABEL: @elts_smulh_v8i64(
+; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <8 x i64> [[A0:%.*]], <8 x i64> poison, <8 x i32> <i32 0, i32 1, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2>
+; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <8 x i64> [[A1:%.*]], <8 x i64> poison, <8 x i32> <i32 0, i32 1, i32 3, i32 2, i32 5, i32 4, i32 7, i32 6>
+; CHECK-NEXT: [[TMP3:%.*]] = call <8 x i64> @llvm.smulh.v8i64(<8 x i64> [[TMP1]], <8 x i64> [[TMP2]])
+; CHECK-NEXT: [[TMP4:%.*]] = shufflevector <8 x i64> [[TMP3]], <8 x i64> poison, <8 x i32> zeroinitializer
+; CHECK-NEXT: ret <8 x i64> [[TMP4]]
+;
+ %1 = shufflevector <8 x i64> %a0, <8 x i64> undef, <8 x i32> <i32 0, i32 1, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2>
+ %2 = shufflevector <8 x i64> %a1, <8 x i64> undef, <8 x i32> <i32 0, i32 1, i32 3, i32 2, i32 5, i32 4, i32 7, i32 6>
+ %3 = call <8 x i64> @llvm.smulh.v8i64(<8 x i64> %1, <8 x i64> %2)
+ %4 = shufflevector <8 x i64> %3, <8 x i64> poison, <8 x i32> zeroinitializer
+ ret <8 x i64> %4
+}
+
+;
+; Known Bits
+;
+
+define <8 x i16> @known_smulh_v8i16(<8 x i16> %a0, <8 x i16> %a1, <8 x i16> %a2) {
+; CHECK-LABEL: @known_smulh_v8i16(
+; CHECK-NEXT: ret <8 x i16> [[A2:%.*]]
+;
+ %x0 = lshr <8 x i16> %a0, <i16 8, i16 9, i16 10, i16 11, i16 12, i16 13, i16 14, i16 15>
+ %x1 = and <8 x i16> %a1, <i16 3, i16 3, i16 3, i16 3, i16 3, i16 3, i16 3, i16 3>
+ %m = tail call <8 x i16> @llvm.smulh.v8i16(<8 x i16> %x0, <8 x i16> %x1)
+ %r = add <8 x i16> %m, %a2
+ ret <8 x i16> %r
+}
diff --git a/llvm/test/Transforms/InstCombine/umulh.ll b/llvm/test/Transforms/InstCombine/umulh.ll
new file mode 100644
index 0000000000000..f2e2c3f54df2e
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/umulh.ll
@@ -0,0 +1,216 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+;
+; UNDEF Elts
+;
+
+define i32 @undef_umulh_i32(i32 %a0) {
+; CHECK-LABEL: @undef_umulh_i32(
+; CHECK-NEXT: ret i32 0
+;
+ %1 = call i32 @llvm.umulh.i32(i32 %a0, i32 undef)
+ ret i32 %1
+}
+
+define i32 @undef_umulh_i32_commute(i32 %a0) {
+; CHECK-LABEL: @undef_umulh_i32_commute(
+; CHECK-NEXT: ret i32 0
+;
+ %1 = call i32 @llvm.umulh.i32(i32 undef, i32 %a0)
+ ret i32 %1
+}
+
+define <8 x i16> @undef_umulh_v8i16(<8 x i16> %a0) {
+; CHECK-LABEL: @undef_umulh_v8i16(
+; CHECK-NEXT: ret <8 x i16> zeroinitializer
+;
+ %1 = call <8 x i16> @llvm.umulh.v8i16(<8 x i16> %a0, <8 x i16> undef)
+ ret <8 x i16> %1
+}
+
+define <32 x i8> @undef_umulh_v32i8_commute(<32 x i8> %a0) {
+; CHECK-LABEL: @undef_umulh_v32i8_commute(
+; CHECK-NEXT: ret <32 x i8> zeroinitializer
+;
+ %1 = call <32 x i8> @llvm.umulh.v32i8(<32 x i8> undef, <32 x i8> %a0)
+ ret <32 x i8> %1
+}
+
+;
+; POISON Elts
+;
+
+define i32 @poison_umulh_i32(i32 %a0) {
+; CHECK-LABEL: @poison_umulh_i32(
+; CHECK-NEXT: ret i32 poison
+;
+ %1 = call i32 @llvm.umulh.i32(i32 %a0, i32 poison)
+ ret i32 %1
+}
+
+define i32 @poison_umulh_i32_commute(i32 %a0) {
+; CHECK-LABEL: @poison_umulh_i32_commute(
+; CHECK-NEXT: ret i32 poison
+;
+ %1 = call i32 @llvm.umulh.i32(i32 poison, i32 %a0)
+ ret i32 %1
+}
+
+define <8 x i16> @poison_umulh_v8i16(<8 x i16> %a0) {
+; CHECK-LABEL: @poison_umulh_v8i16(
+; CHECK-NEXT: ret <8 x i16> poison
+;
+ %1 = call <8 x i16> @llvm.umulh.v8i16(<8 x i16> %a0, <8 x i16> poison)
+ ret <8 x i16> %1
+}
+
+define <32 x i8> @poison_umulh_v32i8_commute(<32 x i8> %a0) {
+; CHECK-LABEL: @poison_umulh_v32i8_commute(
+; CHECK-NEXT: ret <32 x i8> poison
+;
+ %1 = call <32 x i8> @llvm.umulh.v32i8(<32 x i8> poison, <32 x i8> %a0)
+ ret <32 x i8> %1
+}
+
+;
+; Zero Elts
+;
+
+define i32 @zero_umulh_i32(i32 %a0) {
+; CHECK-LABEL: @zero_umulh_i32(
+; CHECK-NEXT: ret i32 0
+;
+ %1 = call i32 @llvm.umulh.i32(i32 %a0, i32 zeroinitializer)
+ ret i32 %1
+}
+
+define i32 @zero_umulh_i32_commute(i32 %a0) {
+; CHECK-LABEL: @zero_umulh_i32_commute(
+; CHECK-NEXT: ret i32 0
+;
+ %1 = call i32 @llvm.umulh.i32(i32 zeroinitializer, i32 %a0)
+ ret i32 %1
+}
+
+define <2 x i32> @zero_umulh_v2i32(<2 x i32> %a0) {
+; CHECK-LABEL: @zero_umulh_v2i32(
+; CHECK-NEXT: ret <2 x i32> zeroinitializer
+;
+ %1 = call <2 x i32> @llvm.umulh.v2i32(<2 x i32> %a0, <2 x i32> zeroinitializer)
+ ret <2 x i32> %1
+}
+
+define <8 x i64> @zero_umulh_v8i64_commute(<8 x i64> %a0) {
+; CHECK-LABEL: @zero_umulh_v8i64_commute(
+; CHECK-NEXT: ret <8 x i64> zeroinitializer
+;
+ %1 = call <8 x i64> @llvm.umulh.v8i64(<8 x i64> zeroinitializer, <8 x i64> %a0)
+ ret <8 x i64> %1
+}
+
+;
+; Multiply by One
+;
+
+define i32 @one_umulh_i32(i32 %a0) {
+; CHECK-LABEL: @one_umulh_i32(
+; CHECK-NEXT: ret i32 0
+;
+ %1 = call i32 @llvm.umulh.i32(i32 %a0, i32 1)
+ ret i32 %1
+}
+
+define i32 @one_umulh_i32_commute(i32 %a0) {
+; CHECK-LABEL: @one_umulh_i32_commute(
+; CHECK-NEXT: ret i32 0
+;
+ %1 = call i32 @llvm.umulh.i32(i32 1, i32 %a0)
+ ret i32 %1
+}
+
+define <8 x i8> @one_umulh_v8i8(<8 x i8> %a0) {
+; CHECK-LABEL: @one_umulh_v8i8(
+; CHECK-NEXT: ret <8 x i8> zeroinitializer
+;
+ %1 = call <8 x i8> @llvm.umulh.v8i8(<8 x i8> %a0, <8 x i8> splat (i8 1))
+ ret <8 x i8> %1
+}
+
+define <16 x i16> @one_umulh_v16i16_commute(<16 x i16> %a0) {
+; CHECK-LABEL: @one_umulh_v16i16_commute(
+; CHECK-NEXT: ret <16 x i16> zeroinitializer
+;
+ %1 = call <16 x i16> @llvm.umulh.v16i16(<16 x i16> splat (i16 1), <16 x i16> %a0)
+ ret <16 x i16> %1
+}
+
+;
+; Constant Folding
+;
+
+define i32 @fold_umulh_i32() {
+; CHECK-LABEL: @fold_umulh_i32(
+; CHECK-NEXT: ret i32 1
+;
+ %1 = call i32 @llvm.umulh.v8i16(i32 2, i32 -32768)
+ ret i32 %1
+}
+
+define <8 x i16> @fold_umulh_v8i16() {
+; CHECK-LABEL: @fold_umulh_v8i16(
+; CHECK-NEXT: ret <8 x i16> <i16 -6, i16 0, i16 1, i16 32763, i16 -14, i16 5, i16 3, i16 32757>
+;
+ %1 = call <8 x i16> @llvm.umulh.v8i16(<8 x i16> <i16 -1, i16 2, i16 3, i16 -4, i16 -5, i16 6, i16 7, i16 -8>, <8 x i16> <i16 -5, i16 7, i16 -32768, i16 32765, i16 -9, i16 -11, i16 -32763, i16 32761>)
+ ret <8 x i16> %1
+}
+
+define <16 x i16> @fold_umulh_v16i16() {
+; CHECK-LABEL: @fold_umulh_v16i16(
+; CHECK-NEXT: ret <16 x i16> <i16 0, i16 6, i16 1, i16 1, i16 -13, i16 -16, i16 3, i16 3, i16 12, i16 8, i16 -32766, i16 5, i16 16, i16 12, i16 -32764, i16 32748>
+;
+ %1 = call <16 x i16> @llvm.umulh.v16i16(<16 x i16> <i16 0, i16 -1, i16 2, i16 3, i16 -4, i16 -5, i16 6, i16 7, i16 -8, i16 9, i16 -10, i16 11, i16 -12, i16 13, i16 -14, i16 -15>, <16 x i16> <i16 -5, i16 7, i16 -32768, i16 32766, i16 -9, i16 -11, i16 -32764, i16 32762, i16 13, i16 -15, i16 -32760, i16 32758, i16 17, i16 -19, i16 -32756, i16 32756>)
+ ret <16 x i16> %1
+}
+
+define <32 x i16> @fold_umulh_v32i16() {
+; CHECK-LABEL: @fold_umulh_v32i16(
+; CHECK-NEXT: ret <32 x i16> <i16 0, i16 6, i16 1, i16 1, i16 -13, i16 -16, i16 3, i16 3, i16 12, i16 8, i16 -32766, i16 5, i16 16, i16 12, i16 -32764, i16 32748, i16 0, i16 6, i16 1, i16 1, i16 -13, i16 -16, i16 3, i16 3, i16 12, i16 8, i16 -32766, i16 5, i16 16, i16 12, i16 -32764, i16 32748>
+;
+ %1 = call <32 x i16> @llvm.umulh.v32i16(<32 x i16> <i16 0, i16 -1, i16 2, i16 3, i16 -4, i16 -5, i16 6, i16 7, i16 -8, i16 9, i16 -10, i16 11, i16 -12, i16 13, i16 -14, i16 -15, i16 -5, i16 7, i16 -32768, i16 32766, i16 -9, i16 -11, i16 -32764, i16 32762, i16 13, i16 -15, i16 -32760, i16 32758, i16 17, i16 -19, i16 -32756, i16 32756>, <32 x i16> <i16 -5, i16 7, i16 -32768, i16 32766, i16 -9, i16 -11, i16 -32764, i16 32762, i16 13, i16 -15, i16 -32760, i16 32758, i16 17, i16 -19, i16 -32756, i16 32756, i16 0, i16 -1, i16 2, i16 3, i16 -4, i16 -5, i16 6, i16 7, i16 -8, i16 9, i16 -10, i16 11, i16 -12, i16 13, i16 -14, i16 -15>)
+ ret <32 x i16> %1
+}
+
+;
+; Demanded Elts
+;
+
+define <8 x i64> @elts_umulh_v8i64(<8 x i64> %a0, <8 x i64> %a1) {
+; CHECK-LABEL: @elts_umulh_v8i64(
+; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <8 x i64> [[A0:%.*]], <8 x i64> poison, <8 x i32> <i32 0, i32 1, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2>
+; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <8 x i64> [[A1:%.*]], <8 x i64> poison, <8 x i32> <i32 0, i32 1, i32 3, i32 2, i32 5, i32 4, i32 7, i32 6>
+; CHECK-NEXT: [[TMP3:%.*]] = call <8 x i64> @llvm.umulh.v8i64(<8 x i64> [[TMP1]], <8 x i64> [[TMP2]])
+; CHECK-NEXT: [[TMP4:%.*]] = shufflevector <8 x i64> [[TMP3]], <8 x i64> poison, <8 x i32> zeroinitializer
+; CHECK-NEXT: ret <8 x i64> [[TMP4]]
+;
+ %1 = shufflevector <8 x i64> %a0, <8 x i64> undef, <8 x i32> <i32 0, i32 1, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2>
+ %2 = shufflevector <8 x i64> %a1, <8 x i64> undef, <8 x i32> <i32 0, i32 1, i32 3, i32 2, i32 5, i32 4, i32 7, i32 6>
+ %3 = call <8 x i64> @llvm.umulh.v8i64(<8 x i64> %1, <8 x i64> %2)
+ %4 = shufflevector <8 x i64> %3, <8 x i64> poison, <8 x i32> zeroinitializer
+ ret <8 x i64> %4
+}
+
+;
+; Known Bits
+;
+
+define <8 x i16> @known_umulh_v8i16(<8 x i16> %a0, <8 x i16> %a1, <8 x i16> %a2) {
+; CHECK-LABEL: @known_umulh_v8i16(
+; CHECK-NEXT: ret <8 x i16> [[A2:%.*]]
+;
+ %x0 = lshr <8 x i16> %a0, <i16 8, i16 9, i16 10, i16 11, i16 12, i16 13, i16 14, i16 15>
+ %x1 = and <8 x i16> %a1, <i16 3, i16 3, i16 3, i16 3, i16 3, i16 3, i16 3, i16 3>
+ %m = tail call <8 x i16> @llvm.umulh.v8i16(<8 x i16> %x0, <8 x i16> %x1)
+ %r = add <8 x i16> %m, %a2
+ ret <8 x i16> %r
+}
More information about the llvm-commits
mailing list