[llvm] [AArch64] Combine truncate(buildvector) -> buildvector (PR #223787)

David Green via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 22 23:07:31 PDT 2026


https://github.com/davemgreen updated https://github.com/llvm/llvm-project/pull/223787

>From 4a7e370a5030e12264f1415cb8e1a649643179d9 Mon Sep 17 00:00:00 2001
From: David Green <david.green at arm.com>
Date: Tue, 15 Sep 2026 20:11:41 +0100
Subject: [PATCH] [AArch64] Combine truncate(buildvector) -> buildvector

If late in the pipeline we are left with truncate(buildvector), we can generate
the buildvector directly. This helps remove the xtn and can lead to other
simplification.
---
 .../Target/AArch64/AArch64ISelLowering.cpp    |  7 ++++
 llvm/test/CodeGen/AArch64/binopshuffles.ll    |  2 +-
 .../CodeGen/AArch64/fp-intrinsics-vector.ll   | 36 +++++++++----------
 llvm/test/CodeGen/AArch64/neon-truncstore.ll  |  2 --
 llvm/test/CodeGen/AArch64/store.ll            |  5 ++-
 .../sve-extract-vector-to-predicate-store.ll  |  7 ++--
 .../AArch64/vec3-loads-ext-trunc-stores.ll    | 14 ++++----
 7 files changed, 37 insertions(+), 36 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 2a50c0c474ab95..2ffc0069d6a1f4 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -24045,6 +24045,13 @@ static SDValue performTruncateCombine(SDNode *N, SelectionDAG &DAG,
                        DAG.getVectorIdxConstant(ExtractIndex * 2, DL));
   }
 
+  // truncate(buildvector) -> buildvector if we still have it late in the
+  // pipeline. We do not truncate the operand types as the buildvector
+  // implicitly truncates.
+  if (!DCI.isBeforeLegalizeOps() && N0.getOpcode() == ISD::BUILD_VECTOR &&
+      N0.hasOneUse() && (VT == MVT::v8i8 || VT == MVT::v4i16))
+    return DAG.getBuildVector(VT, DL, N0->ops());
+
   return SDValue();
 }
 
