diff --git a/llvm/include/llvm/CodeGen/CodeGenPassBuilder.h b/llvm/include/llvm/CodeGen/CodeGenPassBuilder.h index ac9e66c4dc2fd3..5edfa1f685af21 100644 --- a/llvm/include/llvm/CodeGen/CodeGenPassBuilder.h +++ b/llvm/include/llvm/CodeGen/CodeGenPassBuilder.h @@ -701,6 +701,7 @@ void CodeGenPassBuilder::addPassesToHandleExceptions( case ExceptionHandling::DwarfCFI: case ExceptionHandling::ARM: case ExceptionHandling::AIX: + case ExceptionHandling::ZOS: addPass(DwarfEHPreparePass(&TM)); break; case ExceptionHandling::WinEH: diff --git a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h index 9f92b919824d2d..4a7c1ca4a57182 100644 --- a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -309,6 +309,8 @@ class TargetLoweringObjectFileGOFF : public TargetLoweringObjectFile { const TargetMachine &TM) const override; MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const override; + MCSection *getSectionForLSDA(const Function &F, const MCSymbol &FnSym, + const TargetMachine &TM) const override; }; } // end namespace llvm diff --git a/llvm/include/llvm/MC/MCAsmInfo.h b/llvm/include/llvm/MC/MCAsmInfo.h index a3c9b19e859d93..56492368bd984a 100644 --- a/llvm/include/llvm/MC/MCAsmInfo.h +++ b/llvm/include/llvm/MC/MCAsmInfo.h @@ -799,7 +799,8 @@ class MCAsmInfo { /// frame information to unwind. bool usesCFIForEH() const { return (ExceptionsType == ExceptionHandling::DwarfCFI || - ExceptionsType == ExceptionHandling::ARM || usesWindowsCFI()); + ExceptionsType == ExceptionHandling::ARM || + ExceptionsType == ExceptionHandling::ZOS || usesWindowsCFI()); } bool usesWindowsCFI() const { diff --git a/llvm/include/llvm/MC/MCTargetOptions.h b/llvm/include/llvm/MC/MCTargetOptions.h index afb329eb6f935e..e2dd1e0433dbe4 100644 --- a/llvm/include/llvm/MC/MCTargetOptions.h +++ b/llvm/include/llvm/MC/MCTargetOptions.h @@ -24,6 +24,8 @@ enum class ExceptionHandling { WinEH, ///< Windows Exception Handling Wasm, ///< WebAssembly Exception Handling AIX, ///< AIX Exception Handling + ZOS, ///< z/OS MVS Exception Handling. Very similar to DwarfCFI, but the PPA1 + ///< is used instead of an .eh_frame section. }; enum class EmitDwarfUnwindType { diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 61309c51336e52..4dd27702786e42 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -583,6 +583,7 @@ bool AsmPrinter::doInitialization(Module &M) { [[fallthrough]]; case ExceptionHandling::SjLj: case ExceptionHandling::DwarfCFI: + case ExceptionHandling::ZOS: ES = new DwarfCFIException(this); break; case ExceptionHandling::ARM: diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index 9a0dd92bb58e87..6e69dc66429d31 100644 --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -2681,6 +2681,13 @@ MCSection *TargetLoweringObjectFileGOFF::getExplicitSectionGlobal( return SelectSectionForGlobal(GO, Kind, TM); } +MCSection *TargetLoweringObjectFileGOFF::getSectionForLSDA( + const Function &F, const MCSymbol &FnSym, const TargetMachine &TM) const { + std::string Name = ".gcc_exception_table." + F.getName().str(); + return getContext().getGOFFSection(Name, SectionKind::getData(), nullptr, + nullptr); +} + MCSection *TargetLoweringObjectFileGOFF::SelectSectionForGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { auto *Symbol = TM.getSymbol(GO); diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp b/llvm/lib/CodeGen/TargetPassConfig.cpp index faa5466b69e8b3..4003a08a5422dd 100644 --- a/llvm/lib/CodeGen/TargetPassConfig.cpp +++ b/llvm/lib/CodeGen/TargetPassConfig.cpp @@ -947,6 +947,7 @@ void TargetPassConfig::addPassesToHandleExceptions() { case ExceptionHandling::DwarfCFI: case ExceptionHandling::ARM: case ExceptionHandling::AIX: + case ExceptionHandling::ZOS: addPass(createDwarfEHPass(getOptLevel())); break; case ExceptionHandling::WinEH: diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp index 6e72b5062a1d8d..c1db7e3943c47c 100644 --- a/llvm/lib/MC/MCContext.cpp +++ b/llvm/lib/MC/MCContext.cpp @@ -650,10 +650,16 @@ MCSectionGOFF *MCContext::getGOFFSection(StringRef Section, SectionKind Kind, MCSection *Parent, const MCExpr *SubsectionId) { // Do the lookup. If we don't have a hit, return a new section. - auto &GOFFSection = GOFFUniquingMap[Section.str()]; - if (!GOFFSection) - GOFFSection = new (GOFFAllocator.Allocate()) - MCSectionGOFF(Section, Kind, Parent, SubsectionId); + auto IterBool = + GOFFUniquingMap.insert(std::make_pair(Section.str(), nullptr)); + auto Iter = IterBool.first; + if (!IterBool.second) + return Iter->second; + + StringRef CachedName = Iter->first; + MCSectionGOFF *GOFFSection = new (GOFFAllocator.Allocate()) + MCSectionGOFF(CachedName, Kind, Parent, SubsectionId); + Iter->second = GOFFSection; return GOFFSection; } diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp index e61b07e973e930..66555fa06b0688 100644 --- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp +++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp @@ -38,6 +38,7 @@ SystemZMCAsmInfoGOFF::SystemZMCAsmInfoGOFF(const Triple &TT) { DotIsPC = false; EmitGNUAsmStartIndentationMarker = false; EmitLabelsInUpperCase = true; + ExceptionsType = ExceptionHandling::ZOS; IsLittleEndian = false; MaxInstLength = 6; RestrictCommentStringToStartOfStatement = true; diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp index 3186002c57d98a..243461c0316e53 100644 --- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp +++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp @@ -1115,7 +1115,7 @@ void SystemZAsmPrinter::emitFunctionBodyEnd() { static void emitPPA1Flags(std::unique_ptr &OutStreamer, bool VarArg, bool StackProtector, bool FPRMask, bool VRMask, - bool HasName) { + bool EHBlock, bool HasName) { enum class PPA1Flag1 : uint8_t { DSA64Bit = (0x80 >> 0), VarArg = (0x80 >> 7), @@ -1133,6 +1133,7 @@ static void emitPPA1Flags(std::unique_ptr &OutStreamer, bool VarArg, enum class PPA1Flag4 : uint8_t { EPMOffsetPresent = (0x80 >> 0), VRMask = (0x80 >> 2), + EHBlock = (0x80 >> 3), ProcedureNamePresent = (0x80 >> 7), LLVM_MARK_AS_BITMASK_ENUM(EPMOffsetPresent) }; @@ -1158,6 +1159,9 @@ static void emitPPA1Flags(std::unique_ptr &OutStreamer, bool VarArg, if (VRMask) Flags4 |= PPA1Flag4::VRMask; // Add emit VR mask flag. + if (EHBlock) + Flags4 |= PPA1Flag4::EHBlock; // Add optional EH block. + if (HasName) Flags4 |= PPA1Flag4::ProcedureNamePresent; // Add optional name block. @@ -1188,6 +1192,8 @@ static void emitPPA1Flags(std::unique_ptr &OutStreamer, bool VarArg, OutStreamer->AddComment("PPA1 Flags 4"); if ((Flags4 & PPA1Flag4::VRMask) == PPA1Flag4::VRMask) OutStreamer->AddComment(" Bit 2: 1 = Vector Reg Mask is in optional area"); + if ((Flags4 & PPA1Flag4::EHBlock) == PPA1Flag4::EHBlock) + OutStreamer->AddComment(" Bit 3: 1 = C++ EH block"); if ((Flags4 & PPA1Flag4::ProcedureNamePresent) == PPA1Flag4::ProcedureNamePresent) OutStreamer->AddComment(" Bit 7: 1 = Name Length and Name"); @@ -1314,12 +1320,14 @@ void SystemZAsmPrinter::emitPPA1(MCSymbol *FnEndSym) { OutStreamer->AddComment("Offset to PPA2"); OutStreamer->emitAbsoluteSymbolDiff(PPA2Sym, CurrentFnPPA1Sym, 4); + bool NeedEmitEHBlock = !MF->getLandingPads().empty(); + bool HasName = MF->getFunction().hasName() && MF->getFunction().getName().size() > 0; emitPPA1Flags(OutStreamer, MF->getFunction().isVarArg(), MFFrame.hasStackProtectorIndex(), SavedFPRMask != 0, - TargetHasVector && SavedVRMask != 0, HasName); + TargetHasVector && SavedVRMask != 0, NeedEmitEHBlock, HasName); OutStreamer->AddComment("Length/4 of Parms"); OutStreamer->emitInt16( @@ -1361,6 +1369,29 @@ void SystemZAsmPrinter::emitPPA1(MCSymbol *FnEndSym) { OutStreamer->emitInt32(FrameAndVROffset); } + // Emit C++ EH information block + const Function *Per = nullptr; + if (NeedEmitEHBlock) { + Per = dyn_cast( + MF->getFunction().getPersonalityFn()->stripPointerCasts()); + MCSymbol *PersonalityRoutine = + Per ? MF->getTarget().getSymbol(Per) : nullptr; + assert(PersonalityRoutine && "Missing personality routine"); + + OutStreamer->AddComment("Version"); + OutStreamer->emitInt32(1); + OutStreamer->AddComment("Flags"); + OutStreamer->emitInt32(0); // LSDA field is a WAS offset + OutStreamer->AddComment("Personality routine"); + OutStreamer->emitInt64(ADATable.insert( + PersonalityRoutine, SystemZII::MO_ADA_INDIRECT_FUNC_DESC)); + OutStreamer->AddComment("LSDA location"); + MCSymbol *GCCEH = MF->getContext().getOrCreateSymbol( + Twine("GCC_except_table") + Twine(MF->getFunctionNumber())); + OutStreamer->emitInt64( + ADATable.insert(GCCEH, SystemZII::MO_ADA_DATA_SYMBOL_ADDR)); + } + // Emit name length and name optional section (0x01 of flags 4) if (HasName) emitPPA1Name(OutStreamer, MF->getFunction().getName()); diff --git a/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp b/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp index 7522998fd06d8e..db19c8881c685a 100644 --- a/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp @@ -17,6 +17,7 @@ #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/IR/Function.h" #include "llvm/Target/TargetMachine.h" @@ -994,6 +995,11 @@ bool SystemZXPLINKFrameLowering::assignCalleeSavedSpillSlots( if (hasFP(MF) || Subtarget.hasBackChain()) CSI.push_back(CalleeSavedInfo(Regs.getStackPointerRegister())); + // If this function has an associated personality function then the + // environment register R5 must be saved in the DSA. + if (!MF.getLandingPads().empty()) + CSI.push_back(CalleeSavedInfo(Regs.getADARegister())); + // Scan the call-saved GPRs and find the bounds of the register spill area. Register LowRestoreGPR = 0; int LowRestoreOffset = INT32_MAX; diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp index a1803cf9a042f7..559f2ca476d709 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -1362,6 +1362,16 @@ SystemZTargetLowering::getRegisterByName(const char *RegName, LLT VT, report_fatal_error("Invalid register name global variable"); } +Register SystemZTargetLowering::getExceptionPointerRegister( + const Constant *PersonalityFn) const { + return Subtarget.isTargetXPLINK64() ? SystemZ::R1D : SystemZ::R6D; +} + +Register SystemZTargetLowering::getExceptionSelectorRegister( + const Constant *PersonalityFn) const { + return Subtarget.isTargetXPLINK64() ? SystemZ::R2D : SystemZ::R7D; +} + void SystemZTargetLowering::LowerAsmOperandForConstraint( SDValue Op, StringRef Constraint, std::vector &Ops, SelectionDAG &DAG) const { diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h index 6b3ce3f8c1d2b1..baf4ba41654879 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h @@ -555,16 +555,12 @@ class SystemZTargetLowering : public TargetLowering { /// If a physical register, this returns the register that receives the /// exception address on entry to an EH pad. Register - getExceptionPointerRegister(const Constant *PersonalityFn) const override { - return SystemZ::R6D; - } + getExceptionPointerRegister(const Constant *PersonalityFn) const override; /// If a physical register, this returns the register that receives the /// exception typeid on entry to a landing pad. Register - getExceptionSelectorRegister(const Constant *PersonalityFn) const override { - return SystemZ::R7D; - } + getExceptionSelectorRegister(const Constant *PersonalityFn) const override; /// Override to support customized stack guard loading. bool useLoadStackGuardNode() const override { diff --git a/llvm/test/CodeGen/SystemZ/zos-landingpad.ll b/llvm/test/CodeGen/SystemZ/zos-landingpad.ll new file mode 100644 index 00000000000000..481efb5935b36e --- /dev/null +++ b/llvm/test/CodeGen/SystemZ/zos-landingpad.ll @@ -0,0 +1,41 @@ +; RUN: llc < %s -mtriple=s390x-none-zos -mcpu=z10 | FileCheck %s +; +; Ensures that landingpad instructions use the right Exception Pointer +; and Exception Selector registers, and that the exception table is emitted. + +declare void @callee() +declare void @passeh(i8*, i32) noreturn +declare i32 @__zos_cxx_personality_v2(...) + +define void @test1() uwtable personality i32 (...)* @__zos_cxx_personality_v2 { +entry: + %ehptr = alloca i8*, align 8 + %ehsel = alloca i32, align 8 + invoke void @callee() to label %done unwind label %lpad +done: + ret void +; Match the return instruction. +; CHECK: b 2(7) +lpad: + %0 = landingpad { i8*, i32 } cleanup +; The Exception Pointer is %r1; the Exception Selector, %r2. +; CHECK: @BB{{[^%]*}} %lpad +; CHECK-DAG: stg 1, {{.*}} +; CHECK-DAG: st 2, {{.*}} + %1 = extractvalue { i8*, i32 } %0, 0 + %2 = extractvalue { i8*, i32 } %0, 1 + store i8* %1, i8** %ehptr, align 8 + store i32 %2, i32* %ehsel, align 8 + call void @passeh(i8* %1, i32 %2) + unreachable +} + +; Check that offsets to the FD of the personality routine and LSDA are emitted in PPA1 +; CHECK: .byte 145 {{.*PPA1 Flags}} +; CHECK: Bit 3: 1 = C++ EH block +; TODO: Emit the value instead of a dummy value. +; CHECK: Personality routine +; CHECK: LSDA location +; Check that the exception table is emitted into .lsda section. +; CHECK: .section ".gcc_exception_table.test1" +; CHECK: GCC_except_table0: