From e88f8ae98f7c7409be8f383d0968023ef6294a00 Mon Sep 17 00:00:00 2001 From: Kai Nacke Date: Wed, 26 Nov 2025 12:01:45 -0500 Subject: [PATCH 1/2] [SystemZ] Emit optional argument area length field The Language Environment (LE) reserves 128 byte for the argument area when the optional field is not present. If the argument area is larger, then the field must be present to guarantee that the space is reseverd on stack extension. Creating this field when alloca() is used may reduce the needed stack space in case alloca() causes a stack extension. --- llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 33 +++++++++- llvm/test/CodeGen/SystemZ/zos-ppa1-argarea.ll | 66 +++++++++++++++++++ 2 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 llvm/test/CodeGen/SystemZ/zos-ppa1-argarea.ll diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp index e31d7c6a86476..f6dd60fa8b199 100644 --- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp +++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp @@ -1270,7 +1270,7 @@ void SystemZAsmPrinter::emitFunctionBodyEnd() { static void emitPPA1Flags(std::unique_ptr &OutStreamer, bool VarArg, bool StackProtector, bool FPRMask, bool VRMask, - bool EHBlock, bool HasName) { + bool EHBlock, bool HasArgAreaLength, bool HasName) { enum class PPA1Flag1 : uint8_t { DSA64Bit = (0x80 >> 0), VarArg = (0x80 >> 7), @@ -1282,8 +1282,9 @@ static void emitPPA1Flags(std::unique_ptr &OutStreamer, bool VarArg, LLVM_MARK_AS_BITMASK_ENUM(ExternalProcedure) }; enum class PPA1Flag3 : uint8_t { + HasArgAreaLength = (0x80 >> 1), FPRMask = (0x80 >> 2), - LLVM_MARK_AS_BITMASK_ENUM(FPRMask) + LLVM_MARK_AS_BITMASK_ENUM(HasArgAreaLength) }; enum class PPA1Flag4 : uint8_t { EPMOffsetPresent = (0x80 >> 0), @@ -1307,6 +1308,9 @@ static void emitPPA1Flags(std::unique_ptr &OutStreamer, bool VarArg, if (StackProtector) Flags2 |= PPA1Flag2::STACKPROTECTOR; + if (HasArgAreaLength) + Flags3 |= PPA1Flag3::HasArgAreaLength; // Add emit ArgAreaLength flag. + // SavedGPRMask, SavedFPRMask, and SavedVRMask are precomputed in. if (FPRMask) Flags3 |= PPA1Flag3::FPRMask; // Add emit FPR mask flag. @@ -1339,6 +1343,10 @@ static void emitPPA1Flags(std::unique_ptr &OutStreamer, bool VarArg, OutStreamer->emitInt8(static_cast(Flags2)); // Flags 2. OutStreamer->AddComment("PPA1 Flags 3"); + if ((Flags3 & PPA1Flag3::HasArgAreaLength) == + PPA1Flag3::HasArgAreaLength) + OutStreamer->AddComment( + " Bit 1: 1 = Argument Area Length is in optional area"); if ((Flags3 & PPA1Flag3::FPRMask) == PPA1Flag3::FPRMask) OutStreamer->AddComment(" Bit 2: 1 = FP Reg Mask is in optional area"); OutStreamer->emitInt8( @@ -1477,12 +1485,26 @@ void SystemZAsmPrinter::emitPPA1(MCSymbol *FnEndSym) { bool NeedEmitEHBlock = !MF->getLandingPads().empty(); + // Optional Argument Area Length. + // Note: This represents the length of the argument area that we reserve + // in our stack for setting up arguments for calls to other + // routines. If this optional field is not set, LE will reserve + // 128 bytes for the argument area. This optional field is + // created if greater than 128 bytes is required - to guarantee + // the required space is reserved on stack extension in the new + // extension. This optional field is also created if the + // routine has alloca(). This may reduce stack space + // if alloca() call causes a stack extension. + bool HasArgAreaLength = + (AllocaReg != 0) || (MFFrame.getMaxCallFrameSize() > 128); + bool HasName = MF->getFunction().hasName() && MF->getFunction().getName().size() > 0; emitPPA1Flags(OutStreamer, MF->getFunction().isVarArg(), MFFrame.hasStackProtectorIndex(), SavedFPRMask != 0, - TargetHasVector && SavedVRMask != 0, NeedEmitEHBlock, HasName); + TargetHasVector && SavedVRMask != 0, NeedEmitEHBlock, + HasArgAreaLength, HasName); OutStreamer->AddComment("Length/4 of Parms"); OutStreamer->emitInt16( @@ -1490,6 +1512,11 @@ void SystemZAsmPrinter::emitPPA1(MCSymbol *FnEndSym) { OutStreamer->AddComment("Length of Code"); OutStreamer->emitAbsoluteSymbolDiff(FnEndSym, CurrentFnEPMarkerSym, 4); + if (HasArgAreaLength) { + OutStreamer->AddComment("Argument Area Length"); + OutStreamer->emitInt32(MFFrame.getMaxCallFrameSize()); + } + // Emit saved FPR mask and offset to FPR save area (0x20 of flags 3). if (SavedFPRMask) { OutStreamer->AddComment("FPR mask"); diff --git a/llvm/test/CodeGen/SystemZ/zos-ppa1-argarea.ll b/llvm/test/CodeGen/SystemZ/zos-ppa1-argarea.ll new file mode 100644 index 0000000000000..511bc46567607 --- /dev/null +++ b/llvm/test/CodeGen/SystemZ/zos-ppa1-argarea.ll @@ -0,0 +1,66 @@ +; RUN: llc < %s -mtriple=s390x-ibm-zos -emit-gnuas-syntax-on-zos=0 | FileCheck %s +%struct.LargeStruct_t = type { [33 x i32] } + +@GlobLargeS = hidden global %struct.LargeStruct_t zeroinitializer, align 4 +@GlobInt = hidden global i32 0, align 4 + +; === Check that function with small frame does not emit PPA1 Argument Area Length. +define void @fSmallOutArgArea() { +; CHECK-LABEL: L#EPM_fSmallOutArgArea_0 DS 0H +; CHECK: * Bit 1: 1 = Leaf function +; CHECK: * Bit 2: 0 = Does not use alloca +; CHECK: DC XL4'00000008' +; CHECK: fSmallOutArgArea DS 0H +; CHECK: L#PPA1_fSmallOutArgArea_0 DS 0H +; CHECK: * PPA1 Flags 3 +; CHECK: DC XL1'00' + ret void +} + +; === Check that function with large frame does emit PPA1 Argument Area Length. +define void @fLargeOutArgArea() { +; CHECK-LABEL: L#EPM_fLargeOutArgArea_0 DS 0H +; CHECK: * Bit 1: 0 = Non-leaf function +; CHECK: * Bit 2: 0 = Does not use alloca +; CHECK: DC XL4'00000220' +; CHECK: fLargeOutArgArea DS 0H +; CHECK: L#PPA1_fLargeOutArgArea_0 DS 0H +; CHECK: * PPA1 Flags 3 +; CHECK: * Bit 1: 1 = Argument Area Length is in optional area +; CHECK: DC XL1'40' +; CHECK: * Argument Area Length +; CHECK: DC XL4'00000140' + %1 = load [33 x i32], ptr @GlobLargeS, align 4 + call void @fLargeParm([33 x i32] inreg %1) + ret void +} + +; === Check that function with parameter does emit PPA1 Length/4 of parms +define void @fLargeParm([33 x i64] inreg %arr) { +; CHECK-LABEL: L#EPM_fLargeParm_0 DS 0H +; CHECK: * Length/4 of Parms +; CHECK: DC XL2'0042' + %1 = extractvalue [33 x i64] %arr, 1 + call void @foo(i64 %1) + ret void +} + +; === Check that function with alloca call does emit PPA1 Argument Area Length. +define hidden void @fHasAlloca() { +; CHECK-LABEL: L#EPM_fHasAlloca_0 DS 0H +; CHECK: * Bit 2: 1 = Uses alloca +; CHECK: fHasAlloca DS 0H +; CHECK: L#PPA1_fHasAlloca_0 DS 0H +; CHECK: * PPA1 Flags 3 +; CHECK: * Bit 1: 1 = Argument Area Length is in optional area +; CHECK: DC XL1'40' +; CHECK: * Argument Area Length +; CHECK: DC XL4'00000040' + %p = alloca ptr, align 4 + %1 = load i32, ptr @GlobInt, align 4 + %2 = alloca i8, i32 %1, align 8 + store ptr %2, ptr %p, align 4 + ret void +} + +declare void @foo(i64) From 820bf320ab7ed6ad22481349cf2816ada79f8de8 Mon Sep 17 00:00:00 2001 From: Kai Nacke Date: Wed, 26 Nov 2025 13:19:58 -0500 Subject: [PATCH 2/2] Fix formatting --- llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp index f6dd60fa8b199..f061272d3fad4 100644 --- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp +++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp @@ -1343,8 +1343,7 @@ static void emitPPA1Flags(std::unique_ptr &OutStreamer, bool VarArg, OutStreamer->emitInt8(static_cast(Flags2)); // Flags 2. OutStreamer->AddComment("PPA1 Flags 3"); - if ((Flags3 & PPA1Flag3::HasArgAreaLength) == - PPA1Flag3::HasArgAreaLength) + if ((Flags3 & PPA1Flag3::HasArgAreaLength) == PPA1Flag3::HasArgAreaLength) OutStreamer->AddComment( " Bit 1: 1 = Argument Area Length is in optional area"); if ((Flags3 & PPA1Flag3::FPRMask) == PPA1Flag3::FPRMask)