https://github.com/zibi2 updated https://github.com/llvm/llvm-project/pull/223026
>From f8b97cc936cc8e9ba56a32809d8abece43d2f074 Mon Sep 17 00:00:00 2001 From: Zibi Sarbinowski <[email protected]> Date: Fri, 11 Sep 2026 15:33:39 -0400 Subject: [PATCH 1/2] [SystemZ] Add i128 support for z/OS XPLINK64 ABI Add support for passing and returning 128-bit integers (i128) in the z/OS XPLINK64 calling convention using vector registers. - Gate i128 availability on z/OS behind the vector facility (arch11/z13) via hasInt128Type() override in the SystemZ target - Add CC_XPLINK_Int128 custom handler that maps i128 to v16i8 for register allocation in VR24-VR31 - Add CC_XPLINK_Int128 to RetCC_SystemZ_XPLINK64 and CC_SystemZ_XPLINK64 - Update convertLocVTToValVT/convertValVTToLocVT to handle i128<->v16i8 bitcast in addition to the existing i64->v2i64 short vector path - Guard the i128>64-bit return stack spill path behind isTargetLinux() so z/OS can return i128 in a vector register - Add isTargetLinux() predicate to SystemZSubtarget - Add driver check: -mvx with hard-float ABI requires at least arch11; emit err_drv_incompatible_arch diagnostic for older -march values - Pass Triple through to getSystemZTargetFeatures() so the -mvx arch check has access to target information - Add new diagnostic err_drv_incompatible_arch to DiagnosticDriverKinds.td Tests: - clang/test/CodeGen/SystemZ/zos-alignment.c: gate __int128 layout test behind -target-cpu z13 - clang/test/CodeGen/zos-abi-int128-error.c: verify i128 is rejected without vector facility and -mvx arch check - clang/test/Sema/zvector.c: add z/OS zvector test variant - llvm/test/CodeGen/SystemZ/zos-abi-int128-64.ll: end-to-end ABI test for i128 argument/return passing in VRs - llvm/test/CodeGen/SystemZ/call-zos-i128.ll: update to reflect new vector register passing convention - llvm/test/CodeGen/SystemZ/int-div-09.ll: i128 arg to v16i8 conversion --- .../clang/Basic/DiagnosticDriverKinds.td | 3 + clang/lib/Basic/Targets/SystemZ.h | 5 + clang/lib/Driver/ToolChains/Arch/SystemZ.cpp | 33 ++- 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/CodeGen/zos-abi-int128-error.c | 16 ++ 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, 370 insertions(+), 33 deletions(-) create mode 100644 clang/test/CodeGen/zos-abi-int128-error.c 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..583d04d8c84f5 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,18 +63,36 @@ void systemz::getSystemZTargetFeatures(const Driver &D, const ArgList &Args, else Features.push_back("-transactional-execution"); } + + bool HardFloatABI = false; + systemz::FloatABI FloatABI = systemz::getSystemZFloatABI(D, Args); + if (FloatABI == systemz::FloatABI::Soft) + Features.push_back("+soft-float"); + else if (FloatABI == systemz::FloatABI::Hard) + HardFloatABI = true; + // -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 when -mhard-float is in affect. + if (A->getOption().matches(options::OPT_mvx)) { + auto Arch = getSystemZTargetCPU(Args, T); + if (HardFloatABI && 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"); } - systemz::FloatABI FloatABI = systemz::getSystemZFloatABI(D, Args); - if (FloatABI == systemz::FloatABI::Soft) - Features.push_back("+soft-float"); - if (const Arg *A = Args.getLastArg(options::OPT_munaligned_symbols, options::OPT_mno_unaligned_symbols)) { if (A->getOption().matches(options::OPT_munaligned_symbols)) 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/CodeGen/zos-abi-int128-error.c b/clang/test/CodeGen/zos-abi-int128-error.c new file mode 100644 index 0000000000000..2f5eff1a885c7 --- /dev/null +++ b/clang/test/CodeGen/zos-abi-int128-error.c @@ -0,0 +1,16 @@ +// The following verifies that __int128 is not supported +// RUN: %clang_cc1 -triple s390x-unknown-zos -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple s390x-unknown-zos -fsyntax-only -target-cpu arch10 -verify %s +// RUN: not %clang -msoft-float --target=s390x-unknown-zos %s 2> %t.err +// RUN: FileCheck -check-prefix=CHECK-1 %s < %t.err +// RUN: not %clang -mvx -march=zEC12 --target=s390x-unknown-linux-gnu %s 2> %t.err +// RUN: FileCheck -check-prefix=CHECK-2 %s < %t.err +// RUN: not %clang -mvx -march=zEC12 -mhard-float --target=s390x-unknown-linux-gnu %s 2> %t.err +// RUN: FileCheck -check-prefix=CHECK-2 %s < %t.err +// RUN: not %clang -mvx -march=zEC12 -msoft-float --target=s390x-unknown-linux-gnu %s 2> %t.err +// RUN: not FileCheck -check-prefix=CHECK-2 %s < %t.err + +__int128 pass_int128(__int128 arg) { return arg; } // expected-error {{__int128 is not supported on this target}} expected-error {{__int128 is not supported on this target}} + +// CHECK-1: error: unsupported option '-msoft-float' for target 's390x-unknown-zos' +// CHECK-2: error: '-mvx' option requires at least '-march=arch11', current 'zEC12' is too low 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..88f532125abe3 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 431747b3cd53d77b6d32974615931ea1f8965efb Mon Sep 17 00:00:00 2001 From: Zibi Sarbinowski <[email protected]> Date: Fri, 11 Sep 2026 15:46:15 -0400 Subject: [PATCH 2/2] [SystemZ] clang-format fixes for i128 XPLINK64 ABI changes --- clang/lib/Driver/ToolChains/Arch/SystemZ.cpp | 17 +++++++++-------- llvm/lib/Target/SystemZ/SystemZCallingConv.h | 4 ++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp b/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp index 583d04d8c84f5..69a06f1dddf46 100644 --- a/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp +++ b/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp @@ -74,17 +74,18 @@ void systemz::getSystemZTargetFeatures(const Driver &D, const llvm::Triple &T, // -m(no-)vx overrides use of the vector facility. if (Arg *A = Args.getLastArg(options::OPT_mvx, options::OPT_mno_vx)) { - // The -mvx requires at least -march=arch11/z13 when -mhard-float is in affect. + // The -mvx requires at least -march=arch11/z13 when -mhard-float is in + // affect. if (A->getOption().matches(options::OPT_mvx)) { auto Arch = getSystemZTargetCPU(Args, T); if (HardFloatABI && llvm::StringSwitch<bool>(Arch) - .Case("arch8", true) - .Case("z10", true) - .Case("arch9", true) - .Case("z196", true) - .Case("arch10", true) - .Case("zEC12", true) - .Default(false)) { + .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; } diff --git a/llvm/lib/Target/SystemZ/SystemZCallingConv.h b/llvm/lib/Target/SystemZ/SystemZCallingConv.h index 88f532125abe3..91a1fe8f12d96 100644 --- a/llvm/lib/Target/SystemZ/SystemZCallingConv.h +++ b/llvm/lib/Target/SystemZ/SystemZCallingConv.h @@ -97,8 +97,8 @@ inline bool CC_XPLINK64_Pointer(unsigned &ValNo, MVT &ValVT, MVT &LocVT, } inline bool CC_XPLINK_Int128(unsigned &ValNo, MVT &ValVT, MVT &LocVT, - CCValAssign::LocInfo &LocInfo, - ISD::ArgFlagsTy &ArgFlags, CCState &State) { + CCValAssign::LocInfo &LocInfo, + ISD::ArgFlagsTy &ArgFlags, CCState &State) { LocVT = MVT::v16i8; LocInfo = CCValAssign::BCvt; return false; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
