diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp index e31d7c6a86476..f061272d3fad4 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,9 @@ 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 +1484,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 +1511,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)