[llvm] [AArch64][SVE] Enable known bits for predicated shifts (PR #200347)
Harry Ramsey via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 8 05:08:00 PDT 2026
https://github.com/Harry-Ramsey updated https://github.com/llvm/llvm-project/pull/200347
>From 797f92b9d920e364e779460b6724f70d28527ecc Mon Sep 17 00:00:00 2001
From: Harry Ramsey <harry.ramsey at arm.com>
Date: Thu, 28 May 2026 10:44:45 +0000
Subject: [PATCH 1/2] [AArch64][SVE] Enable known bits for predicated shifts
Allow SelectionDAG to query target known-bits information for scalable
vector nodes, and known-bits cases for SVE predicated SHL, SRL and SRA
nodes.
This enables DAG combines to prove disjointness for ORs involving scalable
vector shifts, enabling USRA/SSRA instruction selection.
---
.../CodeGen/AArch64/sve2-fixed-length-sra.ll | 302 ++++++++++++++++++
llvm/test/CodeGen/AArch64/sve2-sra.ll | 245 ++++++++++++++
2 files changed, 547 insertions(+)
create mode 100644 llvm/test/CodeGen/AArch64/sve2-fixed-length-sra.ll
diff --git a/llvm/test/CodeGen/AArch64/sve2-fixed-length-sra.ll b/llvm/test/CodeGen/AArch64/sve2-fixed-length-sra.ll
new file mode 100644
index 0000000000000..81511a1298447
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/sve2-fixed-length-sra.ll
@@ -0,0 +1,302 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s | FileCheck %s
+
+target triple = "aarch64-unknown-linux-gnu"
+
+define <16 x i8> @usra_disjoint_or16xi8(<16 x i8> %a, <16 x i8> %b) #0 {
+; CHECK-LABEL: usra_disjoint_or16xi8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: usra v0.16b, v1.16b, #4
+; CHECK-NEXT: ret
+ %shift = lshr <16 x i8> %b, splat(i8 4)
+ %add = or disjoint <16 x i8> %a, %shift
+ ret <16 x i8> %add
+}
+
+define <8 x i16> @usra_disjoint_or8xi16(<8 x i16> %a, <8 x i16> %b) #0 {
+; CHECK-LABEL: usra_disjoint_or8xi16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: usra v0.8h, v1.8h, #4
+; CHECK-NEXT: ret
+ %shift = lshr <8 x i16> %b, splat(i16 4)
+ %add = or disjoint <8 x i16> %a, %shift
+ ret <8 x i16> %add
+}
+
+define <4 x i32> @usra_disjoint_or4xi32(<4 x i32> %a, <4 x i32> %b) #0 {
+; CHECK-LABEL: usra_disjoint_or4xi32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: usra v0.4s, v1.4s, #4
+; CHECK-NEXT: ret
+ %shift = lshr <4 x i32> %b, splat(i32 4)
+ %add = or disjoint <4 x i32> %a, %shift
+ ret <4 x i32> %add
+}
+
+define <2 x i64> @usra_disjoint_or2xi64(<2 x i64> %a, <2 x i64> %b) #0 {
+; CHECK-LABEL: usra_disjoint_or2xi64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: usra v0.2d, v1.2d, #4
+; CHECK-NEXT: ret
+ %shift = lshr <2 x i64> %b, splat(i64 4)
+ %add = or disjoint <2 x i64> %a, %shift
+ ret <2 x i64> %add
+}
+
+define <16 x i8> @ssra_disjoint_or16xi8(<16 x i8> %a, <16 x i8> %b) #0 {
+; CHECK-LABEL: ssra_disjoint_or16xi8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ssra v0.16b, v1.16b, #4
+; CHECK-NEXT: ret
+ %shift = ashr <16 x i8> %b, splat(i8 4)
+ %add = or disjoint <16 x i8> %a, %shift
+ ret <16 x i8> %add
+}
+
+define <8 x i16> @ssra_disjoint_or8xi16(<8 x i16> %a, <8 x i16> %b) #0 {
+; CHECK-LABEL: ssra_disjoint_or8xi16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ssra v0.8h, v1.8h, #4
+; CHECK-NEXT: ret
+ %shift = ashr <8 x i16> %b, splat(i16 4)
+ %add = or disjoint <8 x i16> %a, %shift
+ ret <8 x i16> %add
+}
+
+define <4 x i32> @ssra_disjoint_or4xi32(<4 x i32> %a, <4 x i32> %b) #0 {
+; CHECK-LABEL: ssra_disjoint_or4xi32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ssra v0.4s, v1.4s, #4
+; CHECK-NEXT: ret
+ %shift = ashr <4 x i32> %b, splat(i32 4)
+ %add = or disjoint <4 x i32> %a, %shift
+ ret <4 x i32> %add
+}
+
+define <2 x i64> @ssra_disjoint_or2xi64(<2 x i64> %a, <2 x i64> %b) #0 {
+; CHECK-LABEL: ssra_disjoint_or2xi64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ssra v0.2d, v1.2d, #4
+; CHECK-NEXT: ret
+ %shift = ashr <2 x i64> %b, splat(i64 4)
+ %add = or disjoint <2 x i64> %a, %shift
+ ret <2 x i64> %add
+}
+
+define <16 x i8> @usra_disjoint_shift_or16xi8(<16 x i8> %a, <16 x i8> %b) #0 {
+; CHECK-LABEL: usra_disjoint_shift_or16xi8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: shl v0.16b, v0.16b, #7
+; CHECK-NEXT: usra v0.16b, v1.16b, #1
+; CHECK-NEXT: ret
+ %shl = shl <16 x i8> %a, splat (i8 7)
+ %srl = lshr <16 x i8> %b, splat (i8 1)
+ %r = or <16 x i8> %shl, %srl
+ ret <16 x i8> %r
+}
+
+define <8 x i16> @usra_disjoint_shift_or8xi16(<8 x i16> %a, <8 x i16> %b) #0 {
+; CHECK-LABEL: usra_disjoint_shift_or8xi16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: shl v0.8h, v0.8h, #7
+; CHECK-NEXT: usra v0.8h, v1.8h, #9
+; CHECK-NEXT: ret
+ %shl = shl <8 x i16> %a, splat (i16 7)
+ %srl = lshr <8 x i16> %b, splat (i16 9)
+ %r = or <8 x i16> %shl, %srl
+ ret <8 x i16> %r
+}
+
+define <4 x i32> @usra_disjoint_shift_or4xi32(<4 x i32> %a, <4 x i32> %b) #0 {
+; CHECK-LABEL: usra_disjoint_shift_or4xi32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: shl v0.4s, v0.4s, #7
+; CHECK-NEXT: usra v0.4s, v1.4s, #25
+; CHECK-NEXT: ret
+ %shl = shl <4 x i32> %a, splat (i32 7)
+ %srl = lshr <4 x i32> %b, splat (i32 25)
+ %r = or <4 x i32> %shl, %srl
+ ret <4 x i32> %r
+}
+
+define <2 x i64> @usra_disjoint_shift_or2xi64(<2 x i64> %a, <2 x i64> %b) #0 {
+; CHECK-LABEL: usra_disjoint_shift_or2xi64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: shl v0.2d, v0.2d, #7
+; CHECK-NEXT: usra v0.2d, v1.2d, #57
+; CHECK-NEXT: ret
+ %shl = shl <2 x i64> %a, splat (i64 7)
+ %srl = lshr <2 x i64> %b, splat (i64 57)
+ %r = or <2 x i64> %shl, %srl
+ ret <2 x i64> %r
+}
+
+define <16 x i8> @usra_disjoint_shl_lsr_or16xi8(<16 x i8> %a, <16 x i8> %b) #0 {
+; CHECK-LABEL: usra_disjoint_shl_lsr_or16xi8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: shl v0.16b, v0.16b, #4
+; CHECK-NEXT: usra v0.16b, v1.16b, #4
+; CHECK-NEXT: ret
+ %shl = call <16 x i8> @llvm.aarch64.neon.ushl.v16i8(<16 x i8> %a, <16 x i8> splat (i8 4))
+ %srl = call <16 x i8> @llvm.aarch64.neon.ushl.v16i8(<16 x i8> %b, <16 x i8> splat (i8 -4))
+ %r = or <16 x i8> %shl, %srl
+ ret <16 x i8> %r
+}
+
+define <8 x i16> @usra_disjoint_shl_lsr_or8xi16(<8 x i16> %a, <8 x i16> %b) #0 {
+; CHECK-LABEL: usra_disjoint_shl_lsr_or8xi16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: shl v0.8h, v0.8h, #8
+; CHECK-NEXT: usra v0.8h, v1.8h, #8
+; CHECK-NEXT: ret
+ %shl = call <8 x i16> @llvm.aarch64.neon.ushl.v8i16(<8 x i16> %a, <8 x i16> splat (i16 8))
+ %srl = call <8 x i16> @llvm.aarch64.neon.ushl.v8i16(<8 x i16> %b, <8 x i16> splat (i16 -8))
+ %r = or <8 x i16> %shl, %srl
+ ret <8 x i16> %r
+}
+
+define <4 x i32> @usra_disjoint_shl_lsr_or4xi32(<4 x i32> %a, <4 x i32> %b) #0 {
+; CHECK-LABEL: usra_disjoint_shl_lsr_or4xi32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: shl v0.4s, v0.4s, #16
+; CHECK-NEXT: usra v0.4s, v1.4s, #16
+; CHECK-NEXT: ret
+ %shl = call <4 x i32> @llvm.aarch64.neon.ushl.v4i32(<4 x i32> %a, <4 x i32> splat (i32 16))
+ %srl = call <4 x i32> @llvm.aarch64.neon.ushl.v4i32(<4 x i32> %b, <4 x i32> splat (i32 -16))
+ %r = or <4 x i32> %shl, %srl
+ ret <4 x i32> %r
+}
+
+define <2 x i64> @usra_disjoint_shl_lsr_or2xi64(<2 x i64> %a, <2 x i64> %b) #0 {
+; CHECK-LABEL: usra_disjoint_shl_lsr_or2xi64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: shl v0.2d, v0.2d, #32
+; CHECK-NEXT: usra v0.2d, v1.2d, #32
+; CHECK-NEXT: ret
+ %shl = call <2 x i64> @llvm.aarch64.neon.ushl.v2i64(<2 x i64> %a, <2 x i64> splat (i64 32))
+ %srl = call <2 x i64> @llvm.aarch64.neon.ushl.v2i64(<2 x i64> %b, <2 x i64> splat (i64 -32))
+ %r = or <2 x i64> %shl, %srl
+ ret <2 x i64> %r
+}
+
+define <16 x i8> @ssra_disjoint_sshl_or16xi8(<16 x i8> %a, <16 x i8> %b) #0 {
+; CHECK-LABEL: ssra_disjoint_sshl_or16xi8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ushr v0.16b, v0.16b, #2
+; CHECK-NEXT: shl v1.16b, v1.16b, #7
+; CHECK-NEXT: ssra v0.16b, v1.16b, #1
+; CHECK-NEXT: ret
+ %acc = call <16 x i8> @llvm.aarch64.neon.ushl.v16i8(<16 x i8> %a, <16 x i8> splat (i8 -2))
+ %sign = call <16 x i8> @llvm.aarch64.neon.ushl.v16i8(<16 x i8> %b, <16 x i8> splat (i8 7))
+ %shift = call <16 x i8> @llvm.aarch64.neon.sshl.v16i8(<16 x i8> %sign, <16 x i8> splat (i8 -1))
+ %r = or <16 x i8> %acc, %shift
+ ret <16 x i8> %r
+}
+
+define <8 x i16> @ssra_disjoint_sshl_or8xi16(<8 x i16> %a, <8 x i16> %b) #0 {
+; CHECK-LABEL: ssra_disjoint_sshl_or8xi16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ushr v0.8h, v0.8h, #10
+; CHECK-NEXT: shl v1.8h, v1.8h, #15
+; CHECK-NEXT: ssra v0.8h, v1.8h, #9
+; CHECK-NEXT: ret
+ %acc = call <8 x i16> @llvm.aarch64.neon.ushl.v8i16(<8 x i16> %a, <8 x i16> splat (i16 -10))
+ %sign = call <8 x i16> @llvm.aarch64.neon.ushl.v8i16(<8 x i16> %b, <8 x i16> splat (i16 15))
+ %shift = call <8 x i16> @llvm.aarch64.neon.sshl.v8i16(<8 x i16> %sign, <8 x i16> splat (i16 -9))
+ %r = or <8 x i16> %acc, %shift
+ ret <8 x i16> %r
+}
+
+define <4 x i32> @ssra_disjoint_sshl_or4xi32(<4 x i32> %a, <4 x i32> %b) #0 {
+; CHECK-LABEL: ssra_disjoint_sshl_or4xi32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ushr v0.4s, v0.4s, #26
+; CHECK-NEXT: shl v1.4s, v1.4s, #31
+; CHECK-NEXT: ssra v0.4s, v1.4s, #25
+; CHECK-NEXT: ret
+ %acc = call <4 x i32> @llvm.aarch64.neon.ushl.v4i32(<4 x i32> %a, <4 x i32> splat (i32 -26))
+ %sign = call <4 x i32> @llvm.aarch64.neon.ushl.v4i32(<4 x i32> %b, <4 x i32> splat (i32 31))
+ %shift = call <4 x i32> @llvm.aarch64.neon.sshl.v4i32(<4 x i32> %sign, <4 x i32> splat (i32 -25))
+ %r = or <4 x i32> %acc, %shift
+ ret <4 x i32> %r
+}
+
+define <2 x i64> @ssra_disjoint_sshl_or2xi64(<2 x i64> %a, <2 x i64> %b) #0 {
+; CHECK-LABEL: ssra_disjoint_sshl_or2xi64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ushr v0.2d, v0.2d, #58
+; CHECK-NEXT: shl v1.2d, v1.2d, #63
+; CHECK-NEXT: ssra v0.2d, v1.2d, #57
+; CHECK-NEXT: ret
+ %acc = call <2 x i64> @llvm.aarch64.neon.ushl.v2i64(<2 x i64> %a, <2 x i64> splat (i64 -58))
+ %sign = call <2 x i64> @llvm.aarch64.neon.ushl.v2i64(<2 x i64> %b, <2 x i64> splat (i64 63))
+ %shift = call <2 x i64> @llvm.aarch64.neon.sshl.v2i64(<2 x i64> %sign, <2 x i64> splat (i64 -57))
+ %r = or <2 x i64> %acc, %shift
+ ret <2 x i64> %r
+}
+
+define <16 x i8> @ssra_disjoint_shift_or16xi8(<16 x i8> %a, <16 x i8> %b) #0 {
+; CHECK-LABEL: ssra_disjoint_shift_or16xi8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ushr v0.16b, v0.16b, #2
+; CHECK-NEXT: shl v1.16b, v1.16b, #7
+; CHECK-NEXT: ssra v0.16b, v1.16b, #1
+; CHECK-NEXT: ret
+ %acc = lshr <16 x i8> %a, splat (i8 2)
+ %sign = shl <16 x i8> %b, splat (i8 7)
+ %sra = ashr <16 x i8> %sign, splat (i8 1)
+ %r = or <16 x i8> %acc, %sra
+ ret <16 x i8> %r
+}
+
+define <8 x i16> @ssra_disjoint_shift_or8xi16(<8 x i16> %a, <8 x i16> %b) #0 {
+; CHECK-LABEL: ssra_disjoint_shift_or8xi16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ushr v0.8h, v0.8h, #10
+; CHECK-NEXT: shl v1.8h, v1.8h, #15
+; CHECK-NEXT: ssra v0.8h, v1.8h, #9
+; CHECK-NEXT: ret
+ %acc = lshr <8 x i16> %a, splat (i16 10)
+ %sign = shl <8 x i16> %b, splat (i16 15)
+ %sra = ashr <8 x i16> %sign, splat (i16 9)
+ %r = or <8 x i16> %acc, %sra
+ ret <8 x i16> %r
+}
+
+define <4 x i32> @ssra_disjoint_shift_or4xi32(<4 x i32> %a, <4 x i32> %b) #0 {
+; CHECK-LABEL: ssra_disjoint_shift_or4xi32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ushr v0.4s, v0.4s, #26
+; CHECK-NEXT: shl v1.4s, v1.4s, #31
+; CHECK-NEXT: ssra v0.4s, v1.4s, #25
+; CHECK-NEXT: ret
+ %acc = lshr <4 x i32> %a, splat (i32 26)
+ %sign = shl <4 x i32> %b, splat (i32 31)
+ %sra = ashr <4 x i32> %sign, splat (i32 25)
+ %r = or <4 x i32> %acc, %sra
+ ret <4 x i32> %r
+}
+
+define <2 x i64> @ssra_disjoint_shift_or2xi64(<2 x i64> %a, <2 x i64> %b) #0 {
+; CHECK-LABEL: ssra_disjoint_shift_or2xi64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ushr v0.2d, v0.2d, #58
+; CHECK-NEXT: shl v1.2d, v1.2d, #63
+; CHECK-NEXT: ssra v0.2d, v1.2d, #57
+; CHECK-NEXT: ret
+ %acc = lshr <2 x i64> %a, splat (i64 58)
+ %sign = shl <2 x i64> %b, splat (i64 63)
+ %sra = ashr <2 x i64> %sign, splat (i64 57)
+ %r = or <2 x i64> %acc, %sra
+ ret <2 x i64> %r
+}
+
+declare <16 x i8> @llvm.aarch64.neon.ushl.v16i8(<16 x i8>, <16 x i8>)
+declare <8 x i16> @llvm.aarch64.neon.ushl.v8i16(<8 x i16>, <8 x i16>)
+declare <4 x i32> @llvm.aarch64.neon.ushl.v4i32(<4 x i32>, <4 x i32>)
+declare <2 x i64> @llvm.aarch64.neon.ushl.v2i64(<2 x i64>, <2 x i64>)
+
+declare <16 x i8> @llvm.aarch64.neon.sshl.v16i8(<16 x i8>, <16 x i8>)
+declare <8 x i16> @llvm.aarch64.neon.sshl.v8i16(<8 x i16>, <8 x i16>)
+declare <4 x i32> @llvm.aarch64.neon.sshl.v4i32(<4 x i32>, <4 x i32>)
+declare <2 x i64> @llvm.aarch64.neon.sshl.v2i64(<2 x i64>, <2 x i64>)
diff --git a/llvm/test/CodeGen/AArch64/sve2-sra.ll b/llvm/test/CodeGen/AArch64/sve2-sra.ll
index 0b951b01a5e90..5e5f4234e5e06 100644
--- a/llvm/test/CodeGen/AArch64/sve2-sra.ll
+++ b/llvm/test/CodeGen/AArch64/sve2-sra.ll
@@ -255,6 +255,8 @@ define <vscale x 2 x i64> @ssra_intr_u_i64(<vscale x 2 x i1> %pg, <vscale x 2 x
ret <vscale x 2 x i64> %add
}
+; USRA
+
define <vscale x 16 x i8> @usra_disjoint_or16xi8(<vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
; CHECK-LABEL: usra_disjoint_or16xi8:
; CHECK: // %bb.0:
@@ -335,6 +337,244 @@ define <vscale x 2 x i64> @ssra_disjoint_or2xi64(<vscale x 2 x i64> %a, <vscale
ret <vscale x 2 x i64> %add
}
+define <vscale x 16 x i8> @usra_disjoint_shift_or16xi8(<vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
+; CHECK-LABEL: usra_disjoint_shift_or16xi8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsl z0.b, z0.b, #7
+; CHECK-NEXT: lsr z1.b, z1.b, #1
+; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: ret
+ %shl = shl <vscale x 16 x i8> %a, splat (i8 7)
+ %srl = lshr <vscale x 16 x i8> %b, splat (i8 1)
+ %r = or <vscale x 16 x i8> %shl, %srl
+ ret <vscale x 16 x i8> %r
+}
+
+define <vscale x 8 x i16> @usra_disjoint_shift_or8xi16(<vscale x 8 x i16> %a, <vscale x 8 x i16> %b) #0 {
+; CHECK-LABEL: usra_disjoint_shift_or8xi16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsl z0.h, z0.h, #7
+; CHECK-NEXT: lsr z1.h, z1.h, #9
+; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: ret
+ %shl = shl <vscale x 8 x i16> %a, splat (i16 7)
+ %srl = lshr <vscale x 8 x i16> %b, splat (i16 9)
+ %r = or <vscale x 8 x i16> %shl, %srl
+ ret <vscale x 8 x i16> %r
+}
+
+define <vscale x 4 x i32> @usra_disjoint_shift_or4xi32(<vscale x 4 x i32> %a, <vscale x 4 x i32> %b) #0 {
+; CHECK-LABEL: usra_disjoint_shift_or4xi32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsl z0.s, z0.s, #7
+; CHECK-NEXT: lsr z1.s, z1.s, #25
+; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: ret
+ %shl = shl <vscale x 4 x i32> %a, splat (i32 7)
+ %srl = lshr <vscale x 4 x i32> %b, splat (i32 25)
+ %r = or <vscale x 4 x i32> %shl, %srl
+ ret <vscale x 4 x i32> %r
+}
+
+define <vscale x 2 x i64> @usra_disjoint_shift_or2xi64(<vscale x 2 x i64> %a, <vscale x 2 x i64> %b) #0 {
+; CHECK-LABEL: usra_disjoint_shift_or2xi64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsl z0.d, z0.d, #7
+; CHECK-NEXT: lsr z1.d, z1.d, #57
+; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: ret
+ %shl = shl <vscale x 2 x i64> %a, splat (i64 7)
+ %srl = lshr <vscale x 2 x i64> %b, splat (i64 57)
+ %r = or <vscale x 2 x i64> %shl, %srl
+ ret <vscale x 2 x i64> %r
+}
+
+; SSRA
+
+define <vscale x 16 x i8> @ssra_disjoint_shift_or16xi8(<vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
+; CHECK-LABEL: ssra_disjoint_shift_or16xi8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsl z1.b, z1.b, #7
+; CHECK-NEXT: lsr z0.b, z0.b, #2
+; CHECK-NEXT: asr z1.b, z1.b, #1
+; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: ret
+ %acc = lshr <vscale x 16 x i8> %a, splat (i8 2)
+ %sign = shl <vscale x 16 x i8> %b, splat (i8 7)
+ %sra = ashr <vscale x 16 x i8> %sign, splat (i8 1)
+ %r = or <vscale x 16 x i8> %acc, %sra
+ ret <vscale x 16 x i8> %r
+}
+
+define <vscale x 8 x i16> @ssra_disjoint_shift_or8xi16(<vscale x 8 x i16> %a, <vscale x 8 x i16> %b) #0 {
+; CHECK-LABEL: ssra_disjoint_shift_or8xi16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsl z1.h, z1.h, #15
+; CHECK-NEXT: lsr z0.h, z0.h, #10
+; CHECK-NEXT: asr z1.h, z1.h, #9
+; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: ret
+ %acc = lshr <vscale x 8 x i16> %a, splat (i16 10)
+ %sign = shl <vscale x 8 x i16> %b, splat (i16 15)
+ %sra = ashr <vscale x 8 x i16> %sign, splat (i16 9)
+ %r = or <vscale x 8 x i16> %acc, %sra
+ ret <vscale x 8 x i16> %r
+}
+
+define <vscale x 4 x i32> @ssra_disjoint_shift_or4xi32(<vscale x 4 x i32> %a, <vscale x 4 x i32> %b) #0 {
+; CHECK-LABEL: ssra_disjoint_shift_or4xi32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsl z1.s, z1.s, #31
+; CHECK-NEXT: lsr z0.s, z0.s, #26
+; CHECK-NEXT: asr z1.s, z1.s, #25
+; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: ret
+ %acc = lshr <vscale x 4 x i32> %a, splat (i32 26)
+ %sign = shl <vscale x 4 x i32> %b, splat (i32 31)
+ %sra = ashr <vscale x 4 x i32> %sign, splat (i32 25)
+ %r = or <vscale x 4 x i32> %acc, %sra
+ ret <vscale x 4 x i32> %r
+}
+
+define <vscale x 2 x i64> @ssra_disjoint_shift_or2xi64(<vscale x 2 x i64> %a, <vscale x 2 x i64> %b) #0 {
+; CHECK-LABEL: ssra_disjoint_shift_or2xi64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsl z1.d, z1.d, #63
+; CHECK-NEXT: lsr z0.d, z0.d, #58
+; CHECK-NEXT: asr z1.d, z1.d, #57
+; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: ret
+ %acc = lshr <vscale x 2 x i64> %a, splat (i64 58)
+ %sign = shl <vscale x 2 x i64> %b, splat (i64 63)
+ %sra = ashr <vscale x 2 x i64> %sign, splat (i64 57)
+ %r = or <vscale x 2 x i64> %acc, %sra
+ ret <vscale x 2 x i64> %r
+}
+
+; USRA
+
+define <vscale x 16 x i8> @usra_disjoint_shl_lsr_or16xi8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
+; CHECK-LABEL: usra_disjoint_shl_lsr_or16xi8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsl z0.b, z0.b, #4
+; CHECK-NEXT: lsr z1.b, z1.b, #4
+; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: ret
+ %ptrue = call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 31)
+ %shl = call <vscale x 16 x i8> @llvm.aarch64.sve.lsl.u.nxv16i8(<vscale x 16 x i1> %ptrue, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat(i8 4))
+ %srl = call <vscale x 16 x i8> @llvm.aarch64.sve.lsr.u.nxv16i8(<vscale x 16 x i1> %ptrue, <vscale x 16 x i8> %b, <vscale x 16 x i8> splat(i8 4))
+ %r = or <vscale x 16 x i8> %shl, %srl
+ ret <vscale x 16 x i8> %r
+}
+
+define <vscale x 8 x i16> @usra_disjoint_shl_lsr_or8xi16(<vscale x 8 x i1> %pg, <vscale x 8 x i16> %a, <vscale x 8 x i16> %b) #0 {
+; CHECK-LABEL: usra_disjoint_shl_lsr_or8xi16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsl z0.h, z0.h, #8
+; CHECK-NEXT: lsr z1.h, z1.h, #8
+; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: ret
+ %ptrue = call <vscale x 8 x i1> @llvm.aarch64.sve.ptrue.nxv8i1(i32 31)
+ %shl = call <vscale x 8 x i16> @llvm.aarch64.sve.lsl.u.nxv8i16(<vscale x 8 x i1> %ptrue, <vscale x 8 x i16> %a, <vscale x 8 x i16> splat(i16 8))
+ %srl = call <vscale x 8 x i16> @llvm.aarch64.sve.lsr.u.nxv8i16(<vscale x 8 x i1> %ptrue, <vscale x 8 x i16> %b, <vscale x 8 x i16> splat(i16 8))
+ %r = or <vscale x 8 x i16> %shl, %srl
+ ret <vscale x 8 x i16> %r
+}
+
+define <vscale x 4 x i32> @usra_disjoint_shl_lsr_or4xi32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> %a, <vscale x 4 x i32> %b) #0 {
+; CHECK-LABEL: usra_disjoint_shl_lsr_or4xi32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsl z0.s, z0.s, #16
+; CHECK-NEXT: lsr z1.s, z1.s, #16
+; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: ret
+ %ptrue = call <vscale x 4 x i1> @llvm.aarch64.sve.ptrue.nxv4i1(i32 31)
+ %shl = call <vscale x 4 x i32> @llvm.aarch64.sve.lsl.u.nxv4i32(<vscale x 4 x i1> %ptrue, <vscale x 4 x i32> %a, <vscale x 4 x i32> splat(i32 16))
+ %srl = call <vscale x 4 x i32> @llvm.aarch64.sve.lsr.u.nxv4i32(<vscale x 4 x i1> %ptrue, <vscale x 4 x i32> %b, <vscale x 4 x i32> splat(i32 16))
+ %r = or <vscale x 4 x i32> %shl, %srl
+ ret <vscale x 4 x i32> %r
+}
+
+define <vscale x 2 x i64> @usra_disjoint_shl_lsr_or2xi64(<vscale x 2 x i1> %pg, <vscale x 2 x i64> %a, <vscale x 2 x i64> %b) #0 {
+; CHECK-LABEL: usra_disjoint_shl_lsr_or2xi64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsl z0.d, z0.d, #32
+; CHECK-NEXT: lsr z1.d, z1.d, #32
+; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: ret
+ %ptrue = call <vscale x 2 x i1> @llvm.aarch64.sve.ptrue.nxv2i1(i32 31)
+ %shl = call <vscale x 2 x i64> @llvm.aarch64.sve.lsl.u.nxv2i64(<vscale x 2 x i1> %ptrue, <vscale x 2 x i64> %a, <vscale x 2 x i64> splat(i64 32))
+ %srl = call <vscale x 2 x i64> @llvm.aarch64.sve.lsr.u.nxv2i64(<vscale x 2 x i1> %ptrue, <vscale x 2 x i64> %b, <vscale x 2 x i64> splat(i64 32))
+ %r = or <vscale x 2 x i64> %shl, %srl
+ ret <vscale x 2 x i64> %r
+}
+
+; SSRA
+
+define <vscale x 16 x i8> @ssra_disjoint_shift_intr_or16xi8(<vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
+; CHECK-LABEL: ssra_disjoint_shift_intr_or16xi8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsl z1.b, z1.b, #7
+; CHECK-NEXT: lsr z0.b, z0.b, #2
+; CHECK-NEXT: asr z1.b, z1.b, #1
+; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: ret
+ %pg = call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 31)
+ %acc = call <vscale x 16 x i8> @llvm.aarch64.sve.lsr.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat(i8 2))
+ %sign = call <vscale x 16 x i8> @llvm.aarch64.sve.lsl.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %b, <vscale x 16 x i8> splat(i8 7))
+ %sra = call <vscale x 16 x i8> @llvm.aarch64.sve.asr.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %sign, <vscale x 16 x i8> splat(i8 1))
+ %r = or <vscale x 16 x i8> %acc, %sra
+ ret <vscale x 16 x i8> %r
+}
+
+define <vscale x 8 x i16> @ssra_disjoint_shift_intr_or8xi16(<vscale x 8 x i16> %a, <vscale x 8 x i16> %b) #0 {
+; CHECK-LABEL: ssra_disjoint_shift_intr_or8xi16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsl z1.h, z1.h, #15
+; CHECK-NEXT: lsr z0.h, z0.h, #10
+; CHECK-NEXT: asr z1.h, z1.h, #9
+; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: ret
+ %pg = call <vscale x 8 x i1> @llvm.aarch64.sve.ptrue.nxv8i1(i32 31)
+ %acc = call <vscale x 8 x i16> @llvm.aarch64.sve.lsr.u.nxv8i16(<vscale x 8 x i1> %pg, <vscale x 8 x i16> %a, <vscale x 8 x i16> splat(i16 10))
+ %sign = call <vscale x 8 x i16> @llvm.aarch64.sve.lsl.u.nxv8i16(<vscale x 8 x i1> %pg, <vscale x 8 x i16> %b, <vscale x 8 x i16> splat(i16 15))
+ %sra = call <vscale x 8 x i16> @llvm.aarch64.sve.asr.u.nxv8i16(<vscale x 8 x i1> %pg, <vscale x 8 x i16> %sign, <vscale x 8 x i16> splat(i16 9))
+ %r = or <vscale x 8 x i16> %acc, %sra
+ ret <vscale x 8 x i16> %r
+}
+
+define <vscale x 4 x i32> @ssra_disjoint_shift_intr_or4xi32(<vscale x 4 x i32> %a, <vscale x 4 x i32> %b) #0 {
+; CHECK-LABEL: ssra_disjoint_shift_intr_or4xi32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsl z1.s, z1.s, #31
+; CHECK-NEXT: lsr z0.s, z0.s, #26
+; CHECK-NEXT: asr z1.s, z1.s, #25
+; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: ret
+ %pg = call <vscale x 4 x i1> @llvm.aarch64.sve.ptrue.nxv4i1(i32 31)
+ %acc = call <vscale x 4 x i32> @llvm.aarch64.sve.lsr.u.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> %a, <vscale x 4 x i32> splat(i32 26))
+ %sign = call <vscale x 4 x i32> @llvm.aarch64.sve.lsl.u.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> %b, <vscale x 4 x i32> splat(i32 31))
+ %sra = call <vscale x 4 x i32> @llvm.aarch64.sve.asr.u.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> %sign, <vscale x 4 x i32> splat(i32 25))
+ %r = or <vscale x 4 x i32> %acc, %sra
+ ret <vscale x 4 x i32> %r
+}
+
+define <vscale x 2 x i64> @ssra_disjoint_shift_intr_or2xi64(<vscale x 2 x i64> %a, <vscale x 2 x i64> %b) #0 {
+; CHECK-LABEL: ssra_disjoint_shift_intr_or2xi64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsl z1.d, z1.d, #63
+; CHECK-NEXT: lsr z0.d, z0.d, #58
+; CHECK-NEXT: asr z1.d, z1.d, #57
+; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: ret
+ %pg = call <vscale x 2 x i1> @llvm.aarch64.sve.ptrue.nxv2i1(i32 31)
+ %acc = call <vscale x 2 x i64> @llvm.aarch64.sve.lsr.u.nxv2i64(<vscale x 2 x i1> %pg, <vscale x 2 x i64> %a, <vscale x 2 x i64> splat(i64 58))
+ %sign = call <vscale x 2 x i64> @llvm.aarch64.sve.lsl.u.nxv2i64(<vscale x 2 x i1> %pg, <vscale x 2 x i64> %b, <vscale x 2 x i64> splat(i64 63))
+ %sra = call <vscale x 2 x i64> @llvm.aarch64.sve.asr.u.nxv2i64(<vscale x 2 x i1> %pg, <vscale x 2 x i64> %sign, <vscale x 2 x i64> splat(i64 57))
+ %r = or <vscale x 2 x i64> %acc, %sra
+ ret <vscale x 2 x i64> %r
+}
+
declare <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 immarg)
declare <vscale x 8 x i1> @llvm.aarch64.sve.ptrue.nxv8i1(i32 immarg)
declare <vscale x 4 x i1> @llvm.aarch64.sve.ptrue.nxv4i1(i32 immarg)
@@ -345,6 +585,11 @@ declare <vscale x 8 x i16> @llvm.aarch64.sve.lsr.u.nxv8i16(<vscale x 8 x i1>, <v
declare <vscale x 4 x i32> @llvm.aarch64.sve.lsr.u.nxv4i32(<vscale x 4 x i1>, <vscale x 4 x i32>, <vscale x 4 x i32>)
declare <vscale x 2 x i64> @llvm.aarch64.sve.lsr.u.nxv2i64(<vscale x 2 x i1>, <vscale x 2 x i64>, <vscale x 2 x i64>)
+declare <vscale x 16 x i8> @llvm.aarch64.sve.lsl.u.nxv16i8(<vscale x 16 x i1>, <vscale x 16 x i8>, <vscale x 16 x i8>)
+declare <vscale x 8 x i16> @llvm.aarch64.sve.lsl.u.nxv8i16(<vscale x 8 x i1>, <vscale x 8 x i16>, <vscale x 8 x i16>)
+declare <vscale x 4 x i32> @llvm.aarch64.sve.lsl.u.nxv4i32(<vscale x 4 x i1>, <vscale x 4 x i32>, <vscale x 4 x i32>)
+declare <vscale x 2 x i64> @llvm.aarch64.sve.lsl.u.nxv2i64(<vscale x 2 x i1>, <vscale x 2 x i64>, <vscale x 2 x i64>)
+
declare <vscale x 16 x i8> @llvm.aarch64.sve.asr.u.nxv16i8(<vscale x 16 x i1>, <vscale x 16 x i8>, <vscale x 16 x i8>)
declare <vscale x 8 x i16> @llvm.aarch64.sve.asr.u.nxv8i16(<vscale x 8 x i1>, <vscale x 8 x i16>, <vscale x 8 x i16>)
declare <vscale x 4 x i32> @llvm.aarch64.sve.asr.u.nxv4i32(<vscale x 4 x i1>, <vscale x 4 x i32>, <vscale x 4 x i32>)
>From 73213649874e868a5a4b297e27df292afbedb451 Mon Sep 17 00:00:00 2001
From: Harry Ramsey <harry.ramsey at arm.com>
Date: Thu, 28 May 2026 11:22:24 +0000
Subject: [PATCH 2/2] fixup! [AArch64][SVE] Enable known bits for predicated
shifts
---
.../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 5 --
.../Target/AArch64/AArch64ISelLowering.cpp | 23 ++++++-
llvm/lib/Target/AArch64/AArch64ISelLowering.h | 2 +-
llvm/test/CodeGen/AArch64/sve2-sli-sri.ll | 24 ++++---
llvm/test/CodeGen/AArch64/sve2-sra.ll | 64 +++++++------------
5 files changed, 62 insertions(+), 56 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 75d550801315b..8cbd3e9df11db 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -4527,11 +4527,6 @@ KnownBits SelectionDAG::computeKnownBits(SDValue Op, const APInt &DemandedElts,
case ISD::INTRINSIC_WO_CHAIN:
case ISD::INTRINSIC_W_CHAIN:
case ISD::INTRINSIC_VOID:
- // TODO: Probably okay to remove after audit; here to reduce change size
- // in initial enablement patch for scalable vectors
- if (Op.getValueType().isScalableVector())
- break;
-
// Allow the target to implement this method for its nodes.
TLI->computeKnownBitsForTargetNode(Op, Known, DemandedElts, *this, Depth);
break;
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 0992f329e1d6c..328048f1cb06a 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -2938,6 +2938,25 @@ void AArch64TargetLowering::computeKnownBitsForTargetNode(
}
break;
}
+ case AArch64ISD::SHL_PRED:
+ case AArch64ISD::SRL_PRED:
+ case AArch64ISD::SRA_PRED: {
+ if (!isAllActivePredicate(DAG, Op->getOperand(0)))
+ break;
+
+ KnownBits KnownVal =
+ DAG.computeKnownBits(Op->getOperand(1), DemandedElts, Depth + 1);
+ KnownBits KnownAmt =
+ DAG.computeKnownBits(Op->getOperand(2), DemandedElts, Depth + 1);
+
+ if (Op.getOpcode() == AArch64ISD::SHL_PRED)
+ Known = KnownBits::shl(KnownVal, KnownAmt);
+ else if (Op.getOpcode() == AArch64ISD::SRL_PRED)
+ Known = KnownBits::lshr(KnownVal, KnownAmt);
+ else
+ Known = KnownBits::ashr(KnownVal, KnownAmt);
+ break;
+ }
case ISD::INTRINSIC_WO_CHAIN:
case ISD::INTRINSIC_VOID: {
unsigned IntNo = Op.getConstantOperandVal(0);
@@ -15784,7 +15803,7 @@ static bool isAllInactivePredicate(SDValue N) {
return ISD::isConstantSplatVectorAllZeros(N.getNode());
}
-static bool isAllActivePredicate(SelectionDAG &DAG, SDValue N) {
+static bool isAllActivePredicate(const SelectionDAG &DAG, SDValue N) {
unsigned NumElts = N.getValueType().getVectorMinNumElements();
// Look through cast.
@@ -33675,7 +33694,7 @@ SDValue AArch64TargetLowering::getSVESafeBitCast(EVT VT, SDValue Op,
return Op;
}
-bool AArch64TargetLowering::isAllActivePredicate(SelectionDAG &DAG,
+bool AArch64TargetLowering::isAllActivePredicate(const SelectionDAG &DAG,
SDValue N) const {
return ::isAllActivePredicate(DAG, N);
}
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
index 3a93d9a3c0d1e..d354bb726b709 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
@@ -545,7 +545,7 @@ class AArch64TargetLowering : public TargetLowering {
return 128;
}
- bool isAllActivePredicate(SelectionDAG &DAG, SDValue N) const;
+ bool isAllActivePredicate(const SelectionDAG &DAG, SDValue N) const;
EVT getPromotedVTForPredicate(EVT VT) const;
EVT getAsmOperandValueType(const DataLayout &DL, Type *Ty,
diff --git a/llvm/test/CodeGen/AArch64/sve2-sli-sri.ll b/llvm/test/CodeGen/AArch64/sve2-sli-sri.ll
index 80999fb1f4864..a7048731850d3 100644
--- a/llvm/test/CodeGen/AArch64/sve2-sli-sri.ll
+++ b/llvm/test/CodeGen/AArch64/sve2-sli-sri.ll
@@ -118,14 +118,22 @@ define <vscale x 8 x i16> @testRightGood8x16(<vscale x 8 x i16> %src1, <vscale x
}
define <vscale x 8 x i16> @testRightBad8x16(<vscale x 8 x i16> %src1, <vscale x 8 x i16> %src2) {
-; CHECK-LABEL: testRightBad8x16:
-; CHECK: // %bb.0:
-; CHECK-NEXT: mov w8, #16500 // =0x4074
-; CHECK-NEXT: lsr z1.h, z1.h, #14
-; CHECK-NEXT: mov z2.h, w8
-; CHECK-NEXT: and z0.d, z0.d, z2.d
-; CHECK-NEXT: orr z0.d, z0.d, z1.d
-; CHECK-NEXT: ret
+; SVE-LABEL: testRightBad8x16:
+; SVE: // %bb.0:
+; SVE-NEXT: mov w8, #16500 // =0x4074
+; SVE-NEXT: lsr z1.h, z1.h, #14
+; SVE-NEXT: mov z2.h, w8
+; SVE-NEXT: and z0.d, z0.d, z2.d
+; SVE-NEXT: orr z0.d, z0.d, z1.d
+; SVE-NEXT: ret
+;
+; SVE2-LABEL: testRightBad8x16:
+; SVE2: // %bb.0:
+; SVE2-NEXT: mov w8, #16500 // =0x4074
+; SVE2-NEXT: mov z2.h, w8
+; SVE2-NEXT: and z0.d, z0.d, z2.d
+; SVE2-NEXT: usra z0.h, z1.h, #14
+; SVE2-NEXT: ret
%and.i = and <vscale x 8 x i16> %src1, splat(i16 16500)
%vshl_n = lshr <vscale x 8 x i16> %src2, splat(i16 14)
%result = or <vscale x 8 x i16> %and.i, %vshl_n
diff --git a/llvm/test/CodeGen/AArch64/sve2-sra.ll b/llvm/test/CodeGen/AArch64/sve2-sra.ll
index 5e5f4234e5e06..e317af0b1de7b 100644
--- a/llvm/test/CodeGen/AArch64/sve2-sra.ll
+++ b/llvm/test/CodeGen/AArch64/sve2-sra.ll
@@ -341,8 +341,7 @@ define <vscale x 16 x i8> @usra_disjoint_shift_or16xi8(<vscale x 16 x i8> %a, <v
; CHECK-LABEL: usra_disjoint_shift_or16xi8:
; CHECK: // %bb.0:
; CHECK-NEXT: lsl z0.b, z0.b, #7
-; CHECK-NEXT: lsr z1.b, z1.b, #1
-; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: usra z0.b, z1.b, #1
; CHECK-NEXT: ret
%shl = shl <vscale x 16 x i8> %a, splat (i8 7)
%srl = lshr <vscale x 16 x i8> %b, splat (i8 1)
@@ -354,8 +353,7 @@ define <vscale x 8 x i16> @usra_disjoint_shift_or8xi16(<vscale x 8 x i16> %a, <v
; CHECK-LABEL: usra_disjoint_shift_or8xi16:
; CHECK: // %bb.0:
; CHECK-NEXT: lsl z0.h, z0.h, #7
-; CHECK-NEXT: lsr z1.h, z1.h, #9
-; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: usra z0.h, z1.h, #9
; CHECK-NEXT: ret
%shl = shl <vscale x 8 x i16> %a, splat (i16 7)
%srl = lshr <vscale x 8 x i16> %b, splat (i16 9)
@@ -367,8 +365,7 @@ define <vscale x 4 x i32> @usra_disjoint_shift_or4xi32(<vscale x 4 x i32> %a, <v
; CHECK-LABEL: usra_disjoint_shift_or4xi32:
; CHECK: // %bb.0:
; CHECK-NEXT: lsl z0.s, z0.s, #7
-; CHECK-NEXT: lsr z1.s, z1.s, #25
-; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: usra z0.s, z1.s, #25
; CHECK-NEXT: ret
%shl = shl <vscale x 4 x i32> %a, splat (i32 7)
%srl = lshr <vscale x 4 x i32> %b, splat (i32 25)
@@ -380,8 +377,7 @@ define <vscale x 2 x i64> @usra_disjoint_shift_or2xi64(<vscale x 2 x i64> %a, <v
; CHECK-LABEL: usra_disjoint_shift_or2xi64:
; CHECK: // %bb.0:
; CHECK-NEXT: lsl z0.d, z0.d, #7
-; CHECK-NEXT: lsr z1.d, z1.d, #57
-; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: usra z0.d, z1.d, #57
; CHECK-NEXT: ret
%shl = shl <vscale x 2 x i64> %a, splat (i64 7)
%srl = lshr <vscale x 2 x i64> %b, splat (i64 57)
@@ -394,10 +390,9 @@ define <vscale x 2 x i64> @usra_disjoint_shift_or2xi64(<vscale x 2 x i64> %a, <v
define <vscale x 16 x i8> @ssra_disjoint_shift_or16xi8(<vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
; CHECK-LABEL: ssra_disjoint_shift_or16xi8:
; CHECK: // %bb.0:
-; CHECK-NEXT: lsl z1.b, z1.b, #7
; CHECK-NEXT: lsr z0.b, z0.b, #2
-; CHECK-NEXT: asr z1.b, z1.b, #1
-; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: lsl z1.b, z1.b, #7
+; CHECK-NEXT: ssra z0.b, z1.b, #1
; CHECK-NEXT: ret
%acc = lshr <vscale x 16 x i8> %a, splat (i8 2)
%sign = shl <vscale x 16 x i8> %b, splat (i8 7)
@@ -409,10 +404,9 @@ define <vscale x 16 x i8> @ssra_disjoint_shift_or16xi8(<vscale x 16 x i8> %a, <v
define <vscale x 8 x i16> @ssra_disjoint_shift_or8xi16(<vscale x 8 x i16> %a, <vscale x 8 x i16> %b) #0 {
; CHECK-LABEL: ssra_disjoint_shift_or8xi16:
; CHECK: // %bb.0:
-; CHECK-NEXT: lsl z1.h, z1.h, #15
; CHECK-NEXT: lsr z0.h, z0.h, #10
-; CHECK-NEXT: asr z1.h, z1.h, #9
-; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: lsl z1.h, z1.h, #15
+; CHECK-NEXT: ssra z0.h, z1.h, #9
; CHECK-NEXT: ret
%acc = lshr <vscale x 8 x i16> %a, splat (i16 10)
%sign = shl <vscale x 8 x i16> %b, splat (i16 15)
@@ -424,10 +418,9 @@ define <vscale x 8 x i16> @ssra_disjoint_shift_or8xi16(<vscale x 8 x i16> %a, <v
define <vscale x 4 x i32> @ssra_disjoint_shift_or4xi32(<vscale x 4 x i32> %a, <vscale x 4 x i32> %b) #0 {
; CHECK-LABEL: ssra_disjoint_shift_or4xi32:
; CHECK: // %bb.0:
-; CHECK-NEXT: lsl z1.s, z1.s, #31
; CHECK-NEXT: lsr z0.s, z0.s, #26
-; CHECK-NEXT: asr z1.s, z1.s, #25
-; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: lsl z1.s, z1.s, #31
+; CHECK-NEXT: ssra z0.s, z1.s, #25
; CHECK-NEXT: ret
%acc = lshr <vscale x 4 x i32> %a, splat (i32 26)
%sign = shl <vscale x 4 x i32> %b, splat (i32 31)
@@ -439,10 +432,9 @@ define <vscale x 4 x i32> @ssra_disjoint_shift_or4xi32(<vscale x 4 x i32> %a, <v
define <vscale x 2 x i64> @ssra_disjoint_shift_or2xi64(<vscale x 2 x i64> %a, <vscale x 2 x i64> %b) #0 {
; CHECK-LABEL: ssra_disjoint_shift_or2xi64:
; CHECK: // %bb.0:
-; CHECK-NEXT: lsl z1.d, z1.d, #63
; CHECK-NEXT: lsr z0.d, z0.d, #58
-; CHECK-NEXT: asr z1.d, z1.d, #57
-; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: lsl z1.d, z1.d, #63
+; CHECK-NEXT: ssra z0.d, z1.d, #57
; CHECK-NEXT: ret
%acc = lshr <vscale x 2 x i64> %a, splat (i64 58)
%sign = shl <vscale x 2 x i64> %b, splat (i64 63)
@@ -457,8 +449,7 @@ define <vscale x 16 x i8> @usra_disjoint_shl_lsr_or16xi8(<vscale x 16 x i1> %pg,
; CHECK-LABEL: usra_disjoint_shl_lsr_or16xi8:
; CHECK: // %bb.0:
; CHECK-NEXT: lsl z0.b, z0.b, #4
-; CHECK-NEXT: lsr z1.b, z1.b, #4
-; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: usra z0.b, z1.b, #4
; CHECK-NEXT: ret
%ptrue = call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 31)
%shl = call <vscale x 16 x i8> @llvm.aarch64.sve.lsl.u.nxv16i8(<vscale x 16 x i1> %ptrue, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat(i8 4))
@@ -471,8 +462,7 @@ define <vscale x 8 x i16> @usra_disjoint_shl_lsr_or8xi16(<vscale x 8 x i1> %pg,
; CHECK-LABEL: usra_disjoint_shl_lsr_or8xi16:
; CHECK: // %bb.0:
; CHECK-NEXT: lsl z0.h, z0.h, #8
-; CHECK-NEXT: lsr z1.h, z1.h, #8
-; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: usra z0.h, z1.h, #8
; CHECK-NEXT: ret
%ptrue = call <vscale x 8 x i1> @llvm.aarch64.sve.ptrue.nxv8i1(i32 31)
%shl = call <vscale x 8 x i16> @llvm.aarch64.sve.lsl.u.nxv8i16(<vscale x 8 x i1> %ptrue, <vscale x 8 x i16> %a, <vscale x 8 x i16> splat(i16 8))
@@ -485,8 +475,7 @@ define <vscale x 4 x i32> @usra_disjoint_shl_lsr_or4xi32(<vscale x 4 x i1> %pg,
; CHECK-LABEL: usra_disjoint_shl_lsr_or4xi32:
; CHECK: // %bb.0:
; CHECK-NEXT: lsl z0.s, z0.s, #16
-; CHECK-NEXT: lsr z1.s, z1.s, #16
-; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: usra z0.s, z1.s, #16
; CHECK-NEXT: ret
%ptrue = call <vscale x 4 x i1> @llvm.aarch64.sve.ptrue.nxv4i1(i32 31)
%shl = call <vscale x 4 x i32> @llvm.aarch64.sve.lsl.u.nxv4i32(<vscale x 4 x i1> %ptrue, <vscale x 4 x i32> %a, <vscale x 4 x i32> splat(i32 16))
@@ -499,8 +488,7 @@ define <vscale x 2 x i64> @usra_disjoint_shl_lsr_or2xi64(<vscale x 2 x i1> %pg,
; CHECK-LABEL: usra_disjoint_shl_lsr_or2xi64:
; CHECK: // %bb.0:
; CHECK-NEXT: lsl z0.d, z0.d, #32
-; CHECK-NEXT: lsr z1.d, z1.d, #32
-; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: usra z0.d, z1.d, #32
; CHECK-NEXT: ret
%ptrue = call <vscale x 2 x i1> @llvm.aarch64.sve.ptrue.nxv2i1(i32 31)
%shl = call <vscale x 2 x i64> @llvm.aarch64.sve.lsl.u.nxv2i64(<vscale x 2 x i1> %ptrue, <vscale x 2 x i64> %a, <vscale x 2 x i64> splat(i64 32))
@@ -514,10 +502,9 @@ define <vscale x 2 x i64> @usra_disjoint_shl_lsr_or2xi64(<vscale x 2 x i1> %pg,
define <vscale x 16 x i8> @ssra_disjoint_shift_intr_or16xi8(<vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
; CHECK-LABEL: ssra_disjoint_shift_intr_or16xi8:
; CHECK: // %bb.0:
-; CHECK-NEXT: lsl z1.b, z1.b, #7
; CHECK-NEXT: lsr z0.b, z0.b, #2
-; CHECK-NEXT: asr z1.b, z1.b, #1
-; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: lsl z1.b, z1.b, #7
+; CHECK-NEXT: ssra z0.b, z1.b, #1
; CHECK-NEXT: ret
%pg = call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 31)
%acc = call <vscale x 16 x i8> @llvm.aarch64.sve.lsr.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat(i8 2))
@@ -530,10 +517,9 @@ define <vscale x 16 x i8> @ssra_disjoint_shift_intr_or16xi8(<vscale x 16 x i8> %
define <vscale x 8 x i16> @ssra_disjoint_shift_intr_or8xi16(<vscale x 8 x i16> %a, <vscale x 8 x i16> %b) #0 {
; CHECK-LABEL: ssra_disjoint_shift_intr_or8xi16:
; CHECK: // %bb.0:
-; CHECK-NEXT: lsl z1.h, z1.h, #15
; CHECK-NEXT: lsr z0.h, z0.h, #10
-; CHECK-NEXT: asr z1.h, z1.h, #9
-; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: lsl z1.h, z1.h, #15
+; CHECK-NEXT: ssra z0.h, z1.h, #9
; CHECK-NEXT: ret
%pg = call <vscale x 8 x i1> @llvm.aarch64.sve.ptrue.nxv8i1(i32 31)
%acc = call <vscale x 8 x i16> @llvm.aarch64.sve.lsr.u.nxv8i16(<vscale x 8 x i1> %pg, <vscale x 8 x i16> %a, <vscale x 8 x i16> splat(i16 10))
@@ -546,10 +532,9 @@ define <vscale x 8 x i16> @ssra_disjoint_shift_intr_or8xi16(<vscale x 8 x i16> %
define <vscale x 4 x i32> @ssra_disjoint_shift_intr_or4xi32(<vscale x 4 x i32> %a, <vscale x 4 x i32> %b) #0 {
; CHECK-LABEL: ssra_disjoint_shift_intr_or4xi32:
; CHECK: // %bb.0:
-; CHECK-NEXT: lsl z1.s, z1.s, #31
; CHECK-NEXT: lsr z0.s, z0.s, #26
-; CHECK-NEXT: asr z1.s, z1.s, #25
-; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: lsl z1.s, z1.s, #31
+; CHECK-NEXT: ssra z0.s, z1.s, #25
; CHECK-NEXT: ret
%pg = call <vscale x 4 x i1> @llvm.aarch64.sve.ptrue.nxv4i1(i32 31)
%acc = call <vscale x 4 x i32> @llvm.aarch64.sve.lsr.u.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> %a, <vscale x 4 x i32> splat(i32 26))
@@ -562,10 +547,9 @@ define <vscale x 4 x i32> @ssra_disjoint_shift_intr_or4xi32(<vscale x 4 x i32> %
define <vscale x 2 x i64> @ssra_disjoint_shift_intr_or2xi64(<vscale x 2 x i64> %a, <vscale x 2 x i64> %b) #0 {
; CHECK-LABEL: ssra_disjoint_shift_intr_or2xi64:
; CHECK: // %bb.0:
-; CHECK-NEXT: lsl z1.d, z1.d, #63
; CHECK-NEXT: lsr z0.d, z0.d, #58
-; CHECK-NEXT: asr z1.d, z1.d, #57
-; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: lsl z1.d, z1.d, #63
+; CHECK-NEXT: ssra z0.d, z1.d, #57
; CHECK-NEXT: ret
%pg = call <vscale x 2 x i1> @llvm.aarch64.sve.ptrue.nxv2i1(i32 31)
%acc = call <vscale x 2 x i64> @llvm.aarch64.sve.lsr.u.nxv2i64(<vscale x 2 x i1> %pg, <vscale x 2 x i64> %a, <vscale x 2 x i64> splat(i64 58))
More information about the llvm-commits
mailing list