[llvm] [SLP][NFC]Add tests with missing aggregate bitpacks support, NFC (PR #228947)

Alexey Bataev via llvm-commits llvm-commits at lists.llvm.org
Sun Oct 4 15:44:47 PDT 2026


https://github.com/alexey-bataev created https://github.com/llvm/llvm-project/pull/228947

None

>From f1e80ed300e714e160e2c2ee92f4e1c4d9b020f3 Mon Sep 17 00:00:00 2001
From: Alexey Bataev <a.bataev at outlook.com>
Date: Sun, 4 Oct 2026 15:44:35 -0700
Subject: [PATCH] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20initia?=
 =?UTF-8?q?l=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.7
---
 .../AArch64/bitpacked-aggregate.ll            | 233 +++++
 .../SLPVectorizer/X86/bitpacked-aggregate.ll  | 818 ++++++++++++++++++
 2 files changed, 1051 insertions(+)
 create mode 100644 llvm/test/Transforms/SLPVectorizer/AArch64/bitpacked-aggregate.ll
 create mode 100644 llvm/test/Transforms/SLPVectorizer/X86/bitpacked-aggregate.ll

diff --git a/llvm/test/Transforms/SLPVectorizer/AArch64/bitpacked-aggregate.ll b/llvm/test/Transforms/SLPVectorizer/AArch64/bitpacked-aggregate.ll
new file mode 100644
index 0000000000000..ceddd89057dc2
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/AArch64/bitpacked-aggregate.ll
@@ -0,0 +1,233 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=slp-vectorizer -S -mtriple=aarch64-linux-gnu | FileCheck %s
+
+; The packs of the aggregate are vectorized together as the single vector of the fields.
+
+define { i64, i64 } @pack_i16x8(ptr %x, ptr %y) {
+; CHECK-LABEL: @pack_i16x8(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[X_4_P:%.*]] = getelementptr inbounds i16, ptr [[X:%.*]], i64 4
+; CHECK-NEXT:    [[Y_4_P:%.*]] = getelementptr inbounds i16, ptr [[Y:%.*]], i64 4
+; CHECK-NEXT:    [[TMP0:%.*]] = load <4 x i16>, ptr [[X]], align 2
+; CHECK-NEXT:    [[TMP1:%.*]] = load <4 x i16>, ptr [[Y]], align 2
+; CHECK-NEXT:    [[TMP2:%.*]] = call <4 x i16> @llvm.smin.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
+; CHECK-NEXT:    [[TMP4:%.*]] = bitcast <4 x i16> [[TMP2]] to i64
+; CHECK-NEXT:    [[AGG_0:%.*]] = insertvalue { i64, i64 } poison, i64 [[TMP4]], 0
+; CHECK-NEXT:    [[TMP7:%.*]] = load <4 x i16>, ptr [[X_4_P]], align 2
+; CHECK-NEXT:    [[TMP8:%.*]] = load <4 x i16>, ptr [[Y_4_P]], align 2
+; CHECK-NEXT:    [[TMP6:%.*]] = call <4 x i16> @llvm.smin.v4i16(<4 x i16> [[TMP7]], <4 x i16> [[TMP8]])
+; CHECK-NEXT:    [[TMP5:%.*]] = bitcast <4 x i16> [[TMP6]] to i64
+; CHECK-NEXT:    [[AGG_1:%.*]] = insertvalue { i64, i64 } [[AGG_0]], i64 [[TMP5]], 1
+; CHECK-NEXT:    ret { i64, i64 } [[AGG_1]]
+;
+entry:
+  %x.0 = load i16, ptr %x, align 2
+  %y.0 = load i16, ptr %y, align 2
+  %m.0 = call i16 @llvm.smin.i16(i16 %x.0, i16 %y.0)
+  %x.1.p = getelementptr inbounds i16, ptr %x, i64 1
+  %y.1.p = getelementptr inbounds i16, ptr %y, i64 1
+  %x.1 = load i16, ptr %x.1.p, align 2
+  %y.1 = load i16, ptr %y.1.p, align 2
+  %m.1 = call i16 @llvm.smin.i16(i16 %x.1, i16 %y.1)
+  %x.2.p = getelementptr inbounds i16, ptr %x, i64 2
+  %y.2.p = getelementptr inbounds i16, ptr %y, i64 2
+  %x.2 = load i16, ptr %x.2.p, align 2
+  %y.2 = load i16, ptr %y.2.p, align 2
+  %m.2 = call i16 @llvm.smin.i16(i16 %x.2, i16 %y.2)
+  %x.3.p = getelementptr inbounds i16, ptr %x, i64 3
+  %y.3.p = getelementptr inbounds i16, ptr %y, i64 3
+  %x.3 = load i16, ptr %x.3.p, align 2
+  %y.3 = load i16, ptr %y.3.p, align 2
+  %m.3 = call i16 @llvm.smin.i16(i16 %x.3, i16 %y.3)
+  %x.4.p = getelementptr inbounds i16, ptr %x, i64 4
+  %y.4.p = getelementptr inbounds i16, ptr %y, i64 4
+  %x.4 = load i16, ptr %x.4.p, align 2
+  %y.4 = load i16, ptr %y.4.p, align 2
+  %m.4 = call i16 @llvm.smin.i16(i16 %x.4, i16 %y.4)
+  %x.5.p = getelementptr inbounds i16, ptr %x, i64 5
+  %y.5.p = getelementptr inbounds i16, ptr %y, i64 5
+  %x.5 = load i16, ptr %x.5.p, align 2
+  %y.5 = load i16, ptr %y.5.p, align 2
+  %m.5 = call i16 @llvm.smin.i16(i16 %x.5, i16 %y.5)
+  %x.6.p = getelementptr inbounds i16, ptr %x, i64 6
+  %y.6.p = getelementptr inbounds i16, ptr %y, i64 6
+  %x.6 = load i16, ptr %x.6.p, align 2
+  %y.6 = load i16, ptr %y.6.p, align 2
+  %m.6 = call i16 @llvm.smin.i16(i16 %x.6, i16 %y.6)
+  %x.7.p = getelementptr inbounds i16, ptr %x, i64 7
+  %y.7.p = getelementptr inbounds i16, ptr %y, i64 7
+  %x.7 = load i16, ptr %x.7.p, align 2
+  %y.7 = load i16, ptr %y.7.p, align 2
+  %m.7 = call i16 @llvm.smin.i16(i16 %x.7, i16 %y.7)
+  %z.0 = zext i16 %m.0 to i64
+  %z.1 = zext i16 %m.1 to i64
+  %s.1 = shl nuw nsw i64 %z.1, 16
+  %z.2 = zext i16 %m.2 to i64
+  %s.2 = shl nuw nsw i64 %z.2, 32
+  %z.3 = zext i16 %m.3 to i64
+  %s.3 = shl nuw i64 %z.3, 48
+  %o.2 = or disjoint i64 %s.3, %s.2
+  %o.1 = or disjoint i64 %o.2, %s.1
+  %w.0 = or disjoint i64 %o.1, %z.0
+  %agg.0 = insertvalue { i64, i64 } poison, i64 %w.0, 0
+  %z.4 = zext i16 %m.4 to i64
+  %z.5 = zext i16 %m.5 to i64
+  %s.5 = shl nuw nsw i64 %z.5, 16
+  %z.6 = zext i16 %m.6 to i64
+  %s.6 = shl nuw nsw i64 %z.6, 32
+  %z.7 = zext i16 %m.7 to i64
+  %s.7 = shl nuw i64 %z.7, 48
+  %o.6 = or disjoint i64 %s.7, %s.6
+  %o.5 = or disjoint i64 %o.6, %s.5
+  %w.1 = or disjoint i64 %o.5, %z.4
+  %agg.1 = insertvalue { i64, i64 } %agg.0, i64 %w.1, 1
+  ret { i64, i64 } %agg.1
+}
+
+define { i64, i64 } @pack_i8x16(ptr %x, ptr %y) {
+; CHECK-LABEL: @pack_i8x16(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[X_8_P:%.*]] = getelementptr inbounds i8, ptr [[X:%.*]], i64 8
+; CHECK-NEXT:    [[Y_8_P:%.*]] = getelementptr inbounds i8, ptr [[Y:%.*]], i64 8
+; CHECK-NEXT:    [[TMP0:%.*]] = load <8 x i8>, ptr [[X]], align 1
+; CHECK-NEXT:    [[TMP1:%.*]] = load <8 x i8>, ptr [[Y]], align 1
+; CHECK-NEXT:    [[TMP2:%.*]] = call <8 x i8> @llvm.smin.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]])
+; CHECK-NEXT:    [[TMP4:%.*]] = bitcast <8 x i8> [[TMP2]] to i64
+; CHECK-NEXT:    [[AGG_0:%.*]] = insertvalue { i64, i64 } poison, i64 [[TMP4]], 0
+; CHECK-NEXT:    [[TMP7:%.*]] = load <8 x i8>, ptr [[X_8_P]], align 1
+; CHECK-NEXT:    [[TMP8:%.*]] = load <8 x i8>, ptr [[Y_8_P]], align 1
+; CHECK-NEXT:    [[TMP6:%.*]] = call <8 x i8> @llvm.smin.v8i8(<8 x i8> [[TMP7]], <8 x i8> [[TMP8]])
+; CHECK-NEXT:    [[TMP5:%.*]] = bitcast <8 x i8> [[TMP6]] to i64
+; CHECK-NEXT:    [[AGG_1:%.*]] = insertvalue { i64, i64 } [[AGG_0]], i64 [[TMP5]], 1
+; CHECK-NEXT:    ret { i64, i64 } [[AGG_1]]
+;
+entry:
+  %x.0 = load i8, ptr %x, align 1
+  %y.0 = load i8, ptr %y, align 1
+  %m.0 = call i8 @llvm.smin.i8(i8 %x.0, i8 %y.0)
+  %x.1.p = getelementptr inbounds i8, ptr %x, i64 1
+  %y.1.p = getelementptr inbounds i8, ptr %y, i64 1
+  %x.1 = load i8, ptr %x.1.p, align 1
+  %y.1 = load i8, ptr %y.1.p, align 1
+  %m.1 = call i8 @llvm.smin.i8(i8 %x.1, i8 %y.1)
+  %x.2.p = getelementptr inbounds i8, ptr %x, i64 2
+  %y.2.p = getelementptr inbounds i8, ptr %y, i64 2
+  %x.2 = load i8, ptr %x.2.p, align 1
+  %y.2 = load i8, ptr %y.2.p, align 1
+  %m.2 = call i8 @llvm.smin.i8(i8 %x.2, i8 %y.2)
+  %x.3.p = getelementptr inbounds i8, ptr %x, i64 3
+  %y.3.p = getelementptr inbounds i8, ptr %y, i64 3
+  %x.3 = load i8, ptr %x.3.p, align 1
+  %y.3 = load i8, ptr %y.3.p, align 1
+  %m.3 = call i8 @llvm.smin.i8(i8 %x.3, i8 %y.3)
+  %x.4.p = getelementptr inbounds i8, ptr %x, i64 4
+  %y.4.p = getelementptr inbounds i8, ptr %y, i64 4
+  %x.4 = load i8, ptr %x.4.p, align 1
+  %y.4 = load i8, ptr %y.4.p, align 1
+  %m.4 = call i8 @llvm.smin.i8(i8 %x.4, i8 %y.4)
+  %x.5.p = getelementptr inbounds i8, ptr %x, i64 5
+  %y.5.p = getelementptr inbounds i8, ptr %y, i64 5
+  %x.5 = load i8, ptr %x.5.p, align 1
+  %y.5 = load i8, ptr %y.5.p, align 1
+  %m.5 = call i8 @llvm.smin.i8(i8 %x.5, i8 %y.5)
+  %x.6.p = getelementptr inbounds i8, ptr %x, i64 6
+  %y.6.p = getelementptr inbounds i8, ptr %y, i64 6
+  %x.6 = load i8, ptr %x.6.p, align 1
+  %y.6 = load i8, ptr %y.6.p, align 1
+  %m.6 = call i8 @llvm.smin.i8(i8 %x.6, i8 %y.6)
+  %x.7.p = getelementptr inbounds i8, ptr %x, i64 7
+  %y.7.p = getelementptr inbounds i8, ptr %y, i64 7
+  %x.7 = load i8, ptr %x.7.p, align 1
+  %y.7 = load i8, ptr %y.7.p, align 1
+  %m.7 = call i8 @llvm.smin.i8(i8 %x.7, i8 %y.7)
+  %x.8.p = getelementptr inbounds i8, ptr %x, i64 8
+  %y.8.p = getelementptr inbounds i8, ptr %y, i64 8
+  %x.8 = load i8, ptr %x.8.p, align 1
+  %y.8 = load i8, ptr %y.8.p, align 1
+  %m.8 = call i8 @llvm.smin.i8(i8 %x.8, i8 %y.8)
+  %x.9.p = getelementptr inbounds i8, ptr %x, i64 9
+  %y.9.p = getelementptr inbounds i8, ptr %y, i64 9
+  %x.9 = load i8, ptr %x.9.p, align 1
+  %y.9 = load i8, ptr %y.9.p, align 1
+  %m.9 = call i8 @llvm.smin.i8(i8 %x.9, i8 %y.9)
+  %x.10.p = getelementptr inbounds i8, ptr %x, i64 10
+  %y.10.p = getelementptr inbounds i8, ptr %y, i64 10
+  %x.10 = load i8, ptr %x.10.p, align 1
+  %y.10 = load i8, ptr %y.10.p, align 1
+  %m.10 = call i8 @llvm.smin.i8(i8 %x.10, i8 %y.10)
+  %x.11.p = getelementptr inbounds i8, ptr %x, i64 11
+  %y.11.p = getelementptr inbounds i8, ptr %y, i64 11
+  %x.11 = load i8, ptr %x.11.p, align 1
+  %y.11 = load i8, ptr %y.11.p, align 1
+  %m.11 = call i8 @llvm.smin.i8(i8 %x.11, i8 %y.11)
+  %x.12.p = getelementptr inbounds i8, ptr %x, i64 12
+  %y.12.p = getelementptr inbounds i8, ptr %y, i64 12
+  %x.12 = load i8, ptr %x.12.p, align 1
+  %y.12 = load i8, ptr %y.12.p, align 1
+  %m.12 = call i8 @llvm.smin.i8(i8 %x.12, i8 %y.12)
+  %x.13.p = getelementptr inbounds i8, ptr %x, i64 13
+  %y.13.p = getelementptr inbounds i8, ptr %y, i64 13
+  %x.13 = load i8, ptr %x.13.p, align 1
+  %y.13 = load i8, ptr %y.13.p, align 1
+  %m.13 = call i8 @llvm.smin.i8(i8 %x.13, i8 %y.13)
+  %x.14.p = getelementptr inbounds i8, ptr %x, i64 14
+  %y.14.p = getelementptr inbounds i8, ptr %y, i64 14
+  %x.14 = load i8, ptr %x.14.p, align 1
+  %y.14 = load i8, ptr %y.14.p, align 1
+  %m.14 = call i8 @llvm.smin.i8(i8 %x.14, i8 %y.14)
+  %x.15.p = getelementptr inbounds i8, ptr %x, i64 15
+  %y.15.p = getelementptr inbounds i8, ptr %y, i64 15
+  %x.15 = load i8, ptr %x.15.p, align 1
+  %y.15 = load i8, ptr %y.15.p, align 1
+  %m.15 = call i8 @llvm.smin.i8(i8 %x.15, i8 %y.15)
+  %z.0 = zext i8 %m.0 to i64
+  %z.1 = zext i8 %m.1 to i64
+  %s.1 = shl nuw nsw i64 %z.1, 8
+  %z.2 = zext i8 %m.2 to i64
+  %s.2 = shl nuw nsw i64 %z.2, 16
+  %z.3 = zext i8 %m.3 to i64
+  %s.3 = shl nuw nsw i64 %z.3, 24
+  %z.4 = zext i8 %m.4 to i64
+  %s.4 = shl nuw nsw i64 %z.4, 32
+  %z.5 = zext i8 %m.5 to i64
+  %s.5 = shl nuw nsw i64 %z.5, 40
+  %z.6 = zext i8 %m.6 to i64
+  %s.6 = shl nuw nsw i64 %z.6, 48
+  %z.7 = zext i8 %m.7 to i64
+  %s.7 = shl nuw i64 %z.7, 56
+  %o.6 = or disjoint i64 %s.7, %s.6
+  %o.5 = or disjoint i64 %o.6, %s.5
+  %o.4 = or disjoint i64 %o.5, %s.4
+  %o.3 = or disjoint i64 %o.4, %s.3
+  %o.2 = or disjoint i64 %o.3, %s.2
+  %o.1 = or disjoint i64 %o.2, %s.1
+  %w.0 = or disjoint i64 %o.1, %z.0
+  %agg.0 = insertvalue { i64, i64 } poison, i64 %w.0, 0
+  %z.8 = zext i8 %m.8 to i64
+  %z.9 = zext i8 %m.9 to i64
+  %s.9 = shl nuw nsw i64 %z.9, 8
+  %z.10 = zext i8 %m.10 to i64
+  %s.10 = shl nuw nsw i64 %z.10, 16
+  %z.11 = zext i8 %m.11 to i64
+  %s.11 = shl nuw nsw i64 %z.11, 24
+  %z.12 = zext i8 %m.12 to i64
+  %s.12 = shl nuw nsw i64 %z.12, 32
+  %z.13 = zext i8 %m.13 to i64
+  %s.13 = shl nuw nsw i64 %z.13, 40
+  %z.14 = zext i8 %m.14 to i64
+  %s.14 = shl nuw nsw i64 %z.14, 48
+  %z.15 = zext i8 %m.15 to i64
+  %s.15 = shl nuw i64 %z.15, 56
+  %o.14 = or disjoint i64 %s.15, %s.14
+  %o.13 = or disjoint i64 %o.14, %s.13
+  %o.12 = or disjoint i64 %o.13, %s.12
+  %o.11 = or disjoint i64 %o.12, %s.11
+  %o.10 = or disjoint i64 %o.11, %s.10
+  %o.9 = or disjoint i64 %o.10, %s.9
+  %w.1 = or disjoint i64 %o.9, %z.8
+  %agg.1 = insertvalue { i64, i64 } %agg.0, i64 %w.1, 1
+  ret { i64, i64 } %agg.1
+}
+
+declare i16 @llvm.smin.i16(i16, i16)
+declare i8 @llvm.smin.i8(i8, i8)
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/bitpacked-aggregate.ll b/llvm/test/Transforms/SLPVectorizer/X86/bitpacked-aggregate.ll
new file mode 100644
index 0000000000000..9eb2b060e3781
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/X86/bitpacked-aggregate.ll
@@ -0,0 +1,818 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -mtriple=x86_64-unknown -passes=slp-vectorizer -mcpu=x86-64-v2 -S | FileCheck %s
+
+; The packs of the aggregate are vectorized together as the single vector of the fields.
+
+define { i64, i64 } @pack_i16x8(ptr %x, ptr %y) {
+; CHECK-LABEL: @pack_i16x8(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[X_4_P:%.*]] = getelementptr inbounds i16, ptr [[X:%.*]], i64 4
+; CHECK-NEXT:    [[Y_4_P:%.*]] = getelementptr inbounds i16, ptr [[Y:%.*]], i64 4
+; CHECK-NEXT:    [[TMP0:%.*]] = load <4 x i16>, ptr [[X]], align 2
+; CHECK-NEXT:    [[TMP1:%.*]] = load <4 x i16>, ptr [[Y]], align 2
+; CHECK-NEXT:    [[TMP2:%.*]] = call <4 x i16> @llvm.smin.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
+; CHECK-NEXT:    [[TMP4:%.*]] = bitcast <4 x i16> [[TMP2]] to i64
+; CHECK-NEXT:    [[AGG_0:%.*]] = insertvalue { i64, i64 } poison, i64 [[TMP4]], 0
+; CHECK-NEXT:    [[TMP7:%.*]] = load <4 x i16>, ptr [[X_4_P]], align 2
+; CHECK-NEXT:    [[TMP8:%.*]] = load <4 x i16>, ptr [[Y_4_P]], align 2
+; CHECK-NEXT:    [[TMP6:%.*]] = call <4 x i16> @llvm.smin.v4i16(<4 x i16> [[TMP7]], <4 x i16> [[TMP8]])
+; CHECK-NEXT:    [[TMP5:%.*]] = bitcast <4 x i16> [[TMP6]] to i64
+; CHECK-NEXT:    [[AGG_1:%.*]] = insertvalue { i64, i64 } [[AGG_0]], i64 [[TMP5]], 1
+; CHECK-NEXT:    ret { i64, i64 } [[AGG_1]]
+;
+entry:
+  %x.0 = load i16, ptr %x, align 2
+  %y.0 = load i16, ptr %y, align 2
+  %m.0 = call i16 @llvm.smin.i16(i16 %x.0, i16 %y.0)
+  %x.1.p = getelementptr inbounds i16, ptr %x, i64 1
+  %y.1.p = getelementptr inbounds i16, ptr %y, i64 1
+  %x.1 = load i16, ptr %x.1.p, align 2
+  %y.1 = load i16, ptr %y.1.p, align 2
+  %m.1 = call i16 @llvm.smin.i16(i16 %x.1, i16 %y.1)
+  %x.2.p = getelementptr inbounds i16, ptr %x, i64 2
+  %y.2.p = getelementptr inbounds i16, ptr %y, i64 2
+  %x.2 = load i16, ptr %x.2.p, align 2
+  %y.2 = load i16, ptr %y.2.p, align 2
+  %m.2 = call i16 @llvm.smin.i16(i16 %x.2, i16 %y.2)
+  %x.3.p = getelementptr inbounds i16, ptr %x, i64 3
+  %y.3.p = getelementptr inbounds i16, ptr %y, i64 3
+  %x.3 = load i16, ptr %x.3.p, align 2
+  %y.3 = load i16, ptr %y.3.p, align 2
+  %m.3 = call i16 @llvm.smin.i16(i16 %x.3, i16 %y.3)
+  %x.4.p = getelementptr inbounds i16, ptr %x, i64 4
+  %y.4.p = getelementptr inbounds i16, ptr %y, i64 4
+  %x.4 = load i16, ptr %x.4.p, align 2
+  %y.4 = load i16, ptr %y.4.p, align 2
+  %m.4 = call i16 @llvm.smin.i16(i16 %x.4, i16 %y.4)
+  %x.5.p = getelementptr inbounds i16, ptr %x, i64 5
+  %y.5.p = getelementptr inbounds i16, ptr %y, i64 5
+  %x.5 = load i16, ptr %x.5.p, align 2
+  %y.5 = load i16, ptr %y.5.p, align 2
+  %m.5 = call i16 @llvm.smin.i16(i16 %x.5, i16 %y.5)
+  %x.6.p = getelementptr inbounds i16, ptr %x, i64 6
+  %y.6.p = getelementptr inbounds i16, ptr %y, i64 6
+  %x.6 = load i16, ptr %x.6.p, align 2
+  %y.6 = load i16, ptr %y.6.p, align 2
+  %m.6 = call i16 @llvm.smin.i16(i16 %x.6, i16 %y.6)
+  %x.7.p = getelementptr inbounds i16, ptr %x, i64 7
+  %y.7.p = getelementptr inbounds i16, ptr %y, i64 7
+  %x.7 = load i16, ptr %x.7.p, align 2
+  %y.7 = load i16, ptr %y.7.p, align 2
+  %m.7 = call i16 @llvm.smin.i16(i16 %x.7, i16 %y.7)
+  %z.0 = zext i16 %m.0 to i64
+  %z.1 = zext i16 %m.1 to i64
+  %s.1 = shl nuw nsw i64 %z.1, 16
+  %z.2 = zext i16 %m.2 to i64
+  %s.2 = shl nuw nsw i64 %z.2, 32
+  %z.3 = zext i16 %m.3 to i64
+  %s.3 = shl nuw i64 %z.3, 48
+  %o.2 = or disjoint i64 %s.3, %s.2
+  %o.1 = or disjoint i64 %o.2, %s.1
+  %w.0 = or disjoint i64 %o.1, %z.0
+  %agg.0 = insertvalue { i64, i64 } poison, i64 %w.0, 0
+  %z.4 = zext i16 %m.4 to i64
+  %z.5 = zext i16 %m.5 to i64
+  %s.5 = shl nuw nsw i64 %z.5, 16
+  %z.6 = zext i16 %m.6 to i64
+  %s.6 = shl nuw nsw i64 %z.6, 32
+  %z.7 = zext i16 %m.7 to i64
+  %s.7 = shl nuw i64 %z.7, 48
+  %o.6 = or disjoint i64 %s.7, %s.6
+  %o.5 = or disjoint i64 %o.6, %s.5
+  %w.1 = or disjoint i64 %o.5, %z.4
+  %agg.1 = insertvalue { i64, i64 } %agg.0, i64 %w.1, 1
+  ret { i64, i64 } %agg.1
+}
+
+define { i64, i64 } @pack_i8x16(ptr %x, ptr %y) {
+; CHECK-LABEL: @pack_i8x16(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[X_8_P:%.*]] = getelementptr inbounds i8, ptr [[X:%.*]], i64 8
+; CHECK-NEXT:    [[Y_8_P:%.*]] = getelementptr inbounds i8, ptr [[Y:%.*]], i64 8
+; CHECK-NEXT:    [[TMP0:%.*]] = load <8 x i8>, ptr [[X]], align 1
+; CHECK-NEXT:    [[TMP1:%.*]] = load <8 x i8>, ptr [[Y]], align 1
+; CHECK-NEXT:    [[TMP2:%.*]] = call <8 x i8> @llvm.umin.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]])
+; CHECK-NEXT:    [[TMP4:%.*]] = bitcast <8 x i8> [[TMP2]] to i64
+; CHECK-NEXT:    [[AGG_0:%.*]] = insertvalue { i64, i64 } poison, i64 [[TMP4]], 0
+; CHECK-NEXT:    [[TMP7:%.*]] = load <8 x i8>, ptr [[X_8_P]], align 1
+; CHECK-NEXT:    [[TMP8:%.*]] = load <8 x i8>, ptr [[Y_8_P]], align 1
+; CHECK-NEXT:    [[TMP6:%.*]] = call <8 x i8> @llvm.umin.v8i8(<8 x i8> [[TMP7]], <8 x i8> [[TMP8]])
+; CHECK-NEXT:    [[TMP5:%.*]] = bitcast <8 x i8> [[TMP6]] to i64
+; CHECK-NEXT:    [[AGG_1:%.*]] = insertvalue { i64, i64 } [[AGG_0]], i64 [[TMP5]], 1
+; CHECK-NEXT:    ret { i64, i64 } [[AGG_1]]
+;
+entry:
+  %x.0 = load i8, ptr %x, align 1
+  %y.0 = load i8, ptr %y, align 1
+  %m.0 = call i8 @llvm.umin.i8(i8 %x.0, i8 %y.0)
+  %x.1.p = getelementptr inbounds i8, ptr %x, i64 1
+  %y.1.p = getelementptr inbounds i8, ptr %y, i64 1
+  %x.1 = load i8, ptr %x.1.p, align 1
+  %y.1 = load i8, ptr %y.1.p, align 1
+  %m.1 = call i8 @llvm.umin.i8(i8 %x.1, i8 %y.1)
+  %x.2.p = getelementptr inbounds i8, ptr %x, i64 2
+  %y.2.p = getelementptr inbounds i8, ptr %y, i64 2
+  %x.2 = load i8, ptr %x.2.p, align 1
+  %y.2 = load i8, ptr %y.2.p, align 1
+  %m.2 = call i8 @llvm.umin.i8(i8 %x.2, i8 %y.2)
+  %x.3.p = getelementptr inbounds i8, ptr %x, i64 3
+  %y.3.p = getelementptr inbounds i8, ptr %y, i64 3
+  %x.3 = load i8, ptr %x.3.p, align 1
+  %y.3 = load i8, ptr %y.3.p, align 1
+  %m.3 = call i8 @llvm.umin.i8(i8 %x.3, i8 %y.3)
+  %x.4.p = getelementptr inbounds i8, ptr %x, i64 4
+  %y.4.p = getelementptr inbounds i8, ptr %y, i64 4
+  %x.4 = load i8, ptr %x.4.p, align 1
+  %y.4 = load i8, ptr %y.4.p, align 1
+  %m.4 = call i8 @llvm.umin.i8(i8 %x.4, i8 %y.4)
+  %x.5.p = getelementptr inbounds i8, ptr %x, i64 5
+  %y.5.p = getelementptr inbounds i8, ptr %y, i64 5
+  %x.5 = load i8, ptr %x.5.p, align 1
+  %y.5 = load i8, ptr %y.5.p, align 1
+  %m.5 = call i8 @llvm.umin.i8(i8 %x.5, i8 %y.5)
+  %x.6.p = getelementptr inbounds i8, ptr %x, i64 6
+  %y.6.p = getelementptr inbounds i8, ptr %y, i64 6
+  %x.6 = load i8, ptr %x.6.p, align 1
+  %y.6 = load i8, ptr %y.6.p, align 1
+  %m.6 = call i8 @llvm.umin.i8(i8 %x.6, i8 %y.6)
+  %x.7.p = getelementptr inbounds i8, ptr %x, i64 7
+  %y.7.p = getelementptr inbounds i8, ptr %y, i64 7
+  %x.7 = load i8, ptr %x.7.p, align 1
+  %y.7 = load i8, ptr %y.7.p, align 1
+  %m.7 = call i8 @llvm.umin.i8(i8 %x.7, i8 %y.7)
+  %x.8.p = getelementptr inbounds i8, ptr %x, i64 8
+  %y.8.p = getelementptr inbounds i8, ptr %y, i64 8
+  %x.8 = load i8, ptr %x.8.p, align 1
+  %y.8 = load i8, ptr %y.8.p, align 1
+  %m.8 = call i8 @llvm.umin.i8(i8 %x.8, i8 %y.8)
+  %x.9.p = getelementptr inbounds i8, ptr %x, i64 9
+  %y.9.p = getelementptr inbounds i8, ptr %y, i64 9
+  %x.9 = load i8, ptr %x.9.p, align 1
+  %y.9 = load i8, ptr %y.9.p, align 1
+  %m.9 = call i8 @llvm.umin.i8(i8 %x.9, i8 %y.9)
+  %x.10.p = getelementptr inbounds i8, ptr %x, i64 10
+  %y.10.p = getelementptr inbounds i8, ptr %y, i64 10
+  %x.10 = load i8, ptr %x.10.p, align 1
+  %y.10 = load i8, ptr %y.10.p, align 1
+  %m.10 = call i8 @llvm.umin.i8(i8 %x.10, i8 %y.10)
+  %x.11.p = getelementptr inbounds i8, ptr %x, i64 11
+  %y.11.p = getelementptr inbounds i8, ptr %y, i64 11
+  %x.11 = load i8, ptr %x.11.p, align 1
+  %y.11 = load i8, ptr %y.11.p, align 1
+  %m.11 = call i8 @llvm.umin.i8(i8 %x.11, i8 %y.11)
+  %x.12.p = getelementptr inbounds i8, ptr %x, i64 12
+  %y.12.p = getelementptr inbounds i8, ptr %y, i64 12
+  %x.12 = load i8, ptr %x.12.p, align 1
+  %y.12 = load i8, ptr %y.12.p, align 1
+  %m.12 = call i8 @llvm.umin.i8(i8 %x.12, i8 %y.12)
+  %x.13.p = getelementptr inbounds i8, ptr %x, i64 13
+  %y.13.p = getelementptr inbounds i8, ptr %y, i64 13
+  %x.13 = load i8, ptr %x.13.p, align 1
+  %y.13 = load i8, ptr %y.13.p, align 1
+  %m.13 = call i8 @llvm.umin.i8(i8 %x.13, i8 %y.13)
+  %x.14.p = getelementptr inbounds i8, ptr %x, i64 14
+  %y.14.p = getelementptr inbounds i8, ptr %y, i64 14
+  %x.14 = load i8, ptr %x.14.p, align 1
+  %y.14 = load i8, ptr %y.14.p, align 1
+  %m.14 = call i8 @llvm.umin.i8(i8 %x.14, i8 %y.14)
+  %x.15.p = getelementptr inbounds i8, ptr %x, i64 15
+  %y.15.p = getelementptr inbounds i8, ptr %y, i64 15
+  %x.15 = load i8, ptr %x.15.p, align 1
+  %y.15 = load i8, ptr %y.15.p, align 1
+  %m.15 = call i8 @llvm.umin.i8(i8 %x.15, i8 %y.15)
+  %z.0 = zext i8 %m.0 to i64
+  %z.1 = zext i8 %m.1 to i64
+  %s.1 = shl nuw nsw i64 %z.1, 8
+  %z.2 = zext i8 %m.2 to i64
+  %s.2 = shl nuw nsw i64 %z.2, 16
+  %z.3 = zext i8 %m.3 to i64
+  %s.3 = shl nuw nsw i64 %z.3, 24
+  %z.4 = zext i8 %m.4 to i64
+  %s.4 = shl nuw nsw i64 %z.4, 32
+  %z.5 = zext i8 %m.5 to i64
+  %s.5 = shl nuw nsw i64 %z.5, 40
+  %z.6 = zext i8 %m.6 to i64
+  %s.6 = shl nuw nsw i64 %z.6, 48
+  %z.7 = zext i8 %m.7 to i64
+  %s.7 = shl nuw i64 %z.7, 56
+  %o.6 = or disjoint i64 %s.7, %s.6
+  %o.5 = or disjoint i64 %o.6, %s.5
+  %o.4 = or disjoint i64 %o.5, %s.4
+  %o.3 = or disjoint i64 %o.4, %s.3
+  %o.2 = or disjoint i64 %o.3, %s.2
+  %o.1 = or disjoint i64 %o.2, %s.1
+  %w.0 = or disjoint i64 %o.1, %z.0
+  %agg.0 = insertvalue { i64, i64 } poison, i64 %w.0, 0
+  %z.8 = zext i8 %m.8 to i64
+  %z.9 = zext i8 %m.9 to i64
+  %s.9 = shl nuw nsw i64 %z.9, 8
+  %z.10 = zext i8 %m.10 to i64
+  %s.10 = shl nuw nsw i64 %z.10, 16
+  %z.11 = zext i8 %m.11 to i64
+  %s.11 = shl nuw nsw i64 %z.11, 24
+  %z.12 = zext i8 %m.12 to i64
+  %s.12 = shl nuw nsw i64 %z.12, 32
+  %z.13 = zext i8 %m.13 to i64
+  %s.13 = shl nuw nsw i64 %z.13, 40
+  %z.14 = zext i8 %m.14 to i64
+  %s.14 = shl nuw nsw i64 %z.14, 48
+  %z.15 = zext i8 %m.15 to i64
+  %s.15 = shl nuw i64 %z.15, 56
+  %o.14 = or disjoint i64 %s.15, %s.14
+  %o.13 = or disjoint i64 %o.14, %s.13
+  %o.12 = or disjoint i64 %o.13, %s.12
+  %o.11 = or disjoint i64 %o.12, %s.11
+  %o.10 = or disjoint i64 %o.11, %s.10
+  %o.9 = or disjoint i64 %o.10, %s.9
+  %w.1 = or disjoint i64 %o.9, %z.8
+  %agg.1 = insertvalue { i64, i64 } %agg.0, i64 %w.1, 1
+  ret { i64, i64 } %agg.1
+}
+
+define { i64, i64 } @pack_i32x4(ptr %x, ptr %y) {
+; CHECK-LABEL: @pack_i32x4(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[VEC2STRUCT_SLOT:%.*]] = alloca { i64, i64 }, align 16
+; CHECK-NEXT:    [[TMP0:%.*]] = load <4 x i32>, ptr [[X:%.*]], align 4
+; CHECK-NEXT:    [[TMP1:%.*]] = load <4 x i32>, ptr [[Y:%.*]], align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = shufflevector <4 x i32> [[TMP0]], <4 x i32> poison, <2 x i32> <i32 0, i32 2>
+; CHECK-NEXT:    [[TMP3:%.*]] = shufflevector <4 x i32> [[TMP1]], <4 x i32> poison, <2 x i32> <i32 0, i32 2>
+; CHECK-NEXT:    [[TMP4:%.*]] = call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[TMP2]], <2 x i32> [[TMP3]])
+; CHECK-NEXT:    [[TMP5:%.*]] = shufflevector <4 x i32> [[TMP0]], <4 x i32> poison, <2 x i32> <i32 1, i32 3>
+; CHECK-NEXT:    [[TMP6:%.*]] = shufflevector <4 x i32> [[TMP1]], <4 x i32> poison, <2 x i32> <i32 1, i32 3>
+; CHECK-NEXT:    [[TMP7:%.*]] = call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[TMP5]], <2 x i32> [[TMP6]])
+; CHECK-NEXT:    [[TMP8:%.*]] = zext <2 x i32> [[TMP4]] to <2 x i64>
+; CHECK-NEXT:    [[TMP9:%.*]] = zext <2 x i32> [[TMP7]] to <2 x i64>
+; CHECK-NEXT:    [[TMP10:%.*]] = shl nuw <2 x i64> [[TMP9]], splat (i64 32)
+; CHECK-NEXT:    [[TMP11:%.*]] = or disjoint <2 x i64> [[TMP10]], [[TMP8]]
+; CHECK-NEXT:    store <2 x i64> [[TMP11]], ptr [[VEC2STRUCT_SLOT]], align 16
+; CHECK-NEXT:    [[AGG_1:%.*]] = load { i64, i64 }, ptr [[VEC2STRUCT_SLOT]], align 16
+; CHECK-NEXT:    ret { i64, i64 } [[AGG_1]]
+;
+entry:
+  %x.0 = load i32, ptr %x, align 4
+  %y.0 = load i32, ptr %y, align 4
+  %m.0 = call i32 @llvm.smin.i32(i32 %x.0, i32 %y.0)
+  %x.1.p = getelementptr inbounds i32, ptr %x, i64 1
+  %y.1.p = getelementptr inbounds i32, ptr %y, i64 1
+  %x.1 = load i32, ptr %x.1.p, align 4
+  %y.1 = load i32, ptr %y.1.p, align 4
+  %m.1 = call i32 @llvm.smin.i32(i32 %x.1, i32 %y.1)
+  %x.2.p = getelementptr inbounds i32, ptr %x, i64 2
+  %y.2.p = getelementptr inbounds i32, ptr %y, i64 2
+  %x.2 = load i32, ptr %x.2.p, align 4
+  %y.2 = load i32, ptr %y.2.p, align 4
+  %m.2 = call i32 @llvm.smin.i32(i32 %x.2, i32 %y.2)
+  %x.3.p = getelementptr inbounds i32, ptr %x, i64 3
+  %y.3.p = getelementptr inbounds i32, ptr %y, i64 3
+  %x.3 = load i32, ptr %x.3.p, align 4
+  %y.3 = load i32, ptr %y.3.p, align 4
+  %m.3 = call i32 @llvm.smin.i32(i32 %x.3, i32 %y.3)
+  %z.0 = zext i32 %m.0 to i64
+  %z.1 = zext i32 %m.1 to i64
+  %s.1 = shl nuw i64 %z.1, 32
+  %w.0 = or disjoint i64 %s.1, %z.0
+  %agg.0 = insertvalue { i64, i64 } poison, i64 %w.0, 0
+  %z.2 = zext i32 %m.2 to i64
+  %z.3 = zext i32 %m.3 to i64
+  %s.3 = shl nuw i64 %z.3, 32
+  %w.1 = or disjoint i64 %s.3, %z.2
+  %agg.1 = insertvalue { i64, i64 } %agg.0, i64 %w.1, 1
+  ret { i64, i64 } %agg.1
+}
+
+define [2 x i64] @pack_array(ptr %x, ptr %y) {
+; CHECK-LABEL: @pack_array(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[X_4_P:%.*]] = getelementptr inbounds i16, ptr [[X:%.*]], i64 4
+; CHECK-NEXT:    [[Y_4_P:%.*]] = getelementptr inbounds i16, ptr [[Y:%.*]], i64 4
+; CHECK-NEXT:    [[TMP0:%.*]] = load <4 x i16>, ptr [[X]], align 2
+; CHECK-NEXT:    [[TMP1:%.*]] = load <4 x i16>, ptr [[Y]], align 2
+; CHECK-NEXT:    [[TMP2:%.*]] = call <4 x i16> @llvm.smin.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
+; CHECK-NEXT:    [[TMP4:%.*]] = bitcast <4 x i16> [[TMP2]] to i64
+; CHECK-NEXT:    [[AGG_0:%.*]] = insertvalue [2 x i64] poison, i64 [[TMP4]], 0
+; CHECK-NEXT:    [[TMP7:%.*]] = load <4 x i16>, ptr [[X_4_P]], align 2
+; CHECK-NEXT:    [[TMP8:%.*]] = load <4 x i16>, ptr [[Y_4_P]], align 2
+; CHECK-NEXT:    [[TMP6:%.*]] = call <4 x i16> @llvm.smin.v4i16(<4 x i16> [[TMP7]], <4 x i16> [[TMP8]])
+; CHECK-NEXT:    [[TMP5:%.*]] = bitcast <4 x i16> [[TMP6]] to i64
+; CHECK-NEXT:    [[AGG_1:%.*]] = insertvalue [2 x i64] [[AGG_0]], i64 [[TMP5]], 1
+; CHECK-NEXT:    ret [2 x i64] [[AGG_1]]
+;
+entry:
+  %x.0 = load i16, ptr %x, align 2
+  %y.0 = load i16, ptr %y, align 2
+  %m.0 = call i16 @llvm.smin.i16(i16 %x.0, i16 %y.0)
+  %x.1.p = getelementptr inbounds i16, ptr %x, i64 1
+  %y.1.p = getelementptr inbounds i16, ptr %y, i64 1
+  %x.1 = load i16, ptr %x.1.p, align 2
+  %y.1 = load i16, ptr %y.1.p, align 2
+  %m.1 = call i16 @llvm.smin.i16(i16 %x.1, i16 %y.1)
+  %x.2.p = getelementptr inbounds i16, ptr %x, i64 2
+  %y.2.p = getelementptr inbounds i16, ptr %y, i64 2
+  %x.2 = load i16, ptr %x.2.p, align 2
+  %y.2 = load i16, ptr %y.2.p, align 2
+  %m.2 = call i16 @llvm.smin.i16(i16 %x.2, i16 %y.2)
+  %x.3.p = getelementptr inbounds i16, ptr %x, i64 3
+  %y.3.p = getelementptr inbounds i16, ptr %y, i64 3
+  %x.3 = load i16, ptr %x.3.p, align 2
+  %y.3 = load i16, ptr %y.3.p, align 2
+  %m.3 = call i16 @llvm.smin.i16(i16 %x.3, i16 %y.3)
+  %x.4.p = getelementptr inbounds i16, ptr %x, i64 4
+  %y.4.p = getelementptr inbounds i16, ptr %y, i64 4
+  %x.4 = load i16, ptr %x.4.p, align 2
+  %y.4 = load i16, ptr %y.4.p, align 2
+  %m.4 = call i16 @llvm.smin.i16(i16 %x.4, i16 %y.4)
+  %x.5.p = getelementptr inbounds i16, ptr %x, i64 5
+  %y.5.p = getelementptr inbounds i16, ptr %y, i64 5
+  %x.5 = load i16, ptr %x.5.p, align 2
+  %y.5 = load i16, ptr %y.5.p, align 2
+  %m.5 = call i16 @llvm.smin.i16(i16 %x.5, i16 %y.5)
+  %x.6.p = getelementptr inbounds i16, ptr %x, i64 6
+  %y.6.p = getelementptr inbounds i16, ptr %y, i64 6
+  %x.6 = load i16, ptr %x.6.p, align 2
+  %y.6 = load i16, ptr %y.6.p, align 2
+  %m.6 = call i16 @llvm.smin.i16(i16 %x.6, i16 %y.6)
+  %x.7.p = getelementptr inbounds i16, ptr %x, i64 7
+  %y.7.p = getelementptr inbounds i16, ptr %y, i64 7
+  %x.7 = load i16, ptr %x.7.p, align 2
+  %y.7 = load i16, ptr %y.7.p, align 2
+  %m.7 = call i16 @llvm.smin.i16(i16 %x.7, i16 %y.7)
+  %z.0 = zext i16 %m.0 to i64
+  %z.1 = zext i16 %m.1 to i64
+  %s.1 = shl nuw nsw i64 %z.1, 16
+  %z.2 = zext i16 %m.2 to i64
+  %s.2 = shl nuw nsw i64 %z.2, 32
+  %z.3 = zext i16 %m.3 to i64
+  %s.3 = shl nuw i64 %z.3, 48
+  %o.2 = or disjoint i64 %s.3, %s.2
+  %o.1 = or disjoint i64 %o.2, %s.1
+  %w.0 = or disjoint i64 %o.1, %z.0
+  %agg.0 = insertvalue [2 x i64] poison, i64 %w.0, 0
+  %z.4 = zext i16 %m.4 to i64
+  %z.5 = zext i16 %m.5 to i64
+  %s.5 = shl nuw nsw i64 %z.5, 16
+  %z.6 = zext i16 %m.6 to i64
+  %s.6 = shl nuw nsw i64 %z.6, 32
+  %z.7 = zext i16 %m.7 to i64
+  %s.7 = shl nuw i64 %z.7, 48
+  %o.6 = or disjoint i64 %s.7, %s.6
+  %o.5 = or disjoint i64 %o.6, %s.5
+  %w.1 = or disjoint i64 %o.5, %z.4
+  %agg.1 = insertvalue [2 x i64] %agg.0, i64 %w.1, 1
+  ret [2 x i64] %agg.1
+}
+
+; The first insert precedes the fields of the second pack.
+
+define { i64, i64 } @insert_before_fields(ptr %x, ptr %y) {
+; CHECK-LABEL: @insert_before_fields(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load <4 x i16>, ptr [[X:%.*]], align 2
+; CHECK-NEXT:    [[TMP1:%.*]] = load <4 x i16>, ptr [[Y:%.*]], align 2
+; CHECK-NEXT:    [[TMP2:%.*]] = call <4 x i16> @llvm.smin.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
+; CHECK-NEXT:    [[TMP4:%.*]] = bitcast <4 x i16> [[TMP2]] to i64
+; CHECK-NEXT:    [[AGG_0:%.*]] = insertvalue { i64, i64 } poison, i64 [[TMP4]], 0
+; CHECK-NEXT:    [[X_4_P:%.*]] = getelementptr inbounds i16, ptr [[X]], i64 4
+; CHECK-NEXT:    [[Y_4_P:%.*]] = getelementptr inbounds i16, ptr [[Y]], i64 4
+; CHECK-NEXT:    [[TMP7:%.*]] = load <4 x i16>, ptr [[X_4_P]], align 2
+; CHECK-NEXT:    [[TMP8:%.*]] = load <4 x i16>, ptr [[Y_4_P]], align 2
+; CHECK-NEXT:    [[TMP6:%.*]] = call <4 x i16> @llvm.smin.v4i16(<4 x i16> [[TMP7]], <4 x i16> [[TMP8]])
+; CHECK-NEXT:    [[TMP5:%.*]] = bitcast <4 x i16> [[TMP6]] to i64
+; CHECK-NEXT:    [[AGG_1:%.*]] = insertvalue { i64, i64 } [[AGG_0]], i64 [[TMP5]], 1
+; CHECK-NEXT:    ret { i64, i64 } [[AGG_1]]
+;
+entry:
+  %x.0 = load i16, ptr %x, align 2
+  %y.0 = load i16, ptr %y, align 2
+  %m.0 = call i16 @llvm.smin.i16(i16 %x.0, i16 %y.0)
+  %x.1.p = getelementptr inbounds i16, ptr %x, i64 1
+  %y.1.p = getelementptr inbounds i16, ptr %y, i64 1
+  %x.1 = load i16, ptr %x.1.p, align 2
+  %y.1 = load i16, ptr %y.1.p, align 2
+  %m.1 = call i16 @llvm.smin.i16(i16 %x.1, i16 %y.1)
+  %x.2.p = getelementptr inbounds i16, ptr %x, i64 2
+  %y.2.p = getelementptr inbounds i16, ptr %y, i64 2
+  %x.2 = load i16, ptr %x.2.p, align 2
+  %y.2 = load i16, ptr %y.2.p, align 2
+  %m.2 = call i16 @llvm.smin.i16(i16 %x.2, i16 %y.2)
+  %x.3.p = getelementptr inbounds i16, ptr %x, i64 3
+  %y.3.p = getelementptr inbounds i16, ptr %y, i64 3
+  %x.3 = load i16, ptr %x.3.p, align 2
+  %y.3 = load i16, ptr %y.3.p, align 2
+  %m.3 = call i16 @llvm.smin.i16(i16 %x.3, i16 %y.3)
+  %z.0 = zext i16 %m.0 to i64
+  %z.1 = zext i16 %m.1 to i64
+  %s.1 = shl nuw i64 %z.1, 16
+  %z.2 = zext i16 %m.2 to i64
+  %s.2 = shl nuw i64 %z.2, 32
+  %z.3 = zext i16 %m.3 to i64
+  %s.3 = shl nuw i64 %z.3, 48
+  %o.2 = or disjoint i64 %s.3, %s.2
+  %o.1 = or disjoint i64 %o.2, %s.1
+  %w.0 = or disjoint i64 %o.1, %z.0
+  %agg.0 = insertvalue { i64, i64 } poison, i64 %w.0, 0
+  %x.4.p = getelementptr inbounds i16, ptr %x, i64 4
+  %y.4.p = getelementptr inbounds i16, ptr %y, i64 4
+  %x.4 = load i16, ptr %x.4.p, align 2
+  %y.4 = load i16, ptr %y.4.p, align 2
+  %m.4 = call i16 @llvm.smin.i16(i16 %x.4, i16 %y.4)
+  %x.5.p = getelementptr inbounds i16, ptr %x, i64 5
+  %y.5.p = getelementptr inbounds i16, ptr %y, i64 5
+  %x.5 = load i16, ptr %x.5.p, align 2
+  %y.5 = load i16, ptr %y.5.p, align 2
+  %m.5 = call i16 @llvm.smin.i16(i16 %x.5, i16 %y.5)
+  %x.6.p = getelementptr inbounds i16, ptr %x, i64 6
+  %y.6.p = getelementptr inbounds i16, ptr %y, i64 6
+  %x.6 = load i16, ptr %x.6.p, align 2
+  %y.6 = load i16, ptr %y.6.p, align 2
+  %m.6 = call i16 @llvm.smin.i16(i16 %x.6, i16 %y.6)
+  %x.7.p = getelementptr inbounds i16, ptr %x, i64 7
+  %y.7.p = getelementptr inbounds i16, ptr %y, i64 7
+  %x.7 = load i16, ptr %x.7.p, align 2
+  %y.7 = load i16, ptr %y.7.p, align 2
+  %m.7 = call i16 @llvm.smin.i16(i16 %x.7, i16 %y.7)
+  %z.4 = zext i16 %m.4 to i64
+  %z.5 = zext i16 %m.5 to i64
+  %s.5 = shl nuw i64 %z.5, 16
+  %z.6 = zext i16 %m.6 to i64
+  %s.6 = shl nuw i64 %z.6, 32
+  %z.7 = zext i16 %m.7 to i64
+  %s.7 = shl nuw i64 %z.7, 48
+  %o.6 = or disjoint i64 %s.7, %s.6
+  %o.5 = or disjoint i64 %o.6, %s.5
+  %w.1 = or disjoint i64 %o.5, %z.4
+  %agg.1 = insertvalue { i64, i64 } %agg.0, i64 %w.1, 1
+  ret { i64, i64 } %agg.1
+}
+
+; The field is also used outside of the packs.
+
+define { i64, i64 } @field_external_use(ptr %x, ptr %y, ptr %p) {
+; CHECK-LABEL: @field_external_use(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[X_4_P:%.*]] = getelementptr inbounds i16, ptr [[X:%.*]], i64 4
+; CHECK-NEXT:    [[Y_4_P:%.*]] = getelementptr inbounds i16, ptr [[Y:%.*]], i64 4
+; CHECK-NEXT:    [[TMP0:%.*]] = load <4 x i16>, ptr [[X]], align 2
+; CHECK-NEXT:    [[TMP1:%.*]] = load <4 x i16>, ptr [[Y]], align 2
+; CHECK-NEXT:    [[TMP2:%.*]] = call <4 x i16> @llvm.smin.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
+; CHECK-NEXT:    [[TMP4:%.*]] = bitcast <4 x i16> [[TMP2]] to i64
+; CHECK-NEXT:    [[AGG_0:%.*]] = insertvalue { i64, i64 } poison, i64 [[TMP4]], 0
+; CHECK-NEXT:    [[TMP7:%.*]] = load <4 x i16>, ptr [[X_4_P]], align 2
+; CHECK-NEXT:    [[TMP8:%.*]] = load <4 x i16>, ptr [[Y_4_P]], align 2
+; CHECK-NEXT:    [[TMP9:%.*]] = call <4 x i16> @llvm.smin.v4i16(<4 x i16> [[TMP7]], <4 x i16> [[TMP8]])
+; CHECK-NEXT:    [[TMP5:%.*]] = bitcast <4 x i16> [[TMP9]] to i64
+; CHECK-NEXT:    [[AGG_1:%.*]] = insertvalue { i64, i64 } [[AGG_0]], i64 [[TMP5]], 1
+; CHECK-NEXT:    [[TMP6:%.*]] = extractelement <4 x i16> [[TMP2]], i64 1
+; CHECK-NEXT:    store i16 [[TMP6]], ptr [[P:%.*]], align 2
+; CHECK-NEXT:    ret { i64, i64 } [[AGG_1]]
+;
+entry:
+  %x.0 = load i16, ptr %x, align 2
+  %y.0 = load i16, ptr %y, align 2
+  %m.0 = call i16 @llvm.smin.i16(i16 %x.0, i16 %y.0)
+  %x.1.p = getelementptr inbounds i16, ptr %x, i64 1
+  %y.1.p = getelementptr inbounds i16, ptr %y, i64 1
+  %x.1 = load i16, ptr %x.1.p, align 2
+  %y.1 = load i16, ptr %y.1.p, align 2
+  %m.1 = call i16 @llvm.smin.i16(i16 %x.1, i16 %y.1)
+  %x.2.p = getelementptr inbounds i16, ptr %x, i64 2
+  %y.2.p = getelementptr inbounds i16, ptr %y, i64 2
+  %x.2 = load i16, ptr %x.2.p, align 2
+  %y.2 = load i16, ptr %y.2.p, align 2
+  %m.2 = call i16 @llvm.smin.i16(i16 %x.2, i16 %y.2)
+  %x.3.p = getelementptr inbounds i16, ptr %x, i64 3
+  %y.3.p = getelementptr inbounds i16, ptr %y, i64 3
+  %x.3 = load i16, ptr %x.3.p, align 2
+  %y.3 = load i16, ptr %y.3.p, align 2
+  %m.3 = call i16 @llvm.smin.i16(i16 %x.3, i16 %y.3)
+  %x.4.p = getelementptr inbounds i16, ptr %x, i64 4
+  %y.4.p = getelementptr inbounds i16, ptr %y, i64 4
+  %x.4 = load i16, ptr %x.4.p, align 2
+  %y.4 = load i16, ptr %y.4.p, align 2
+  %m.4 = call i16 @llvm.smin.i16(i16 %x.4, i16 %y.4)
+  %x.5.p = getelementptr inbounds i16, ptr %x, i64 5
+  %y.5.p = getelementptr inbounds i16, ptr %y, i64 5
+  %x.5 = load i16, ptr %x.5.p, align 2
+  %y.5 = load i16, ptr %y.5.p, align 2
+  %m.5 = call i16 @llvm.smin.i16(i16 %x.5, i16 %y.5)
+  %x.6.p = getelementptr inbounds i16, ptr %x, i64 6
+  %y.6.p = getelementptr inbounds i16, ptr %y, i64 6
+  %x.6 = load i16, ptr %x.6.p, align 2
+  %y.6 = load i16, ptr %y.6.p, align 2
+  %m.6 = call i16 @llvm.smin.i16(i16 %x.6, i16 %y.6)
+  %x.7.p = getelementptr inbounds i16, ptr %x, i64 7
+  %y.7.p = getelementptr inbounds i16, ptr %y, i64 7
+  %x.7 = load i16, ptr %x.7.p, align 2
+  %y.7 = load i16, ptr %y.7.p, align 2
+  %m.7 = call i16 @llvm.smin.i16(i16 %x.7, i16 %y.7)
+  %z.0 = zext i16 %m.0 to i64
+  %z.1 = zext i16 %m.1 to i64
+  %s.1 = shl nuw nsw i64 %z.1, 16
+  %z.2 = zext i16 %m.2 to i64
+  %s.2 = shl nuw nsw i64 %z.2, 32
+  %z.3 = zext i16 %m.3 to i64
+  %s.3 = shl nuw i64 %z.3, 48
+  %o.2 = or disjoint i64 %s.3, %s.2
+  %o.1 = or disjoint i64 %o.2, %s.1
+  %w.0 = or disjoint i64 %o.1, %z.0
+  %agg.0 = insertvalue { i64, i64 } poison, i64 %w.0, 0
+  %z.4 = zext i16 %m.4 to i64
+  %z.5 = zext i16 %m.5 to i64
+  %s.5 = shl nuw nsw i64 %z.5, 16
+  %z.6 = zext i16 %m.6 to i64
+  %s.6 = shl nuw nsw i64 %z.6, 32
+  %z.7 = zext i16 %m.7 to i64
+  %s.7 = shl nuw i64 %z.7, 48
+  %o.6 = or disjoint i64 %s.7, %s.6
+  %o.5 = or disjoint i64 %o.6, %s.5
+  %w.1 = or disjoint i64 %o.5, %z.4
+  %agg.1 = insertvalue { i64, i64 } %agg.0, i64 %w.1, 1
+  store i16 %m.1, ptr %p, align 2
+  ret { i64, i64 } %agg.1
+}
+
+; The fields are extracted from the vector, which is bitcasted as is.
+define { i64, i64 } @repack(<8 x i16> %v) {
+; CHECK-LABEL: @repack(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = shufflevector <8 x i16> [[V:%.*]], <8 x i16> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast <4 x i16> [[TMP0]] to i64
+; CHECK-NEXT:    [[TMP3:%.*]] = shufflevector <8 x i16> [[V]], <8 x i16> poison, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast <4 x i16> [[TMP3]] to i64
+; CHECK-NEXT:    [[A0:%.*]] = insertvalue { i64, i64 } poison, i64 [[TMP1]], 0
+; CHECK-NEXT:    [[A1:%.*]] = insertvalue { i64, i64 } [[A0]], i64 [[TMP2]], 1
+; CHECK-NEXT:    ret { i64, i64 } [[A1]]
+;
+entry:
+  %e0 = extractelement <8 x i16> %v, i32 0
+  %e1 = extractelement <8 x i16> %v, i32 1
+  %e2 = extractelement <8 x i16> %v, i32 2
+  %e3 = extractelement <8 x i16> %v, i32 3
+  %e4 = extractelement <8 x i16> %v, i32 4
+  %e5 = extractelement <8 x i16> %v, i32 5
+  %e6 = extractelement <8 x i16> %v, i32 6
+  %e7 = extractelement <8 x i16> %v, i32 7
+  %z0 = zext i16 %e0 to i64
+  %z1 = zext i16 %e1 to i64
+  %z2 = zext i16 %e2 to i64
+  %z3 = zext i16 %e3 to i64
+  %z4 = zext i16 %e4 to i64
+  %z5 = zext i16 %e5 to i64
+  %z6 = zext i16 %e6 to i64
+  %z7 = zext i16 %e7 to i64
+  %s1 = shl nuw i64 %z1, 16
+  %s2 = shl nuw i64 %z2, 32
+  %s3 = shl nuw i64 %z3, 48
+  %s5 = shl nuw i64 %z5, 16
+  %s6 = shl nuw i64 %z6, 32
+  %s7 = shl nuw i64 %z7, 48
+  %o0 = or disjoint i64 %s3, %s2
+  %o1 = or disjoint i64 %o0, %s1
+  %w0 = or disjoint i64 %o1, %z0
+  %o2 = or disjoint i64 %s7, %s6
+  %o3 = or disjoint i64 %o2, %s5
+  %w1 = or disjoint i64 %o3, %z4
+  %a0 = insertvalue { i64, i64 } poison, i64 %w0, 0
+  %a1 = insertvalue { i64, i64 } %a0, i64 %w1, 1
+  ret { i64, i64 } %a1
+}
+
+; The packs below are not vectorized together.
+
+; Extra use of a pack instruction.
+define { i64, i64 } @extra_use(ptr %x, ptr %y, ptr %p) {
+; CHECK-LABEL: @extra_use(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load <4 x i32>, ptr [[X:%.*]], align 4
+; CHECK-NEXT:    [[TMP1:%.*]] = load <4 x i32>, ptr [[Y:%.*]], align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = shufflevector <4 x i32> [[TMP0]], <4 x i32> poison, <2 x i32> <i32 0, i32 2>
+; CHECK-NEXT:    [[TMP3:%.*]] = shufflevector <4 x i32> [[TMP1]], <4 x i32> poison, <2 x i32> <i32 0, i32 2>
+; CHECK-NEXT:    [[TMP4:%.*]] = call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[TMP2]], <2 x i32> [[TMP3]])
+; CHECK-NEXT:    [[TMP5:%.*]] = shufflevector <4 x i32> [[TMP0]], <4 x i32> poison, <2 x i32> <i32 1, i32 3>
+; CHECK-NEXT:    [[TMP6:%.*]] = shufflevector <4 x i32> [[TMP1]], <4 x i32> poison, <2 x i32> <i32 1, i32 3>
+; CHECK-NEXT:    [[TMP7:%.*]] = call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[TMP5]], <2 x i32> [[TMP6]])
+; CHECK-NEXT:    [[TMP8:%.*]] = zext <2 x i32> [[TMP4]] to <2 x i64>
+; CHECK-NEXT:    [[TMP9:%.*]] = zext <2 x i32> [[TMP7]] to <2 x i64>
+; CHECK-NEXT:    [[TMP10:%.*]] = shl nuw <2 x i64> [[TMP9]], splat (i64 32)
+; CHECK-NEXT:    [[TMP11:%.*]] = or disjoint <2 x i64> [[TMP10]], [[TMP8]]
+; CHECK-NEXT:    [[TMP12:%.*]] = extractelement <2 x i64> [[TMP10]], i64 1
+; CHECK-NEXT:    store i64 [[TMP12]], ptr [[P:%.*]], align 8
+; CHECK-NEXT:    [[TMP13:%.*]] = extractelement <2 x i64> [[TMP11]], i64 0
+; CHECK-NEXT:    [[A0:%.*]] = insertvalue { i64, i64 } poison, i64 [[TMP13]], 0
+; CHECK-NEXT:    [[TMP14:%.*]] = extractelement <2 x i64> [[TMP11]], i64 1
+; CHECK-NEXT:    [[A1:%.*]] = insertvalue { i64, i64 } [[A0]], i64 [[TMP14]], 1
+; CHECK-NEXT:    ret { i64, i64 } [[A1]]
+;
+entry:
+  %x1.p = getelementptr inbounds i32, ptr %x, i64 1
+  %x2.p = getelementptr inbounds i32, ptr %x, i64 2
+  %x3.p = getelementptr inbounds i32, ptr %x, i64 3
+  %y1.p = getelementptr inbounds i32, ptr %y, i64 1
+  %y2.p = getelementptr inbounds i32, ptr %y, i64 2
+  %y3.p = getelementptr inbounds i32, ptr %y, i64 3
+  %x0 = load i32, ptr %x, align 4
+  %x1 = load i32, ptr %x1.p, align 4
+  %x2 = load i32, ptr %x2.p, align 4
+  %x3 = load i32, ptr %x3.p, align 4
+  %y0 = load i32, ptr %y, align 4
+  %y1 = load i32, ptr %y1.p, align 4
+  %y2 = load i32, ptr %y2.p, align 4
+  %y3 = load i32, ptr %y3.p, align 4
+  %m0 = call i32 @llvm.smin.i32(i32 %x0, i32 %y0)
+  %m1 = call i32 @llvm.smin.i32(i32 %x1, i32 %y1)
+  %m2 = call i32 @llvm.smin.i32(i32 %x2, i32 %y2)
+  %m3 = call i32 @llvm.smin.i32(i32 %x3, i32 %y3)
+  %z0 = zext i32 %m0 to i64
+  %z1 = zext i32 %m1 to i64
+  %z2 = zext i32 %m2 to i64
+  %z3 = zext i32 %m3 to i64
+  %s1 = shl nuw i64 %z1, 32
+  %s3 = shl nuw i64 %z3, 32
+  %w0 = or disjoint i64 %s1, %z0
+  %w1 = or disjoint i64 %s3, %z2
+  store i64 %s3, ptr %p, align 8
+  %a0 = insertvalue { i64, i64 } poison, i64 %w0, 0
+  %a1 = insertvalue { i64, i64 } %a0, i64 %w1, 1
+  ret { i64, i64 } %a1
+}
+
+; The second element is not a pack.
+define { i64, i64 } @not_pack(ptr %x, ptr %y, i64 %v) {
+; CHECK-LABEL: @not_pack(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load <2 x i32>, ptr [[X:%.*]], align 4
+; CHECK-NEXT:    [[TMP1:%.*]] = load <2 x i32>, ptr [[Y:%.*]], align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[TMP0]], <2 x i32> [[TMP1]])
+; CHECK-NEXT:    [[TMP3:%.*]] = extractelement <2 x i32> [[TMP2]], i64 0
+; CHECK-NEXT:    [[Z0:%.*]] = zext i32 [[TMP3]] to i64
+; CHECK-NEXT:    [[TMP4:%.*]] = extractelement <2 x i32> [[TMP2]], i64 1
+; CHECK-NEXT:    [[Z1:%.*]] = zext i32 [[TMP4]] to i64
+; CHECK-NEXT:    [[S1:%.*]] = shl nuw i64 [[Z1]], 32
+; CHECK-NEXT:    [[W0:%.*]] = or disjoint i64 [[S1]], [[Z0]]
+; CHECK-NEXT:    [[A0:%.*]] = insertvalue { i64, i64 } poison, i64 [[W0]], 0
+; CHECK-NEXT:    [[A1:%.*]] = insertvalue { i64, i64 } [[A0]], i64 [[V:%.*]], 1
+; CHECK-NEXT:    ret { i64, i64 } [[A1]]
+;
+entry:
+  %x1.p = getelementptr inbounds i32, ptr %x, i64 1
+  %y1.p = getelementptr inbounds i32, ptr %y, i64 1
+  %x0 = load i32, ptr %x, align 4
+  %x1 = load i32, ptr %x1.p, align 4
+  %y0 = load i32, ptr %y, align 4
+  %y1 = load i32, ptr %y1.p, align 4
+  %m0 = call i32 @llvm.smin.i32(i32 %x0, i32 %y0)
+  %m1 = call i32 @llvm.smin.i32(i32 %x1, i32 %y1)
+  %z0 = zext i32 %m0 to i64
+  %z1 = zext i32 %m1 to i64
+  %s1 = shl nuw i64 %z1, 32
+  %w0 = or disjoint i64 %s1, %z0
+  %a0 = insertvalue { i64, i64 } poison, i64 %w0, 0
+  %a1 = insertvalue { i64, i64 } %a0, i64 %v, 1
+  ret { i64, i64 } %a1
+}
+
+; The packs have a different number of fields.
+define { i64, i64 } @mixed_widths(ptr %x, ptr %y) {
+; CHECK-LABEL: @mixed_widths(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load <2 x i32>, ptr [[X:%.*]], align 4
+; CHECK-NEXT:    [[TMP1:%.*]] = load <2 x i32>, ptr [[Y:%.*]], align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[TMP0]], <2 x i32> [[TMP1]])
+; CHECK-NEXT:    [[TMP3:%.*]] = extractelement <2 x i32> [[TMP2]], i64 0
+; CHECK-NEXT:    [[Z0:%.*]] = zext i32 [[TMP3]] to i64
+; CHECK-NEXT:    [[TMP4:%.*]] = extractelement <2 x i32> [[TMP2]], i64 1
+; CHECK-NEXT:    [[Z1:%.*]] = zext i32 [[TMP4]] to i64
+; CHECK-NEXT:    [[S1:%.*]] = shl nuw i64 [[Z1]], 32
+; CHECK-NEXT:    [[W0:%.*]] = or disjoint i64 [[S1]], [[Z0]]
+; CHECK-NEXT:    [[P:%.*]] = getelementptr inbounds i8, ptr [[X]], i64 16
+; CHECK-NEXT:    [[Q:%.*]] = getelementptr inbounds i8, ptr [[Y]], i64 16
+; CHECK-NEXT:    [[TMP5:%.*]] = load i32, ptr [[P]], align 1
+; CHECK-NEXT:    [[TMP6:%.*]] = zext i32 [[TMP5]] to i64
+; CHECK-NEXT:    [[A0:%.*]] = insertvalue { i64, i64 } poison, i64 [[W0]], 0
+; CHECK-NEXT:    [[A1:%.*]] = insertvalue { i64, i64 } [[A0]], i64 [[TMP6]], 1
+; CHECK-NEXT:    ret { i64, i64 } [[A1]]
+;
+entry:
+  %x1.p = getelementptr inbounds i32, ptr %x, i64 1
+  %y1.p = getelementptr inbounds i32, ptr %y, i64 1
+  %x0 = load i32, ptr %x, align 4
+  %x1 = load i32, ptr %x1.p, align 4
+  %y0 = load i32, ptr %y, align 4
+  %y1 = load i32, ptr %y1.p, align 4
+  %m0 = call i32 @llvm.smin.i32(i32 %x0, i32 %y0)
+  %m1 = call i32 @llvm.smin.i32(i32 %x1, i32 %y1)
+  %z0 = zext i32 %m0 to i64
+  %z1 = zext i32 %m1 to i64
+  %s1 = shl nuw i64 %z1, 32
+  %w0 = or disjoint i64 %s1, %z0
+  %p = getelementptr inbounds i8, ptr %x, i64 16
+  %q = getelementptr inbounds i8, ptr %y, i64 16
+  %b0 = load i8, ptr %p, align 1
+  %b1.p = getelementptr inbounds i8, ptr %p, i64 1
+  %b1 = load i8, ptr %b1.p, align 1
+  %b2.p = getelementptr inbounds i8, ptr %p, i64 2
+  %b2 = load i8, ptr %b2.p, align 1
+  %b3.p = getelementptr inbounds i8, ptr %p, i64 3
+  %b3 = load i8, ptr %b3.p, align 1
+  %e0 = zext i8 %b0 to i64
+  %e1 = zext i8 %b1 to i64
+  %e2 = zext i8 %b2 to i64
+  %e3 = zext i8 %b3 to i64
+  %t1 = shl nuw nsw i64 %e1, 8
+  %t2 = shl nuw nsw i64 %e2, 16
+  %t3 = shl nuw nsw i64 %e3, 24
+  %u0 = or disjoint i64 %t1, %e0
+  %u1 = or disjoint i64 %u0, %t2
+  %w1 = or disjoint i64 %u1, %t3
+  %a0 = insertvalue { i64, i64 } poison, i64 %w0, 0
+  %a1 = insertvalue { i64, i64 } %a0, i64 %w1, 1
+  ret { i64, i64 } %a1
+}
+
+; A field is shared between the packs.
+define { i64, i64 } @shared_field(ptr %x, ptr %y) {
+; CHECK-LABEL: @shared_field(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[X1_P:%.*]] = getelementptr inbounds i32, ptr [[X:%.*]], i64 1
+; CHECK-NEXT:    [[Y1_P:%.*]] = getelementptr inbounds i32, ptr [[Y:%.*]], i64 1
+; CHECK-NEXT:    [[X0:%.*]] = load i32, ptr [[X]], align 4
+; CHECK-NEXT:    [[X1:%.*]] = load i32, ptr [[X1_P]], align 4
+; CHECK-NEXT:    [[Y0:%.*]] = load i32, ptr [[Y]], align 4
+; CHECK-NEXT:    [[Y1:%.*]] = load i32, ptr [[Y1_P]], align 4
+; CHECK-NEXT:    [[M0:%.*]] = call i32 @llvm.smin.i32(i32 [[X0]], i32 [[Y0]])
+; CHECK-NEXT:    [[M1:%.*]] = call i32 @llvm.smin.i32(i32 [[X1]], i32 [[Y1]])
+; CHECK-NEXT:    [[Z0:%.*]] = zext i32 [[M0]] to i64
+; CHECK-NEXT:    [[Z1:%.*]] = zext i32 [[M1]] to i64
+; CHECK-NEXT:    [[S1:%.*]] = shl nuw i64 [[Z1]], 32
+; CHECK-NEXT:    [[W0:%.*]] = or disjoint i64 [[S1]], [[Z0]]
+; CHECK-NEXT:    [[W1:%.*]] = or disjoint i64 [[S1]], [[Z1]]
+; CHECK-NEXT:    [[A0:%.*]] = insertvalue { i64, i64 } poison, i64 [[W0]], 0
+; CHECK-NEXT:    [[A1:%.*]] = insertvalue { i64, i64 } [[A0]], i64 [[W1]], 1
+; CHECK-NEXT:    ret { i64, i64 } [[A1]]
+;
+entry:
+  %x1.p = getelementptr inbounds i32, ptr %x, i64 1
+  %y1.p = getelementptr inbounds i32, ptr %y, i64 1
+  %x0 = load i32, ptr %x, align 4
+  %x1 = load i32, ptr %x1.p, align 4
+  %y0 = load i32, ptr %y, align 4
+  %y1 = load i32, ptr %y1.p, align 4
+  %m0 = call i32 @llvm.smin.i32(i32 %x0, i32 %y0)
+  %m1 = call i32 @llvm.smin.i32(i32 %x1, i32 %y1)
+  %z0 = zext i32 %m0 to i64
+  %z1 = zext i32 %m1 to i64
+  %s1 = shl nuw i64 %z1, 32
+  %w0 = or disjoint i64 %s1, %z0
+  %w1 = or disjoint i64 %s1, %z1
+  %a0 = insertvalue { i64, i64 } poison, i64 %w0, 0
+  %a1 = insertvalue { i64, i64 } %a0, i64 %w1, 1
+  ret { i64, i64 } %a1
+}
+
+; The fields are the loads, merged per pack.
+define { i64, i64 } @loads(ptr %x) {
+; CHECK-LABEL: @loads(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[X1_P:%.*]] = getelementptr inbounds i32, ptr [[X:%.*]], i64 1
+; CHECK-NEXT:    [[X2_P:%.*]] = getelementptr inbounds i32, ptr [[X]], i64 2
+; CHECK-NEXT:    [[X3_P:%.*]] = getelementptr inbounds i32, ptr [[X]], i64 3
+; CHECK-NEXT:    [[X0:%.*]] = load i32, ptr [[X]], align 4
+; CHECK-NEXT:    [[X1:%.*]] = load i32, ptr [[X1_P]], align 4
+; CHECK-NEXT:    [[X2:%.*]] = load i32, ptr [[X2_P]], align 4
+; CHECK-NEXT:    [[X3:%.*]] = load i32, ptr [[X3_P]], align 4
+; CHECK-NEXT:    [[Z0:%.*]] = zext i32 [[X0]] to i64
+; CHECK-NEXT:    [[Z1:%.*]] = zext i32 [[X1]] to i64
+; CHECK-NEXT:    [[Z2:%.*]] = zext i32 [[X2]] to i64
+; CHECK-NEXT:    [[Z3:%.*]] = zext i32 [[X3]] to i64
+; CHECK-NEXT:    [[S1:%.*]] = shl nuw i64 [[Z1]], 32
+; CHECK-NEXT:    [[S3:%.*]] = shl nuw i64 [[Z3]], 32
+; CHECK-NEXT:    [[W0:%.*]] = or disjoint i64 [[S1]], [[Z0]]
+; CHECK-NEXT:    [[W1:%.*]] = or disjoint i64 [[S3]], [[Z2]]
+; CHECK-NEXT:    [[A0:%.*]] = insertvalue { i64, i64 } poison, i64 [[W0]], 0
+; CHECK-NEXT:    [[A1:%.*]] = insertvalue { i64, i64 } [[A0]], i64 [[W1]], 1
+; CHECK-NEXT:    ret { i64, i64 } [[A1]]
+;
+entry:
+  %x1.p = getelementptr inbounds i32, ptr %x, i64 1
+  %x2.p = getelementptr inbounds i32, ptr %x, i64 2
+  %x3.p = getelementptr inbounds i32, ptr %x, i64 3
+  %x0 = load i32, ptr %x, align 4
+  %x1 = load i32, ptr %x1.p, align 4
+  %x2 = load i32, ptr %x2.p, align 4
+  %x3 = load i32, ptr %x3.p, align 4
+  %z0 = zext i32 %x0 to i64
+  %z1 = zext i32 %x1 to i64
+  %z2 = zext i32 %x2 to i64
+  %z3 = zext i32 %x3 to i64
+  %s1 = shl nuw i64 %z1, 32
+  %s3 = shl nuw i64 %z3, 32
+  %w0 = or disjoint i64 %s1, %z0
+  %w1 = or disjoint i64 %s3, %z2
+  %a0 = insertvalue { i64, i64 } poison, i64 %w0, 0
+  %a1 = insertvalue { i64, i64 } %a0, i64 %w1, 1
+  ret { i64, i64 } %a1
+}
+
+declare i16 @llvm.smin.i16(i16, i16)
+declare i8 @llvm.umin.i8(i8, i8)
+declare i32 @llvm.smin.i32(i32, i32)



More information about the llvm-commits mailing list