[llvm] [DAGCombiner] Fold trunc(build_vector(ext(x), ext(x)) -> build_vector(x,x) (PR #179857)
Liao Chunyu via llvm-commits
llvm-commits at lists.llvm.org
Wed Feb 4 20:05:52 PST 2026
https://github.com/ChunyuLiao created https://github.com/llvm/llvm-project/pull/179857
The original implementation performed the transformation when isTruncateFree was true:
truncate(build_vector(x, x)) -> build_vector(truncate(x), truncate(x)).
In some cases, x comes from an ext, try to pre-truncate build_vectors source operands
when the source operands of build_vectors comes from an ext.
Testcase from: https://gcc.godbolt.org/z/bbxbYK7dh
>From a9dd2febe5390187a5bfe5e8b955360c3a890b95 Mon Sep 17 00:00:00 2001
From: Liao Chunyu <chunyu at iscas.ac.cn>
Date: Thu, 5 Feb 2026 03:06:34 +0000
Subject: [PATCH 1/2] init testcase
---
.../CodeGen/RISCV/rvv/fixed-vectors-vaaddu.ll | 45 +++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vaaddu.ll b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vaaddu.ll
index dc432efbd5c47..8d11f9b306265 100644
--- a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vaaddu.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vaaddu.ll
@@ -212,6 +212,51 @@ define <8 x i64> @vaaddu_vx_v8i64_floor(<8 x i64> %x, i64 %y) {
ret <8 x i64> %ret
}
+define <8 x i8> @vaaddu_vx_floor_splat_scalar(<8 x i8> %a, i8 %sc) {
+; CHECK-LABEL: vaaddu_vx_floor_splat_scalar:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xori a0, a0, -126
+; CHECK-NEXT: vsetivli zero, 8, e16, m1, ta, ma
+; CHECK-NEXT: vmv.v.x v9, a0
+; CHECK-NEXT: vsetvli zero, zero, e8, mf2, ta, ma
+; CHECK-NEXT: vnsrl.wi v9, v9, 0
+; CHECK-NEXT: csrwi vxrm, 2
+; CHECK-NEXT: vaaddu.vv v8, v9, v8
+; CHECK-NEXT: ret
+ %1 = xor i8 %sc, -126
+ %c = zext i8 %1 to i16
+ %za = zext <8 x i8> %a to <8 x i16>
+ %yhead = insertelement <8 x i16> poison, i16 %c, i64 0
+ %yzv = shufflevector <8 x i16> %yhead, <8 x i16> poison, <8 x i32> zeroinitializer
+ %add = add nuw nsw <8 x i16> %yzv, %za
+ %div = lshr <8 x i16> %add, splat (i16 1)
+ %ret = trunc nuw <8 x i16> %div to <8 x i8>
+ ret <8 x i8> %ret
+}
+
+define <8 x i8> @vaaddu_vx_ceil_splat_scalar(<8 x i8> %x, i8 %y) {
+; CHECK-LABEL: vaaddu_vx_ceil_splat_scalar:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xori a0, a0, -126
+; CHECK-NEXT: vsetivli zero, 8, e16, m1, ta, ma
+; CHECK-NEXT: vmv.v.x v9, a0
+; CHECK-NEXT: vsetvli zero, zero, e8, mf2, ta, ma
+; CHECK-NEXT: vnsrl.wi v9, v9, 0
+; CHECK-NEXT: csrwi vxrm, 0
+; CHECK-NEXT: vaaddu.vv v8, v8, v9
+; CHECK-NEXT: ret
+ %1 = xor i8 %y, -126
+ %c = zext i8 %1 to i16
+ %xzv = zext <8 x i8> %x to <8 x i16>
+ %yhead = insertelement <8 x i16> poison, i16 %c, i32 0
+ %yzv = shufflevector <8 x i16> %yhead, <8 x i16> poison, <8 x i32> zeroinitializer
+ %add = add nuw nsw <8 x i16> %xzv, %yzv
+ %add1 = add nuw nsw <8 x i16> %add, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+ %div = lshr <8 x i16> %add1, splat (i16 1)
+ %ret = trunc <8 x i16> %div to <8 x i8>
+ ret <8 x i8> %ret
+}
+
define <8 x i8> @vaaddu_vv_v8i8_ceil(<8 x i8> %x, <8 x i8> %y) {
; CHECK-LABEL: vaaddu_vv_v8i8_ceil:
; CHECK: # %bb.0:
>From 0fe9fd3b3052fe3297dfdbf179b38230286fb309 Mon Sep 17 00:00:00 2001
From: Liao Chunyu <chunyu at iscas.ac.cn>
Date: Thu, 5 Feb 2026 03:59:34 +0000
Subject: [PATCH 2/2] [DAGCombiner] Fold trunc(build_vector(ext(x), ext(x)) ->
build_vector(x,x)
The original implementation performed the transformation when isTruncateFree was true:
truncate(build_vector(x, x)) -> build_vector(truncate(x), truncate(x)).
In some cases, x comes from an ext, try to pre-truncate build_vectors source operands
when the source operands of build_vectors comes from an ext.
Testcase from: https://gcc.godbolt.org/z/bbxbYK7dh
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 24 +++++++++++++++----
.../CodeGen/RISCV/rvv/fixed-vectors-vaaddu.ll | 18 +++++---------
2 files changed, 25 insertions(+), 17 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index df69f0870d27a..772dedf5f79cd 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -16634,16 +16634,30 @@ SDValue DAGCombiner::visitTRUNCATE(SDNode *N) {
// Attempt to pre-truncate BUILD_VECTOR sources.
if (N0.getOpcode() == ISD::BUILD_VECTOR && !LegalOperations &&
N0.hasOneUse() &&
- TLI.isTruncateFree(SrcVT.getScalarType(), VT.getScalarType()) &&
// Avoid creating illegal types if running after type legalizer.
(!LegalTypes || TLI.isTypeLegal(VT.getScalarType()))) {
EVT SVT = VT.getScalarType();
SmallVector<SDValue, 8> TruncOps;
- for (const SDValue &Op : N0->op_values()) {
- SDValue TruncOp = DAG.getNode(ISD::TRUNCATE, DL, SVT, Op);
- TruncOps.push_back(TruncOp);
+
+ if (TLI.isTruncateFree(SrcVT.getScalarType(), VT.getScalarType())) {
+ for (const SDValue &Op : N0->op_values()) {
+ SDValue TruncOp = DAG.getNode(ISD::TRUNCATE, DL, SVT, Op);
+ TruncOps.push_back(TruncOp);
+ }
+ return DAG.getBuildVector(VT, DL, TruncOps);
+ }
+ // trunc(build_vector(ext(x), ext(x)) -> build_vector(x,x)
+ SDValue SplatVal = DAG.getSplatValue(N0);
+ if (SplatVal) {
+ unsigned Opcode = SplatVal.getOpcode();
+ if ((Opcode == ISD::SIGN_EXTEND || Opcode == ISD::ZERO_EXTEND ||
+ Opcode == ISD::ANY_EXTEND) &&
+ SrcVT.getScalarType() == SplatVal.getValueType()) {
+ for (const SDValue &Op : N0->op_values())
+ TruncOps.push_back(Op);
+ return DAG.getBuildVector(VT, DL, TruncOps);
+ }
}
- return DAG.getBuildVector(VT, DL, TruncOps);
}
// trunc (splat_vector x) -> splat_vector (trunc x)
diff --git a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vaaddu.ll b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vaaddu.ll
index 8d11f9b306265..755ad8c402628 100644
--- a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vaaddu.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vaaddu.ll
@@ -215,13 +215,10 @@ define <8 x i64> @vaaddu_vx_v8i64_floor(<8 x i64> %x, i64 %y) {
define <8 x i8> @vaaddu_vx_floor_splat_scalar(<8 x i8> %a, i8 %sc) {
; CHECK-LABEL: vaaddu_vx_floor_splat_scalar:
; CHECK: # %bb.0:
-; CHECK-NEXT: xori a0, a0, -126
-; CHECK-NEXT: vsetivli zero, 8, e16, m1, ta, ma
-; CHECK-NEXT: vmv.v.x v9, a0
-; CHECK-NEXT: vsetvli zero, zero, e8, mf2, ta, ma
-; CHECK-NEXT: vnsrl.wi v9, v9, 0
+; CHECK-NEXT: xori a0, a0, 130
; CHECK-NEXT: csrwi vxrm, 2
-; CHECK-NEXT: vaaddu.vv v8, v9, v8
+; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
+; CHECK-NEXT: vaaddu.vx v8, v8, a0
; CHECK-NEXT: ret
%1 = xor i8 %sc, -126
%c = zext i8 %1 to i16
@@ -237,13 +234,10 @@ define <8 x i8> @vaaddu_vx_floor_splat_scalar(<8 x i8> %a, i8 %sc) {
define <8 x i8> @vaaddu_vx_ceil_splat_scalar(<8 x i8> %x, i8 %y) {
; CHECK-LABEL: vaaddu_vx_ceil_splat_scalar:
; CHECK: # %bb.0:
-; CHECK-NEXT: xori a0, a0, -126
-; CHECK-NEXT: vsetivli zero, 8, e16, m1, ta, ma
-; CHECK-NEXT: vmv.v.x v9, a0
-; CHECK-NEXT: vsetvli zero, zero, e8, mf2, ta, ma
-; CHECK-NEXT: vnsrl.wi v9, v9, 0
+; CHECK-NEXT: xori a0, a0, 130
; CHECK-NEXT: csrwi vxrm, 0
-; CHECK-NEXT: vaaddu.vv v8, v8, v9
+; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
+; CHECK-NEXT: vaaddu.vx v8, v8, a0
; CHECK-NEXT: ret
%1 = xor i8 %y, -126
%c = zext i8 %1 to i16
More information about the llvm-commits
mailing list