[llvm] [SystemZ] Don't zero extend after a VLGV[BHF] instruction. (PR #201109)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 2 05:59:29 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-systemz

Author: Jonas Paulsson (JonPsson1)

<details>
<summary>Changes</summary>

The VLGV already zero extends up to 64 bits, so a following zero extend is not needed.

New TableGen patterns for these cases as well as a handling to avoid tryRISBGZero() selecting i64 cases.

---
Full diff: https://github.com/llvm/llvm-project/pull/201109.diff


3 Files Affected:

- (modified) llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp (+17-1) 
- (modified) llvm/lib/Target/SystemZ/SystemZInstrVector.td (+25) 
- (added) llvm/test/CodeGen/SystemZ/vec-move-25.ll (+206) 


``````````diff
diff --git a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
index a05fdc74e6366..5291a9d782e4e 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
@@ -1643,9 +1643,25 @@ void SystemZDAGToDAGISel::Select(SDNode *Node) {
     break;
 
   case ISD::AND:
-    if (Node->getOperand(1).getOpcode() != ISD::Constant)
+    if (Node->getOperand(1).getOpcode() != ISD::Constant) {
       if (tryRxSBG(Node, SystemZ::RNSBG))
         return;
+    } else {
+      // Use patterns for zero-extending of vector element extraction.
+      if (Node->getValueType(0) == MVT::i64 &&
+          Node->getOperand(0)->getOpcode() == ISD::ANY_EXTEND) {
+        SDValue Input = Node->getOperand(0)->getOperand(0);
+        uint64_t Mask =
+            cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue();
+        if (Input->getOpcode() == ISD::EXTRACT_VECTOR_ELT) {
+          EVT VecVT = Input->getOperand(0)->getValueType(0);
+          unsigned EltBits = VecVT.getScalarSizeInBits();
+          if (allOnes(EltBits) == Mask)
+            break;
+        }
+      }
+    }
+
     [[fallthrough]];
   case ISD::ROTL:
   case ISD::SHL:
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrVector.td b/llvm/lib/Target/SystemZ/SystemZInstrVector.td
index fe26bdc72799b..1dbbb1b9222cc 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrVector.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrVector.td
@@ -53,6 +53,31 @@ def : VectorExtractSubreg<v16i8, VLGVB>;
 def : VectorExtractSubreg<v8i16, VLGVH>;
 def : VectorExtractSubreg<v4i32, VLGVF>;
 
+// VLGVX extractions always zero extend to 64 bits, so no need for a
+// following zero extend.
+// i8/i16 -> i32.
+class VectorExtractZextSubreg<ValueType VecTy, Instruction insn,
+                              SDPatternOperator operator>
+  : Pat<(i32 (operator (i32 (z_vector_extract (VecTy VR128:$vec),
+                                              shift12only:$index)))),
+        (EXTRACT_SUBREG (insn VR128:$vec, shift12only:$index), subreg_l32)>;
+def : VectorExtractZextSubreg<v16i8, VLGVB, zext8>;
+def : VectorExtractZextSubreg<v8i16, VLGVH, zext16>;
+
+// i8/i16 -> i64.
+class VectorExtractZext<ValueType VecTy, Instruction insn,
+                        SDPatternOperator operator>
+  : Pat<(i64 (operator (anyext (i32 (z_vector_extract (VecTy VR128:$vec),
+                                                      shift12only:$index))))),
+        (insn VR128:$vec, shift12only:$index)>;
+def : VectorExtractZext<v16i8, VLGVB, zext8>;
+def : VectorExtractZext<v8i16, VLGVH, zext16>;
+
+// i32 -> i64.
+def : Pat<(i64 (zext (i32 (z_vector_extract (v4i32 VR128:$vec),
+                                            shift12only:$index)))),
+          (VLGVF VR128:$vec, shift12only:$index)>;
+
 //===----------------------------------------------------------------------===//
 // Immediate instructions
 //===----------------------------------------------------------------------===//
diff --git a/llvm/test/CodeGen/SystemZ/vec-move-25.ll b/llvm/test/CodeGen/SystemZ/vec-move-25.ll
new file mode 100644
index 0000000000000..ebebb20599393
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/vec-move-25.ll
@@ -0,0 +1,206 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z17 | FileCheck %s
+;
+; Test that zero extension is not made after a vector element extraction.
+
+define i16 @fun0(<16 x i8> %Arg) {
+; CHECK-LABEL: fun0:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vlgvb %r2, %v24, 0
+; CHECK-NEXT:    # kill: def $r2l killed $r2l killed $r2d
+; CHECK-NEXT:    br %r14
+  %Elt = extractelement <16 x i8> %Arg, i32 0
+  %Ext = zext i8 %Elt to i16
+  ret i16 %Ext
+}
+
+define i32 @fun1(<16 x i8> %Arg) {
+; CHECK-LABEL: fun1:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vlgvb %r2, %v24, 0
+; CHECK-NEXT:    # kill: def $r2l killed $r2l killed $r2d
+; CHECK-NEXT:    br %r14
+  %Elt = extractelement <16 x i8> %Arg, i32 0
+  %Ext = zext i8 %Elt to i32
+  ret i32 %Ext
+}
+
+define i64 @fun2(<16 x i8> %Arg) {
+; CHECK-LABEL: fun2:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vlgvb %r2, %v24, 0
+; CHECK-NEXT:    br %r14
+  %Elt = extractelement <16 x i8> %Arg, i32 0
+  %Ext = zext i8 %Elt to i64
+  ret i64 %Ext
+}
+
+define i128 @fun3(<16 x i8> %Arg) {
+; CHECK-LABEL: fun3:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vlgvb %r0, %v24, 0
+; CHECK-NEXT:    vgbm %v0, 0
+; CHECK-NEXT:    vlvgb %v0, %r0, 15
+; CHECK-NEXT:    vst %v0, 0(%r2), 3
+; CHECK-NEXT:    br %r14
+  %Elt = extractelement <16 x i8> %Arg, i32 0
+  %Ext = zext i8 %Elt to i128
+  ret i128 %Ext
+}
+
+define i32 @fun4(<8 x i16> %Arg) {
+; CHECK-LABEL: fun4:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vlgvh %r2, %v24, 0
+; CHECK-NEXT:    # kill: def $r2l killed $r2l killed $r2d
+; CHECK-NEXT:    br %r14
+  %Elt = extractelement <8 x i16> %Arg, i32 0
+  %Ext = zext i16 %Elt to i32
+  ret i32 %Ext
+}
+
+define i64 @fun5(<8 x i16> %Arg) {
+; CHECK-LABEL: fun5:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vlgvh %r2, %v24, 0
+; CHECK-NEXT:    br %r14
+  %Elt = extractelement <8 x i16> %Arg, i32 0
+  %Ext = zext i16 %Elt to i64
+  ret i64 %Ext
+}
+
+define i128 @fun6(<8 x i16> %Arg) {
+; CHECK-LABEL: fun6:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vlgvh %r0, %v24, 0
+; CHECK-NEXT:    vgbm %v0, 0
+; CHECK-NEXT:    vlvgh %v0, %r0, 7
+; CHECK-NEXT:    vst %v0, 0(%r2), 3
+; CHECK-NEXT:    br %r14
+  %Elt = extractelement <8 x i16> %Arg, i32 0
+  %Ext = zext i16 %Elt to i128
+  ret i128 %Ext
+}
+
+define i64 @fun7(<4 x i32> %Arg) {
+; CHECK-LABEL: fun7:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vlgvf %r2, %v24, 0
+; CHECK-NEXT:    br %r14
+  %Elt = extractelement <4 x i32> %Arg, i32 0
+  %Ext = zext i32 %Elt to i64
+  ret i64 %Ext
+}
+
+define i128 @fun8(<4 x i32> %Arg) {
+; CHECK-LABEL: fun8:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vuplhf %v0, %v24
+; CHECK-NEXT:    vuplhg %v0, %v0
+; CHECK-NEXT:    vst %v0, 0(%r2), 3
+; CHECK-NEXT:    br %r14
+  %Elt = extractelement <4 x i32> %Arg, i32 0
+  %Ext = zext i32 %Elt to i128
+  ret i128 %Ext
+}
+
+define i16 @fun9(<16 x i8> %Arg, i32 %index) {
+; CHECK-LABEL: fun9:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vlgvb %r2, %v24, 0
+; CHECK-NEXT:    # kill: def $r2l killed $r2l killed $r2d
+; CHECK-NEXT:    br %r14
+  %Elt = extractelement <16 x i8> %Arg, i32 0
+  %Ext = zext i8 %Elt to i16
+  ret i16 %Ext
+}
+
+define i32 @fun10(<16 x i8> %Arg, i32 %index) {
+; CHECK-LABEL: fun10:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vlgvb %r2, %v24, 0
+; CHECK-NEXT:    # kill: def $r2l killed $r2l killed $r2d
+; CHECK-NEXT:    br %r14
+  %Elt = extractelement <16 x i8> %Arg, i32 0
+  %Ext = zext i8 %Elt to i32
+  ret i32 %Ext
+}
+
+define i64 @fun11(<16 x i8> %Arg, i32 %index) {
+; CHECK-LABEL: fun11:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vlgvb %r2, %v24, 0
+; CHECK-NEXT:    br %r14
+  %Elt = extractelement <16 x i8> %Arg, i32 0
+  %Ext = zext i8 %Elt to i64
+  ret i64 %Ext
+}
+
+define i128 @fun12(<16 x i8> %Arg, i32 %index) {
+; CHECK-LABEL: fun12:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vlgvb %r0, %v24, 0
+; CHECK-NEXT:    vgbm %v0, 0
+; CHECK-NEXT:    vlvgb %v0, %r0, 15
+; CHECK-NEXT:    vst %v0, 0(%r2), 3
+; CHECK-NEXT:    br %r14
+  %Elt = extractelement <16 x i8> %Arg, i32 0
+  %Ext = zext i8 %Elt to i128
+  ret i128 %Ext
+}
+
+define i32 @fun13(<8 x i16> %Arg, i32 %index) {
+; CHECK-LABEL: fun13:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vlgvh %r2, %v24, 0
+; CHECK-NEXT:    # kill: def $r2l killed $r2l killed $r2d
+; CHECK-NEXT:    br %r14
+  %Elt = extractelement <8 x i16> %Arg, i32 0
+  %Ext = zext i16 %Elt to i32
+  ret i32 %Ext
+}
+
+define i64 @fun14(<8 x i16> %Arg, i32 %index) {
+; CHECK-LABEL: fun14:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vlgvh %r2, %v24, 0
+; CHECK-NEXT:    br %r14
+  %Elt = extractelement <8 x i16> %Arg, i32 0
+  %Ext = zext i16 %Elt to i64
+  ret i64 %Ext
+}
+
+define i128 @fun15(<8 x i16> %Arg, i32 %index) {
+; CHECK-LABEL: fun15:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vlgvh %r0, %v24, 0
+; CHECK-NEXT:    vgbm %v0, 0
+; CHECK-NEXT:    vlvgh %v0, %r0, 7
+; CHECK-NEXT:    vst %v0, 0(%r2), 3
+; CHECK-NEXT:    br %r14
+  %Elt = extractelement <8 x i16> %Arg, i32 0
+  %Ext = zext i16 %Elt to i128
+  ret i128 %Ext
+}
+
+define i64 @fun16(<4 x i32> %Arg, i32 %index) {
+; CHECK-LABEL: fun16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vlgvf %r2, %v24, 0
+; CHECK-NEXT:    br %r14
+  %Elt = extractelement <4 x i32> %Arg, i32 0
+  %Ext = zext i32 %Elt to i64
+  ret i64 %Ext
+}
+
+define i128 @fun17(<4 x i32> %Arg, i32 %index) {
+; CHECK-LABEL: fun17:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vuplhf %v0, %v24
+; CHECK-NEXT:    vuplhg %v0, %v0
+; CHECK-NEXT:    vst %v0, 0(%r2), 3
+; CHECK-NEXT:    br %r14
+  %Elt = extractelement <4 x i32> %Arg, i32 0
+  %Ext = zext i32 %Elt to i128
+  ret i128 %Ext
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/201109


More information about the llvm-commits mailing list