https://github.com/zibi2 updated 
https://github.com/llvm/llvm-project/pull/223026

>From de8f5889e0bada955aaa3f37c67cf1b8d273f646 Mon Sep 17 00:00:00 2001
From: Zibi Sarbinowski <[email protected]>
Date: Tue, 15 Sep 2026 11:01:11 -0400
Subject: [PATCH 1/2] [SystemZ][z/OS] Add -mvx/-msoft-float diagnostics and fix
 arch guard

Port of Woz commits 3ba754d, 5e94ae9, 8702193:

- Add err_drv_incompatible_arch diagnostic: '-mvx' requires at least
  '-march=arch11' on z/OS; the guard is T.isOSzOS() so Linux targets
  are unaffected
- Add err_drv_unsupported_opt_for_target diagnostic for '-msoft-float'
  on z/OS targets
- Pass Triple into getSystemZTargetFeatures() to enable the OS check
- Move FloatABI handling after the -mvx block (no functional change for
  the feature vector ordering)
- Extend systemz-features.cpp with s390x-ibm-zos RUN lines; -mvx z/OS
  lines require -march=arch11 since the default z/OS CPU is zEC12
---
 .../clang/Basic/DiagnosticDriverKinds.td      |   3 +
 clang/lib/Basic/Targets/SystemZ.h             |   5 +
 clang/lib/Driver/ToolChains/Arch/SystemZ.cpp  |  22 +-
 clang/lib/Driver/ToolChains/Arch/SystemZ.h    |   3 +-
 clang/lib/Driver/ToolChains/CommonArgs.cpp    |   2 +-
 clang/test/CodeGen/SystemZ/zos-alignment.c    |  10 +-
 clang/test/Driver/systemz-features.cpp        |   9 +
 clang/test/Sema/zvector.c                     |   4 +
 llvm/lib/Target/SystemZ/SystemZCallingConv.h  |   8 +
 llvm/lib/Target/SystemZ/SystemZCallingConv.td |   7 +
 .../Target/SystemZ/SystemZISelLowering.cpp    |  29 +-
 llvm/lib/Target/SystemZ/SystemZSubtarget.h    |   3 +
 llvm/test/CodeGen/SystemZ/call-zos-i128.ll    |  14 +-
 llvm/test/CodeGen/SystemZ/int-div-09.ll       |  13 +
 .../test/CodeGen/SystemZ/zos-abi-int128-64.ll | 253 ++++++++++++++++++
 15 files changed, 356 insertions(+), 29 deletions(-)
 create mode 100644 llvm/test/CodeGen/SystemZ/int-div-09.ll
 create mode 100644 llvm/test/CodeGen/SystemZ/zos-abi-int128-64.ll

diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td 
b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index df6ff0c2cf399..7e872c5da674d 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -203,6 +203,9 @@ def err_drv_unsupported_unwind_for_platform : Error<
   "unsupported unwind library '%0' for platform '%1'">;
 def err_drv_incompatible_unwindlib : Error<
   "--rtlib=libgcc requires --unwindlib=libgcc">;
+def err_drv_incompatible_arch : Error<
+  "'%0' option requires at least '%1', current '%2' is too low">;
+
 def err_drv_incompatible_options : Error<
   "the combination of '%0' and '%1' is incompatible">;
 def err_drv_invalid_cstdlib_name : Error<
diff --git a/clang/lib/Basic/Targets/SystemZ.h 
b/clang/lib/Basic/Targets/SystemZ.h
index cf7d940c1b2e5..6aaf47fb44f5b 100644
--- a/clang/lib/Basic/Targets/SystemZ.h
+++ b/clang/lib/Basic/Targets/SystemZ.h
@@ -261,6 +261,11 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public 
TargetInfo {
   uint64_t getPointerAlignV(LangAS AddrSpace) const override {
     return getPointerWidthV(AddrSpace);
   }
+
+  bool hasInt128Type() const override {
+    return (getTriple().isOSzOS() ? hasFeature("vx")
+                                  : TargetInfo::hasInt128Type());
+  }
 };
 } // namespace targets
 } // namespace clang
diff --git a/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp 
b/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp
index 1ef6a725483e8..6ac0f8ffba47d 100644
--- a/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp
@@ -53,7 +53,8 @@ std::string systemz::getSystemZTargetCPU(const ArgList &Args,
   return CLANG_SYSTEMZ_DEFAULT_ARCH;
 }
 
