Files
clang-p2996/llvm/test/CodeGen/AArch64/sinksplat.ll
David Green 50af82701c [AArch64] Cost all perfect shuffles entries as cost 1
A brief introduction to perfect shuffles - AArch64 NEON has a number of
shuffle operations - dups, zips, exts, movs etc that can in some way
shuffle around the lanes of a vector. Given a shuffle of size 4 with 2
inputs, some shuffle masks can be easily codegen'd to a single
instruction. A <0,0,1,1> mask for example is a zip LHS, LHS. This is
great, but some masks are not so simple, like a <0,0,1,2>. It turns out
we can generate that from zip LHS, <0,2,0,2>, having generated
<0,2,0,2> from uzp LHS, LHS, producing the result in 2 instructions.

It is not obvious from a given mask how to get there though. So we have
a simple program (PerfectShuffle.cpp in the util folder) that can scan
through all combinations of 4-element vectors and generate the perfect
combination of results needed for each shuffle mask (for some definition
of perfect). This is run offline to generate a table that is queried for
generating shuffle instructions. (Because the table could get quite big,
it is limited to 4 element vectors).

In the perfect shuffle tables zip, unz and trn shuffles were being cost
as 2, which is higher than needed and skews the perfect shuffle tables
to create inefficient combinations. This sets them to 1 and regenerates
the tables. The codegen will usually be better and the costs should be
more precise (but it can get less second-order re-use of values from
multiple shuffles, these cases should be fixed up in subsequent patches.

Differential Revision: https://reviews.llvm.org/D123379
2022-04-19 12:05:05 +01:00

375 lines
12 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=aarch64-linux-gnu -o - %s | FileCheck %s
define <4 x i32> @smull(<4 x i16> %x, <4 x i16> *%y) {
; CHECK-LABEL: smull:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: fmov d1, d0
; CHECK-NEXT: mov w8, #1
; CHECK-NEXT: movi v0.2d, #0000000000000000
; CHECK-NEXT: .LBB0_1: // %l1
; CHECK-NEXT: // =>This Inner Loop Header: Depth=1
; CHECK-NEXT: ldr d2, [x0]
; CHECK-NEXT: subs w8, w8, #1
; CHECK-NEXT: smlal v0.4s, v2.4h, v1.h[3]
; CHECK-NEXT: b.eq .LBB0_1
; CHECK-NEXT: // %bb.2: // %l2
; CHECK-NEXT: ret
entry:
%a = shufflevector <4 x i16> %x, <4 x i16> undef, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
br label %l1
l1:
%p = phi i32 [ 0, %entry ], [ %pa, %l1 ]
%q = phi <4 x i32> [ zeroinitializer, %entry ], [ %c, %l1 ]
%l = load <4 x i16>, <4 x i16> *%y
%b = tail call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %l, <4 x i16> %a)
%c = add nsw <4 x i32> %q, %b
%pa = add i32 %p, 1
%c1 = icmp eq i32 %p, 0
br i1 %c1, label %l1, label %l2
l2:
ret <4 x i32> %c
}
define <4 x i32> @umull(<4 x i16> %x, <4 x i16> *%y) {
; CHECK-LABEL: umull:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: fmov d1, d0
; CHECK-NEXT: mov w8, #1
; CHECK-NEXT: movi v0.2d, #0000000000000000
; CHECK-NEXT: .LBB1_1: // %l1
; CHECK-NEXT: // =>This Inner Loop Header: Depth=1
; CHECK-NEXT: ldr d2, [x0]
; CHECK-NEXT: subs w8, w8, #1
; CHECK-NEXT: umlal v0.4s, v2.4h, v1.h[3]
; CHECK-NEXT: b.eq .LBB1_1
; CHECK-NEXT: // %bb.2: // %l2
; CHECK-NEXT: ret
entry:
%a = shufflevector <4 x i16> %x, <4 x i16> undef, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
br label %l1
l1:
%p = phi i32 [ 0, %entry ], [ %pa, %l1 ]
%q = phi <4 x i32> [ zeroinitializer, %entry ], [ %c, %l1 ]
%l = load <4 x i16>, <4 x i16> *%y
%b = tail call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %l, <4 x i16> %a)
%c = add nsw <4 x i32> %q, %b
%pa = add i32 %p, 1
%c1 = icmp eq i32 %p, 0
br i1 %c1, label %l1, label %l2
l2:
ret <4 x i32> %c
}
define <4 x i32> @sqadd(<4 x i32> %x, <4 x i32> *%y) {
; CHECK-LABEL: sqadd:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov v1.16b, v0.16b
; CHECK-NEXT: mov w8, #1
; CHECK-NEXT: movi v0.2d, #0000000000000000
; CHECK-NEXT: .LBB2_1: // %l1
; CHECK-NEXT: // =>This Inner Loop Header: Depth=1
; CHECK-NEXT: ldr q2, [x0]
; CHECK-NEXT: subs w8, w8, #1
; CHECK-NEXT: sqrdmulh v2.4s, v2.4s, v1.s[3]
; CHECK-NEXT: sqadd v0.4s, v0.4s, v2.4s
; CHECK-NEXT: b.eq .LBB2_1
; CHECK-NEXT: // %bb.2: // %l2
; CHECK-NEXT: ret
entry:
%a = shufflevector <4 x i32> %x, <4 x i32> undef, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
br label %l1
l1:
%p = phi i32 [ 0, %entry ], [ %pa, %l1 ]
%q = phi <4 x i32> [ zeroinitializer, %entry ], [ %c, %l1 ]
%l = load <4 x i32>, <4 x i32> *%y
%b = tail call <4 x i32> @llvm.aarch64.neon.sqrdmulh.v4i32(<4 x i32> %l, <4 x i32> %a)
%c = tail call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %q, <4 x i32> %b)
%pa = add i32 %p, 1
%c1 = icmp eq i32 %p, 0
br i1 %c1, label %l1, label %l2
l2:
ret <4 x i32> %c
}
define <4 x i32> @sqsub(<4 x i32> %x, <4 x i32> *%y) {
; CHECK-LABEL: sqsub:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov v1.16b, v0.16b
; CHECK-NEXT: mov w8, #1
; CHECK-NEXT: movi v0.2d, #0000000000000000
; CHECK-NEXT: .LBB3_1: // %l1
; CHECK-NEXT: // =>This Inner Loop Header: Depth=1
; CHECK-NEXT: ldr q2, [x0]
; CHECK-NEXT: subs w8, w8, #1
; CHECK-NEXT: sqrdmulh v2.4s, v2.4s, v1.s[3]
; CHECK-NEXT: sqsub v0.4s, v0.4s, v2.4s
; CHECK-NEXT: b.eq .LBB3_1
; CHECK-NEXT: // %bb.2: // %l2
; CHECK-NEXT: ret
entry:
%a = shufflevector <4 x i32> %x, <4 x i32> undef, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
br label %l1
l1:
%p = phi i32 [ 0, %entry ], [ %pa, %l1 ]
%q = phi <4 x i32> [ zeroinitializer, %entry ], [ %c, %l1 ]
%l = load <4 x i32>, <4 x i32> *%y
%b = tail call <4 x i32> @llvm.aarch64.neon.sqrdmulh.v4i32(<4 x i32> %l, <4 x i32> %a)
%c = tail call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %q, <4 x i32> %b)
%pa = add i32 %p, 1
%c1 = icmp eq i32 %p, 0
br i1 %c1, label %l1, label %l2
l2:
ret <4 x i32> %c
}
define <4 x i32> @sqdmulh(<4 x i32> %x, <4 x i32> *%y) {
; CHECK-LABEL: sqdmulh:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov v1.16b, v0.16b
; CHECK-NEXT: mov w8, #1
; CHECK-NEXT: movi v0.2d, #0000000000000000
; CHECK-NEXT: .LBB4_1: // %l1
; CHECK-NEXT: // =>This Inner Loop Header: Depth=1
; CHECK-NEXT: ldr q2, [x0]
; CHECK-NEXT: subs w8, w8, #1
; CHECK-NEXT: sqdmulh v2.4s, v2.4s, v1.s[3]
; CHECK-NEXT: add v0.4s, v0.4s, v2.4s
; CHECK-NEXT: b.eq .LBB4_1
; CHECK-NEXT: // %bb.2: // %l2
; CHECK-NEXT: ret
entry:
%a = shufflevector <4 x i32> %x, <4 x i32> undef, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
br label %l1
l1:
%p = phi i32 [ 0, %entry ], [ %pa, %l1 ]
%q = phi <4 x i32> [ zeroinitializer, %entry ], [ %c, %l1 ]
%l = load <4 x i32>, <4 x i32> *%y
%b = tail call <4 x i32> @llvm.aarch64.neon.sqdmulh.v4i32(<4 x i32> %l, <4 x i32> %a)
%c = add nsw <4 x i32> %q, %b
%pa = add i32 %p, 1
%c1 = icmp eq i32 %p, 0
br i1 %c1, label %l1, label %l2
l2:
ret <4 x i32> %c
}
define <4 x i32> @sqdmull(<4 x i16> %x, <4 x i16> *%y) {
; CHECK-LABEL: sqdmull:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: fmov d1, d0
; CHECK-NEXT: mov w8, #1
; CHECK-NEXT: movi v0.2d, #0000000000000000
; CHECK-NEXT: .LBB5_1: // %l1
; CHECK-NEXT: // =>This Inner Loop Header: Depth=1
; CHECK-NEXT: ldr d2, [x0]
; CHECK-NEXT: subs w8, w8, #1
; CHECK-NEXT: sqdmull v2.4s, v2.4h, v1.h[3]
; CHECK-NEXT: add v0.4s, v0.4s, v2.4s
; CHECK-NEXT: b.eq .LBB5_1
; CHECK-NEXT: // %bb.2: // %l2
; CHECK-NEXT: ret
entry:
%a = shufflevector <4 x i16> %x, <4 x i16> undef, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
br label %l1
l1:
%p = phi i32 [ 0, %entry ], [ %pa, %l1 ]
%q = phi <4 x i32> [ zeroinitializer, %entry ], [ %c, %l1 ]
%l = load <4 x i16>, <4 x i16> *%y
%b = tail call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %l, <4 x i16> %a)
%c = add nsw <4 x i32> %q, %b
%pa = add i32 %p, 1
%c1 = icmp eq i32 %p, 0
br i1 %c1, label %l1, label %l2
l2:
ret <4 x i32> %c
}
define <4 x i32> @mlal(<4 x i32> %x, <4 x i32> *%y) {
; CHECK-LABEL: mlal:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov v1.16b, v0.16b
; CHECK-NEXT: mov w8, #1
; CHECK-NEXT: movi v0.2d, #0000000000000000
; CHECK-NEXT: dup v1.4s, v1.s[3]
; CHECK-NEXT: .LBB6_1: // %l1
; CHECK-NEXT: // =>This Inner Loop Header: Depth=1
; CHECK-NEXT: ldr q2, [x0]
; CHECK-NEXT: subs w8, w8, #1
; CHECK-NEXT: mla v0.4s, v2.4s, v1.4s
; CHECK-NEXT: b.eq .LBB6_1
; CHECK-NEXT: // %bb.2: // %l2
; CHECK-NEXT: ret
entry:
%a = shufflevector <4 x i32> %x, <4 x i32> undef, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
br label %l1
l1:
%p = phi i32 [ 0, %entry ], [ %pa, %l1 ]
%q = phi <4 x i32> [ zeroinitializer, %entry ], [ %c, %l1 ]
%l = load <4 x i32>, <4 x i32> *%y
%b = mul <4 x i32> %l, %a
%c = add <4 x i32> %q, %b
%pa = add i32 %p, 1
%c1 = icmp eq i32 %p, 0
br i1 %c1, label %l1, label %l2
l2:
ret <4 x i32> %c
}
define <4 x float> @fmul(<4 x float> %x, <4 x float> *%y) {
; CHECK-LABEL: fmul:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov v1.16b, v0.16b
; CHECK-NEXT: mov w8, #1
; CHECK-NEXT: movi v0.2d, #0000000000000000
; CHECK-NEXT: .LBB7_1: // %l1
; CHECK-NEXT: // =>This Inner Loop Header: Depth=1
; CHECK-NEXT: ldr q2, [x0]
; CHECK-NEXT: subs w8, w8, #1
; CHECK-NEXT: fmul v2.4s, v2.4s, v1.s[3]
; CHECK-NEXT: fadd v0.4s, v2.4s, v0.4s
; CHECK-NEXT: b.eq .LBB7_1
; CHECK-NEXT: // %bb.2: // %l2
; CHECK-NEXT: ret
entry:
%a = shufflevector <4 x float> %x, <4 x float> undef, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
br label %l1
l1:
%p = phi i32 [ 0, %entry ], [ %pa, %l1 ]
%q = phi <4 x float> [ zeroinitializer, %entry ], [ %c, %l1 ]
%l = load <4 x float>, <4 x float> *%y
%b = fmul <4 x float> %l, %a
%c = fadd <4 x float> %b, %q
%pa = add i32 %p, 1
%c1 = icmp eq i32 %p, 0
br i1 %c1, label %l1, label %l2
l2:
ret <4 x float> %c
}
define <4 x float> @fmuladd(<4 x float> %x, <4 x float> *%y) {
; CHECK-LABEL: fmuladd:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov v1.16b, v0.16b
; CHECK-NEXT: mov w8, #1
; CHECK-NEXT: movi v0.2d, #0000000000000000
; CHECK-NEXT: dup v1.4s, v1.s[3]
; CHECK-NEXT: .LBB8_1: // %l1
; CHECK-NEXT: // =>This Inner Loop Header: Depth=1
; CHECK-NEXT: ldr q2, [x0]
; CHECK-NEXT: subs w8, w8, #1
; CHECK-NEXT: fmla v0.4s, v1.4s, v2.4s
; CHECK-NEXT: b.eq .LBB8_1
; CHECK-NEXT: // %bb.2: // %l2
; CHECK-NEXT: ret
entry:
%a = shufflevector <4 x float> %x, <4 x float> undef, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
br label %l1
l1:
%p = phi i32 [ 0, %entry ], [ %pa, %l1 ]
%q = phi <4 x float> [ zeroinitializer, %entry ], [ %c, %l1 ]
%l = load <4 x float>, <4 x float> *%y
%b = fmul fast <4 x float> %l, %a
%c = fadd fast <4 x float> %b, %q
%pa = add i32 %p, 1
%c1 = icmp eq i32 %p, 0
br i1 %c1, label %l1, label %l2
l2:
ret <4 x float> %c
}
define <4 x float> @fma(<4 x float> %x, <4 x float> *%y) {
; CHECK-LABEL: fma:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov v1.16b, v0.16b
; CHECK-NEXT: mov w8, #1
; CHECK-NEXT: movi v0.2d, #0000000000000000
; CHECK-NEXT: dup v1.4s, v1.s[3]
; CHECK-NEXT: .LBB9_1: // %l1
; CHECK-NEXT: // =>This Inner Loop Header: Depth=1
; CHECK-NEXT: ldr q3, [x0]
; CHECK-NEXT: subs w8, w8, #1
; CHECK-NEXT: mov v2.16b, v0.16b
; CHECK-NEXT: mov v0.16b, v1.16b
; CHECK-NEXT: fmla v0.4s, v2.4s, v3.4s
; CHECK-NEXT: b.eq .LBB9_1
; CHECK-NEXT: // %bb.2: // %l2
; CHECK-NEXT: ret
entry:
%a = shufflevector <4 x float> %x, <4 x float> undef, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
br label %l1
l1:
%p = phi i32 [ 0, %entry ], [ %pa, %l1 ]
%q = phi <4 x float> [ zeroinitializer, %entry ], [ %c, %l1 ]
%l = load <4 x float>, <4 x float> *%y
%c = tail call <4 x float> @llvm.fma.v4f32(<4 x float> %l, <4 x float> %q, <4 x float> %a)
%pa = add i32 %p, 1
%c1 = icmp eq i32 %p, 0
br i1 %c1, label %l1, label %l2
l2:
ret <4 x float> %c
}
define <4 x i32> @smull_nonsplat(<4 x i16> %x, <4 x i16> *%y) {
; CHECK-LABEL: smull_nonsplat:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: fmov d1, d0
; CHECK-NEXT: mov w8, #1
; CHECK-NEXT: movi v0.2d, #0000000000000000
; CHECK-NEXT: trn2 v2.4h, v1.4h, v1.4h
; CHECK-NEXT: zip2 v1.4h, v2.4h, v1.4h
; CHECK-NEXT: .LBB10_1: // %l1
; CHECK-NEXT: // =>This Inner Loop Header: Depth=1
; CHECK-NEXT: ldr d2, [x0]
; CHECK-NEXT: subs w8, w8, #1
; CHECK-NEXT: smlal v0.4s, v2.4h, v1.4h
; CHECK-NEXT: b.eq .LBB10_1
; CHECK-NEXT: // %bb.2: // %l2
; CHECK-NEXT: ret
entry:
%a = shufflevector <4 x i16> %x, <4 x i16> undef, <4 x i32> <i32 3, i32 2, i32 3, i32 3>
br label %l1
l1:
%p = phi i32 [ 0, %entry ], [ %pa, %l1 ]
%q = phi <4 x i32> [ zeroinitializer, %entry ], [ %c, %l1 ]
%l = load <4 x i16>, <4 x i16> *%y
%b = tail call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %l, <4 x i16> %a)
%c = add nsw <4 x i32> %q, %b
%pa = add i32 %p, 1
%c1 = icmp eq i32 %p, 0
br i1 %c1, label %l1, label %l2
l2:
ret <4 x i32> %c
}
declare <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16>, <4 x i16>)
declare <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16>, <4 x i16>)
declare <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32>, <4 x i32>)
declare <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32>, <4 x i32>)
declare <4 x i32> @llvm.aarch64.neon.sqrdmulh.v4i32(<4 x i32>, <4 x i32>)
declare <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16>, <4 x i16>)
declare <4 x i32> @llvm.aarch64.neon.sqdmulh.v4i32(<4 x i32>, <4 x i32>)
declare <4 x float> @llvm.fma.v4f32(<4 x float> %l, <4 x float> %a, <4 x float> %q)