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