diff --git a/llvm/test/CodeGen/AArch64/binopshuffles.ll b/llvm/test/CodeGen/AArch64/binopshuffles.ll
index 3ee9df3165c985..0f2fe1cabe2b66 100644
--- a/llvm/test/CodeGen/AArch64/binopshuffles.ll
+++ b/llvm/test/CodeGen/AArch64/binopshuffles.ll
@@ -173,7 +173,7 @@ define void @noncanonical(ptr %p0, ptr %p1, ptr %p2) {
 ; CHECK-LABEL: noncanonical:
 ; CHECK:       // %bb.0: // %entry
 ; CHECK-NEXT:    ldr d0, [x1]
-; CHECK-NEXT:    xtn v0.8b, v0.8h
+; CHECK-NEXT:    uzp1 v0.8b, v0.8b, v0.8b
 ; CHECK-NEXT:    str s0, [x2]
 ; CHECK-NEXT:    ret
 entry:
diff --git a/llvm/test/CodeGen/AArch64/fp-intrinsics-vector.ll b/llvm/test/CodeGen/AArch64/fp-intrinsics-vector.ll
index 0b05e00a1b0db2..8e63ee39839be5 100644
--- a/llvm/test/CodeGen/AArch64/fp-intrinsics-vector.ll
+++ b/llvm/test/CodeGen/AArch64/fp-intrinsics-vector.ll
@@ -345,22 +345,22 @@ define <4 x i1> @fcmp_v4f32(<4 x float> %x, <4 x float> %y) #0 {
 ; CHECK-NEXT:    mov s2, v1.s[1]
 ; CHECK-NEXT:    mov s3, v0.s[1]
 ; CHECK-NEXT:    fcmp s0, s1
+; CHECK-NEXT:    mov s4, v0.s[2]
+; CHECK-NEXT:    mov s0, v0.s[3]
 ; CHECK-NEXT:    csetm w8, eq
 ; CHECK-NEXT:    fcmp s3, s2
-; CHECK-NEXT:    mov s2, v1.s[2]
-; CHECK-NEXT:    mov s3, v0.s[2]
-; CHECK-NEXT:    fmov s4, w8
+; CHECK-NEXT:    mov s3, v1.s[2]
+; CHECK-NEXT:    fmov s2, w8
 ; CHECK-NEXT:    mov s1, v1.s[3]
-; CHECK-NEXT:    mov s0, v0.s[3]
 ; CHECK-NEXT:    csetm w8, eq
-; CHECK-NEXT:    mov v4.s[1], w8
-; CHECK-NEXT:    fcmp s3, s2
+; CHECK-NEXT:    mov v2.h[1], w8
+; CHECK-NEXT:    fcmp s4, s3
 ; CHECK-NEXT:    csetm w8, eq
 ; CHECK-NEXT:    fcmp s0, s1
-; CHECK-NEXT:    mov v4.s[2], w8
+; CHECK-NEXT:    mov v2.h[2], w8
 ; CHECK-NEXT:    csetm w8, eq
-; CHECK-NEXT:    mov v4.s[3], w8
-; CHECK-NEXT:    xtn v0.4h, v4.4s
+; CHECK-NEXT:    mov v2.h[3], w8
+; CHECK-NEXT:    fmov d0, d2
 ; CHECK-NEXT:    ret
 entry:
   %val = call <4 x i1> @llvm.experimental.constrained.fcmp.v4f64(<4 x float> %x, <4 x float> %y, metadata !"oeq", metadata !"fpexcept.strict")
@@ -373,22 +373,22 @@ define <4 x i1> @fcmps_v4f32(<4 x float> %x, <4 x float> %y) #0 {
 ; CHECK-NEXT:    mov s2, v1.s[1]
 ; CHECK-NEXT:    mov s3, v0.s[1]
 ; CHECK-NEXT:    fcmpe s0, s1
+; CHECK-NEXT:    mov s4, v0.s[2]
+; CHECK-NEXT:    mov s0, v0.s[3]
 ; CHECK-NEXT:    csetm w8, eq
 ; CHECK-NEXT:    fcmpe s3, s2
-; CHECK-NEXT:    mov s2, v1.s[2]
-; CHECK-NEXT:    mov s3, v0.s[2]
-; CHECK-NEXT:    fmov s4, w8
+; CHECK-NEXT:    mov s3, v1.s[2]
+; CHECK-NEXT:    fmov s2, w8
 ; CHECK-NEXT:    mov s1, v1.s[3]
-; CHECK-NEXT:    mov s0, v0.s[3]
 ; CHECK-NEXT:    csetm w8, eq
-; CHECK-NEXT:    mov v4.s[1], w8
-; CHECK-NEXT:    fcmpe s3, s2
+; CHECK-NEXT:    mov v2.h[1], w8
+; CHECK-NEXT:    fcmpe s4, s3
 ; CHECK-NEXT:    csetm w8, eq
 ; CHECK-NEXT:    fcmpe s0, s1
-; CHECK-NEXT:    mov v4.s[2], w8
+; CHECK-NEXT:    mov v2.h[2], w8
 ; CHECK-NEXT:    csetm w8, eq
-; CHECK-NEXT:    mov v4.s[3], w8
-; CHECK-NEXT:    xtn v0.4h, v4.4s
+; CHECK-NEXT:    mov v2.h[3], w8
+; CHECK-NEXT:    fmov d0, d2
 ; CHECK-NEXT:    ret
 entry:
   %val = call <4 x i1> @llvm.experimental.constrained.fcmps.v4f32(<4 x float> %x, <4 x float> %y, metadata !"oeq", metadata !"fpexcept.strict")
diff --git a/llvm/test/CodeGen/AArch64/neon-truncstore.ll b/llvm/test/CodeGen/AArch64/neon-truncstore.ll
index 9666cd705cbf6a..88e1deff375c17 100644
--- a/llvm/test/CodeGen/AArch64/neon-truncstore.ll
+++ b/llvm/test/CodeGen/AArch64/neon-truncstore.ll
@@ -262,8 +262,6 @@ define void @extract_v4i8_v8i8(<8 x i8> %a, ptr %p) {
 ; CHECK-LABEL: extract_v4i8_v8i8:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    // kill: def $d0 killed $d0 def $q0
-; CHECK-NEXT:    zip1 v0.16b, v0.16b, v0.16b
-; CHECK-NEXT:    xtn v0.8b, v0.8h
 ; CHECK-NEXT:    str s0, [x0]
 ; CHECK-NEXT:    ret
   %c = shufflevector <8 x i8> %a, <8 x i8> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
diff --git a/llvm/test/CodeGen/AArch64/store.ll b/llvm/test/CodeGen/AArch64/store.ll
index 72f1cb5a0b22fc..5daf8c2317ca07 100644
--- a/llvm/test/CodeGen/AArch64/store.ll
+++ b/llvm/test/CodeGen/AArch64/store.ll
@@ -231,9 +231,8 @@ define void @store_v3i8(<3 x i8> %a, ptr %ptr){
 ; CHECK-SD-NEXT:    .cfi_def_cfa_offset 16
 ; CHECK-SD-NEXT:    fmov s0, w0
 ; CHECK-SD-NEXT:    strb w2, [x3, #2]
-; CHECK-SD-NEXT:    mov v0.h[1], w1
-; CHECK-SD-NEXT:    mov v0.h[2], w2
-; CHECK-SD-NEXT:    xtn v0.8b, v0.8h
+; CHECK-SD-NEXT:    mov v0.b[1], w1
+; CHECK-SD-NEXT:    mov v0.b[2], w2
 ; CHECK-SD-NEXT:    ushll v0.4s, v0.4h, #0
 ; CHECK-SD-NEXT:    str h0, [x3]
 ; CHECK-SD-NEXT:    add sp, sp, #16
diff --git a/llvm/test/CodeGen/AArch64/sve-extract-vector-to-predicate-store.ll b/llvm/test/CodeGen/AArch64/sve-extract-vector-to-predicate-store.ll
index a432e9590ec3b6..0c7849ad40b28a 100644
--- a/llvm/test/CodeGen/AArch64/sve-extract-vector-to-predicate-store.ll
+++ b/llvm/test/CodeGen/AArch64/sve-extract-vector-to-predicate-store.ll
@@ -51,12 +51,11 @@ define void @pred_store_neg1(<vscale x 16 x i1> %pred, ptr %addr) #0 {
 ; CHECK-NEXT:    mov w8, v0.s[2]
 ; CHECK-NEXT:    mov z2.s, z0.s[4]
 ; CHECK-NEXT:    mov z1.s, z0.s[6]
-; CHECK-NEXT:    mov v0.h[1], w8
+; CHECK-NEXT:    mov v0.b[1], w8
 ; CHECK-NEXT:    fmov w8, s2
-; CHECK-NEXT:    mov v0.h[2], w8
+; CHECK-NEXT:    mov v0.b[2], w8
 ; CHECK-NEXT:    fmov w8, s1
-; CHECK-NEXT:    mov v0.h[3], w8
-; CHECK-NEXT:    xtn v0.8b, v0.8h
+; CHECK-NEXT:    mov v0.b[3], w8
 ; CHECK-NEXT:    str s0, [x0]
 ; CHECK-NEXT:    addvl sp, sp, #1
 ; CHECK-NEXT:    ldr x29, [sp], #16 // 8-byte Folded Reload
diff --git a/llvm/test/CodeGen/AArch64/vec3-loads-ext-trunc-stores.ll b/llvm/test/CodeGen/AArch64/vec3-loads-ext-trunc-stores.ll
index 538dbf94608c7f..b58af24483b254 100644
--- a/llvm/test/CodeGen/AArch64/vec3-loads-ext-trunc-stores.ll
+++ b/llvm/test/CodeGen/AArch64/vec3-loads-ext-trunc-stores.ll
@@ -897,11 +897,10 @@ define void @store_trunc_v3i64_to_v3i8(ptr %p, <3 x i64> %x) {
 ; CHECK-NEXT:    xtn.2s v0, v0
 ; CHECK-NEXT:    stur b1, [x0, #2]
 ; CHECK-NEXT:    mov.s w8, v0[1]
-; CHECK-NEXT:    mov.h v0[1], w8
+; CHECK-NEXT:    mov.b v0[1], w8
 ; CHECK-NEXT:    mov.s w8, v1[1]
-; CHECK-NEXT:    mov.h v0[2], v1[0]
-; CHECK-NEXT:    mov.h v0[3], w8
-; CHECK-NEXT:    xtn.8b v0, v0
+; CHECK-NEXT:    mov.b v0[2], v1[0]
+; CHECK-NEXT:    mov.b v0[3], w8
 ; CHECK-NEXT:    ushll.4s v0, v0, #0
 ; CHECK-NEXT:    str h0, [x0]
 ; CHECK-NEXT:    add sp, sp, #16
@@ -919,11 +918,10 @@ define void @store_trunc_v3i64_to_v3i8(ptr %p, <3 x i64> %x) {
 ; BE-NEXT:    xtn v0.2s, v0.2d
 ; BE-NEXT:    stur b1, [x0, #2]
 ; BE-NEXT:    mov w8, v0.s[1]
-; BE-NEXT:    mov v0.h[1], w8
+; BE-NEXT:    mov v0.b[1], w8
 ; BE-NEXT:    mov w8, v1.s[1]
-; BE-NEXT:    mov v0.h[2], v1.h[0]
-; BE-NEXT:    mov v0.h[3], w8
-; BE-NEXT:    xtn v0.8b, v0.8h
+; BE-NEXT:    mov v0.b[2], v1.b[0]
+; BE-NEXT:    mov v0.b[3], w8
 ; BE-NEXT:    rev32 v0.16b, v0.16b
 ; BE-NEXT:    rev32 v0.4h, v0.4h
 ; BE-NEXT:    ushll v0.4s, v0.4h, #0



More information about the llvm-commits mailing list