[llvm] [SystemZ] Fix assertion failures during DAG combine (PR #215027)

Jacob Young via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 18 13:47:51 PDT 2026


https://github.com/jacobly0 updated https://github.com/llvm/llvm-project/pull/215027

>From 829234107ccde8b6dc2547ccbf0fa215f6507d6c Mon Sep 17 00:00:00 2001
From: Jacob Young <jacobly at ziglang.org>
Date: Tue, 18 Aug 2026 15:25:01 -0400
Subject: [PATCH] [SystemZ] Fix assertion failures during DAG combine

Previously this code would generate:

    i16 = bitcast f16
    i32 = truncate i16

Which would immediately assert due to the invalid truncate, but even
with that fixed it would assert later due to the illegal i16.  Instead,
bail out on illegal integer types.
---
 .../Target/SystemZ/SystemZISelLowering.cpp    |  14 +-
 .../CodeGen/SystemZ/fp-half-vector-abs.ll     | 124 ++++++++++++++++++
 2 files changed, 133 insertions(+), 5 deletions(-)
 create mode 100644 llvm/test/CodeGen/SystemZ/fp-half-vector-abs.ll

diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 3773f550eab1f..9c81005d6bd59 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -7631,14 +7631,18 @@ SDValue SystemZTargetLowering::combineExtract(const SDLoc &DL, EVT ResVT,
         break;
       // We're extracting the low part of one operand of the BUILD_VECTOR.
       Op = Op.getOperand(End / OpBytesPerElement - 1);
+      EVT ResIntVT = MVT::getIntegerVT(ResVT.getSizeInBits());
+      if (!isTypeLegal(ResIntVT))
+        break;
       if (!Op.getValueType().isInteger()) {
-        EVT VT = MVT::getIntegerVT(Op.getValueSizeInBits());
-        Op = DAG.getNode(ISD::BITCAST, DL, VT, Op);
+        EVT OpIntVT = MVT::getIntegerVT(Op.getValueSizeInBits());
+        if (!isTypeLegal(OpIntVT))
+          break;
+        Op = DAG.getNode(ISD::BITCAST, DL, OpIntVT, Op);
         DCI.AddToWorklist(Op.getNode());
       }
-      EVT VT = MVT::getIntegerVT(ResVT.getSizeInBits());
-      Op = DAG.getNode(ISD::TRUNCATE, DL, VT, Op);
-      if (VT != ResVT) {
+      Op = DAG.getNode(ISD::TRUNCATE, DL, ResIntVT, Op);
+      if (ResIntVT != ResVT) {
         DCI.AddToWorklist(Op.getNode());
         Op = DAG.getNode(ISD::BITCAST, DL, ResVT, Op);
       }
diff --git a/llvm/test/CodeGen/SystemZ/fp-half-vector-abs.ll b/llvm/test/CodeGen/SystemZ/fp-half-vector-abs.ll
new file mode 100644
index 0000000000000..38d22fc557793
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/fp-half-vector-abs.ll
@@ -0,0 +1,124 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
+; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z16 | FileCheck %s --check-prefix=VECTOR
+
+define <2 x half> @fabs_v2f16(<2 x half> %arg) {
+; CHECK-LABEL: fabs_v2f16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    stmg %r12, %r15, 96(%r15)
+; CHECK-NEXT:    .cfi_offset %r12, -64
+; CHECK-NEXT:    .cfi_offset %r13, -56
+; CHECK-NEXT:    .cfi_offset %r14, -48
+; CHECK-NEXT:    .cfi_offset %r15, -40
+; CHECK-NEXT:    aghi %r15, -184
+; CHECK-NEXT:    .cfi_def_cfa_offset 344
+; CHECK-NEXT:    std %f8, 176(%r15) # 8-byte Spill
+; CHECK-NEXT:    std %f9, 168(%r15) # 8-byte Spill
+; CHECK-NEXT:    std %f10, 160(%r15) # 8-byte Spill
+; CHECK-NEXT:    .cfi_offset %f8, -168
+; CHECK-NEXT:    .cfi_offset %f9, -176
+; CHECK-NEXT:    .cfi_offset %f10, -184
+; CHECK-NEXT:    ler %f8, %f2
+; CHECK-NEXT:    ler %f10, %f0
+; CHECK-NEXT:    lgdr %r0, %f8
+; CHECK-NEXT:    srlg %r0, %r0, 48
+; CHECK-NEXT:    lhr %r13, %r0
+; CHECK-NEXT:    lgdr %r0, %f10
+; CHECK-NEXT:    srlg %r0, %r0, 48
+; CHECK-NEXT:    lcdfr %f0, %f0
+; CHECK-NEXT:    lhr %r12, %r0
+; CHECK-NEXT:    brasl %r14, __extendhfsf2 at PLT
+; CHECK-NEXT:    ler %f9, %f0
+; CHECK-NEXT:    ler %f0, %f10
+; CHECK-NEXT:    brasl %r14, __extendhfsf2 at PLT
+; CHECK-NEXT:    lcdfr %f10, %f8
+; CHECK-NEXT:    cijl %r12, 0, .LBB0_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    ler %f9, %f0
+; CHECK-NEXT:  .LBB0_2:
+; CHECK-NEXT:    ler %f0, %f9
+; CHECK-NEXT:    brasl %r14, __truncsfhf2 at PLT
+; CHECK-NEXT:    ler %f9, %f0
+; CHECK-NEXT:    ler %f0, %f10
+; CHECK-NEXT:    brasl %r14, __extendhfsf2 at PLT
+; CHECK-NEXT:    ler %f10, %f0
+; CHECK-NEXT:    ler %f0, %f8
+; CHECK-NEXT:    brasl %r14, __extendhfsf2 at PLT
+; CHECK-NEXT:    cijl %r13, 0, .LBB0_4
+; CHECK-NEXT:  # %bb.3:
+; CHECK-NEXT:    ler %f10, %f0
+; CHECK-NEXT:  .LBB0_4:
+; CHECK-NEXT:    ler %f0, %f10
+; CHECK-NEXT:    brasl %r14, __truncsfhf2 at PLT
+; CHECK-NEXT:    ler %f2, %f0
+; CHECK-NEXT:    ler %f0, %f9
+; CHECK-NEXT:    ld %f8, 176(%r15) # 8-byte Reload
+; CHECK-NEXT:    ld %f9, 168(%r15) # 8-byte Reload
+; CHECK-NEXT:    ld %f10, 160(%r15) # 8-byte Reload
+; CHECK-NEXT:    lmg %r12, %r15, 280(%r15)
+; CHECK-NEXT:    br %r14
+;
+; VECTOR-LABEL: fabs_v2f16:
+; VECTOR:       # %bb.0:
+; VECTOR-NEXT:    stmg %r12, %r15, 96(%r15)
+; VECTOR-NEXT:    .cfi_offset %r12, -64
+; VECTOR-NEXT:    .cfi_offset %r13, -56
+; VECTOR-NEXT:    .cfi_offset %r14, -48
+; VECTOR-NEXT:    .cfi_offset %r15, -40
+; VECTOR-NEXT:    aghi %r15, -208
+; VECTOR-NEXT:    .cfi_def_cfa_offset 368
+; VECTOR-NEXT:    std %f8, 200(%r15) # 8-byte Spill
+; VECTOR-NEXT:    std %f9, 192(%r15) # 8-byte Spill
+; VECTOR-NEXT:    .cfi_offset %f8, -168
+; VECTOR-NEXT:    .cfi_offset %f9, -176
+; VECTOR-NEXT:    vlgvh %r0, %v24, 1
+; VECTOR-NEXT:    vreph %v0, %v24, 1
+; VECTOR-NEXT:    lhr %r13, %r0
+; VECTOR-NEXT:    vlgvh %r0, %v24, 0
+; VECTOR-NEXT:    vlr %v1, %v24
+; VECTOR-NEXT:    vst %v0, 176(%r15), 3 # 16-byte Spill
+; VECTOR-NEXT:    lcdfr %f0, %f1
+; VECTOR-NEXT:    vst %v24, 160(%r15), 3 # 16-byte Spill
+; VECTOR-NEXT:    lhr %r12, %r0
+; VECTOR-NEXT:    brasl %r14, __extendhfsf2 at PLT
+; VECTOR-NEXT:    ldr %f8, %f0
+; VECTOR-NEXT:    vl %v0, 160(%r15), 3 # 16-byte Reload
+; VECTOR-NEXT:    # kill: def $f0h killed $f0h killed $v0
+; VECTOR-NEXT:    brasl %r14, __extendhfsf2 at PLT
+; VECTOR-NEXT:    vl %v1, 176(%r15), 3 # 16-byte Reload
+; VECTOR-NEXT:    lcdfr %f9, %f1
+; VECTOR-NEXT:    cijl %r12, 0, .LBB0_2
+; VECTOR-NEXT:  # %bb.1:
+; VECTOR-NEXT:    ldr %f8, %f0
+; VECTOR-NEXT:  .LBB0_2:
+; VECTOR-NEXT:    ldr %f0, %f8
+; VECTOR-NEXT:    brasl %r14, __truncsfhf2 at PLT
+; VECTOR-NEXT:    # kill: def $f0h killed $f0h def $v0
+; VECTOR-NEXT:    vst %v0, 160(%r15), 3 # 16-byte Spill
+; VECTOR-NEXT:    ldr %f0, %f9
+; VECTOR-NEXT:    brasl %r14, __extendhfsf2 at PLT
+; VECTOR-NEXT:    ldr %f8, %f0
+; VECTOR-NEXT:    vl %v0, 176(%r15), 3 # 16-byte Reload
+; VECTOR-NEXT:    # kill: def $f0h killed $f0h killed $v0
+; VECTOR-NEXT:    brasl %r14, __extendhfsf2 at PLT
+; VECTOR-NEXT:    cijl %r13, 0, .LBB0_4
+; VECTOR-NEXT:  # %bb.3:
+; VECTOR-NEXT:    ldr %f8, %f0
+; VECTOR-NEXT:  .LBB0_4:
+; VECTOR-NEXT:    ldr %f0, %f8
+; VECTOR-NEXT:    brasl %r14, __truncsfhf2 at PLT
+; VECTOR-NEXT:    vl %v1, 160(%r15), 3 # 16-byte Reload
+; VECTOR-NEXT:    # kill: def $f0h killed $f0h def $v0
+; VECTOR-NEXT:    vmrhh %v0, %v1, %v0
+; VECTOR-NEXT:    ld %f8, 200(%r15) # 8-byte Reload
+; VECTOR-NEXT:    ld %f9, 192(%r15) # 8-byte Reload
+; VECTOR-NEXT:    vmrhf %v0, %v0, %v0
+; VECTOR-NEXT:    vmrhg %v24, %v0, %v0
+; VECTOR-NEXT:    lmg %r12, %r15, 304(%r15)
+; VECTOR-NEXT:    br %r14
+  %bits = bitcast <2 x half> %arg to <2 x i16>
+  %is_neg = icmp slt <2 x i16> %bits, zeroinitializer
+  %neg = fneg <2 x half> %arg
+  %res = select <2 x i1> %is_neg, <2 x half> %neg, <2 x half> %arg
+  ret <2 x half> %res
+}



More information about the llvm-commits mailing list