[llvm] [SLP][X86] Add pre-commit tests for merging binary-operator input ope… (PR #210004)
Balakrishna Bandlapalli via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 17 04:53:44 PDT 2026
https://github.com/amd-bbandlap updated https://github.com/llvm/llvm-project/pull/210004
>From 6381c4d21304d309837ee0b123b04a8b15c97555 Mon Sep 17 00:00:00 2001
From: Balakrishna Bandlapalli <bbandlap at gmail.com>
Date: Thu, 16 Jul 2026 13:27:02 +0530
Subject: [PATCH] [SLP][X86] Add pre-commit tests for merging binary-operator
input operands
Add baseline SLP vectorizer tests covering the merge-input-operands
transform, including cases that exercise IR flag propagation (fast-math
flags, integer nsw/nuw wrap flags, and the exact flag on shifts) onto
the merged operand node. These checks reflect current (pre-transform)
codegen; a follow-up patch enables the transform and updates the checks
to show the delta.
Co-authored-by: Cursor <cursoragent at cursor.com>
---
.../SLPVectorizer/X86/merge-input-operands.ll | 462 ++++++++++++++++++
1 file changed, 462 insertions(+)
create mode 100644 llvm/test/Transforms/SLPVectorizer/X86/merge-input-operands.ll
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/merge-input-operands.ll b/llvm/test/Transforms/SLPVectorizer/X86/merge-input-operands.ll
new file mode 100644
index 0000000000000..16786b42e426e
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/X86/merge-input-operands.ll
@@ -0,0 +1,462 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -mtriple=x86_64-unknown-linux -mcpu=znver4 -passes=slp-vectorizer < %s | FileCheck %s
+
+; The MergeInputOps transform targets a binary-operator bundle whose two operand
+; bundles each reuse a small set of scalars. Here a 4-wide fmul has
+; left operands = [s0, s1, s0, s1]
+; right operands = [s2, s3, s3, s2]
+; and the four sums s0..s3 are all fadd. With merging enabled the union
+; [s0,s1,s2,s3] becomes one <4 x float> add feeding two reuse shuffles; with it
+; disabled the sums are built as two separate <2 x float> adds.
+define void @merge_products_of_sums(ptr %A, ptr %Out) {
+; CHECK-LABEL: @merge_products_of_sums(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[P2:%.*]] = getelementptr float, ptr [[A:%.*]], i64 2
+; CHECK-NEXT: [[P4:%.*]] = getelementptr float, ptr [[A]], i64 4
+; CHECK-NEXT: [[P6:%.*]] = getelementptr float, ptr [[A]], i64 6
+; CHECK-NEXT: [[TMP0:%.*]] = load <2 x float>, ptr [[A]], align 4
+; CHECK-NEXT: [[TMP1:%.*]] = load <2 x float>, ptr [[P2]], align 4
+; CHECK-NEXT: [[TMP2:%.*]] = load <2 x float>, ptr [[P4]], align 4
+; CHECK-NEXT: [[TMP3:%.*]] = load <2 x float>, ptr [[P6]], align 4
+; CHECK-NEXT: [[TMP4:%.*]] = fadd <2 x float> [[TMP0]], [[TMP2]]
+; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <2 x float> [[TMP4]], <2 x float> poison, <4 x i32> <i32 0, i32 1, i32 0, i32 1>
+; CHECK-NEXT: [[TMP6:%.*]] = fadd <2 x float> [[TMP1]], [[TMP3]]
+; CHECK-NEXT: [[TMP7:%.*]] = shufflevector <2 x float> [[TMP6]], <2 x float> poison, <4 x i32> <i32 0, i32 1, i32 1, i32 0>
+; CHECK-NEXT: [[TMP8:%.*]] = fmul <4 x float> [[TMP5]], [[TMP7]]
+; CHECK-NEXT: store <4 x float> [[TMP8]], ptr [[OUT:%.*]], align 4
+; CHECK-NEXT: ret void
+;
+entry:
+ %a0 = load float, ptr %A
+ %p1 = getelementptr float, ptr %A, i64 1
+ %a1 = load float, ptr %p1
+ %p2 = getelementptr float, ptr %A, i64 2
+ %a2 = load float, ptr %p2
+ %p3 = getelementptr float, ptr %A, i64 3
+ %a3 = load float, ptr %p3
+ %p4 = getelementptr float, ptr %A, i64 4
+ %a4 = load float, ptr %p4
+ %p5 = getelementptr float, ptr %A, i64 5
+ %a5 = load float, ptr %p5
+ %p6 = getelementptr float, ptr %A, i64 6
+ %a6 = load float, ptr %p6
+ %p7 = getelementptr float, ptr %A, i64 7
+ %a7 = load float, ptr %p7
+
+ %s0 = fadd float %a0, %a4
+ %s1 = fadd float %a1, %a5
+ %s2 = fadd float %a2, %a6
+ %s3 = fadd float %a3, %a7
+
+ %m0 = fmul float %s0, %s2
+ %m1 = fmul float %s1, %s3
+ %m2 = fmul float %s0, %s3
+ %m3 = fmul float %s1, %s2
+
+ store float %m0, ptr %Out
+ %q1 = getelementptr float, ptr %Out, i64 1
+ store float %m1, ptr %q1
+ %q2 = getelementptr float, ptr %Out, i64 2
+ store float %m2, ptr %q2
+ %q3 = getelementptr float, ptr %Out, i64 3
+ store float %m3, ptr %q3
+ ret void
+}
+
+; Negative: the two operand sides have different opcodes (add vs mul), so the
+; merged bundle would be an alt-shuffle node. Merging must be rejected and the
+; output must be identical with the flag on or off.
+define void @no_merge_mixed_opcode(ptr %A, ptr %Out) {
+; CHECK-LABEL: @no_merge_mixed_opcode(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[V:%.*]] = load <16 x i32>, ptr [[A:%.*]], align 64
+; CHECK-NEXT: [[TMP0:%.*]] = shufflevector <16 x i32> [[V]], <16 x i32> poison, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <16 x i32> [[V]], <16 x i32> poison, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+; CHECK-NEXT: [[TMP2:%.*]] = add <4 x i32> [[TMP0]], [[TMP1]]
+; CHECK-NEXT: [[TMP3:%.*]] = shufflevector <4 x i32> [[TMP2]], <4 x i32> poison, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3>
+; CHECK-NEXT: [[TMP4:%.*]] = mul <4 x i32> [[TMP0]], [[TMP1]]
+; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <4 x i32> [[TMP4]], <4 x i32> poison, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 1, i32 2, i32 3, i32 0>
+; CHECK-NEXT: [[TMP6:%.*]] = sub <8 x i32> [[TMP3]], [[TMP5]]
+; CHECK-NEXT: store <8 x i32> [[TMP6]], ptr [[OUT:%.*]], align 4
+; CHECK-NEXT: ret void
+;
+entry:
+ %v = load <16 x i32>, ptr %A
+ %a0 = extractelement <16 x i32> %v, i64 0
+ %a1 = extractelement <16 x i32> %v, i64 1
+ %a2 = extractelement <16 x i32> %v, i64 2
+ %a3 = extractelement <16 x i32> %v, i64 3
+ %a4 = extractelement <16 x i32> %v, i64 4
+ %a5 = extractelement <16 x i32> %v, i64 5
+ %a6 = extractelement <16 x i32> %v, i64 6
+ %a7 = extractelement <16 x i32> %v, i64 7
+ %l0 = add i32 %a0, %a1
+ %l1 = add i32 %a2, %a3
+ %l2 = add i32 %a4, %a5
+ %l3 = add i32 %a6, %a7
+ %r0 = mul i32 %a0, %a1
+ %r1 = mul i32 %a2, %a3
+ %r2 = mul i32 %a4, %a5
+ %r3 = mul i32 %a6, %a7
+ %m0 = sub i32 %l0, %r0
+ %m1 = sub i32 %l1, %r1
+ %m2 = sub i32 %l2, %r2
+ %m3 = sub i32 %l3, %r3
+ %m4 = sub i32 %l0, %r1
+ %m5 = sub i32 %l1, %r2
+ %m6 = sub i32 %l2, %r3
+ %m7 = sub i32 %l3, %r0
+ store i32 %m0, ptr %Out
+ %o1 = getelementptr i32, ptr %Out, i64 1
+ store i32 %m1, ptr %o1
+ %o2 = getelementptr i32, ptr %Out, i64 2
+ store i32 %m2, ptr %o2
+ %o3 = getelementptr i32, ptr %Out, i64 3
+ store i32 %m3, ptr %o3
+ %o4 = getelementptr i32, ptr %Out, i64 4
+ store i32 %m4, ptr %o4
+ %o5 = getelementptr i32, ptr %Out, i64 5
+ store i32 %m5, ptr %o5
+ %o6 = getelementptr i32, ptr %Out, i64 6
+ store i32 %m6, ptr %o6
+ %o7 = getelementptr i32, ptr %Out, i64 7
+ store i32 %m7, ptr %o7
+ ret void
+}
+
+; Negative: a value (s0) is used on both operand sides, so the merged bundle
+; would contain a duplicate lane. Merging must be rejected.
+define void @no_merge_overlapping_operands(ptr %A, ptr %Out) {
+; CHECK-LABEL: @no_merge_overlapping_operands(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[P1:%.*]] = getelementptr float, ptr [[A:%.*]], i64 1
+; CHECK-NEXT: [[TMP0:%.*]] = load <2 x float>, ptr [[P1]], align 4
+; CHECK-NEXT: [[TMP1:%.*]] = call <6 x float> @llvm.masked.load.v6f32.p0(ptr align 4 [[A]], <6 x i1> <i1 true, i1 false, i1 false, i1 true, i1 true, i1 true>, <6 x float> poison)
+; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <6 x float> [[TMP1]], <6 x float> poison, <4 x i32> <i32 0, i32 3, i32 4, i32 5>
+; CHECK-NEXT: [[TMP3:%.*]] = shufflevector <4 x float> [[TMP2]], <4 x float> poison, <2 x i32> <i32 0, i32 1>
+; CHECK-NEXT: [[TMP4:%.*]] = fadd <2 x float> [[TMP0]], [[TMP3]]
+; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <2 x float> [[TMP4]], <2 x float> poison, <4 x i32> <i32 0, i32 1, i32 0, i32 1>
+; CHECK-NEXT: [[TMP6:%.*]] = shufflevector <6 x float> [[TMP1]], <6 x float> poison, <2 x i32> <i32 0, i32 4>
+; CHECK-NEXT: [[TMP7:%.*]] = shufflevector <2 x float> [[TMP0]], <2 x float> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+; CHECK-NEXT: [[TMP8:%.*]] = shufflevector <4 x float> [[TMP7]], <4 x float> poison, <6 x i32> <i32 0, i32 1, i32 2, i32 3, i32 poison, i32 poison>
+; CHECK-NEXT: [[TMP9:%.*]] = shufflevector <6 x float> [[TMP8]], <6 x float> [[TMP1]], <2 x i32> <i32 0, i32 11>
+; CHECK-NEXT: [[TMP10:%.*]] = fadd <2 x float> [[TMP6]], [[TMP9]]
+; CHECK-NEXT: [[TMP11:%.*]] = shufflevector <2 x float> [[TMP10]], <2 x float> poison, <4 x i32> <i32 0, i32 1, i32 1, i32 0>
+; CHECK-NEXT: [[TMP12:%.*]] = fmul <4 x float> [[TMP5]], [[TMP11]]
+; CHECK-NEXT: store <4 x float> [[TMP12]], ptr [[OUT:%.*]], align 4
+; CHECK-NEXT: ret void
+;
+entry:
+ %a0 = load float, ptr %A
+ %p1 = getelementptr float, ptr %A, i64 1
+ %a1 = load float, ptr %p1
+ %p2 = getelementptr float, ptr %A, i64 2
+ %a2 = load float, ptr %p2
+ %p3 = getelementptr float, ptr %A, i64 3
+ %a3 = load float, ptr %p3
+ %p4 = getelementptr float, ptr %A, i64 4
+ %a4 = load float, ptr %p4
+ %p5 = getelementptr float, ptr %A, i64 5
+ %a5 = load float, ptr %p5
+ %s0 = fadd float %a0, %a1
+ %s1 = fadd float %a2, %a3
+ %s2 = fadd float %a4, %a5
+ %m0 = fmul float %s0, %s0
+ %m1 = fmul float %s1, %s2
+ %m2 = fmul float %s0, %s2
+ %m3 = fmul float %s1, %s0
+ store float %m0, ptr %Out
+ %q1 = getelementptr float, ptr %Out, i64 1
+ store float %m1, ptr %q1
+ %q2 = getelementptr float, ptr %Out, i64 2
+ store float %m2, ptr %q2
+ %q3 = getelementptr float, ptr %Out, i64 3
+ store float %m3, ptr %q3
+ ret void
+}
+
+; Flag propagation: every merged scalar (the four fadd sums) carries the same
+; fast-math flags, so the single merged fadd must keep the full "fast" flag set.
+define void @merge_fmf_uniform(ptr %A, ptr %Out) {
+; CHECK-LABEL: @merge_fmf_uniform(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[P2:%.*]] = getelementptr float, ptr [[A:%.*]], i64 2
+; CHECK-NEXT: [[P4:%.*]] = getelementptr float, ptr [[A]], i64 4
+; CHECK-NEXT: [[P6:%.*]] = getelementptr float, ptr [[A]], i64 6
+; CHECK-NEXT: [[TMP0:%.*]] = load <2 x float>, ptr [[A]], align 4
+; CHECK-NEXT: [[TMP1:%.*]] = load <2 x float>, ptr [[P2]], align 4
+; CHECK-NEXT: [[TMP2:%.*]] = load <2 x float>, ptr [[P4]], align 4
+; CHECK-NEXT: [[TMP3:%.*]] = load <2 x float>, ptr [[P6]], align 4
+; CHECK-NEXT: [[TMP4:%.*]] = fadd fast <2 x float> [[TMP0]], [[TMP2]]
+; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <2 x float> [[TMP4]], <2 x float> poison, <4 x i32> <i32 0, i32 1, i32 0, i32 1>
+; CHECK-NEXT: [[TMP6:%.*]] = fadd fast <2 x float> [[TMP1]], [[TMP3]]
+; CHECK-NEXT: [[TMP7:%.*]] = shufflevector <2 x float> [[TMP6]], <2 x float> poison, <4 x i32> <i32 0, i32 1, i32 1, i32 0>
+; CHECK-NEXT: [[TMP8:%.*]] = fmul fast <4 x float> [[TMP5]], [[TMP7]]
+; CHECK-NEXT: store <4 x float> [[TMP8]], ptr [[OUT:%.*]], align 4
+; CHECK-NEXT: ret void
+;
+entry:
+ %a0 = load float, ptr %A
+ %p1 = getelementptr float, ptr %A, i64 1
+ %a1 = load float, ptr %p1
+ %p2 = getelementptr float, ptr %A, i64 2
+ %a2 = load float, ptr %p2
+ %p3 = getelementptr float, ptr %A, i64 3
+ %a3 = load float, ptr %p3
+ %p4 = getelementptr float, ptr %A, i64 4
+ %a4 = load float, ptr %p4
+ %p5 = getelementptr float, ptr %A, i64 5
+ %a5 = load float, ptr %p5
+ %p6 = getelementptr float, ptr %A, i64 6
+ %a6 = load float, ptr %p6
+ %p7 = getelementptr float, ptr %A, i64 7
+ %a7 = load float, ptr %p7
+
+ %s0 = fadd fast float %a0, %a4
+ %s1 = fadd fast float %a1, %a5
+ %s2 = fadd fast float %a2, %a6
+ %s3 = fadd fast float %a3, %a7
+
+ %m0 = fmul fast float %s0, %s2
+ %m1 = fmul fast float %s1, %s3
+ %m2 = fmul fast float %s0, %s3
+ %m3 = fmul fast float %s1, %s2
+
+ store float %m0, ptr %Out
+ %q1 = getelementptr float, ptr %Out, i64 1
+ store float %m1, ptr %q1
+ %q2 = getelementptr float, ptr %Out, i64 2
+ store float %m2, ptr %q2
+ %q3 = getelementptr float, ptr %Out, i64 3
+ store float %m3, ptr %q3
+ ret void
+}
+
+; Flag propagation: the merged scalars carry different fast-math flags. Two sums
+; are "fast" and two are only "nnan ninf", so the single merged fadd must keep
+; only the common subset ("nnan ninf"), not the full "fast" set.
+define void @merge_fmf_mixed(ptr %A, ptr %Out) {
+; CHECK-LABEL: @merge_fmf_mixed(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[P2:%.*]] = getelementptr float, ptr [[A:%.*]], i64 2
+; CHECK-NEXT: [[P4:%.*]] = getelementptr float, ptr [[A]], i64 4
+; CHECK-NEXT: [[P6:%.*]] = getelementptr float, ptr [[A]], i64 6
+; CHECK-NEXT: [[TMP0:%.*]] = load <2 x float>, ptr [[A]], align 4
+; CHECK-NEXT: [[TMP1:%.*]] = load <2 x float>, ptr [[P2]], align 4
+; CHECK-NEXT: [[TMP2:%.*]] = load <2 x float>, ptr [[P4]], align 4
+; CHECK-NEXT: [[TMP3:%.*]] = load <2 x float>, ptr [[P6]], align 4
+; CHECK-NEXT: [[TMP4:%.*]] = fadd fast <2 x float> [[TMP0]], [[TMP2]]
+; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <2 x float> [[TMP4]], <2 x float> poison, <4 x i32> <i32 0, i32 1, i32 0, i32 1>
+; CHECK-NEXT: [[TMP6:%.*]] = fadd nnan ninf <2 x float> [[TMP1]], [[TMP3]]
+; CHECK-NEXT: [[TMP7:%.*]] = shufflevector <2 x float> [[TMP6]], <2 x float> poison, <4 x i32> <i32 0, i32 1, i32 1, i32 0>
+; CHECK-NEXT: [[TMP8:%.*]] = fmul fast <4 x float> [[TMP5]], [[TMP7]]
+; CHECK-NEXT: store <4 x float> [[TMP8]], ptr [[OUT:%.*]], align 4
+; CHECK-NEXT: ret void
+;
+entry:
+ %a0 = load float, ptr %A
+ %p1 = getelementptr float, ptr %A, i64 1
+ %a1 = load float, ptr %p1
+ %p2 = getelementptr float, ptr %A, i64 2
+ %a2 = load float, ptr %p2
+ %p3 = getelementptr float, ptr %A, i64 3
+ %a3 = load float, ptr %p3
+ %p4 = getelementptr float, ptr %A, i64 4
+ %a4 = load float, ptr %p4
+ %p5 = getelementptr float, ptr %A, i64 5
+ %a5 = load float, ptr %p5
+ %p6 = getelementptr float, ptr %A, i64 6
+ %a6 = load float, ptr %p6
+ %p7 = getelementptr float, ptr %A, i64 7
+ %a7 = load float, ptr %p7
+
+ %s0 = fadd fast float %a0, %a4
+ %s1 = fadd fast float %a1, %a5
+ %s2 = fadd nnan ninf float %a2, %a6
+ %s3 = fadd nnan ninf float %a3, %a7
+
+ %m0 = fmul fast float %s0, %s2
+ %m1 = fmul fast float %s1, %s3
+ %m2 = fmul fast float %s0, %s3
+ %m3 = fmul fast float %s1, %s2
+
+ store float %m0, ptr %Out
+ %q1 = getelementptr float, ptr %Out, i64 1
+ store float %m1, ptr %q1
+ %q2 = getelementptr float, ptr %Out, i64 2
+ store float %m2, ptr %q2
+ %q3 = getelementptr float, ptr %Out, i64 3
+ store float %m3, ptr %q3
+ ret void
+}
+
+; Flag propagation: integer wrap flags. Every merged scalar (the four adds)
+; carries "nsw nuw", so the single merged add must keep both flags.
+define void @merge_int_wrap_uniform(ptr %A, ptr %Out) {
+; CHECK-LABEL: @merge_int_wrap_uniform(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[P2:%.*]] = getelementptr i32, ptr [[A:%.*]], i64 2
+; CHECK-NEXT: [[P4:%.*]] = getelementptr i32, ptr [[A]], i64 4
+; CHECK-NEXT: [[P6:%.*]] = getelementptr i32, ptr [[A]], i64 6
+; CHECK-NEXT: [[TMP0:%.*]] = load <2 x i32>, ptr [[A]], align 4
+; CHECK-NEXT: [[TMP1:%.*]] = load <2 x i32>, ptr [[P2]], align 4
+; CHECK-NEXT: [[TMP2:%.*]] = load <2 x i32>, ptr [[P4]], align 4
+; CHECK-NEXT: [[TMP3:%.*]] = load <2 x i32>, ptr [[P6]], align 4
+; CHECK-NEXT: [[TMP4:%.*]] = add nuw nsw <2 x i32> [[TMP0]], [[TMP2]]
+; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <2 x i32> [[TMP4]], <2 x i32> poison, <4 x i32> <i32 0, i32 1, i32 0, i32 1>
+; CHECK-NEXT: [[TMP6:%.*]] = add nuw nsw <2 x i32> [[TMP1]], [[TMP3]]
+; CHECK-NEXT: [[TMP7:%.*]] = shufflevector <2 x i32> [[TMP6]], <2 x i32> poison, <4 x i32> <i32 0, i32 1, i32 1, i32 0>
+; CHECK-NEXT: [[TMP8:%.*]] = mul <4 x i32> [[TMP5]], [[TMP7]]
+; CHECK-NEXT: store <4 x i32> [[TMP8]], ptr [[OUT:%.*]], align 4
+; CHECK-NEXT: ret void
+;
+entry:
+ %a0 = load i32, ptr %A
+ %p1 = getelementptr i32, ptr %A, i64 1
+ %a1 = load i32, ptr %p1
+ %p2 = getelementptr i32, ptr %A, i64 2
+ %a2 = load i32, ptr %p2
+ %p3 = getelementptr i32, ptr %A, i64 3
+ %a3 = load i32, ptr %p3
+ %p4 = getelementptr i32, ptr %A, i64 4
+ %a4 = load i32, ptr %p4
+ %p5 = getelementptr i32, ptr %A, i64 5
+ %a5 = load i32, ptr %p5
+ %p6 = getelementptr i32, ptr %A, i64 6
+ %a6 = load i32, ptr %p6
+ %p7 = getelementptr i32, ptr %A, i64 7
+ %a7 = load i32, ptr %p7
+
+ %s0 = add nsw nuw i32 %a0, %a4
+ %s1 = add nsw nuw i32 %a1, %a5
+ %s2 = add nsw nuw i32 %a2, %a6
+ %s3 = add nsw nuw i32 %a3, %a7
+
+ %m0 = mul i32 %s0, %s2
+ %m1 = mul i32 %s1, %s3
+ %m2 = mul i32 %s0, %s3
+ %m3 = mul i32 %s1, %s2
+
+ store i32 %m0, ptr %Out
+ %q1 = getelementptr i32, ptr %Out, i64 1
+ store i32 %m1, ptr %q1
+ %q2 = getelementptr i32, ptr %Out, i64 2
+ store i32 %m2, ptr %q2
+ %q3 = getelementptr i32, ptr %Out, i64 3
+ store i32 %m3, ptr %q3
+ ret void
+}
+
+; Flag propagation: mixed integer wrap flags. Two adds carry "nsw nuw" and two
+; carry only "nsw", so the single merged add must keep only "nsw".
+define void @merge_int_wrap_mixed(ptr %A, ptr %Out) {
+; CHECK-LABEL: @merge_int_wrap_mixed(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[P2:%.*]] = getelementptr i32, ptr [[A:%.*]], i64 2
+; CHECK-NEXT: [[P4:%.*]] = getelementptr i32, ptr [[A]], i64 4
+; CHECK-NEXT: [[P6:%.*]] = getelementptr i32, ptr [[A]], i64 6
+; CHECK-NEXT: [[TMP0:%.*]] = load <2 x i32>, ptr [[A]], align 4
+; CHECK-NEXT: [[TMP1:%.*]] = load <2 x i32>, ptr [[P2]], align 4
+; CHECK-NEXT: [[TMP2:%.*]] = load <2 x i32>, ptr [[P4]], align 4
+; CHECK-NEXT: [[TMP3:%.*]] = load <2 x i32>, ptr [[P6]], align 4
+; CHECK-NEXT: [[TMP4:%.*]] = add nuw nsw <2 x i32> [[TMP0]], [[TMP2]]
+; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <2 x i32> [[TMP4]], <2 x i32> poison, <4 x i32> <i32 0, i32 1, i32 0, i32 1>
+; CHECK-NEXT: [[TMP6:%.*]] = add nsw <2 x i32> [[TMP1]], [[TMP3]]
+; CHECK-NEXT: [[TMP7:%.*]] = shufflevector <2 x i32> [[TMP6]], <2 x i32> poison, <4 x i32> <i32 0, i32 1, i32 1, i32 0>
+; CHECK-NEXT: [[TMP8:%.*]] = mul <4 x i32> [[TMP5]], [[TMP7]]
+; CHECK-NEXT: store <4 x i32> [[TMP8]], ptr [[OUT:%.*]], align 4
+; CHECK-NEXT: ret void
+;
+entry:
+ %a0 = load i32, ptr %A
+ %p1 = getelementptr i32, ptr %A, i64 1
+ %a1 = load i32, ptr %p1
+ %p2 = getelementptr i32, ptr %A, i64 2
+ %a2 = load i32, ptr %p2
+ %p3 = getelementptr i32, ptr %A, i64 3
+ %a3 = load i32, ptr %p3
+ %p4 = getelementptr i32, ptr %A, i64 4
+ %a4 = load i32, ptr %p4
+ %p5 = getelementptr i32, ptr %A, i64 5
+ %a5 = load i32, ptr %p5
+ %p6 = getelementptr i32, ptr %A, i64 6
+ %a6 = load i32, ptr %p6
+ %p7 = getelementptr i32, ptr %A, i64 7
+ %a7 = load i32, ptr %p7
+
+ %s0 = add nsw nuw i32 %a0, %a4
+ %s1 = add nsw nuw i32 %a1, %a5
+ %s2 = add nsw i32 %a2, %a6
+ %s3 = add nsw i32 %a3, %a7
+
+ %m0 = mul i32 %s0, %s2
+ %m1 = mul i32 %s1, %s3
+ %m2 = mul i32 %s0, %s3
+ %m3 = mul i32 %s1, %s2
+
+ store i32 %m0, ptr %Out
+ %q1 = getelementptr i32, ptr %Out, i64 1
+ store i32 %m1, ptr %q1
+ %q2 = getelementptr i32, ptr %Out, i64 2
+ store i32 %m2, ptr %q2
+ %q3 = getelementptr i32, ptr %Out, i64 3
+ store i32 %m3, ptr %q3
+ ret void
+}
+
+; Flag propagation: the "exact" flag on shifts. Every merged scalar (the four
+; lshr ops) is "exact", so the single merged lshr must keep "exact".
+define void @merge_exact_shift(ptr %A, ptr %Out) {
+; CHECK-LABEL: @merge_exact_shift(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[P2:%.*]] = getelementptr i32, ptr [[A:%.*]], i64 2
+; CHECK-NEXT: [[P4:%.*]] = getelementptr i32, ptr [[A]], i64 4
+; CHECK-NEXT: [[P6:%.*]] = getelementptr i32, ptr [[A]], i64 6
+; CHECK-NEXT: [[TMP0:%.*]] = load <2 x i32>, ptr [[A]], align 4
+; CHECK-NEXT: [[TMP1:%.*]] = load <2 x i32>, ptr [[P2]], align 4
+; CHECK-NEXT: [[TMP2:%.*]] = load <2 x i32>, ptr [[P4]], align 4
+; CHECK-NEXT: [[TMP3:%.*]] = load <2 x i32>, ptr [[P6]], align 4
+; CHECK-NEXT: [[TMP4:%.*]] = lshr exact <2 x i32> [[TMP0]], [[TMP2]]
+; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <2 x i32> [[TMP4]], <2 x i32> poison, <4 x i32> <i32 0, i32 1, i32 0, i32 1>
+; CHECK-NEXT: [[TMP6:%.*]] = lshr exact <2 x i32> [[TMP1]], [[TMP3]]
+; CHECK-NEXT: [[TMP7:%.*]] = shufflevector <2 x i32> [[TMP6]], <2 x i32> poison, <4 x i32> <i32 0, i32 1, i32 1, i32 0>
+; CHECK-NEXT: [[TMP8:%.*]] = mul <4 x i32> [[TMP5]], [[TMP7]]
+; CHECK-NEXT: store <4 x i32> [[TMP8]], ptr [[OUT:%.*]], align 4
+; CHECK-NEXT: ret void
+;
+entry:
+ %a0 = load i32, ptr %A
+ %p1 = getelementptr i32, ptr %A, i64 1
+ %a1 = load i32, ptr %p1
+ %p2 = getelementptr i32, ptr %A, i64 2
+ %a2 = load i32, ptr %p2
+ %p3 = getelementptr i32, ptr %A, i64 3
+ %a3 = load i32, ptr %p3
+ %p4 = getelementptr i32, ptr %A, i64 4
+ %a4 = load i32, ptr %p4
+ %p5 = getelementptr i32, ptr %A, i64 5
+ %a5 = load i32, ptr %p5
+ %p6 = getelementptr i32, ptr %A, i64 6
+ %a6 = load i32, ptr %p6
+ %p7 = getelementptr i32, ptr %A, i64 7
+ %a7 = load i32, ptr %p7
+
+ %s0 = lshr exact i32 %a0, %a4
+ %s1 = lshr exact i32 %a1, %a5
+ %s2 = lshr exact i32 %a2, %a6
+ %s3 = lshr exact i32 %a3, %a7
+
+ %m0 = mul i32 %s0, %s2
+ %m1 = mul i32 %s1, %s3
+ %m2 = mul i32 %s0, %s3
+ %m3 = mul i32 %s1, %s2
+
+ store i32 %m0, ptr %Out
+ %q1 = getelementptr i32, ptr %Out, i64 1
+ store i32 %m1, ptr %q1
+ %q2 = getelementptr i32, ptr %Out, i64 2
+ store i32 %m2, ptr %q2
+ %q3 = getelementptr i32, ptr %Out, i64 3
+ store i32 %m3, ptr %q3
+ ret void
+}
More information about the llvm-commits
mailing list