[llvm] [NFC][SLP] Precommit tests for the phantom load saving (PR #228901)
Alexey Bataev via llvm-commits
llvm-commits at lists.llvm.org
Sun Oct 4 08:30:54 PDT 2026
================
@@ -0,0 +1,454 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=slp-vectorizer -S -mtriple=amdgpu9.0a-amd-amdhsa < %s | FileCheck %s --check-prefixes=CHECK,GFX9,GFX90A
+; RUN: opt -passes=slp-vectorizer -S -mtriple=amdgpu9.42-amd-amdhsa < %s | FileCheck %s --check-prefixes=CHECK,GFX9,GFX942-950,GFX942
+; RUN: opt -passes=slp-vectorizer -S -mtriple=amdgpu9.50-amd-amdhsa < %s | FileCheck %s --check-prefixes=CHECK,GFX9,GFX942-950,GFX950
+; RUN: opt -passes=slp-vectorizer -S -mtriple=amdgpu10.30-amd-amdhsa < %s | FileCheck %s --check-prefixes=CHECK,GFX1030
+
+; Eight consecutive i8 weights are dequantized against a broadcast zero
+; point and multiplied into an ordered fadd chain. The scalar byte loads
+; already coalesce into one 64 bit load, so the byte loads and their
+; conversions stay scalar. The products stay scalar as well and fuse into
+; the fadd chain. The gfx9 targets subtract the zero point from four lanes
+; as a vector, gfx1030 keeps everything scalar.
+define float @dequant8_ordered(ptr addrspace(1) %mat, ptr addrspace(1) %vec, half %zph, float %acc) {
+; CHECK-LABEL: define float @dequant8_ordered(
+; CHECK-SAME: ptr addrspace(1) [[MAT:%.*]], ptr addrspace(1) [[VEC:%.*]], half [[ZPH:%.*]], float [[ACC:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[ZP:%.*]] = fpext half [[ZPH]] to float
+; CHECK-NEXT: br label %[[BODY:.*]]
+; CHECK: [[BODY]]:
+; CHECK-NEXT: [[TMP0:%.*]] = load <8 x half>, ptr addrspace(1) [[VEC]], align 16
+; CHECK-NEXT: [[TMP1:%.*]] = load <8 x i8>, ptr addrspace(1) [[MAT]], align 2
+; CHECK-NEXT: [[TMP2:%.*]] = fpext <8 x half> [[TMP0]] to <8 x float>
+; CHECK-NEXT: [[TMP3:%.*]] = sitofp <8 x i8> [[TMP1]] to <8 x float>
+; CHECK-NEXT: [[TMP4:%.*]] = insertelement <8 x float> poison, float [[ZP]], i64 0
+; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <8 x float> [[TMP4]], <8 x float> poison, <8 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP6:%.*]] = fsub contract <8 x float> [[TMP3]], [[TMP5]]
+; CHECK-NEXT: [[TMP7:%.*]] = fmul contract <8 x float> [[TMP6]], [[TMP2]]
+; CHECK-NEXT: [[TMP8:%.*]] = extractelement <8 x float> [[TMP7]], i64 0
+; CHECK-NEXT: [[A0:%.*]] = fadd contract float [[ACC]], [[TMP8]]
+; CHECK-NEXT: [[TMP9:%.*]] = extractelement <8 x float> [[TMP7]], i64 1
+; CHECK-NEXT: [[A1:%.*]] = fadd contract float [[A0]], [[TMP9]]
+; CHECK-NEXT: [[TMP10:%.*]] = extractelement <8 x float> [[TMP7]], i64 2
+; CHECK-NEXT: [[A2:%.*]] = fadd contract float [[A1]], [[TMP10]]
+; CHECK-NEXT: [[TMP11:%.*]] = extractelement <8 x float> [[TMP7]], i64 3
+; CHECK-NEXT: [[A3:%.*]] = fadd contract float [[A2]], [[TMP11]]
+; CHECK-NEXT: [[TMP12:%.*]] = extractelement <8 x float> [[TMP7]], i64 4
+; CHECK-NEXT: [[A4:%.*]] = fadd contract float [[A3]], [[TMP12]]
+; CHECK-NEXT: [[TMP13:%.*]] = extractelement <8 x float> [[TMP7]], i64 5
+; CHECK-NEXT: [[A5:%.*]] = fadd contract float [[A4]], [[TMP13]]
+; CHECK-NEXT: [[TMP14:%.*]] = extractelement <8 x float> [[TMP7]], i64 6
+; CHECK-NEXT: [[A6:%.*]] = fadd contract float [[A5]], [[TMP14]]
+; CHECK-NEXT: [[TMP15:%.*]] = extractelement <8 x float> [[TMP7]], i64 7
+; CHECK-NEXT: [[A7:%.*]] = fadd contract float [[A6]], [[TMP15]]
+; CHECK-NEXT: ret float [[A7]]
+;
+entry:
+ %zp = fpext half %zph to float
+ br label %body
+
+body:
+ %v0 = load half, ptr addrspace(1) %vec, align 16
+ %vp1 = getelementptr inbounds i8, ptr addrspace(1) %vec, i64 2
+ %v1 = load half, ptr addrspace(1) %vp1, align 2
+ %vp2 = getelementptr inbounds i8, ptr addrspace(1) %vec, i64 4
+ %v2 = load half, ptr addrspace(1) %vp2, align 4
+ %vp3 = getelementptr inbounds i8, ptr addrspace(1) %vec, i64 6
+ %v3 = load half, ptr addrspace(1) %vp3, align 2
+ %vp4 = getelementptr inbounds i8, ptr addrspace(1) %vec, i64 8
+ %v4 = load half, ptr addrspace(1) %vp4, align 8
+ %vp5 = getelementptr inbounds i8, ptr addrspace(1) %vec, i64 10
+ %v5 = load half, ptr addrspace(1) %vp5, align 2
+ %vp6 = getelementptr inbounds i8, ptr addrspace(1) %vec, i64 12
+ %v6 = load half, ptr addrspace(1) %vp6, align 4
+ %vp7 = getelementptr inbounds i8, ptr addrspace(1) %vec, i64 14
+ %v7 = load half, ptr addrspace(1) %vp7, align 2
+ %q0 = load i8, ptr addrspace(1) %mat, align 2
+ %mp1 = getelementptr inbounds i8, ptr addrspace(1) %mat, i64 1
+ %q1 = load i8, ptr addrspace(1) %mp1, align 1
+ %mp2 = getelementptr inbounds i8, ptr addrspace(1) %mat, i64 2
+ %q2 = load i8, ptr addrspace(1) %mp2, align 2
+ %mp3 = getelementptr inbounds i8, ptr addrspace(1) %mat, i64 3
+ %q3 = load i8, ptr addrspace(1) %mp3, align 1
+ %mp4 = getelementptr inbounds i8, ptr addrspace(1) %mat, i64 4
+ %q4 = load i8, ptr addrspace(1) %mp4, align 2
+ %mp5 = getelementptr inbounds i8, ptr addrspace(1) %mat, i64 5
+ %q5 = load i8, ptr addrspace(1) %mp5, align 1
+ %mp6 = getelementptr inbounds i8, ptr addrspace(1) %mat, i64 6
+ %q6 = load i8, ptr addrspace(1) %mp6, align 2
+ %mp7 = getelementptr inbounds i8, ptr addrspace(1) %mat, i64 7
+ %q7 = load i8, ptr addrspace(1) %mp7, align 1
+ %x0 = fpext half %v0 to float
+ %f0 = sitofp i8 %q0 to float
+ %d0 = fsub contract float %f0, %zp
+ %m0 = fmul contract float %d0, %x0
+ %a0 = fadd contract float %acc, %m0
+ %x1 = fpext half %v1 to float
+ %f1 = sitofp i8 %q1 to float
+ %d1 = fsub contract float %f1, %zp
+ %m1 = fmul contract float %d1, %x1
+ %a1 = fadd contract float %a0, %m1
+ %x2 = fpext half %v2 to float
+ %f2 = sitofp i8 %q2 to float
+ %d2 = fsub contract float %f2, %zp
+ %m2 = fmul contract float %d2, %x2
+ %a2 = fadd contract float %a1, %m2
+ %x3 = fpext half %v3 to float
+ %f3 = sitofp i8 %q3 to float
+ %d3 = fsub contract float %f3, %zp
+ %m3 = fmul contract float %d3, %x3
+ %a3 = fadd contract float %a2, %m3
+ %x4 = fpext half %v4 to float
+ %f4 = sitofp i8 %q4 to float
+ %d4 = fsub contract float %f4, %zp
+ %m4 = fmul contract float %d4, %x4
+ %a4 = fadd contract float %a3, %m4
+ %x5 = fpext half %v5 to float
+ %f5 = sitofp i8 %q5 to float
+ %d5 = fsub contract float %f5, %zp
+ %m5 = fmul contract float %d5, %x5
+ %a5 = fadd contract float %a4, %m5
+ %x6 = fpext half %v6 to float
+ %f6 = sitofp i8 %q6 to float
+ %d6 = fsub contract float %f6, %zp
+ %m6 = fmul contract float %d6, %x6
+ %a6 = fadd contract float %a5, %m6
+ %x7 = fpext half %v7 to float
+ %f7 = sitofp i8 %q7 to float
+ %d7 = fsub contract float %f7, %zp
+ %m7 = fmul contract float %d7, %x7
+ %a7 = fadd contract float %a6, %m7
+ ret float %a7
+}
+
+; A store chain over four converted bytes. The byte loads coalesce, so the
+; loads and the conversions stay scalar. gfx90a stores the converted values
+; with one vector store, gfx942 and gfx950 with two, and gfx1030 keeps the
+; scalar stores.
+define void @store4_sitofp(ptr addrspace(1) %in, ptr addrspace(1) %out) {
+; GFX9-LABEL: define void @store4_sitofp(
+; GFX9-SAME: ptr addrspace(1) [[IN:%.*]], ptr addrspace(1) [[OUT:%.*]]) {
+; GFX9-NEXT: [[TMP1:%.*]] = load <4 x i8>, ptr addrspace(1) [[IN]], align 4
+; GFX9-NEXT: [[TMP2:%.*]] = sitofp <4 x i8> [[TMP1]] to <4 x float>
+; GFX9-NEXT: store <4 x float> [[TMP2]], ptr addrspace(1) [[OUT]], align 16
+; GFX9-NEXT: ret void
+;
+; GFX1030-LABEL: define void @store4_sitofp(
+; GFX1030-SAME: ptr addrspace(1) [[IN:%.*]], ptr addrspace(1) [[OUT:%.*]]) {
+; GFX1030-NEXT: [[P1:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[IN]], i64 1
+; GFX1030-NEXT: [[P2:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[IN]], i64 2
+; GFX1030-NEXT: [[P3:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[IN]], i64 3
+; GFX1030-NEXT: [[Q0:%.*]] = load i8, ptr addrspace(1) [[IN]], align 4
+; GFX1030-NEXT: [[Q1:%.*]] = load i8, ptr addrspace(1) [[P1]], align 1
+; GFX1030-NEXT: [[Q2:%.*]] = load i8, ptr addrspace(1) [[P2]], align 2
+; GFX1030-NEXT: [[Q3:%.*]] = load i8, ptr addrspace(1) [[P3]], align 1
+; GFX1030-NEXT: [[F0:%.*]] = sitofp i8 [[Q0]] to float
+; GFX1030-NEXT: [[F1:%.*]] = sitofp i8 [[Q1]] to float
+; GFX1030-NEXT: [[F2:%.*]] = sitofp i8 [[Q2]] to float
+; GFX1030-NEXT: [[F3:%.*]] = sitofp i8 [[Q3]] to float
+; GFX1030-NEXT: [[O1:%.*]] = getelementptr inbounds float, ptr addrspace(1) [[OUT]], i64 1
+; GFX1030-NEXT: [[O2:%.*]] = getelementptr inbounds float, ptr addrspace(1) [[OUT]], i64 2
+; GFX1030-NEXT: [[O3:%.*]] = getelementptr inbounds float, ptr addrspace(1) [[OUT]], i64 3
+; GFX1030-NEXT: store float [[F0]], ptr addrspace(1) [[OUT]], align 16
+; GFX1030-NEXT: store float [[F1]], ptr addrspace(1) [[O1]], align 4
+; GFX1030-NEXT: store float [[F2]], ptr addrspace(1) [[O2]], align 8
+; GFX1030-NEXT: store float [[F3]], ptr addrspace(1) [[O3]], align 4
+; GFX1030-NEXT: ret void
+;
+ %p1 = getelementptr inbounds i8, ptr addrspace(1) %in, i64 1
+ %p2 = getelementptr inbounds i8, ptr addrspace(1) %in, i64 2
+ %p3 = getelementptr inbounds i8, ptr addrspace(1) %in, i64 3
+ %q0 = load i8, ptr addrspace(1) %in, align 4
+ %q1 = load i8, ptr addrspace(1) %p1, align 1
+ %q2 = load i8, ptr addrspace(1) %p2, align 2
+ %q3 = load i8, ptr addrspace(1) %p3, align 1
+ %f0 = sitofp i8 %q0 to float
+ %f1 = sitofp i8 %q1 to float
+ %f2 = sitofp i8 %q2 to float
+ %f3 = sitofp i8 %q3 to float
+ %o1 = getelementptr inbounds float, ptr addrspace(1) %out, i64 1
+ %o2 = getelementptr inbounds float, ptr addrspace(1) %out, i64 2
+ %o3 = getelementptr inbounds float, ptr addrspace(1) %out, i64 3
+ store float %f0, ptr addrspace(1) %out, align 16
+ store float %f1, ptr addrspace(1) %o1, align 4
+ store float %f2, ptr addrspace(1) %o2, align 8
+ store float %f3, ptr addrspace(1) %o3, align 4
+ ret void
+}
+
+; The same store chain with every byte load aligned to one byte. Global loads
+; coalesce at any alignment, so the loads and the conversions stay scalar.
+define void @store4_sitofp_global_a1(ptr addrspace(1) %in, ptr addrspace(1) %out) {
+; GFX9-LABEL: define void @store4_sitofp_global_a1(
+; GFX9-SAME: ptr addrspace(1) [[IN:%.*]], ptr addrspace(1) [[OUT:%.*]]) {
+; GFX9-NEXT: [[TMP1:%.*]] = load <4 x i8>, ptr addrspace(1) [[IN]], align 1
+; GFX9-NEXT: [[TMP2:%.*]] = sitofp <4 x i8> [[TMP1]] to <4 x float>
+; GFX9-NEXT: store <4 x float> [[TMP2]], ptr addrspace(1) [[OUT]], align 16
+; GFX9-NEXT: ret void
+;
+; GFX1030-LABEL: define void @store4_sitofp_global_a1(
+; GFX1030-SAME: ptr addrspace(1) [[IN:%.*]], ptr addrspace(1) [[OUT:%.*]]) {
+; GFX1030-NEXT: [[P1:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[IN]], i64 1
+; GFX1030-NEXT: [[P2:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[IN]], i64 2
+; GFX1030-NEXT: [[P3:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[IN]], i64 3
+; GFX1030-NEXT: [[Q0:%.*]] = load i8, ptr addrspace(1) [[IN]], align 1
+; GFX1030-NEXT: [[Q1:%.*]] = load i8, ptr addrspace(1) [[P1]], align 1
+; GFX1030-NEXT: [[Q2:%.*]] = load i8, ptr addrspace(1) [[P2]], align 1
+; GFX1030-NEXT: [[Q3:%.*]] = load i8, ptr addrspace(1) [[P3]], align 1
+; GFX1030-NEXT: [[F0:%.*]] = sitofp i8 [[Q0]] to float
+; GFX1030-NEXT: [[F1:%.*]] = sitofp i8 [[Q1]] to float
+; GFX1030-NEXT: [[F2:%.*]] = sitofp i8 [[Q2]] to float
+; GFX1030-NEXT: [[F3:%.*]] = sitofp i8 [[Q3]] to float
+; GFX1030-NEXT: [[O1:%.*]] = getelementptr inbounds float, ptr addrspace(1) [[OUT]], i64 1
+; GFX1030-NEXT: [[O2:%.*]] = getelementptr inbounds float, ptr addrspace(1) [[OUT]], i64 2
+; GFX1030-NEXT: [[O3:%.*]] = getelementptr inbounds float, ptr addrspace(1) [[OUT]], i64 3
+; GFX1030-NEXT: store float [[F0]], ptr addrspace(1) [[OUT]], align 16
+; GFX1030-NEXT: store float [[F1]], ptr addrspace(1) [[O1]], align 4
+; GFX1030-NEXT: store float [[F2]], ptr addrspace(1) [[O2]], align 8
+; GFX1030-NEXT: store float [[F3]], ptr addrspace(1) [[O3]], align 4
+; GFX1030-NEXT: ret void
+;
+ %p1 = getelementptr inbounds i8, ptr addrspace(1) %in, i64 1
+ %p2 = getelementptr inbounds i8, ptr addrspace(1) %in, i64 2
+ %p3 = getelementptr inbounds i8, ptr addrspace(1) %in, i64 3
+ %q0 = load i8, ptr addrspace(1) %in, align 1
+ %q1 = load i8, ptr addrspace(1) %p1, align 1
+ %q2 = load i8, ptr addrspace(1) %p2, align 1
+ %q3 = load i8, ptr addrspace(1) %p3, align 1
+ %f0 = sitofp i8 %q0 to float
+ %f1 = sitofp i8 %q1 to float
+ %f2 = sitofp i8 %q2 to float
+ %f3 = sitofp i8 %q3 to float
+ %o1 = getelementptr inbounds float, ptr addrspace(1) %out, i64 1
+ %o2 = getelementptr inbounds float, ptr addrspace(1) %out, i64 2
+ %o3 = getelementptr inbounds float, ptr addrspace(1) %out, i64 3
+ store float %f0, ptr addrspace(1) %out, align 16
+ store float %f1, ptr addrspace(1) %o1, align 4
+ store float %f2, ptr addrspace(1) %o2, align 8
+ store float %f3, ptr addrspace(1) %o3, align 4
+ ret void
+}
+
+; The same store chain over LDS with the first byte load aligned to four. The
+; byte loads coalesce into one dword load, so the loads and the conversions
+; stay scalar.
+define void @store4_sitofp_lds_a4(ptr addrspace(3) %in, ptr addrspace(1) %out) {
+; GFX9-LABEL: define void @store4_sitofp_lds_a4(
+; GFX9-SAME: ptr addrspace(3) [[IN:%.*]], ptr addrspace(1) [[OUT:%.*]]) {
+; GFX9-NEXT: [[TMP1:%.*]] = load <4 x i8>, ptr addrspace(3) [[IN]], align 4
+; GFX9-NEXT: [[TMP2:%.*]] = sitofp <4 x i8> [[TMP1]] to <4 x float>
+; GFX9-NEXT: store <4 x float> [[TMP2]], ptr addrspace(1) [[OUT]], align 16
+; GFX9-NEXT: ret void
+;
+; GFX1030-LABEL: define void @store4_sitofp_lds_a4(
+; GFX1030-SAME: ptr addrspace(3) [[IN:%.*]], ptr addrspace(1) [[OUT:%.*]]) {
+; GFX1030-NEXT: [[P1:%.*]] = getelementptr inbounds i8, ptr addrspace(3) [[IN]], i32 1
+; GFX1030-NEXT: [[P2:%.*]] = getelementptr inbounds i8, ptr addrspace(3) [[IN]], i32 2
+; GFX1030-NEXT: [[P3:%.*]] = getelementptr inbounds i8, ptr addrspace(3) [[IN]], i32 3
+; GFX1030-NEXT: [[Q0:%.*]] = load i8, ptr addrspace(3) [[IN]], align 4
+; GFX1030-NEXT: [[Q1:%.*]] = load i8, ptr addrspace(3) [[P1]], align 1
+; GFX1030-NEXT: [[Q2:%.*]] = load i8, ptr addrspace(3) [[P2]], align 2
+; GFX1030-NEXT: [[Q3:%.*]] = load i8, ptr addrspace(3) [[P3]], align 1
+; GFX1030-NEXT: [[F0:%.*]] = sitofp i8 [[Q0]] to float
+; GFX1030-NEXT: [[F1:%.*]] = sitofp i8 [[Q1]] to float
+; GFX1030-NEXT: [[F2:%.*]] = sitofp i8 [[Q2]] to float
+; GFX1030-NEXT: [[F3:%.*]] = sitofp i8 [[Q3]] to float
+; GFX1030-NEXT: [[O1:%.*]] = getelementptr inbounds float, ptr addrspace(1) [[OUT]], i64 1
+; GFX1030-NEXT: [[O2:%.*]] = getelementptr inbounds float, ptr addrspace(1) [[OUT]], i64 2
+; GFX1030-NEXT: [[O3:%.*]] = getelementptr inbounds float, ptr addrspace(1) [[OUT]], i64 3
+; GFX1030-NEXT: store float [[F0]], ptr addrspace(1) [[OUT]], align 16
+; GFX1030-NEXT: store float [[F1]], ptr addrspace(1) [[O1]], align 4
+; GFX1030-NEXT: store float [[F2]], ptr addrspace(1) [[O2]], align 8
+; GFX1030-NEXT: store float [[F3]], ptr addrspace(1) [[O3]], align 4
+; GFX1030-NEXT: ret void
+;
+ %p1 = getelementptr inbounds i8, ptr addrspace(3) %in, i32 1
+ %p2 = getelementptr inbounds i8, ptr addrspace(3) %in, i32 2
+ %p3 = getelementptr inbounds i8, ptr addrspace(3) %in, i32 3
+ %q0 = load i8, ptr addrspace(3) %in, align 4
+ %q1 = load i8, ptr addrspace(3) %p1, align 1
+ %q2 = load i8, ptr addrspace(3) %p2, align 2
+ %q3 = load i8, ptr addrspace(3) %p3, align 1
+ %f0 = sitofp i8 %q0 to float
+ %f1 = sitofp i8 %q1 to float
+ %f2 = sitofp i8 %q2 to float
+ %f3 = sitofp i8 %q3 to float
+ %o1 = getelementptr inbounds float, ptr addrspace(1) %out, i64 1
+ %o2 = getelementptr inbounds float, ptr addrspace(1) %out, i64 2
+ %o3 = getelementptr inbounds float, ptr addrspace(1) %out, i64 3
+ store float %f0, ptr addrspace(1) %out, align 16
+ store float %f1, ptr addrspace(1) %o1, align 4
+ store float %f2, ptr addrspace(1) %o2, align 8
+ store float %f3, ptr addrspace(1) %o3, align 4
+ ret void
+}
+
+; The same store chain over LDS with every byte load aligned to one byte. The
+; backend does not merge these byte loads, so the vector load keeps its saving.
+; The gfx9 targets load, convert and store as vectors, gfx1030 keeps the scalar
+; form.
+define void @store4_sitofp_lds_a1(ptr addrspace(3) %in, ptr addrspace(1) %out) {
+; GFX9-LABEL: define void @store4_sitofp_lds_a1(
+; GFX9-SAME: ptr addrspace(3) [[IN:%.*]], ptr addrspace(1) [[OUT:%.*]]) {
+; GFX9-NEXT: [[TMP1:%.*]] = load <4 x i8>, ptr addrspace(3) [[IN]], align 1
+; GFX9-NEXT: [[TMP2:%.*]] = sitofp <4 x i8> [[TMP1]] to <4 x float>
+; GFX9-NEXT: store <4 x float> [[TMP2]], ptr addrspace(1) [[OUT]], align 16
+; GFX9-NEXT: ret void
+;
+; GFX1030-LABEL: define void @store4_sitofp_lds_a1(
+; GFX1030-SAME: ptr addrspace(3) [[IN:%.*]], ptr addrspace(1) [[OUT:%.*]]) {
+; GFX1030-NEXT: [[P1:%.*]] = getelementptr inbounds i8, ptr addrspace(3) [[IN]], i32 1
+; GFX1030-NEXT: [[P2:%.*]] = getelementptr inbounds i8, ptr addrspace(3) [[IN]], i32 2
+; GFX1030-NEXT: [[P3:%.*]] = getelementptr inbounds i8, ptr addrspace(3) [[IN]], i32 3
+; GFX1030-NEXT: [[Q0:%.*]] = load i8, ptr addrspace(3) [[IN]], align 1
+; GFX1030-NEXT: [[Q1:%.*]] = load i8, ptr addrspace(3) [[P1]], align 1
+; GFX1030-NEXT: [[Q2:%.*]] = load i8, ptr addrspace(3) [[P2]], align 1
+; GFX1030-NEXT: [[Q3:%.*]] = load i8, ptr addrspace(3) [[P3]], align 1
+; GFX1030-NEXT: [[F0:%.*]] = sitofp i8 [[Q0]] to float
+; GFX1030-NEXT: [[F1:%.*]] = sitofp i8 [[Q1]] to float
+; GFX1030-NEXT: [[F2:%.*]] = sitofp i8 [[Q2]] to float
+; GFX1030-NEXT: [[F3:%.*]] = sitofp i8 [[Q3]] to float
+; GFX1030-NEXT: [[O1:%.*]] = getelementptr inbounds float, ptr addrspace(1) [[OUT]], i64 1
+; GFX1030-NEXT: [[O2:%.*]] = getelementptr inbounds float, ptr addrspace(1) [[OUT]], i64 2
+; GFX1030-NEXT: [[O3:%.*]] = getelementptr inbounds float, ptr addrspace(1) [[OUT]], i64 3
+; GFX1030-NEXT: store float [[F0]], ptr addrspace(1) [[OUT]], align 16
+; GFX1030-NEXT: store float [[F1]], ptr addrspace(1) [[O1]], align 4
+; GFX1030-NEXT: store float [[F2]], ptr addrspace(1) [[O2]], align 8
+; GFX1030-NEXT: store float [[F3]], ptr addrspace(1) [[O3]], align 4
+; GFX1030-NEXT: ret void
+;
+ %p1 = getelementptr inbounds i8, ptr addrspace(3) %in, i32 1
+ %p2 = getelementptr inbounds i8, ptr addrspace(3) %in, i32 2
+ %p3 = getelementptr inbounds i8, ptr addrspace(3) %in, i32 3
+ %q0 = load i8, ptr addrspace(3) %in, align 1
+ %q1 = load i8, ptr addrspace(3) %p1, align 1
+ %q2 = load i8, ptr addrspace(3) %p2, align 1
+ %q3 = load i8, ptr addrspace(3) %p3, align 1
+ %f0 = sitofp i8 %q0 to float
+ %f1 = sitofp i8 %q1 to float
+ %f2 = sitofp i8 %q2 to float
+ %f3 = sitofp i8 %q3 to float
+ %o1 = getelementptr inbounds float, ptr addrspace(1) %out, i64 1
+ %o2 = getelementptr inbounds float, ptr addrspace(1) %out, i64 2
+ %o3 = getelementptr inbounds float, ptr addrspace(1) %out, i64 3
+ store float %f0, ptr addrspace(1) %out, align 16
+ store float %f1, ptr addrspace(1) %o1, align 4
+ store float %f2, ptr addrspace(1) %o2, align 8
+ store float %f3, ptr addrspace(1) %o3, align 4
+ ret void
+}
+
+; Four zero extended bytes are inserted into a vector that is stored, inside a
+; loop of 16 iterations. The byte loads coalesce, and the load saving that never
+; materializes is cancelled in every iteration, so the loop body stays scalar.
+define void @zext4_bv_loop(ptr addrspace(1) %a, ptr addrspace(1) %out) {
+; CHECK-LABEL: define void @zext4_bv_loop(
+; CHECK-SAME: ptr addrspace(1) [[A:%.*]], ptr addrspace(1) [[OUT:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT: [[OFF:%.*]] = shl i64 [[I]], 2
+; CHECK-NEXT: [[P0:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[A]], i64 [[OFF]]
+; CHECK-NEXT: [[TMP0:%.*]] = load <4 x i8>, ptr addrspace(1) [[P0]], align 4
+; CHECK-NEXT: [[V3:%.*]] = zext <4 x i8> [[TMP0]] to <4 x i32>
+; CHECK-NEXT: [[PO:%.*]] = getelementptr inbounds <4 x i32>, ptr addrspace(1) [[OUT]], i64 [[I]]
+; CHECK-NEXT: store <4 x i32> [[V3]], ptr addrspace(1) [[PO]], align 16
+; CHECK-NEXT: [[I_NEXT]] = add nuw nsw i64 [[I]], 1
+; CHECK-NEXT: [[C:%.*]] = icmp ult i64 [[I_NEXT]], 16
+; CHECK-NEXT: br i1 [[C]], label %[[LOOP]], label %[[EXIT:.*]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
+entry:
+ br label %loop
+loop:
+ %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+ %off = shl i64 %i, 2
+ %p0 = getelementptr inbounds i8, ptr addrspace(1) %a, i64 %off
+ %p1 = getelementptr inbounds i8, ptr addrspace(1) %p0, i64 1
+ %p2 = getelementptr inbounds i8, ptr addrspace(1) %p0, i64 2
+ %p3 = getelementptr inbounds i8, ptr addrspace(1) %p0, i64 3
+ %l0 = load i8, ptr addrspace(1) %p0, align 4
+ %l1 = load i8, ptr addrspace(1) %p1, align 1
+ %l2 = load i8, ptr addrspace(1) %p2, align 2
+ %l3 = load i8, ptr addrspace(1) %p3, align 1
+ %x0 = zext i8 %l0 to i32
+ %x1 = zext i8 %l1 to i32
+ %x2 = zext i8 %l2 to i32
+ %x3 = zext i8 %l3 to i32
+ %v0 = insertelement <4 x i32> poison, i32 %x0, i32 0
+ %v1 = insertelement <4 x i32> %v0, i32 %x1, i32 1
+ %v2 = insertelement <4 x i32> %v1, i32 %x2, i32 2
+ %v3 = insertelement <4 x i32> %v2, i32 %x3, i32 3
+ %po = getelementptr inbounds <4 x i32>, ptr addrspace(1) %out, i64 %i
+ store <4 x i32> %v3, ptr addrspace(1) %po, align 16
+ %i.next = add nuw nsw i64 %i, 1
+ %c = icmp ult i64 %i.next, 16
+ br i1 %c, label %loop, label %exit
+exit:
+ ret void
+}
+
+; Eight bytes are converted to half and stored. Two half lanes fit one
+; register, so the byte loads keep their saving and the loads, the conversions
+; and the stores stay vectorized. On gfx1250 the scalar form takes 37
+; instructions against 27 for the vector form.
+define void @store8_sitofp_half(ptr addrspace(1) %in, ptr addrspace(1) %out) {
+; CHECK-LABEL: define void @store8_sitofp_half(
+; CHECK-SAME: ptr addrspace(1) [[IN:%.*]], ptr addrspace(1) [[OUT:%.*]]) {
+; CHECK-NEXT: [[P4:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[IN]], i64 4
+; CHECK-NEXT: [[O4:%.*]] = getelementptr inbounds half, ptr addrspace(1) [[OUT]], i64 4
+; CHECK-NEXT: [[TMP1:%.*]] = load <4 x i8>, ptr addrspace(1) [[IN]], align 8
+; CHECK-NEXT: [[TMP2:%.*]] = sitofp <4 x i8> [[TMP1]] to <4 x half>
+; CHECK-NEXT: [[TMP3:%.*]] = load <4 x i8>, ptr addrspace(1) [[P4]], align 4
+; CHECK-NEXT: [[TMP4:%.*]] = sitofp <4 x i8> [[TMP3]] to <4 x half>
+; CHECK-NEXT: store <4 x half> [[TMP2]], ptr addrspace(1) [[OUT]], align 16
+; CHECK-NEXT: store <4 x half> [[TMP4]], ptr addrspace(1) [[O4]], align 8
+; CHECK-NEXT: ret void
+;
+ %p1 = getelementptr inbounds i8, ptr addrspace(1) %in, i64 1
+ %p2 = getelementptr inbounds i8, ptr addrspace(1) %in, i64 2
+ %p3 = getelementptr inbounds i8, ptr addrspace(1) %in, i64 3
+ %p4 = getelementptr inbounds i8, ptr addrspace(1) %in, i64 4
+ %p5 = getelementptr inbounds i8, ptr addrspace(1) %in, i64 5
+ %p6 = getelementptr inbounds i8, ptr addrspace(1) %in, i64 6
+ %p7 = getelementptr inbounds i8, ptr addrspace(1) %in, i64 7
+ %q0 = load i8, ptr addrspace(1) %in, align 8
+ %q1 = load i8, ptr addrspace(1) %p1, align 1
+ %q2 = load i8, ptr addrspace(1) %p2, align 2
+ %q3 = load i8, ptr addrspace(1) %p3, align 1
+ %q4 = load i8, ptr addrspace(1) %p4, align 4
+ %q5 = load i8, ptr addrspace(1) %p5, align 1
+ %q6 = load i8, ptr addrspace(1) %p6, align 2
+ %q7 = load i8, ptr addrspace(1) %p7, align 1
+ %f0 = sitofp i8 %q0 to half
+ %f1 = sitofp i8 %q1 to half
+ %f2 = sitofp i8 %q2 to half
+ %f3 = sitofp i8 %q3 to half
+ %f4 = sitofp i8 %q4 to half
+ %f5 = sitofp i8 %q5 to half
+ %f6 = sitofp i8 %q6 to half
+ %f7 = sitofp i8 %q7 to half
+ %o1 = getelementptr inbounds half, ptr addrspace(1) %out, i64 1
+ %o2 = getelementptr inbounds half, ptr addrspace(1) %out, i64 2
+ %o3 = getelementptr inbounds half, ptr addrspace(1) %out, i64 3
+ %o4 = getelementptr inbounds half, ptr addrspace(1) %out, i64 4
+ %o5 = getelementptr inbounds half, ptr addrspace(1) %out, i64 5
+ %o6 = getelementptr inbounds half, ptr addrspace(1) %out, i64 6
+ %o7 = getelementptr inbounds half, ptr addrspace(1) %out, i64 7
+ store half %f0, ptr addrspace(1) %out, align 16
+ store half %f1, ptr addrspace(1) %o1, align 2
+ store half %f2, ptr addrspace(1) %o2, align 4
+ store half %f3, ptr addrspace(1) %o3, align 2
+ store half %f4, ptr addrspace(1) %o4, align 8
+ store half %f5, ptr addrspace(1) %o5, align 2
+ store half %f6, ptr addrspace(1) %o6, align 4
+ store half %f7, ptr addrspace(1) %o7, align 2
+ ret void
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
----------------
alexey-bataev wrote:
It should be cleared
https://github.com/llvm/llvm-project/pull/228901
More information about the llvm-commits
mailing list