-void systemz::getSystemZTargetFeatures(const Driver &D, const ArgList &Args,
+void systemz::getSystemZTargetFeatures(const Driver &D, const llvm::Triple &T,
+                                       const ArgList &Args,
                                        std::vector<llvm::StringRef> &Features) 
{
   // -m(no-)htm overrides use of the transactional-execution facility.
   if (Arg *A = Args.getLastArg(options::OPT_mhtm, options::OPT_mno_htm)) {
@@ -62,11 +63,26 @@ void systemz::getSystemZTargetFeatures(const Driver &D, 
const ArgList &Args,
     else
       Features.push_back("-transactional-execution");
   }
+
   // -m(no-)vx overrides use of the vector facility.
   if (Arg *A = Args.getLastArg(options::OPT_mvx, options::OPT_mno_vx)) {
-    if (A->getOption().matches(options::OPT_mvx))
+
+    // The -mvx requires at least -march=arch11/z13 on z/OS.
+    if (A->getOption().matches(options::OPT_mvx)) {
+      auto Arch = getSystemZTargetCPU(Args, T);
+      if (T.isOSzOS() && llvm::StringSwitch<bool>(Arch)
+                             .Case("arch8", true)
+                             .Case("z10", true)
+                             .Case("arch9", true)
+                             .Case("z196", true)
+                             .Case("arch10", true)
+                             .Case("zEC12", true)
+                             .Default(false)) {
+        D.Diag(diag::err_drv_incompatible_arch)
+            << "-mvx" << "-march=arch11" << Arch;
+      }
       Features.push_back("+vector");
-    else
+    } else
       Features.push_back("-vector");
   }
 
diff --git a/clang/lib/Driver/ToolChains/Arch/SystemZ.h 
b/clang/lib/Driver/ToolChains/Arch/SystemZ.h
index f2d30d24ba63c..b5d1da71f58e1 100644
--- a/clang/lib/Driver/ToolChains/Arch/SystemZ.h
+++ b/clang/lib/Driver/ToolChains/Arch/SystemZ.h
@@ -30,7 +30,8 @@ FloatABI getSystemZFloatABI(const Driver &D, const 
llvm::opt::ArgList &Args);
 std::string getSystemZTargetCPU(const llvm::opt::ArgList &Args,
                                 const llvm::Triple &T);
 
-void getSystemZTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args,
+void getSystemZTargetFeatures(const Driver &D, const llvm::Triple &T,
+                              const llvm::opt::ArgList &Args,
                               std::vector<llvm::StringRef> &Features);
 
 } // end namespace systemz
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp 
b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 64859a318485b..dba514adbff8f 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -922,7 +922,7 @@ void tools::getTargetFeatures(const Driver &D, const 
llvm::Triple &Triple,
     riscv::getRISCVTargetFeatures(D, Triple, Args, Features);
     break;
   case llvm::Triple::systemz:
-    systemz::getSystemZTargetFeatures(D, Args, Features);
+    systemz::getSystemZTargetFeatures(D, Triple, Args, Features);
     break;
   case llvm::Triple::aarch64:
   case llvm::Triple::aarch64_32:
diff --git a/clang/test/CodeGen/SystemZ/zos-alignment.c 
b/clang/test/CodeGen/SystemZ/zos-alignment.c
index 65c6843e0d9ac..a9fe32e248157 100644
--- a/clang/test/CodeGen/SystemZ/zos-alignment.c
+++ b/clang/test/CodeGen/SystemZ/zos-alignment.c
@@ -1,4 +1,6 @@
 // RUN: %clang_cc1 -emit-llvm-only -triple s390x-none-zos 
-fdump-record-layouts %s | FileCheck %s --check-prefix=CHECK
+// RUN: %clang_cc1 -emit-llvm-only -triple s390x-none-zos 
-fdump-record-layouts -DINT128_A \
+// RUN: -target-cpu z13 %s | FileCheck %s --check-prefix=INT128
 // RUN: %clang_cc1 -emit-llvm -triple s390x-none-zos %s -o - | FileCheck %s 
--check-prefix=DECL
 
 static int __attribute__((aligned(32))) v0;
@@ -160,12 +162,14 @@ struct s11 {
 // CHECK-NEXT:         8 |   char b
 // CHECK-NEXT:           | [sizeof=16, align=8]
 
+#ifdef INT128_A
 struct s12 {
   __int128_t a;
 } S12;
-// CHECK:              0 | struct s12
-// CHECK-NEXT:         0 |   __int128_t a
-// CHECK-NEXT:           | [sizeof=16, align=8]
+// INT128:              0 | struct s12
+// INT128-NEXT:         0 |   __int128_t a
+// INT128-NEXT:           | [sizeof=16, align=8]
+#endif
 
 union u0 {
   unsigned short d1 __attribute__((packed));
diff --git a/clang/test/Driver/systemz-features.cpp 
b/clang/test/Driver/systemz-features.cpp
index be1818a032355..4c1e0f3ae6a95 100644
--- a/clang/test/Driver/systemz-features.cpp
+++ b/clang/test/Driver/systemz-features.cpp
@@ -1,5 +1,6 @@
 
 // RUN: %clang -target s390x-unknown-linux-gnu %s -### -o %t.o 2>&1 | 
FileCheck -check-prefix=CHECK-DEFAULT %s
+// RUN: %clang -target s390x-ibm-zos %s -### -o %t.o 2>&1 | FileCheck 
-check-prefix=CHECK-DEFAULT %s
 // CHECK-DEFAULT-NOT: "-target-feature" "+transactional-execution"
 // CHECK-DEFAULT-NOT: "-target-feature" "-transactional-execution"
 // CHECK-DEFAULT-NOT: "-target-feature" "+vector"
@@ -7,20 +8,28 @@
 
 // RUN: %clang -target s390x-unknown-linux-gnu %s -mhtm -### -o %t.o 2>&1 | 
FileCheck -check-prefix=CHECK-HTM %s
 // RUN: %clang -target s390x-unknown-linux-gnu %s -mno-htm -mhtm -### -o %t.o 
2>&1 | FileCheck -check-prefix=CHECK-HTM %s
+// RUN: %clang -target s390x-ibm-zos %s -mhtm -### -o %t.o 2>&1 | FileCheck 
-check-prefix=CHECK-HTM %s
+// RUN: %clang -target s390x-ibm-zos %s -mno-htm -mhtm -### -o %t.o 2>&1 | 
FileCheck -check-prefix=CHECK-HTM %s
 // CHECK-HTM: "-target-feature" "+transactional-execution"
 // CHECK-HTM-NOT: "-target-feature" "-transactional-execution"
 
 // RUN: %clang -target s390x-unknown-linux-gnu %s -mno-htm -### -o %t.o 2>&1 | 
FileCheck -check-prefix=CHECK-NOHTM %s
 // RUN: %clang -target s390x-unknown-linux-gnu %s -mhtm -mno-htm -### -o %t.o 
2>&1 | FileCheck -check-prefix=CHECK-NOHTM %s
+// RUN: %clang -target s390x-ibm-zos %s -mno-htm -### -o %t.o 2>&1 | FileCheck 
-check-prefix=CHECK-NOHTM %s
+// RUN: %clang -target s390x-ibm-zos %s -mhtm -mno-htm -### -o %t.o 2>&1 | 
FileCheck -check-prefix=CHECK-NOHTM %s
 // CHECK-NOHTM: "-target-feature" "-transactional-execution"
 // CHECK-NOHTM-NOT: "-target-feature" "+transactional-execution"
 
 // RUN: %clang -target s390x-unknown-linux-gnu %s -mvx -### -o %t.o 2>&1 | 
FileCheck -check-prefix=CHECK-VX %s
 // RUN: %clang -target s390x-unknown-linux-gnu %s -mno-vx -mvx -### -o %t.o 
2>&1 | FileCheck -check-prefix=CHECK-VX %s
+// RUN: %clang -target s390x-ibm-zos %s -mvx -march=arch11 -### -o %t.o 2>&1 | 
FileCheck -check-prefix=CHECK-VX %s
+// RUN: %clang -target s390x-ibm-zos %s -mno-vx -mvx -march=arch11 -### -o 
%t.o 2>&1 | FileCheck -check-prefix=CHECK-VX %s
 // CHECK-VX: "-target-feature" "+vector"
 // CHECK-VX-NOT: "-target-feature" "-vector"
 //
 // RUN: %clang -target s390x-unknown-linux-gnu %s -mno-vx -### -o %t.o 2>&1 | 
FileCheck -check-prefix=CHECK-NOVX %s
 // RUN: %clang -target s390x-unknown-linux-gnu %s -mvx -mno-vx -### -o %t.o 
2>&1 | FileCheck -check-prefix=CHECK-NOVX %s
+// RUN: %clang -target s390x-ibm-zos %s -mno-vx -### -o %t.o 2>&1 | FileCheck 
-check-prefix=CHECK-NOVX %s
+// RUN: %clang -target s390x-ibm-zos %s -mvx -mno-vx -### -o %t.o 2>&1 | 
FileCheck -check-prefix=CHECK-NOVX %s
 // CHECK-NOVX: "-target-feature" "-vector"
 // CHECK-NOVX-NOT: "-target-feature" "+vector"
diff --git a/clang/test/Sema/zvector.c b/clang/test/Sema/zvector.c
index e1e4ab532426d..e3ceac48faf0b 100644
--- a/clang/test/Sema/zvector.c
+++ b/clang/test/Sema/zvector.c
@@ -2,6 +2,10 @@
 // RUN:  -flax-vector-conversions=none -W -Wall -Wconversion \
 // RUN:  -Werror -fsyntax-only -verify %s
 
+// RUN: %clang_cc1 -triple s390x-ibm-zos -fzvector -target-cpu z13 \
+// RUN:  -flax-vector-conversions=none -W -Wall -Wconversion \
+// RUN:  -Werror -fsyntax-only -verify %s
+
 vector signed char sc, sc2;
 vector unsigned char uc, uc2;
 vector bool char bc, bc2;
diff --git a/llvm/lib/Target/SystemZ/SystemZCallingConv.h 
b/llvm/lib/Target/SystemZ/SystemZCallingConv.h
index 9fcd5b8152c5a..91a1fe8f12d96 100644
--- a/llvm/lib/Target/SystemZ/SystemZCallingConv.h
+++ b/llvm/lib/Target/SystemZ/SystemZCallingConv.h
@@ -96,6 +96,14 @@ inline bool CC_XPLINK64_Pointer(unsigned &ValNo, MVT &ValVT, 
MVT &LocVT,
   return false;
 }
 
+inline bool CC_XPLINK_Int128(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
+                             CCValAssign::LocInfo &LocInfo,
+                             ISD::ArgFlagsTy &ArgFlags, CCState &State) {
+  LocVT = MVT::v16i8;
+  LocInfo = CCValAssign::BCvt;
+  return false;
+}
+
 inline bool CC_XPLINK64_Shadow_Reg(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
                                    CCValAssign::LocInfo &LocInfo,
                                    ISD::ArgFlagsTy &ArgFlags, CCState &State) {
diff --git a/llvm/lib/Target/SystemZ/SystemZCallingConv.td 
b/llvm/lib/Target/SystemZ/SystemZCallingConv.td
index 4f483cf2479dd..7263587d54369 100644
--- a/llvm/lib/Target/SystemZ/SystemZCallingConv.td
+++ b/llvm/lib/Target/SystemZ/SystemZCallingConv.td
@@ -167,6 +167,9 @@ def CSR_SystemZ_XPLINK64_Vector : CalleeSavedRegs<(add 
CSR_SystemZ_XPLINK64,
 // z/OS XPLINK64 return value calling convention
 
//===----------------------------------------------------------------------===//
 def RetCC_SystemZ_XPLINK64 : CallingConv<[
+  // Convert an i128 value to vector
+  CCIfType<[i128], CCCustom<"CC_XPLINK_Int128">>,
+
   // XPLINK64 ABI compliant code widens integral types smaller than i64
   // to i64.
   CCIfType<[i32], CCPromoteToType<i64>>,
@@ -225,6 +228,10 @@ def CC_SystemZ_XPLINK64 : CallingConv<[
   CCIfPtr<CCCustom<"CC_XPLINK64_Pointer">>,
   // long double, can only be passed in GPR2 and GPR3, if available,
   // hence R2Q
+
+  // Convert an i128 value to vector
+  CCIfType<[i128], CCCustom<"CC_XPLINK_Int128">>,
+
   CCIfType<[f128], 
CCIfArgVarArg<CCCustom<"CC_XPLINK64_Allocate128BitVararg">>>,
   // Non fixed vector arguments are treated in the same way as long
   // doubles.
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp 
b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 8e621aafe27d2..f93cbbfb557ca 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -1900,11 +1900,15 @@ static SDValue convertLocVTToValVT(SelectionDAG &DAG, 
const SDLoc &DL,
   if (VA.isExtInLoc())
     Value = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), Value);
   else if (VA.getLocInfo() == CCValAssign::BCvt) {
-    // If this is a short vector argument loaded from the stack,
-    // extend from i64 to full vector size and then bitcast.
-    assert(VA.getLocVT() == MVT::i64);
-    assert(VA.getValVT().isVector());
-    Value = DAG.getBuildVector(MVT::v2i64, DL, {Value, 
DAG.getUNDEF(MVT::i64)});
+    // If the argument is a short vector loaded from the stack,
+    // extend it from i64 to the full vector size and then perform a bitcast.
+    // Alternatively, if the argument is an int128,
+    // directly bitcast it into a vector of v16i8.
+    assert(VA.getLocVT() == MVT::i64 || VA.getLocVT() == MVT::v16i8);
+    assert(VA.getValVT().isVector() || VA.getValVT() == MVT::i128);
+    if (VA.getLocVT() == MVT::i64)
+      Value =
+          DAG.getBuildVector(MVT::v2i64, DL, {Value, DAG.getUNDEF(MVT::i64)});
     Value = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Value);
   } else
     assert(VA.getLocInfo() == CCValAssign::Full && "Unsupported getLocInfo");
@@ -1924,9 +1928,11 @@ static SDValue convertValVTToLocVT(SelectionDAG &DAG, 
const SDLoc &DL,
   case CCValAssign::AExt:
     return DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Value);
   case CCValAssign::BCvt: {
-    assert(VA.getLocVT() == MVT::i64 || VA.getLocVT() == MVT::i128);
+    assert(VA.getLocVT() == MVT::i64 || VA.getLocVT() == MVT::i128 ||
+           VA.getLocVT() == MVT::v16i8);
     assert(VA.getValVT().isVector() || VA.getValVT() == MVT::f32 ||
-           VA.getValVT() == MVT::f64 || VA.getValVT() == MVT::f128);
+           VA.getValVT() == MVT::f64 || VA.getValVT() == MVT::f128 ||
+           VA.getValVT() == MVT::i128);
     // For an f32 vararg we need to first promote it to an f64 and then
     // bitcast it to an i64.
     if (VA.getValVT() == MVT::f32 && VA.getLocVT() == MVT::i64)
@@ -2608,9 +2614,12 @@ bool SystemZTargetLowering::CanLowerReturn(
     const Type *RetTy) const {
   // Special case that we cannot easily detect in RetCC_SystemZ since
   // i128 may not be a legal type.
-  for (auto &Out : Outs)
-    if (Out.ArgVT.isScalarInteger() && Out.ArgVT.getSizeInBits() > 64)
-      return false;
+  // On z/OS we need to skip the convention of passing the return value on
+  // the stack used on zLinux.
+  if (Subtarget.isTargetLinux())
+    for (auto &Out : Outs)
+      if (Out.ArgVT.isScalarInteger() && Out.ArgVT.getSizeInBits() > 64)
+        return false;
 
   SmallVector<CCValAssign, 16> RetLocs;
   CCState RetCCInfo(CallConv, IsVarArg, MF, RetLocs, Context);
diff --git a/llvm/lib/Target/SystemZ/SystemZSubtarget.h 
b/llvm/lib/Target/SystemZ/SystemZSubtarget.h
index 761bc525b59d3..eda9f095fb237 100644
--- a/llvm/lib/Target/SystemZ/SystemZSubtarget.h
+++ b/llvm/lib/Target/SystemZ/SystemZSubtarget.h
@@ -124,6 +124,9 @@ class SystemZSubtarget : public SystemZGenSubtargetInfo {
 
   // Returns TRUE if we are generating code for a s390x machine running zOS
   bool isTargetzOS() const { return TargetTriple.isOSzOS(); }
+
+  // Returns TRUE if we are generating code for a s390x machine running Linux
+  bool isTargetLinux() const { return TargetTriple.isOSLinux(); }
 };
 } // end namespace llvm
 
diff --git a/llvm/test/CodeGen/SystemZ/call-zos-i128.ll 
b/llvm/test/CodeGen/SystemZ/call-zos-i128.ll
index c12e26184f068..e5285377c939e 100644
--- a/llvm/test/CodeGen/SystemZ/call-zos-i128.ll
+++ b/llvm/test/CodeGen/SystemZ/call-zos-i128.ll
@@ -4,14 +4,9 @@
 
 ; CHECK-LABEL: call_i128 DS 0H
 ; CHECK-DAG: larl    1,L#CPI0_0
-; CHECK-DAG: vl      0,0(1),3
-; CHECK-DAG: vst     0,2256(4),3
+; CHECK-DAG: vl      24,0(1),3
 ; CHECK-DAG: larl    1,L#CPI0_1
-; CHECK-DAG: vl      0,0(1),3
-; CHECK-DAG: vst     0,2272(4),3
-; CHECK-DAG: la      1,2288(4)
-; CHECK-DAG: la      2,2272(4)
-; CHECK-DAG: la      3,2256(4)
+; CHECK-DAG: vl      25,0(1),3
 
 define i128 @call_i128() {
 entry:
@@ -20,10 +15,7 @@ entry:
 }
 
 ; CHECK-LABEL: pass_i128 DS 0H
-; CHECK: vl      0,0(3),3
-; CHECK: vl      1,0(2),3
-; CHECK: vaq     0,1,0
-; CHECK: vst     0,0(1),3
+; CHECK: vaq     24,24,25
 define i128 @pass_i128(i128 %arg0, i128 %arg1) {
 entry:
   %N = add i128 %arg0, %arg1
diff --git a/llvm/test/CodeGen/SystemZ/int-div-09.ll 
b/llvm/test/CodeGen/SystemZ/int-div-09.ll
new file mode 100644
index 0000000000000..bd77d62bf23ca
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/int-div-09.ll
@@ -0,0 +1,13 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 
UTC_ARGS: --version 5
+; The objective of this test is to check conversion from i128 argument to 
vector v16i8.
+; This test was derived from builtins/floatuntitf.c residing in compiler.rt.
+
+; RUN: env LLVM_EMIT_GNU_AS_ZOS=0 llc -mtriple s390x-ibm-zos < %s | FileCheck 
%s
+$test_i128_arg = comdat any
+define void @test_i128_arg(ptr %this, i128 %__arg) "target-features"="+vector" 
{
+; CHECK-LABEL: test_i128_arg DS 0H
+; CHECK:       * %entry
+; CHECK-NEXT:  * %bb.0:
+entry:
+  ret void
+}
diff --git a/llvm/test/CodeGen/SystemZ/zos-abi-int128-64.ll 
b/llvm/test/CodeGen/SystemZ/zos-abi-int128-64.ll
new file mode 100644
index 0000000000000..afbd5f0b0d5e9
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/zos-abi-int128-64.ll
@@ -0,0 +1,253 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 
UTC_ARGS: --version 5
+; RUN: env LLVM_EMIT_GNU_AS_ZOS=0 llc < %s| FileCheck %s
+
+source_filename = "zos-abi-int128-input.c"
+target datalayout = 
"E-m:l-p1:32:32-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64"
+target triple = "s390x-ibm-zos"
+
+attributes #0 = { "target-cpu"="z13" "target-features"="+vector" }
+
+; Check if GPR1 is used for the first integer argument and
+; VR24 for the second int128 argument and return value.
+;
+define i128 @pi_1i128(i32 signext %a1, i128 %a2) #0 {
+; CHECK-LABEL: pi_1i128 DS 0H
+; CHECK:        stmg 6,7,1904(4)
+; CHECK-NEXT:  L#stack_update0 DS 0H
+; CHECK-NEXT:   aghi 4,-160
+; CHECK:        L#end_of_prologue0 DS 0H
+; CHECK-NEXT:   vlvgp 0,1,1
+; CHECK-NEXT:   vrepf 0,0,3
+; CHECK-NEXT:   vrepib 1,96
+; CHECK-NEXT:   st 1,2204(4)
+; CHECK-NEXT:   vst 24,2184(4),3
+; CHECK-NEXT:   vsrab 0,0,1
+; CHECK-NEXT:   lg 7,2072(4)
+; CHECK-NEXT:   vaq 24,0,24
+; CHECK-NEXT:   aghi 4,160
+; CHECK-NEXT:   b 2(7)
+entry:
+  %a1.addr = alloca i32, align 4
+  %a2.addr = alloca i128, align 8
+  store i32 %a1, ptr %a1.addr, align 4
+  store i128 %a2, ptr %a2.addr, align 8
+  %0 = load i32, ptr %a1.addr, align 4
+  %conv = sext i32 %0 to i128
+  %1 = load i128, ptr %a2.addr, align 8
+  %add = add nsw i128 %conv, %1
+  ret i128 %add
+}
+
+; Check if VR24-31 are used for the first 8 int128 arguments and
+; the 9th int128 argument is loaded from the stack into VR0.
+; In addition, check VR24 is used for return value.
+;
+define i128 @p9i128(i128 %a1, i128 %a2, i128 %a3, i128 %a4, i128 %a5, i128 
%a6, i128 %a7, i128 %a8, i128 %a9) #0 {
+; CHECK-LABEL: p9i128 DS 0H
+; CHECK:        stmg 6,7,1776(4)
+; CHECK-NEXT:  L#stack_update1 DS 0H
+; CHECK-NEXT:   aghi 4,-288
+; CHECK:        L#end_of_prologue1 DS 0H
+; CHECK-NEXT:   vaq 1,24,25
+; CHECK-NEXT:   vaq 1,1,26
+; CHECK-NEXT:   vaq 1,1,27
+; CHECK-NEXT:   vl 0,2592(4),4
+; CHECK-NEXT:   vaq 1,1,28
+; CHECK-NEXT:   vaq 1,1,29
+; CHECK-NEXT:   vst 24,2320(4),3
+; CHECK-NEXT:   vst 25,2304(4),3
+; CHECK-NEXT:   vst 26,2288(4),3
+; CHECK-NEXT:   vst 27,2272(4),3
+; CHECK-NEXT:   vst 28,2256(4),3
+; CHECK-NEXT:   vst 29,2240(4),3
+; CHECK-NEXT:   vst 30,2224(4),3
+; CHECK-NEXT:   vst 31,2208(4),3
+; CHECK-NEXT:   vst 0,2192(4),3
+; CHECK-NEXT:   vaq 1,1,30
+; CHECK-NEXT:   lg 7,2072(4)
+; CHECK-NEXT:   vaq 1,1,31
+; CHECK-NEXT:   vaq 24,1,0
+; CHECK-NEXT:   aghi 4,288
+; CHECK-NEXT:   b 2(7)
+entry:
+  %a1.addr = alloca i128, align 8
+  %a2.addr = alloca i128, align 8
+  %a3.addr = alloca i128, align 8
+  %a4.addr = alloca i128, align 8
+  %a5.addr = alloca i128, align 8
+  %a6.addr = alloca i128, align 8
+  %a7.addr = alloca i128, align 8
+  %a8.addr = alloca i128, align 8
+  %a9.addr = alloca i128, align 8
+  store i128 %a1, ptr %a1.addr, align 8
+  store i128 %a2, ptr %a2.addr, align 8
+  store i128 %a3, ptr %a3.addr, align 8
+  store i128 %a4, ptr %a4.addr, align 8
+  store i128 %a5, ptr %a5.addr, align 8
+  store i128 %a6, ptr %a6.addr, align 8
+  store i128 %a7, ptr %a7.addr, align 8
+  store i128 %a8, ptr %a8.addr, align 8
+  store i128 %a9, ptr %a9.addr, align 8
+  %0 = load i128, ptr %a1.addr, align 8
+  %1 = load i128, ptr %a2.addr, align 8
+  %add = add nsw i128 %0, %1
+  %2 = load i128, ptr %a3.addr, align 8
+  %add1 = add nsw i128 %add, %2
+  %3 = load i128, ptr %a4.addr, align 8
+  %add2 = add nsw i128 %add1, %3
+  %4 = load i128, ptr %a5.addr, align 8
+  %add3 = add nsw i128 %add2, %4
+  %5 = load i128, ptr %a6.addr, align 8
+  %add4 = add nsw i128 %add3, %5
+  %6 = load i128, ptr %a7.addr, align 8
+  %add5 = add nsw i128 %add4, %6
+  %7 = load i128, ptr %a8.addr, align 8
+  %add6 = add nsw i128 %add5, %7
+  %8 = load i128, ptr %a9.addr, align 8
+  %add7 = add nsw i128 %add6, %8
+  ret i128 %add7
+}
+
+; Check if three int128 arguments in addition to variable argument(s) are 
passed in extended argument list.
+;
+define i128 @p3i128_var(i128 %a1, i128 %a2, i128 %a3, ...) #0 {
+; CHECK-LABEL: p3i128_var DS 0H
+; CHECK:        stmg 6,7,1840(4)
+; CHECK-NEXT:  L#stack_update2 DS 0H
+; CHECK-NEXT:   aghi 4,-224
+; CHECK-NEXT:   stg 1,2400(4)
+; CHECK-NEXT:   stg 2,2408(4)
+; CHECK-NEXT:   stg 3,2416(4)
+; CHECK:        L#end_of_prologue2 DS 0H
+; CHECK-NEXT:   vl 0,2448(4),4
+; CHECK-NEXT:   la 0,2464(4)
+; CHECK-NEXT:   vst 24,2256(4),3
+; CHECK-NEXT:   vst 25,2240(4),3
+; CHECK-NEXT:   vst 26,2224(4),3
+; CHECK-NEXT:   stg 0,2200(4)
+; CHECK-NEXT:   vst 0,2208(4),3
+; CHECK-NEXT:   vaq 1,24,25
+; CHECK-NEXT:   lg 7,2072(4)
+; CHECK-NEXT:   vaq 1,1,26
+; CHECK-NEXT:   vsq 24,1,0
+; CHECK-NEXT:   aghi 4,224
+; CHECK-NEXT:   b 2(7)
+entry:
+  %a1.addr = alloca i128, align 8
+  %a2.addr = alloca i128, align 8
+  %a3.addr = alloca i128, align 8
+  %a4 = alloca i128, align 8
+  %args = alloca ptr, align 8
+  store i128 %a1, ptr %a1.addr, align 8
+  store i128 %a2, ptr %a2.addr, align 8
+  store i128 %a3, ptr %a3.addr, align 8
+  call void @llvm.va_start.p0(ptr %args)
+  %argp.cur = load ptr, ptr %args, align 8
+  %argp.next = getelementptr inbounds i8, ptr %argp.cur, i64 16
+  store ptr %argp.next, ptr %args, align 8
+  %0 = load i128, ptr %argp.cur, align 8
+  store i128 %0, ptr %a4, align 8
+  call void @llvm.va_end.p0(ptr %args)
+  %1 = load i128, ptr %a1.addr, align 8
+  %2 = load i128, ptr %a2.addr, align 8
+  %add = add nsw i128 %1, %2
+  %3 = load i128, ptr %a3.addr, align 8
+  %add1 = add nsw i128 %add, %3
+  %4 = load i128, ptr %a4, align 8
+  %sub = sub nsw i128 %add1, %4
+  ret i128 %sub
+}
+
+; Check the call side for above functions.
+;
+define signext i32 @main() #0 {
+; CHECK-LABEL: main DS 0H
+; CHECK:        stmg 6,8,1584(4)
+; CHECK-NEXT:  L#stack_update3 DS 0H
+; CHECK-NEXT:   aghi 4,-480
+; CHECK:        L#end_of_prologue3 DS 0H
+; CHECK-NEXT:   vgbm 0,0
+; CHECK-NEXT:   vgbm 24,0
+; CHECK-NEXT:   lgr 8,5
+; CHECK-NEXT:   lg 6,8(5)
+; CHECK-NEXT:   lg 5,0(5)
+; CHECK-NEXT:   lghi 1,10
+; CHECK-NEXT:   mvhi 2524(4),0
+; CHECK-NEXT:   vst 0,2504(4),3
+; CHECK-NEXT:   basr 7,6
+; CHECK-NEXT:   bcr 0,0
+; CHECK-NEXT:   vl 0,2504(4),3
+; CHECK-NEXT:   vaq 24,0,24
+; CHECK-NEXT:   vl 0,2376(4),3
+; CHECK-NEXT:   vl 31,2392(4),3
+; CHECK-NEXT:   vl 30,2408(4),3
+; CHECK-NEXT:   vl 29,2424(4),3
+; CHECK-NEXT:   vl 28,2440(4),3
+; CHECK-NEXT:   vl 27,2456(4),3
+; CHECK-NEXT:   vl 26,2472(4),3
+; CHECK-NEXT:   vl 25,2488(4),3
+; CHECK-NEXT:   lg 6,24(8)
+; CHECK-NEXT:   lg 5,16(8)
+; CHECK-NEXT:   vst 24,2504(4),3
+; CHECK-NEXT:   vst 0,2304(4),3
+; CHECK-NEXT:   basr 7,6
+; CHECK-NEXT:   bcr 0,0
+; CHECK-NEXT:   vl 0,2504(4),3
+; CHECK-NEXT:   vaq 24,0,24
+; CHECK-NEXT:   vl 0,2456(4),3
+; CHECK-NEXT:   vl 26,2472(4),3
+; CHECK-NEXT:   vl 25,2488(4),3
+; CHECK-NEXT:   lg 6,40(8)
+; CHECK-NEXT:   lg 5,32(8)
+; CHECK-NEXT:   vst 24,2504(4),3
+; CHECK-NEXT:   vst 0,2224(4),3
+; CHECK-NEXT:   basr 7,6
+; CHECK-NEXT:   bcr 0,0
+; CHECK-NEXT:   vl 0,2504(4),3
+; CHECK-NEXT:   vaq 0,0,24
+; CHECK-NEXT:   vst 0,2504(4),3
+; CHECK-NEXT:   lmg 7,8,2072(4)
+; CHECK-NEXT:   lghi 3,0
+; CHECK-NEXT:   aghi 4,480
+; CHECK-NEXT:   b 2(7)
+entry:
+  %retval = alloca i32, align 4
+  %a1 = alloca i128, align 8
+  %a2 = alloca i128, align 8
+  %a3 = alloca i128, align 8
+  %s4 = alloca i128, align 8
+  %a5 = alloca i128, align 8
+  %a6 = alloca i128, align 8
+  %a7 = alloca i128, align 8
+  %a8 = alloca i128, align 8
+  %a9 = alloca i128, align 8
+  store i32 0, ptr %retval, align 4
+  store i128 0, ptr %a1, align 8
+  %0 = load i128, ptr %a1, align 8
+  %call = call i128 @pi_1i128(i32 signext 10, i128 %0)
+  %1 = load i128, ptr %a1, align 8
+  %add = add nsw i128 %1, %call
+  store i128 %add, ptr %a1, align 8
+  %2 = load i128, ptr %a1, align 8
+  %3 = load i128, ptr %a2, align 8
+  %4 = load i128, ptr %a3, align 8
+  %5 = load i128, ptr %s4, align 8
+  %6 = load i128, ptr %a5, align 8
+  %7 = load i128, ptr %a6, align 8
+  %8 = load i128, ptr %a7, align 8
+  %9 = load i128, ptr %a8, align 8
+  %10 = load i128, ptr %a9, align 8
+  %call1 = call i128 @p9i128(i128 %2, i128 %3, i128 %4, i128 %5, i128 %6, i128 
%7, i128 %8, i128 %9, i128 %10)
+  %11 = load i128, ptr %a1, align 8
+  %add2 = add nsw i128 %11, %call1
+  store i128 %add2, ptr %a1, align 8
+  %12 = load i128, ptr %a1, align 8
+  %13 = load i128, ptr %a2, align 8
+  %14 = load i128, ptr %a3, align 8
+  %15 = load i128, ptr %s4, align 8
+  %call3 = call i128 (i128, i128, i128, ...) @p3i128_var(i128 %12, i128 %13, 
i128 %14, i128 %15)
+  %16 = load i128, ptr %a1, align 8
+  %add4 = add nsw i128 %16, %call3
+  store i128 %add4, ptr %a1, align 8
+  ret i32 0
+}

>From 5f857be0ee07b1126f4ec8324d313010ed42db61 Mon Sep 17 00:00:00 2001
From: Zibi Sarbinowski <[email protected]>
Date: Wed, 16 Sep 2026 16:06:29 -0400
Subject: [PATCH 2/2] [SystemZ] Simplify i128 passing in XPLINK64 calling
 conventions

Remove the CC_XPLINK_Int128 custom handler that mutated i128 LocVT to
v16i8, and instead add i128 directly to the CCIfType rules alongside
vectors in CC_SystemZ_XPLINK64 and RetCC_SystemZ_XPLINK64.

This removes the CCPassIndirect<i64> / CC_SystemZ_I128Indirect path for
i128 in the XPLINK64 argument calling convention and passes i128 in
vector registers V24-V31 (or stack) directly, consistent with how other
128-bit vector types are handled.

The LowerCall_XPLINK guard on lowerI128ToGR128 is updated to only fire
when the i128 is assigned to a GPR pair (R2Q), not when it is in a
VR128 vector register.

Note: removing CCPassIndirect for i128 changes the frame layout for
callers that also pass f64/f128/vector varargs, because the old
CCPassIndirect stack-temporary allocation was shifting the GPR
allocation state seen by subsequent arguments.  Callers mixing i128
fixed args with f64/vector varargs may see different code generation
for the vararg passing compared to code compiled before this change.
---
 llvm/lib/Target/SystemZ/SystemZCallingConv.h  | 10 +-------
 llvm/lib/Target/SystemZ/SystemZCallingConv.td | 23 +++++--------------
 .../Target/SystemZ/SystemZISelLowering.cpp    | 23 ++++++++-----------
 3 files changed, 17 insertions(+), 39 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZCallingConv.h 
b/llvm/lib/Target/SystemZ/SystemZCallingConv.h
index 91a1fe8f12d96..b9b8921d24817 100644
--- a/llvm/lib/Target/SystemZ/SystemZCallingConv.h
+++ b/llvm/lib/Target/SystemZ/SystemZCallingConv.h
@@ -96,21 +96,13 @@ inline bool CC_XPLINK64_Pointer(unsigned &ValNo, MVT 
&ValVT, MVT &LocVT,
   return false;
 }
 
-inline bool CC_XPLINK_Int128(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
-                             CCValAssign::LocInfo &LocInfo,
-                             ISD::ArgFlagsTy &ArgFlags, CCState &State) {
-  LocVT = MVT::v16i8;
-  LocInfo = CCValAssign::BCvt;
-  return false;
-}
-
 inline bool CC_XPLINK64_Shadow_Reg(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
                                    CCValAssign::LocInfo &LocInfo,
                                    ISD::ArgFlagsTy &ArgFlags, CCState &State) {
   if (LocVT == MVT::f32 || LocVT == MVT::f64) {
     State.AllocateReg(SystemZ::XPLINK64ArgGPRs);
   }
-  if (LocVT == MVT::f128 || LocVT.is128BitVector()) {
+  if (LocVT == MVT::f128 || LocVT.is128BitVector() || LocVT == MVT::i128) {
     // Shadow next two GPRs, if available.
     State.AllocateReg(SystemZ::XPLINK64ArgGPRs);
     State.AllocateReg(SystemZ::XPLINK64ArgGPRs);
diff --git a/llvm/lib/Target/SystemZ/SystemZCallingConv.td 
b/llvm/lib/Target/SystemZ/SystemZCallingConv.td
index 7263587d54369..c823051ebc3a1 100644
--- a/llvm/lib/Target/SystemZ/SystemZCallingConv.td
+++ b/llvm/lib/Target/SystemZ/SystemZCallingConv.td
@@ -167,9 +167,6 @@ def CSR_SystemZ_XPLINK64_Vector : CalleeSavedRegs<(add 
CSR_SystemZ_XPLINK64,
 // z/OS XPLINK64 return value calling convention
 
//===----------------------------------------------------------------------===//
 def RetCC_SystemZ_XPLINK64 : CallingConv<[
-  // Convert an i128 value to vector
-  CCIfType<[i128], CCCustom<"CC_XPLINK_Int128">>,
-
   // XPLINK64 ABI compliant code widens integral types smaller than i64
   // to i64.
   CCIfType<[i32], CCPromoteToType<i64>>,
@@ -190,10 +187,10 @@ def RetCC_SystemZ_XPLINK64 : CallingConv<[
   // F4D and F6D, hence F4Q are used for complex long double types.
   CCIfType<[f128], CCAssignToReg<[F0Q,F4Q]>>,
 
-  // ABI compliant code returns vectors in VR24 but other registers
+  // ABI compliant code returns i128 and vectors in VR24 but other registers
   // are provided for code that does not care about the ABI.
   CCIfSubtarget<"hasVector()",
-    CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
+    CCIfType<[i128, v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
              CCAssignToReg<[V24, V25, V26, V27, V28, V29, V30, V31]>>>
 ]>;
 
@@ -229,9 +226,6 @@ def CC_SystemZ_XPLINK64 : CallingConv<[
   // long double, can only be passed in GPR2 and GPR3, if available,
   // hence R2Q
 
-  // Convert an i128 value to vector
-  CCIfType<[i128], CCCustom<"CC_XPLINK_Int128">>,
-
   CCIfType<[f128], 
CCIfArgVarArg<CCCustom<"CC_XPLINK64_Allocate128BitVararg">>>,
   // Non fixed vector arguments are treated in the same way as long
   // doubles.
@@ -245,11 +239,6 @@ def CC_SystemZ_XPLINK64 : CallingConv<[
   // A SwiftError is passed in R0.
   CCIfSwiftError<CCIfType<[i64], CCAssignToReg<[R0D]>>>,
 
-  // Force i128 values to the stack and pass i64 pointers to them.
-  CCIfType<[i128], CCPassIndirect<i64>>,
-  // If i128 is not legal, such values are already split into two i64 here,
-  // so we have to use a custom handler.
-  CCIfType<[i64], CCCustom<"CC_SystemZ_I128Indirect">>,
   // The first 3 integer arguments are passed in registers R1-R3.
   // The rest will be passed in the user area.
   CCIfType<[i32], CCAssignToRegAndStack<[R1L, R2L, R3L], 8, 8>>,
@@ -259,10 +248,10 @@ def CC_SystemZ_XPLINK64 : CallingConv<[
   // are passed in the same way, but they're widened to one of these types
   // during type legalization.
   CCIfSubtarget<"hasVector()",
-    CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
+    CCIfType<[i128, v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
       CCIfArgFixed<CCCustom<"CC_XPLINK64_Shadow_Reg">>>>,
   CCIfSubtarget<"hasVector()",
-    CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
+    CCIfType<[i128, v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
               CCIfArgFixed<CCAssignToRegAndStack<[V24, V25, V26, V27,
                                                   V28, V29, V30, V31], 16, 
8>>>>,
 
@@ -283,9 +272,9 @@ def CC_SystemZ_XPLINK64 : CallingConv<[
   CCIfType<[i32, i64, f32, f64], CCAssignToStack<8, 8>>,
   // Other f128 arguments are passed in 8-byte-aligned 16-byte stack slots.
   CCIfType<[f128], CCAssignToStack<16, 8>>,
-  // Vector arguments are passed in 8-byte-alinged 16-byte stack slots too.
+  // i128 and vector arguments are passed in 8-byte-aligned 16-byte stack 
slots.
   CCIfSubtarget<"hasVector()",
-    CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
+    CCIfType<[i128, v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
              CCAssignToStack<16, 8>>>
 ]>;
 
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp 
b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index f93cbbfb557ca..04bb41b5b4f6c 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -1902,13 +1902,10 @@ static SDValue convertLocVTToValVT(SelectionDAG &DAG, 
const SDLoc &DL,
   else if (VA.getLocInfo() == CCValAssign::BCvt) {
     // If the argument is a short vector loaded from the stack,
     // extend it from i64 to the full vector size and then perform a bitcast.
-    // Alternatively, if the argument is an int128,
-    // directly bitcast it into a vector of v16i8.
-    assert(VA.getLocVT() == MVT::i64 || VA.getLocVT() == MVT::v16i8);
-    assert(VA.getValVT().isVector() || VA.getValVT() == MVT::i128);
-    if (VA.getLocVT() == MVT::i64)
-      Value =
-          DAG.getBuildVector(MVT::v2i64, DL, {Value, DAG.getUNDEF(MVT::i64)});
+    assert(VA.getLocVT() == MVT::i64);
+    assert(VA.getValVT().isVector());
+    Value =
+        DAG.getBuildVector(MVT::v2i64, DL, {Value, DAG.getUNDEF(MVT::i64)});
     Value = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Value);
   } else
     assert(VA.getLocInfo() == CCValAssign::Full && "Unsupported getLocInfo");
@@ -1931,8 +1928,7 @@ static SDValue convertValVTToLocVT(SelectionDAG &DAG, 
const SDLoc &DL,
     assert(VA.getLocVT() == MVT::i64 || VA.getLocVT() == MVT::i128 ||
            VA.getLocVT() == MVT::v16i8);
     assert(VA.getValVT().isVector() || VA.getValVT() == MVT::f32 ||
-           VA.getValVT() == MVT::f64 || VA.getValVT() == MVT::f128 ||
-           VA.getValVT() == MVT::i128);
+           VA.getValVT() == MVT::f64 || VA.getValVT() == MVT::f128);
     // For an f32 vararg we need to first promote it to an f64 and then
     // bitcast it to an i64.
     if (VA.getValVT() == MVT::f32 && VA.getLocVT() == MVT::i64)
@@ -2437,10 +2433,11 @@ SystemZTargetLowering::LowerCall(CallLoweringInfo &CLI,
       ArgValue = convertValVTToLocVT(DAG, DL, VA, ArgValue);
 
     if (VA.isRegLoc()) {
-      // In XPLINK64, for the 128-bit vararg case, ArgValue is bitcasted to a
-      // MVT::i128 type. We decompose the 128-bit type to a pair of its high
-      // and low values.
-      if (VA.getLocVT() == MVT::i128)
+      // i128 in a GR128 register pair (e.g. R2Q) must be decomposed into
+      // hi/lo GPR halves. i128 assigned to a VR128 vector register (V24-V31)
+      // is passed directly — do not decompose in that case.
+      if (VA.getLocVT() == MVT::i128 &&
+          !SystemZ::VR128BitRegClass.contains(VA.getLocReg()))
         ArgValue = lowerI128ToGR128(DAG, ArgValue);
       // Queue up the argument copies and emit them at the end.
       RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue));

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to