[llvm] 163aad6 - [SystemZ][z/OS] z/OS ADA codegen and emission
Yusra Syeda via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 5 10:26:06 PDT 2023
Author: Yusra Syeda
Date: 2023-07-05T13:21:52-04:00
New Revision: 163aad6bcbff6ee2935e24945ddef9719142aff0
URL: https://github.com/llvm/llvm-project/commit/163aad6bcbff6ee2935e24945ddef9719142aff0
DIFF: https://github.com/llvm/llvm-project/commit/163aad6bcbff6ee2935e24945ddef9719142aff0.diff
LOG: [SystemZ][z/OS] z/OS ADA codegen and emission
This patch adds support for the ADA (associated data area), doing the following:
-Creates the ADA table to handle displacements
-Emits the ADA section in the SystemZAsmPrinter
-Lowers the ADA_ENTRY node into the appropriate load instruction
Differential Revision: https://reviews.llvm.org/D153788
Added:
llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.cpp
llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.h
llvm/test/CodeGen/SystemZ/zos-ada-relocations.ll
llvm/test/CodeGen/SystemZ/zos-ada.ll
Modified:
llvm/include/llvm/MC/MCObjectFileInfo.h
llvm/lib/MC/MCObjectFileInfo.cpp
llvm/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt
llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
llvm/lib/Target/SystemZ/SystemZISelLowering.h
llvm/lib/Target/SystemZ/SystemZInstrInfo.h
llvm/lib/Target/SystemZ/SystemZInstrInfo.td
llvm/lib/Target/SystemZ/SystemZMachineFunctionInfo.h
llvm/lib/Target/SystemZ/SystemZOperators.td
llvm/lib/Target/SystemZ/SystemZRegisterInfo.h
llvm/lib/Target/SystemZ/SystemZSubtarget.cpp
llvm/lib/Target/SystemZ/SystemZSubtarget.h
llvm/test/CodeGen/SystemZ/call-zos-vararg.ll
llvm/test/CodeGen/SystemZ/zos-prologue-epilog.ll
Removed:
################################################################################
diff --git a/llvm/include/llvm/MC/MCObjectFileInfo.h b/llvm/include/llvm/MC/MCObjectFileInfo.h
index 43ab85fbc32741..54f696cb795fbc 100644
--- a/llvm/include/llvm/MC/MCObjectFileInfo.h
+++ b/llvm/include/llvm/MC/MCObjectFileInfo.h
@@ -227,6 +227,7 @@ class MCObjectFileInfo {
// GOFF specific sections.
MCSection *PPA1Section = nullptr;
+ MCSection *ADASection = nullptr;
// XCOFF specific sections
MCSection *TOCBaseSection = nullptr;
@@ -430,6 +431,7 @@ class MCObjectFileInfo {
// GOFF specific sections.
MCSection *getPPA1Section() const { return PPA1Section; }
+ MCSection *getADASection() const { return ADASection; }
// XCOFF specific sections
MCSection *getTOCBaseSection() const { return TOCBaseSection; }
diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp
index 9fceaa20ca68c5..df2085e28cbc2a 100644
--- a/llvm/lib/MC/MCObjectFileInfo.cpp
+++ b/llvm/lib/MC/MCObjectFileInfo.cpp
@@ -542,6 +542,8 @@ void MCObjectFileInfo::initGOFFMCObjectFileInfo(const Triple &T) {
PPA1Section =
Ctx->getGOFFSection(".ppa1", SectionKind::getMetadata(), TextSection,
MCConstantExpr::create(GOFF::SK_PPA1, *Ctx));
+ ADASection =
+ Ctx->getGOFFSection(".ada", SectionKind::getData(), nullptr, nullptr);
}
void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) {
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt
index 055482ee31b052..91aac7dd6603cb 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt
@@ -3,6 +3,7 @@ add_llvm_component_library(LLVMSystemZDesc
SystemZMCAsmBackend.cpp
SystemZMCAsmInfo.cpp
SystemZMCCodeEmitter.cpp
+ SystemZMCExpr.cpp
SystemZMCObjectWriter.cpp
SystemZMCTargetDesc.cpp
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.cpp
new file mode 100644
index 00000000000000..647cf765c6a3ea
--- /dev/null
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.cpp
@@ -0,0 +1,49 @@
+//===-- SystemZMCExpr.cpp - SystemZ specific MC expression classes --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "SystemZMCExpr.h"
+#include "llvm/MC/MCContext.h"
+using namespace llvm;
+
+#define DEBUG_TYPE "systemzmcexpr"
+
+const SystemZMCExpr *SystemZMCExpr::create(VariantKind Kind, const MCExpr *Expr,
+ MCContext &Ctx) {
+ return new (Ctx) SystemZMCExpr(Kind, Expr);
+}
+
+StringRef SystemZMCExpr::getVariantKindName() const {
+ switch (static_cast<uint32_t>(getKind())) {
+ case VK_SystemZ_None:
+ return "A";
+ case VK_SystemZ_RCon:
+ return "R";
+ case VK_SystemZ_VCon:
+ return "V";
+ default:
+ llvm_unreachable("Invalid kind");
+ }
+}
+
+void SystemZMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
+ OS << getVariantKindName() << '(';
+ Expr->print(OS, MAI);
+ OS << ')';
+}
+
+bool SystemZMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
+ const MCAsmLayout *Layout,
+ const MCFixup *Fixup) const {
+ if (!getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup))
+ return false;
+
+ Res =
+ MCValue::get(Res.getSymA(), Res.getSymB(), Res.getConstant(), getKind());
+
+ return true;
+}
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.h b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.h
new file mode 100644
index 00000000000000..f548b34baa4242
--- /dev/null
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCExpr.h
@@ -0,0 +1,66 @@
+//===-- SystemZMCExpr.h - SystemZ specific MC expression classes -*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_SystemZ_MCTARGETDESC_SystemZMCEXPR_H
+#define LLVM_LIB_TARGET_SystemZ_MCTARGETDESC_SystemZMCEXPR_H
+
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCValue.h"
+
+namespace llvm {
+
+class SystemZMCExpr : public MCTargetExpr {
+public:
+// HLASM docs for address constants:
+// https://www.ibm.com/docs/en/hla-and-tf/1.6?topic=value-address-constants
+ enum VariantKind {
+ VK_SystemZ_None,
+ VK_SystemZ_RCon, // Address of ADA of symbol.
+ VK_SystemZ_VCon, // Address of external function symbol.
+ };
+
+private:
+ const VariantKind Kind;
+ const MCExpr *Expr;
+
+ explicit SystemZMCExpr(VariantKind Kind, const MCExpr *Expr)
+ : Kind(Kind), Expr(Expr) {}
+
+public:
+ static const SystemZMCExpr *create(VariantKind Kind, const MCExpr *Expr,
+ MCContext &Ctx);
+
+ /// getOpcode - Get the kind of this expression.
+ VariantKind getKind() const { return Kind; }
+
+ /// getSubExpr - Get the child of this expression.
+ const MCExpr *getSubExpr() const { return Expr; }
+
+ StringRef getVariantKindName() const;
+
+ void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override;
+ bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout,
+ const MCFixup *Fixup) const override;
+ void visitUsedExpr(MCStreamer &Streamer) const override {
+ Streamer.visitUsedExpr(*getSubExpr());
+ }
+ MCFragment *findAssociatedFragment() const override {
+ return getSubExpr()->findAssociatedFragment();
+ }
+
+ // There are no TLS SystemZMCExprs at the moment.
+ void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override {}
+
+ static bool classof(const MCExpr *E) {
+ return E->getKind() == MCExpr::Target;
+ }
+};
+} // end namespace llvm
+
+#endif
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index f84af452a01595..19e253898aa2e4 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -13,6 +13,7 @@
#include "SystemZAsmPrinter.h"
#include "MCTargetDesc/SystemZInstPrinter.h"
+#include "MCTargetDesc/SystemZMCExpr.h"
#include "SystemZConstantPoolValue.h"
#include "SystemZMCInstLower.h"
#include "TargetInfo/SystemZTargetInfo.h"
@@ -143,6 +144,50 @@ void SystemZAsmPrinter::emitCallInformation(CallType CT) {
.addReg(SystemZMC::GR64Regs[static_cast<unsigned>(CT)]));
}
+uint32_t SystemZAsmPrinter::AssociatedDataAreaTable::insert(const MCSymbol *Sym,
+ unsigned SlotKind) {
+ auto Key = std::make_pair(Sym, SlotKind);
+ auto It = Displacements.find(Key);
+
+ if (It != Displacements.end())
+ return (*It).second;
+
+ // Determine length of descriptor.
+ uint32_t Length;
+ switch (SlotKind) {
+ case SystemZII::MO_ADA_DIRECT_FUNC_DESC:
+ Length = 2 * PointerSize;
+ break;
+ default:
+ Length = PointerSize;
+ break;
+ }
+
+ uint32_t Displacement = NextDisplacement;
+ Displacements[std::make_pair(Sym, SlotKind)] = NextDisplacement;
+ NextDisplacement += Length;
+
+ return Displacement;
+}
+
+uint32_t
+SystemZAsmPrinter::AssociatedDataAreaTable::insert(const MachineOperand MO) {
+ MCSymbol *Sym;
+ if (MO.getType() == MachineOperand::MO_GlobalAddress) {
+ const GlobalValue *GV = MO.getGlobal();
+ Sym = MO.getParent()->getMF()->getTarget().getSymbol(GV);
+ assert(Sym && "No symbol");
+ } else if (MO.getType() == MachineOperand::MO_ExternalSymbol) {
+ const char *SymName = MO.getSymbolName();
+ Sym = MO.getParent()->getMF()->getContext().getOrCreateSymbol(SymName);
+ assert(Sym && "No symbol");
+ } else
+ llvm_unreachable("Unexpected operand type");
+
+ unsigned ADAslotType = MO.getTargetFlags();
+ return insert(Sym, ADAslotType);
+}
+
void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
SystemZ_MC::verifyInstructionPredicates(MI->getOpcode(),
getSubtargetInfo().getFeatureBits());
@@ -273,6 +318,43 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
emitCallInformation(CallType::BASR33);
return;
+ case SystemZ::ADA_ENTRY_VALUE:
+ case SystemZ::ADA_ENTRY: {
+ const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
+ const SystemZInstrInfo *TII = Subtarget.getInstrInfo();
+ uint32_t Disp = ADATable.insert(MI->getOperand(1));
+ Register TargetReg = MI->getOperand(0).getReg();
+
+ Register ADAReg = MI->getOperand(2).getReg();
+ Disp += MI->getOperand(3).getImm();
+ bool LoadAddr = MI->getOpcode() == SystemZ::ADA_ENTRY;
+
+ unsigned Op0 = LoadAddr ? SystemZ::LA : SystemZ::LG;
+ unsigned Op = TII->getOpcodeForOffset(Op0, Disp);
+
+ Register IndexReg = 0;
+ if (!Op) {
+ if (TargetReg != ADAReg) {
+ IndexReg = TargetReg;
+ // Use TargetReg to store displacement.
+ EmitToStreamer(
+ *OutStreamer,
+ MCInstBuilder(SystemZ::LLILF).addReg(TargetReg).addImm(Disp));
+ } else
+ EmitToStreamer(
+ *OutStreamer,
+ MCInstBuilder(SystemZ::ALGFI).addReg(TargetReg).addImm(Disp));
+ Disp = 0;
+ Op = Op0;
+ }
+ EmitToStreamer(*OutStreamer, MCInstBuilder(Op)
+ .addReg(TargetReg)
+ .addReg(IndexReg)
+ .addImm(Disp)
+ .addReg(ADAReg));
+
+ return;
+ }
case SystemZ::CallBRASL:
LoweredMI = MCInstBuilder(SystemZ::BRASL)
.addReg(SystemZ::R14D)
@@ -867,9 +949,81 @@ bool SystemZAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
}
void SystemZAsmPrinter::emitEndOfAsmFile(Module &M) {
+ auto TT = OutContext.getTargetTriple();
+ if (TT.isOSzOS()) {
+ emitADASection();
+ }
emitAttributes(M);
}
+void SystemZAsmPrinter::emitADASection() {
+ OutStreamer->pushSection();
+
+ const unsigned PointerSize = getDataLayout().getPointerSize();
+ OutStreamer->switchSection(getObjFileLowering().getADASection());
+
+ unsigned EmittedBytes = 0;
+ for (auto &Entry : ADATable.getTable()) {
+ const MCSymbol *Sym;
+ unsigned SlotKind;
+ std::tie(Sym, SlotKind) = Entry.first;
+ unsigned Offset = Entry.second;
+ assert(Offset == EmittedBytes && "Offset not as expected");
+#define EMIT_COMMENT(Str) \
+ OutStreamer->AddComment(Twine("Offset ") \
+ .concat(utostr(Offset)) \
+ .concat(" " Str " ") \
+ .concat(Sym->getName()));
+ switch (SlotKind) {
+ case SystemZII::MO_ADA_DIRECT_FUNC_DESC:
+ // Language Environment DLL logic requires function descriptors, for
+ // imported functions, that are placed in the ADA to be 8 byte aligned.
+ EMIT_COMMENT("function descriptor of");
+ OutStreamer->emitValue(
+ SystemZMCExpr::create(SystemZMCExpr::VK_SystemZ_RCon,
+ MCSymbolRefExpr::create(Sym, OutContext),
+ OutContext),
+ PointerSize);
+ OutStreamer->emitValue(
+ SystemZMCExpr::create(SystemZMCExpr::VK_SystemZ_VCon,
+ MCSymbolRefExpr::create(Sym, OutContext),
+ OutContext),
+ PointerSize);
+ EmittedBytes += PointerSize * 2;
+ break;
+ case SystemZII::MO_ADA_DATA_SYMBOL_ADDR:
+ EMIT_COMMENT("pointer to data symbol");
+ OutStreamer->emitValue(
+ SystemZMCExpr::create(SystemZMCExpr::VK_SystemZ_None,
+ MCSymbolRefExpr::create(Sym, OutContext),
+ OutContext),
+ PointerSize);
+ EmittedBytes += PointerSize;
+ break;
+ case SystemZII::MO_ADA_INDIRECT_FUNC_DESC: {
+ MCSymbol *Alias = OutContext.createTempSymbol(
+ Twine(Sym->getName()).concat("@indirect"));
+ OutStreamer->emitAssignment(Alias,
+ MCSymbolRefExpr::create(Sym, OutContext));
+ OutStreamer->emitSymbolAttribute(Alias, MCSA_IndirectSymbol);
+
+ EMIT_COMMENT("pointer to function descriptor");
+ OutStreamer->emitValue(
+ SystemZMCExpr::create(SystemZMCExpr::VK_SystemZ_VCon,
+ MCSymbolRefExpr::create(Alias, OutContext),
+ OutContext),
+ PointerSize);
+ EmittedBytes += PointerSize;
+ break;
+ }
+ default:
+ llvm_unreachable("Unexpected slot kind");
+ }
+#undef EMIT_COMMENT
+ }
+ OutStreamer->popSection();
+}
+
void SystemZAsmPrinter::emitFunctionBodyEnd() {
if (TM.getTargetTriple().isOSzOS()) {
// Emit symbol for the end of function if the z/OS target streamer
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
index c99fcda6dcc527..c9dbbfd0b4c433 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -46,12 +46,56 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
BASR33 = 7, // b'x111' == BASR r3,r3
};
+ // The Associated Data Area (ADA) contains descriptors which help locating
+ // external symbols. For each symbol and type, the displacement into the ADA
+ // is stored.
+ class AssociatedDataAreaTable {
+ public:
+ using DisplacementTable =
+ MapVector<std::pair<const MCSymbol *, unsigned>, uint32_t>;
+
+ private:
+ const uint64_t PointerSize;
+
+ /// The mapping of name/slot type pairs to displacements.
+ DisplacementTable Displacements;
+
+ /// The next available displacement value. Incremented when new entries into
+ /// the ADA are created.
+ uint32_t NextDisplacement = 0;
+
+ public:
+ AssociatedDataAreaTable(uint64_t PointerSize) : PointerSize(PointerSize) {}
+
+ /// @brief Add a function descriptor to the ADA.
+ /// @param MI Pointer to an ADA_ENTRY instruction.
+ /// @return The displacement of the descriptor into the ADA.
+ uint32_t insert(const MachineOperand MO);
+
+ /// @brief Get the displacement into associated data area (ADA) for a name.
+ /// If no displacement is already associated with the name, assign one and
+ /// return it.
+ /// @param Sym The symbol for which the displacement should be returned.
+ /// @param SlotKind The ADA type.
+ /// @return The displacement of the descriptor into the ADA.
+ uint32_t insert(const MCSymbol *Sym, unsigned SlotKind);
+
+ /// Get the table of GOFF displacements. This is 'const' since it should
+ /// never be modified by anything except the APIs on this class.
+ const DisplacementTable &getTable() const { return Displacements; }
+
+ uint32_t getNextDisplacement() const { return NextDisplacement; }
+ };
+
+ AssociatedDataAreaTable ADATable;
+
void emitPPA1(MCSymbol *FnEndSym);
+ void emitADASection();
public:
SystemZAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
: AsmPrinter(TM, std::move(Streamer)), CurrentFnPPA1Sym(nullptr),
- CurrentFnEPMarkerSym(nullptr) {}
+ CurrentFnEPMarkerSym(nullptr), ADATable(TM.getPointerSize(0)) {}
// Override AsmPrinter.
StringRef getPassName() const override { return "SystemZ Assembly Printer"; }
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index c50e9398a8b168..785a08a763eb7b 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -1642,8 +1642,15 @@ SDValue SystemZTargetLowering::LowerFormalArguments(
}
}
- // FIXME: For XPLINK64, Add in support for handling incoming "ADA" special
- // register (R5)
+ if (Subtarget.isTargetXPLINK64()) {
+ // Create virual register for handling incoming "ADA" special register (R5)
+ const TargetRegisterClass *RC = &SystemZ::ADDR64BitRegClass;
+ Register ADAvReg = MRI.createVirtualRegister(RC);
+ auto *Regs = static_cast<SystemZXPLINK64Registers *>(
+ Subtarget.getSpecialRegisters());
+ MRI.addLiveIn(Regs->getADARegister(), ADAvReg);
+ FuncInfo->setADAVirtualRegister(ADAvReg);
+ }
return Chain;
}
@@ -1668,6 +1675,94 @@ static bool canUseSiblingCall(const CCState &ArgCCInfo,
return true;
}
+static SDValue getADAEntry(SelectionDAG &DAG, SDValue Val, SDLoc DL,
+ unsigned Offset, bool LoadAdr = false) {
+ MachineFunction &MF = DAG.getMachineFunction();
+ SystemZMachineFunctionInfo *MFI = MF.getInfo<SystemZMachineFunctionInfo>();
+ unsigned ADAvReg = MFI->getADAVirtualRegister();
+ EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout());
+
+ SDValue Reg = DAG.getRegister(ADAvReg, PtrVT);
+ SDValue Ofs = DAG.getTargetConstant(Offset, DL, PtrVT);
+
+ SDValue Result = DAG.getNode(SystemZISD::ADA_ENTRY, DL, PtrVT, Val, Reg, Ofs);
+ if (!LoadAdr)
+ Result = DAG.getLoad(
+ PtrVT, DL, DAG.getEntryNode(), Result, MachinePointerInfo(), Align(8),
+ MachineMemOperand::MODereferenceable | MachineMemOperand::MOInvariant);
+
+ return Result;
+}
+
+// ADA access using Global value
+// Note: for functions, address of descriptor is returned
+static SDValue getADAEntry(SelectionDAG &DAG, const GlobalValue *GV, SDLoc DL,
+ EVT PtrVT) {
+ unsigned ADAtype;
+ bool LoadAddr = false;
+ const GlobalAlias *GA = dyn_cast<GlobalAlias>(GV);
+ bool IsFunction =
+ (isa<Function>(GV)) || (GA && isa<Function>(GA->getAliaseeObject()));
+ bool IsInternal = (GV->hasInternalLinkage() || GV->hasPrivateLinkage());
+
+ if (IsFunction) {
+ if (IsInternal) {
+ ADAtype = SystemZII::MO_ADA_DIRECT_FUNC_DESC;
+ LoadAddr = true;
+ } else
+ ADAtype = SystemZII::MO_ADA_INDIRECT_FUNC_DESC;
+ } else {
+ ADAtype = SystemZII::MO_ADA_DATA_SYMBOL_ADDR;
+ }
+ SDValue Val = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, ADAtype);
+
+ return getADAEntry(DAG, Val, DL, 0, LoadAddr);
+}
+
+static bool getzOSCalleeAndADA(SelectionDAG &DAG, SDValue &Callee, SDValue &ADA,
+ SDLoc &DL, SDValue &Chain) {
+ unsigned ADADelta = 0; // ADA offset in desc.
+ unsigned EPADelta = 8; // EPA offset in desc.
+ MachineFunction &MF = DAG.getMachineFunction();
+ EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout());
+
+ // XPLink calling convention.
+ if (auto *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
+ bool IsInternal = (G->getGlobal()->hasInternalLinkage() ||
+ G->getGlobal()->hasPrivateLinkage());
+ if (IsInternal) {
+ SystemZMachineFunctionInfo *MFI =
+ MF.getInfo<SystemZMachineFunctionInfo>();
+ unsigned ADAvReg = MFI->getADAVirtualRegister();
+ ADA = DAG.getCopyFromReg(Chain, DL, ADAvReg, PtrVT);
+ Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, PtrVT);
+ Callee = DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Callee);
+ return true;
+ } else {
+ SDValue GA = DAG.getTargetGlobalAddress(
+ G->getGlobal(), DL, PtrVT, 0, SystemZII::MO_ADA_DIRECT_FUNC_DESC);
+ ADA = getADAEntry(DAG, GA, DL, ADADelta);
+ Callee = getADAEntry(DAG, GA, DL, EPADelta);
+ }
+ } else if (auto *E = dyn_cast<ExternalSymbolSDNode>(Callee)) {
+ SDValue ES = DAG.getTargetExternalSymbol(
+ E->getSymbol(), PtrVT, SystemZII::MO_ADA_DIRECT_FUNC_DESC);
+ ADA = getADAEntry(DAG, ES, DL, ADADelta);
+ Callee = getADAEntry(DAG, ES, DL, EPADelta);
+ } else {
+ // Function pointer case
+ ADA = DAG.getNode(ISD::ADD, DL, PtrVT, Callee,
+ DAG.getConstant(ADADelta, DL, PtrVT));
+ ADA = DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), ADA,
+ MachinePointerInfo::getGOT(DAG.getMachineFunction()));
+ Callee = DAG.getNode(ISD::ADD, DL, PtrVT, Callee,
+ DAG.getConstant(EPADelta, DL, PtrVT));
+ Callee = DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), Callee,
+ MachinePointerInfo::getGOT(DAG.getMachineFunction()));
+ }
+ return false;
+}
+
SDValue
SystemZTargetLowering::LowerCall(CallLoweringInfo &CLI,
SmallVectorImpl<SDValue> &InVals) const {
@@ -1814,17 +1909,31 @@ SystemZTargetLowering::LowerCall(CallLoweringInfo &CLI,
// associated Target* opcodes. Force %r1 to be used for indirect
// tail calls.
SDValue Glue;
- // FIXME: Add support for XPLINK using the ADA register.
- if (auto *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
- Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, PtrVT);
- Callee = DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Callee);
- } else if (auto *E = dyn_cast<ExternalSymbolSDNode>(Callee)) {
- Callee = DAG.getTargetExternalSymbol(E->getSymbol(), PtrVT);
- Callee = DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Callee);
- } else if (IsTailCall) {
- Chain = DAG.getCopyToReg(Chain, DL, SystemZ::R1D, Callee, Glue);
- Glue = Chain.getValue(1);
- Callee = DAG.getRegister(SystemZ::R1D, Callee.getValueType());
+
+ if (Subtarget.isTargetXPLINK64()) {
+ SDValue ADA;
+ bool IsBRASL = getzOSCalleeAndADA(DAG, Callee, ADA, DL, Chain);
+ if (!IsBRASL) {
+ unsigned CalleeReg = static_cast<SystemZXPLINK64Registers *>(Regs)
+ ->getAddressOfCalleeRegister();
+ Chain = DAG.getCopyToReg(Chain, DL, CalleeReg, Callee, Glue);
+ Glue = Chain.getValue(1);
+ Callee = DAG.getRegister(CalleeReg, Callee.getValueType());
+ }
+ RegsToPass.push_back(std::make_pair(
+ static_cast<SystemZXPLINK64Registers *>(Regs)->getADARegister(), ADA));
+ } else {
+ if (auto *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
+ Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, PtrVT);
+ Callee = DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Callee);
+ } else if (auto *E = dyn_cast<ExternalSymbolSDNode>(Callee)) {
+ Callee = DAG.getTargetExternalSymbol(E->getSymbol(), PtrVT);
+ Callee = DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Callee);
+ } else if (IsTailCall) {
+ Chain = DAG.getCopyToReg(Chain, DL, SystemZ::R1D, Callee, Glue);
+ Glue = Chain.getValue(1);
+ Callee = DAG.getRegister(SystemZ::R1D, Callee.getValueType());
+ }
}
// Build a sequence of copy-to-reg nodes, chained and glued together.
@@ -3251,12 +3360,15 @@ SDValue SystemZTargetLowering::lowerGlobalAddress(GlobalAddressSDNode *Node,
Result = DAG.getTargetGlobalAddress(GV, DL, PtrVT);
Result = DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Result);
}
- } else {
+ } else if (Subtarget.isTargetELF()) {
Result = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, SystemZII::MO_GOT);
Result = DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Result);
Result = DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), Result,
MachinePointerInfo::getGOT(DAG.getMachineFunction()));
- }
+ } else if (Subtarget.isTargetzOS()) {
+ Result = getADAEntry(DAG, GV, DL, PtrVT);
+ } else
+ llvm_unreachable("Unexpected Subtarget");
// If there was a non-zero offset that we didn't fold, create an explicit
// addition for it.
@@ -6042,6 +6154,7 @@ const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const {
OPCODE(VLER);
OPCODE(VSTER);
OPCODE(PREFETCH);
+ OPCODE(ADA_ENTRY);
}
return nullptr;
#undef OPCODE
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
index 7f6e25ccf6f7a1..47fa1831c3ee7f 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
@@ -1,4 +1,3 @@
-
//===-- SystemZISelLowering.h - SystemZ DAG lowering interface --*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
@@ -284,6 +283,16 @@ enum NodeType : unsigned {
// Operand 1: the bit mask
TDC,
+ // z/OS XPLINK ADA Entry
+ // Wraps a TargetGlobalAddress that should be loaded from a function's
+ // AssociatedData Area (ADA). Tha ADA is passed to the function by the
+ // caller in the XPLink ABI defined register R5.
+ // Operand 0: the GlobalValue/External Symbol
+ // Operand 1: the ADA register
+ // Operand 2: the offset (0 for the first and 8 for the second element in the
+ // function descriptor)
+ ADA_ENTRY,
+
// Strict variants of scalar floating-point comparisons.
// Quiet and signaling versions.
STRICT_FCMP = ISD::FIRST_TARGET_STRICTFP_OPCODE,
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.h b/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
index 9ce75db6c177c2..bb883ea464d376 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
@@ -74,6 +74,17 @@ enum {
MO_INDNTPOFF = (2 << 0)
};
+// z/OS XPLink specific: classifies the types of
+// accesses to the ADA (Associated Data Area).
+// These enums contains values that overlap with the above MO_ enums,
+// but that's fine since the above enums are used with ELF,
+// while these values are used with z/OS.
+enum {
+ MO_ADA_DATA_SYMBOL_ADDR = 1,
+ MO_ADA_INDIRECT_FUNC_DESC,
+ MO_ADA_DIRECT_FUNC_DESC,
+};
+
// Classifies a branch.
enum BranchType {
// An instruction that branches on the current value of CC.
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index 9d5ad81abf5e33..aa5c181f55f412 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -281,6 +281,9 @@ let isCall = 1, Defs = [CC] in {
def BASR : CallRR <"basr", 0x0D>;
}
+// A symbol in the ADA (z/OS only).
+def adasym : Operand<i64>;
+
// z/OS XPLINK
let Predicates = [IsTargetXPLINK64] in {
let isCall = 1, Defs = [R7D, CC], Uses = [FPC] in {
@@ -293,6 +296,19 @@ let Predicates = [IsTargetXPLINK64] in {
let isCall = 1, Defs = [R3D, CC], Uses = [FPC] in {
def CallBASR_STACKEXT : Alias<4, (outs), (ins ADDR64:$R2), []>;
}
+
+ let hasNoSchedulingInfo = 1, Defs = [CC] in {
+ def ADA_ENTRY : Alias<12, (outs GR64:$Reg), (ins adasym:$addr,
+ ADDR64:$ADA, imm64:$Offset),
+ [(set i64:$Reg, (z_ada_entry i64:$addr,
+ i64:$ADA, i64:$Offset))]>;
+ }
+ let mayLoad = 1, AddedComplexity = 20, hasNoSchedulingInfo = 1, Defs = [CC] in {
+ def ADA_ENTRY_VALUE : Alias<12, (outs GR64:$Reg), (ins adasym:$addr,
+ ADDR64:$ADA, imm64:$Offset),
+ [(set i64:$Reg, (load (z_ada_entry
+ iPTR:$addr, iPTR:$ADA, i64:$Offset)))]>;
+ }
}
// Regular calls.
diff --git a/llvm/lib/Target/SystemZ/SystemZMachineFunctionInfo.h b/llvm/lib/Target/SystemZ/SystemZMachineFunctionInfo.h
index 7a0802abb27656..be7012a37a3d3e 100644
--- a/llvm/lib/Target/SystemZ/SystemZMachineFunctionInfo.h
+++ b/llvm/lib/Target/SystemZ/SystemZMachineFunctionInfo.h
@@ -38,6 +38,8 @@ class SystemZMachineFunctionInfo : public MachineFunctionInfo {
unsigned RegSaveFrameIndex;
int FramePointerSaveIndex;
unsigned NumLocalDynamics;
+ /// z/OS XPLINK ABI: incoming ADA virtual register.
+ Register VRegADA;
public:
SystemZMachineFunctionInfo(const Function &F, const TargetSubtargetInfo *STI)
@@ -100,6 +102,11 @@ class SystemZMachineFunctionInfo : public MachineFunctionInfo {
// Count number of local-dynamic TLS symbols used.
unsigned getNumLocalDynamicTLSAccesses() const { return NumLocalDynamics; }
void incNumLocalDynamicTLSAccesses() { ++NumLocalDynamics; }
+
+ // Get and set the function's incoming special XPLINK ABI defined ADA
+ // register.
+ Register getADAVirtualRegister() const { return VRegADA; }
+ void setADAVirtualRegister(Register Reg) { VRegADA = Reg; }
};
} // end namespace llvm
diff --git a/llvm/lib/Target/SystemZ/SystemZOperators.td b/llvm/lib/Target/SystemZ/SystemZOperators.td
index b16f8f2a7ff35a..6713cac2a78076 100644
--- a/llvm/lib/Target/SystemZ/SystemZOperators.td
+++ b/llvm/lib/Target/SystemZ/SystemZOperators.td
@@ -127,6 +127,11 @@ def SDT_ZTBegin : SDTypeProfile<1, 2,
[SDTCisVT<0, i32>,
SDTCisPtrTy<1>,
SDTCisVT<2, i32>]>;
+def SDT_ZADAENTRY : SDTypeProfile<1, 3,
+ [SDTCisPtrTy<0>,
+ SDTCisPtrTy<1>,
+ SDTCisPtrTy<2>,
+ SDTCisVT<3, i64>]>;
def SDT_ZTEnd : SDTypeProfile<1, 0,
[SDTCisVT<0, i32>]>;
def SDT_ZInsertVectorElt : SDTypeProfile<1, 3,
@@ -433,6 +438,9 @@ def z_tbegin_nofloat : SDNode<"SystemZISD::TBEGIN_NOFLOAT", SDT_ZTBegin,
def z_tend : SDNode<"SystemZISD::TEND", SDT_ZTEnd,
[SDNPHasChain, SDNPSideEffect]>;
+def z_ada_entry : SDNode<"SystemZISD::ADA_ENTRY",
+ SDT_ZADAENTRY>;
+
def z_vshl : SDNode<"ISD::SHL", SDT_ZVecBinary>;
def z_vsra : SDNode<"ISD::SRA", SDT_ZVecBinary>;
def z_vsrl : SDNode<"ISD::SRL", SDT_ZVecBinary>;
diff --git a/llvm/lib/Target/SystemZ/SystemZRegisterInfo.h b/llvm/lib/Target/SystemZ/SystemZRegisterInfo.h
index 78abeb720b43be..cbc02c73f1ac70 100644
--- a/llvm/lib/Target/SystemZ/SystemZRegisterInfo.h
+++ b/llvm/lib/Target/SystemZ/SystemZRegisterInfo.h
@@ -89,6 +89,8 @@ class SystemZXPLINK64Registers : public SystemZCallingConventionRegisters {
int getAddressOfCalleeRegister() { return SystemZ::R6D; };
+ int getADARegister() { return SystemZ::R5D; }
+
const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const final;
const uint32_t *getCallPreservedMask(const MachineFunction &MF,
diff --git a/llvm/lib/Target/SystemZ/SystemZSubtarget.cpp b/llvm/lib/Target/SystemZ/SystemZSubtarget.cpp
index 25b013ba1876b4..e008ce859a9add 100644
--- a/llvm/lib/Target/SystemZ/SystemZSubtarget.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZSubtarget.cpp
@@ -8,6 +8,7 @@
#include "SystemZSubtarget.h"
#include "MCTargetDesc/SystemZMCTargetDesc.h"
+#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/Target/TargetMachine.h"
@@ -77,8 +78,42 @@ bool SystemZSubtarget::enableSubRegLiveness() const {
return UseSubRegLiveness;
}
+bool SystemZSubtarget::isAddressedViaADA(const GlobalValue *GV) const {
+ if (const auto *GO = dyn_cast<GlobalObject>(GV)) {
+ // A R/O variable is placed in code section. If the R/O variable has as
+ // least two byte alignment, then generated code can use relative
+ // instructions to address the variable. Otherwise, use the ADA to address
+ // the variable.
+ if (GO->getAlignment() & 0x1) {
+ return true;
+ }
+
+ // getKindForGlobal only works with definitions
+ if (GO->isDeclaration()) {
+ return true;
+ }
+
+ // check AvailableExternallyLinkage here as getKindForGlobal() asserts
+ if (GO->hasAvailableExternallyLinkage()) {
+ return true;
+ }
+
+ SectionKind GOKind = TargetLoweringObjectFile::getKindForGlobal(
+ GO, TLInfo.getTargetMachine());
+ if (!GOKind.isReadOnly()) {
+ return true;
+ }
+
+ return false; // R/O variable with multiple of 2 byte alignment
+ }
+ return true;
+}
+
bool SystemZSubtarget::isPC32DBLSymbol(const GlobalValue *GV,
CodeModel::Model CM) const {
+ if (isTargetzOS())
+ return !isAddressedViaADA(GV);
+
// PC32DBL accesses require the low bit to be clear.
//
// FIXME: Explicitly check for functions: the datalayout is currently
diff --git a/llvm/lib/Target/SystemZ/SystemZSubtarget.h b/llvm/lib/Target/SystemZ/SystemZSubtarget.h
index 8f766a4d878382..5fa7c8f194ebf3 100644
--- a/llvm/lib/Target/SystemZ/SystemZSubtarget.h
+++ b/llvm/lib/Target/SystemZ/SystemZSubtarget.h
@@ -106,6 +106,8 @@ class SystemZSubtarget : public SystemZGenSubtargetInfo {
bool GETTER() const { return ATTRIBUTE; }
#include "SystemZGenSubtargetInfo.inc"
+ bool isAddressedViaADA(const GlobalValue *GV) const;
+
// Return true if GV can be accessed using LARL for reloc model RM
// and code model CM.
bool isPC32DBLSymbol(const GlobalValue *GV, CodeModel::Model CM) const;
diff --git a/llvm/test/CodeGen/SystemZ/call-zos-vararg.ll b/llvm/test/CodeGen/SystemZ/call-zos-vararg.ll
index ff52e50373e1ec..ac157e5fa67f62 100644
--- a/llvm/test/CodeGen/SystemZ/call-zos-vararg.ll
+++ b/llvm/test/CodeGen/SystemZ/call-zos-vararg.ll
@@ -66,7 +66,7 @@ define i64 @call_vararg_both0(i64 %arg0, double %arg1) {
; CHECK: larl 1, @CPI5_0
; CHECK-NEXT: ld 0, 0(1)
; CHECK-NEXT: ld 2, 8(1)
-; CHECK-NEXT: lgdr 3, 0
+; CHECK: lgdr 3, 0
; CHECK: lghi 1, 1
; CHECK: lghi 2, 2
; CHECK: std 0, 2192(4)
diff --git a/llvm/test/CodeGen/SystemZ/zos-ada-relocations.ll b/llvm/test/CodeGen/SystemZ/zos-ada-relocations.ll
new file mode 100644
index 00000000000000..e25246917ec099
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/zos-ada-relocations.ll
@@ -0,0 +1,67 @@
+; Test the ADA section in the assembly output for all cases.
+;
+; RUN: llc < %s -mtriple=s390x-ibm-zos | FileCheck %s
+
+; CHECK-LABEL: DoIt:
+; CHECK: stmg 6, 7, 1840(4)
+; CHECK: aghi 4, -224
+; CHECK: lg 1, 0(5)
+; CHECK: lg 6, 16(5)
+; CHECK: lg 5, 8(5)
+; CHECK: stg 1, 2264(4)
+; CHECK: basr 7, 6
+; CHECK: bcr 0, 0
+; CHECK: lg 7, 2072(4)
+; CHECK: aghi 4, 224
+; CHECK: b 2(7)
+define hidden void @DoIt() {
+entry:
+ %F = alloca ptr, align 8
+ store ptr @DoFunc, ptr %F, align 8
+ %0 = load ptr, ptr %F, align 8
+ call void @Caller(ptr noundef %0)
+ ret void
+}
+declare void @DoFunc()
+declare void @Caller(ptr noundef)
+
+; CHECK-LABEL: get_i:
+; CHECK: stmg 6, 8, 1872(4)
+; CHECK: aghi 4, -192
+; CHECK: lg 1, 24(5)
+; CHECK: lg 2, 32(5)
+; CHECK: lgf 1, 0(1)
+; CHECK: lg 6, 48(5)
+; CHECK: lg 5, 40(5)
+; CHECK: l 8, 0(2)
+; CHECK: basr 7, 6
+; CHECK: bcr 0, 0
+; CHECK: ar 3, 8
+; CHECK: lgfr 3, 3
+; CHECK: lmg 7, 8, 2072(4)
+; CHECK: aghi 4, 192
+; CHECK: b 2(7)
+ at i = external global i32, align 4
+ at i2 = external global i32, align 4
+
+define signext i32 @get_i() {
+entry:
+ %0 = load i32, ptr @i, align 4
+ %1 = load i32, ptr @i2, align 4
+ %call = call signext i32 @callout(i32 signext %1)
+ %add = add nsw i32 %0, %call
+ ret i32 %add
+}
+
+declare signext i32 @callout(i32 signext)
+
+; CHECK: .section ".ada"
+; CHECK: .set @@DoFunc at indirect0, DoFunc
+; CHECK: .indirect_symbol @@DoFunc at indirect0
+; CHECK: .quad V(@@DoFunc at indirect0) * Offset 0 pointer to function descriptor DoFunc
+; CHECK: .quad R(Caller) * Offset 8 function descriptor of Caller
+; CHECK: .quad V(Caller)
+; CHECK: .quad A(i2) * Offset 24 pointer to data symbol i2
+; CHECK: .quad A(i) * Offset 32 pointer to data symbol i
+; CHECK: .quad R(callout) * Offset 40 function descriptor of callout
+; CHECK: .quad V(callout)
diff --git a/llvm/test/CodeGen/SystemZ/zos-ada.ll b/llvm/test/CodeGen/SystemZ/zos-ada.ll
new file mode 100644
index 00000000000000..18ee9a2255d680
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/zos-ada.ll
@@ -0,0 +1,31 @@
+; Test the setup of the environment area, or associated data area (ADA)
+;
+; RUN: llc < %s -mtriple=s390x-ibm-zos -mcpu=z10 | FileCheck %s
+
+; CHECK-LABEL: caller:
+; CHECK: stmg 6, 8, 1872(4)
+; CHECK-NEXT: aghi 4, -192
+; CHECK-NEXT: lgr 8, 5
+; CHECK-NEXT: brasl 7, callee_internal at PLT
+; CHECK-NEXT: bcr 0, 3
+; CHECK-NEXT: lg 6, 8(8)
+; CHECK-NEXT: lg 5, 0(8)
+; CHECK-NEXT: lgr 8, 3
+; CHECK-NEXT: basr 7, 6
+; CHECK-NEXT: bcr 0, 0
+; CHECK-NEXT: la 3, 0(3,8)
+; CHECK-NEXT: lmg 7, 8, 2072(4)
+; CHECK-NEXT: aghi 4, 192
+; CHECK-NEXT: b 2(7)
+define i64 @caller() {
+ %r1 = call i64 () @callee_internal()
+ %r2 = call i64 () @callee_external()
+ %r3 = add i64 %r1, %r2
+ ret i64 %r3
+}
+
+define internal i64 @callee_internal() {
+ ret i64 10
+}
+
+declare i64 @callee_external()
diff --git a/llvm/test/CodeGen/SystemZ/zos-prologue-epilog.ll b/llvm/test/CodeGen/SystemZ/zos-prologue-epilog.ll
index 6b8c3bf53122dc..510b6188270ab8 100644
--- a/llvm/test/CodeGen/SystemZ/zos-prologue-epilog.ll
+++ b/llvm/test/CodeGen/SystemZ/zos-prologue-epilog.ll
@@ -286,13 +286,14 @@ define void @func3() {
; Requires the saving of r4 due to variable sized
; object in stack frame. (Eg: VLA) Sets up frame pointer in r8
-; CHECK64: stmg 4, 9, 1856(4)
+; CHECK64: stmg 4, 10, 1856(4)
; CHECK64: aghi 4, -192
+; CHECK64: lg 6, 40(5)
+; CHECK64: lg 5, 32(5)
; CHECK64: lgr 8, 4
-; TODO Will change to basr with ADA introduction.
-; CHECK64: brasl 7, @@ALCAXP
-; CHECK64-NEXT: bcr 0, 3
-; CHECK64: lmg 4, 9, 2048(4)
+; CHECK64: basr 7, 6
+; CHECK64-NEXT: bcr 0, 0
+; CHECK64: lmg 4, 10, 2048(4)
define i64 @func4(i64 %n) {
%vla = alloca i64, i64 %n, align 8
%call = call i64 @fun2(i64 %n, ptr nonnull %vla, ptr nonnull %vla)
@@ -303,12 +304,11 @@ define i64 @func4(i64 %n) {
; to force use of agfi before stmg.
; CHECK64: lgr 0, 4
; CHECK64: agfi 4, -1040192
-; CHECK64: stmg 4, 9, 2048(4)
+; CHECK64: stmg 4, 10, 2048(4)
; CHECK64: lgr 8, 4
-; TODO Will change to basr with ADA introduction.
-; CHECK64: brasl 7, @@ALCAXP
-; CHECK64-NEXT: bcr 0, 3
-;; CHECK64: lmg 4, 9, 2048(4)
+; CHECK64: basr 7, 6
+; CHECK64-NEXT: bcr 0, 0
+; CHECK64: lmg 4, 10, 2048(4)
define i64 @func5(i64 %n) {
%vla = alloca i64, i64 %n, align 8
%arr = alloca [130000 x i64], align 8
@@ -369,7 +369,7 @@ define void @large_stack1(i64 %n1, i64 %n2, i64 %n3) {
; CHECK64: @BB8_2:
; CHECK64: lgr 3, 0
; CHECK64: lg 3, 2192(3)
-; CHECK64: stmg 4, 11, 2048(4)
+; CHECK64: stmg 4, 12, 2048(4)
; CHECK64: lgr 8, 4
define void @large_stack2(i64 %n1, i64 %n2, i64 %n3) {
%arr0 = alloca [131072 x i64], align 8
More information about the llvm-commits
mailing list