[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