forked from OSchip/llvm-project
[SystemZ] Support the kernel back chain.
In order to build the Linux kernel, the back chain must be supported with packed-stack. The back chain is then stored topmost in the register save area. Review: Ulrich Weigand Differential Revision: https://reviews.llvm.org/D74506
This commit is contained in:
parent
e9997cfb4d
commit
82879c2913
|
@ -2007,21 +2007,19 @@ void Clang::AddSystemZTargetArgs(const ArgList &Args,
|
|||
options::OPT_mno_backchain, false);
|
||||
bool HasPackedStack = Args.hasFlag(options::OPT_mpacked_stack,
|
||||
options::OPT_mno_packed_stack, false);
|
||||
if (HasBackchain && HasPackedStack) {
|
||||
systemz::FloatABI FloatABI =
|
||||
systemz::getSystemZFloatABI(getToolChain().getDriver(), Args);
|
||||
bool HasSoftFloat = (FloatABI == systemz::FloatABI::Soft);
|
||||
if (HasBackchain && HasPackedStack && !HasSoftFloat) {
|
||||
const Driver &D = getToolChain().getDriver();
|
||||
D.Diag(diag::err_drv_unsupported_opt)
|
||||
<< Args.getLastArg(options::OPT_mpacked_stack)->getAsString(Args) +
|
||||
" " + Args.getLastArg(options::OPT_mbackchain)->getAsString(Args);
|
||||
<< "-mpacked-stack -mbackchain -mhard-float";
|
||||
}
|
||||
if (HasBackchain)
|
||||
CmdArgs.push_back("-mbackchain");
|
||||
if (HasPackedStack)
|
||||
CmdArgs.push_back("-mpacked-stack");
|
||||
|
||||
systemz::FloatABI FloatABI =
|
||||
systemz::getSystemZFloatABI(getToolChain().getDriver(), Args);
|
||||
|
||||
if (FloatABI == systemz::FloatABI::Soft) {
|
||||
if (HasSoftFloat) {
|
||||
// Floating point operations and argument passing are soft.
|
||||
CmdArgs.push_back("-msoft-float");
|
||||
CmdArgs.push_back("-mfloat-abi");
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// RUN: %clang -target s390x -c -### %s -mpacked-stack -mbackchain 2>&1 | FileCheck %s
|
||||
// RUN: %clang -target s390x -c -### %s -mpacked-stack -mbackchain -msoft-float \
|
||||
// RUN: 2>&1 | FileCheck %s --check-prefix=KERNEL-BUILD
|
||||
// REQUIRES: systemz-registered-target
|
||||
|
||||
// CHECK: error: unsupported option '-mpacked-stack -mbackchain'
|
||||
// CHECK: error: unsupported option '-mpacked-stack -mbackchain -mhard-float'
|
||||
// KERNEL-BUILD-NOT: error: unsupported option
|
||||
|
|
|
@ -62,18 +62,6 @@ SystemZFrameLowering::SystemZFrameLowering()
|
|||
RegSpillOffsets[SpillOffsetTable[I].Reg] = SpillOffsetTable[I].Offset;
|
||||
}
|
||||
|
||||
static bool usePackedStack(MachineFunction &MF) {
|
||||
bool HasPackedStackAttr = MF.getFunction().hasFnAttribute("packed-stack");
|
||||
bool IsVarArg = MF.getFunction().isVarArg();
|
||||
bool CallConv = MF.getFunction().getCallingConv() != CallingConv::GHC;
|
||||
bool BackChain = MF.getFunction().hasFnAttribute("backchain");
|
||||
bool FramAddressTaken = MF.getFrameInfo().isFrameAddressTaken();
|
||||
if (HasPackedStackAttr && BackChain)
|
||||
report_fatal_error("packed-stack with backchain is currently unsupported.");
|
||||
return HasPackedStackAttr && !IsVarArg && CallConv && !BackChain &&
|
||||
!FramAddressTaken;
|
||||
}
|
||||
|
||||
bool SystemZFrameLowering::
|
||||
assignCalleeSavedSpillSlots(MachineFunction &MF,
|
||||
const TargetRegisterInfo *TRI,
|
||||
|
@ -87,71 +75,44 @@ assignCalleeSavedSpillSlots(MachineFunction &MF,
|
|||
unsigned LowGPR = 0;
|
||||
unsigned HighGPR = SystemZ::R15D;
|
||||
int StartSPOffset = SystemZMC::CallFrameSize;
|
||||
int CurrOffset;
|
||||
if (!usePackedStack(MF)) {
|
||||
for (auto &CS : CSI) {
|
||||
unsigned Reg = CS.getReg();
|
||||
int Offset = RegSpillOffsets[Reg];
|
||||
if (Offset) {
|
||||
if (SystemZ::GR64BitRegClass.contains(Reg) && StartSPOffset > Offset) {
|
||||
LowGPR = Reg;
|
||||
StartSPOffset = Offset;
|
||||
}
|
||||
Offset -= SystemZMC::CallFrameSize;
|
||||
int FrameIdx = MFFrame.CreateFixedSpillStackObject(8, Offset);
|
||||
CS.setFrameIdx(FrameIdx);
|
||||
} else
|
||||
CS.setFrameIdx(INT32_MAX);
|
||||
}
|
||||
|
||||
// Save the range of call-saved registers, for use by the
|
||||
// prologue/epilogue inserters.
|
||||
ZFI->setRestoreGPRRegs(LowGPR, HighGPR, StartSPOffset);
|
||||
if (IsVarArg) {
|
||||
// Also save the GPR varargs, if any. R6D is call-saved, so would
|
||||
// already be included, but we also need to handle the call-clobbered
|
||||
// argument registers.
|
||||
unsigned FirstGPR = ZFI->getVarArgsFirstGPR();
|
||||
if (FirstGPR < SystemZ::NumArgGPRs) {
|
||||
unsigned Reg = SystemZ::ArgGPRs[FirstGPR];
|
||||
int Offset = RegSpillOffsets[Reg];
|
||||
if (StartSPOffset > Offset) {
|
||||
LowGPR = Reg; StartSPOffset = Offset;
|
||||
}
|
||||
for (auto &CS : CSI) {
|
||||
unsigned Reg = CS.getReg();
|
||||
int Offset = getRegSpillOffset(MF, Reg);
|
||||
if (Offset) {
|
||||
if (SystemZ::GR64BitRegClass.contains(Reg) && StartSPOffset > Offset) {
|
||||
LowGPR = Reg;
|
||||
StartSPOffset = Offset;
|
||||
}
|
||||
}
|
||||
ZFI->setSpillGPRRegs(LowGPR, HighGPR, StartSPOffset);
|
||||
|
||||
CurrOffset = -SystemZMC::CallFrameSize;
|
||||
} else {
|
||||
// Packed stack: put all the GPRs at the top of the Register save area.
|
||||
uint32_t LowGR64Num = UINT32_MAX;
|
||||
for (auto &CS : CSI) {
|
||||
unsigned Reg = CS.getReg();
|
||||
if (SystemZ::GR64BitRegClass.contains(Reg)) {
|
||||
unsigned GR64Num = SystemZMC::getFirstReg(Reg);
|
||||
int Offset = -8 * (15 - GR64Num + 1);
|
||||
if (LowGR64Num > GR64Num) {
|
||||
LowGR64Num = GR64Num;
|
||||
StartSPOffset = SystemZMC::CallFrameSize + Offset;
|
||||
}
|
||||
int FrameIdx = MFFrame.CreateFixedSpillStackObject(8, Offset);
|
||||
CS.setFrameIdx(FrameIdx);
|
||||
} else
|
||||
CS.setFrameIdx(INT32_MAX);
|
||||
}
|
||||
if (LowGR64Num < UINT32_MAX)
|
||||
LowGPR = SystemZMC::GR64Regs[LowGR64Num];
|
||||
|
||||
// Save the range of call-saved registers, for use by the
|
||||
// prologue/epilogue inserters.
|
||||
ZFI->setRestoreGPRRegs(LowGPR, HighGPR, StartSPOffset);
|
||||
ZFI->setSpillGPRRegs(LowGPR, HighGPR, StartSPOffset);
|
||||
|
||||
CurrOffset = LowGPR ? -(SystemZMC::CallFrameSize - StartSPOffset) : 0;
|
||||
Offset -= SystemZMC::CallFrameSize;
|
||||
int FrameIdx = MFFrame.CreateFixedSpillStackObject(8, Offset);
|
||||
CS.setFrameIdx(FrameIdx);
|
||||
} else
|
||||
CS.setFrameIdx(INT32_MAX);
|
||||
}
|
||||
|
||||
// Save the range of call-saved registers, for use by the
|
||||
// prologue/epilogue inserters.
|
||||
ZFI->setRestoreGPRRegs(LowGPR, HighGPR, StartSPOffset);
|
||||
if (IsVarArg) {
|
||||
// Also save the GPR varargs, if any. R6D is call-saved, so would
|
||||
// already be included, but we also need to handle the call-clobbered
|
||||
// argument registers.
|
||||
unsigned FirstGPR = ZFI->getVarArgsFirstGPR();
|
||||
if (FirstGPR < SystemZ::NumArgGPRs) {
|
||||
unsigned Reg = SystemZ::ArgGPRs[FirstGPR];
|
||||
int Offset = getRegSpillOffset(MF, Reg);
|
||||
if (StartSPOffset > Offset) {
|
||||
LowGPR = Reg; StartSPOffset = Offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
ZFI->setSpillGPRRegs(LowGPR, HighGPR, StartSPOffset);
|
||||
|
||||
// Create fixed stack objects for the remaining registers.
|
||||
int CurrOffset = -SystemZMC::CallFrameSize;
|
||||
if (usePackedStack(MF))
|
||||
CurrOffset += StartSPOffset;
|
||||
|
||||
for (auto &CS : CSI) {
|
||||
if (CS.getFrameIdx() != INT32_MAX)
|
||||
continue;
|
||||
|
@ -511,10 +472,13 @@ void SystemZFrameLowering::emitPrologue(MachineFunction &MF,
|
|||
.addCFIIndex(CFIIndex);
|
||||
SPOffsetFromCFA += Delta;
|
||||
|
||||
if (StoreBackchain)
|
||||
if (StoreBackchain) {
|
||||
// The back chain is stored topmost with packed-stack.
|
||||
int Offset = usePackedStack(MF) ? SystemZMC::CallFrameSize - 8 : 0;
|
||||
BuildMI(MBB, MBBI, DL, ZII->get(SystemZ::STG))
|
||||
.addReg(SystemZ::R1D, RegState::Kill).addReg(SystemZ::R15D).addImm(0)
|
||||
.addReg(0);
|
||||
.addReg(SystemZ::R1D, RegState::Kill).addReg(SystemZ::R15D)
|
||||
.addImm(Offset).addReg(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (HasFP) {
|
||||
|
@ -662,14 +626,43 @@ eliminateCallFramePseudoInstr(MachineFunction &MF,
|
|||
}
|
||||
}
|
||||
|
||||
unsigned SystemZFrameLowering::getRegSpillOffset(MachineFunction &MF,
|
||||
unsigned Reg) const {
|
||||
bool IsVarArg = MF.getFunction().isVarArg();
|
||||
bool BackChain = MF.getFunction().hasFnAttribute("backchain");
|
||||
bool SoftFloat = MF.getSubtarget<SystemZSubtarget>().hasSoftFloat();
|
||||
unsigned Offset = RegSpillOffsets[Reg];
|
||||
if (usePackedStack(MF) && !(IsVarArg && !SoftFloat)) {
|
||||
if (SystemZ::GR64BitRegClass.contains(Reg))
|
||||
// Put all GPRs at the top of the Register save area with packed
|
||||
// stack. Make room for the backchain if needed.
|
||||
Offset += BackChain ? 24 : 32;
|
||||
else
|
||||
Offset = 0;
|
||||
}
|
||||
return Offset;
|
||||
}
|
||||
|
||||
int SystemZFrameLowering::
|
||||
getOrCreateFramePointerSaveIndex(MachineFunction &MF) const {
|
||||
SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>();
|
||||
int FI = ZFI->getFramePointerSaveIndex();
|
||||
if (!FI) {
|
||||
MachineFrameInfo &MFFrame = MF.getFrameInfo();
|
||||
FI = MFFrame.CreateFixedObject(8, -SystemZMC::CallFrameSize, false);
|
||||
// The back chain is stored topmost with packed-stack.
|
||||
int Offset = usePackedStack(MF) ? -8 : -SystemZMC::CallFrameSize;
|
||||
FI = MFFrame.CreateFixedObject(8, Offset, false);
|
||||
ZFI->setFramePointerSaveIndex(FI);
|
||||
}
|
||||
return FI;
|
||||
}
|
||||
|
||||
bool SystemZFrameLowering::usePackedStack(MachineFunction &MF) const {
|
||||
bool HasPackedStackAttr = MF.getFunction().hasFnAttribute("packed-stack");
|
||||
bool BackChain = MF.getFunction().hasFnAttribute("backchain");
|
||||
bool SoftFloat = MF.getSubtarget<SystemZSubtarget>().hasSoftFloat();
|
||||
if (HasPackedStackAttr && BackChain && !SoftFloat)
|
||||
report_fatal_error("packed-stack + backchain + hard-float is unsupported.");
|
||||
bool CallConv = MF.getFunction().getCallingConv() != CallingConv::GHC;
|
||||
return HasPackedStackAttr && CallConv;
|
||||
}
|
||||
|
|
|
@ -52,13 +52,14 @@ public:
|
|||
MachineBasicBlock::iterator MI) const override;
|
||||
|
||||
// Return the byte offset from the incoming stack pointer of Reg's
|
||||
// ABI-defined save slot. Return 0 if no slot is defined for Reg.
|
||||
unsigned getRegSpillOffset(unsigned Reg) const {
|
||||
return RegSpillOffsets[Reg];
|
||||
}
|
||||
// ABI-defined save slot. Return 0 if no slot is defined for Reg. Adjust
|
||||
// the offset in case MF has packed-stack.
|
||||
unsigned getRegSpillOffset(MachineFunction &MF, unsigned Reg) const;
|
||||
|
||||
// Get or create the frame index of where the old frame pointer is stored.
|
||||
int getOrCreateFramePointerSaveIndex(MachineFunction &MF) const;
|
||||
|
||||
bool usePackedStack(MachineFunction &MF) const;
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
|
|
|
@ -1464,7 +1464,8 @@ SDValue SystemZTargetLowering::LowerFormalArguments(
|
|||
|
||||
// ...and a similar frame index for the caller-allocated save area
|
||||
// that will be used to store the incoming registers.
|
||||
int64_t RegSaveOffset = -SystemZMC::CallFrameSize;
|
||||
int64_t RegSaveOffset =
|
||||
-SystemZMC::CallFrameSize + TFL->getRegSpillOffset(MF, SystemZ::R2D) - 16;
|
||||
unsigned RegSaveIndex = MFI.CreateFixedObject(1, RegSaveOffset, true);
|
||||
FuncInfo->setRegSaveFrameIndex(RegSaveIndex);
|
||||
|
||||
|
@ -1473,8 +1474,9 @@ SDValue SystemZTargetLowering::LowerFormalArguments(
|
|||
if (NumFixedFPRs < SystemZ::NumArgFPRs && !useSoftFloat()) {
|
||||
SDValue MemOps[SystemZ::NumArgFPRs];
|
||||
for (unsigned I = NumFixedFPRs; I < SystemZ::NumArgFPRs; ++I) {
|
||||
unsigned Offset = TFL->getRegSpillOffset(SystemZ::ArgFPRs[I]);
|
||||
int FI = MFI.CreateFixedObject(8, RegSaveOffset + Offset, true);
|
||||
unsigned Offset = TFL->getRegSpillOffset(MF, SystemZ::ArgFPRs[I]);
|
||||
int FI =
|
||||
MFI.CreateFixedObject(8, -SystemZMC::CallFrameSize + Offset, true);
|
||||
SDValue FIN = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
|
||||
unsigned VReg = MF.addLiveIn(SystemZ::ArgFPRs[I],
|
||||
&SystemZ::FP64BitRegClass);
|
||||
|
@ -3241,6 +3243,8 @@ SDValue SystemZTargetLowering::lowerConstantPool(ConstantPoolSDNode *CP,
|
|||
|
||||
SDValue SystemZTargetLowering::lowerFRAMEADDR(SDValue Op,
|
||||
SelectionDAG &DAG) const {
|
||||
auto *TFL =
|
||||
static_cast<const SystemZFrameLowering *>(Subtarget.getFrameLowering());
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
MFI.setFrameAddressIsTaken(true);
|
||||
|
@ -3249,9 +3253,12 @@ SDValue SystemZTargetLowering::lowerFRAMEADDR(SDValue Op,
|
|||
unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
|
||||
EVT PtrVT = getPointerTy(DAG.getDataLayout());
|
||||
|
||||
// Return null if the back chain is not present.
|
||||
bool HasBackChain = MF.getFunction().hasFnAttribute("backchain");
|
||||
if (TFL->usePackedStack(MF) && !HasBackChain)
|
||||
return DAG.getConstant(0, DL, PtrVT);
|
||||
|
||||
// By definition, the frame address is the address of the back chain.
|
||||
auto *TFL =
|
||||
static_cast<const SystemZFrameLowering *>(Subtarget.getFrameLowering());
|
||||
int BackChainIdx = TFL->getOrCreateFramePointerSaveIndex(MF);
|
||||
SDValue BackChain = DAG.getFrameIndex(BackChainIdx, PtrVT);
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
|
||||
;
|
||||
; Test backchain with packed-stack, which requires soft-float.
|
||||
|
||||
attributes #0 = { nounwind "backchain" "packed-stack" "use-soft-float"="true" }
|
||||
define i64 @fun0(i64 %a) #0 {
|
||||
; CHECK-LABEL: fun0:
|
||||
; CHECK: stmg %r14, %r15, 136(%r15)
|
||||
; CHECK-NEXT: lgr %r1, %r15
|
||||
; CHECK-NEXT: aghi %r15, -24
|
||||
; CHECK-NEXT: stg %r1, 152(%r15)
|
||||
; CHECK-NEXT: brasl %r14, foo@PLT
|
||||
; CHECK-NEXT: lmg %r14, %r15, 160(%r15)
|
||||
; CHECK-NEXT: br %r14
|
||||
entry:
|
||||
%call = call i64 @foo(i64 %a)
|
||||
ret i64 %call
|
||||
}
|
||||
|
||||
declare i64 @foo(i64)
|
|
@ -0,0 +1,72 @@
|
|||
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
|
||||
;
|
||||
; Test saving of vararg registers and backchain with packed stack.
|
||||
|
||||
%struct.__va_list_tag = type { i64, i64, i8*, i8* }
|
||||
declare void @llvm.va_start(i8*)
|
||||
|
||||
attributes #0 = { nounwind "packed-stack"="true" }
|
||||
define void @fun0(i64 %g0, double %d0, i64 %n, ...) #0 {
|
||||
; CHECK-LABEL: fun0:
|
||||
; CHECK: stmg %r4, %r15, 32(%r15)
|
||||
; CHECK-NEXT: aghi %r15, -192
|
||||
; CHECK-NEXT: std %f2, 328(%r15)
|
||||
; CHECK-NEXT: std %f4, 336(%r15)
|
||||
; CHECK-NEXT: std %f6, 344(%r15)
|
||||
; CHECK-NEXT: la %r0, 352(%r15)
|
||||
; CHECK-NEXT: stg %r0, 176(%r15)
|
||||
; CHECK-NEXT: la %r0, 192(%r15)
|
||||
; CHECK-NEXT: stg %r0, 184(%r15)
|
||||
; CHECK-NEXT: mvghi 160(%r15), 2
|
||||
; CHECK-NEXT: mvghi 168(%r15), 1
|
||||
; CHECK-NEXT: lmg %r6, %r15, 240(%r15)
|
||||
; CHECK-NEXT: br %r14
|
||||
entry:
|
||||
%vl = alloca [1 x %struct.__va_list_tag], align 8
|
||||
%0 = bitcast [1 x %struct.__va_list_tag]* %vl to i8*
|
||||
call void @llvm.va_start(i8* nonnull %0)
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #1 = { nounwind "packed-stack"="true" "use-soft-float"="true" }
|
||||
define void @fun1(i64 %g0, double %d0, i64 %n, ...) #1 {
|
||||
; CHECK-LABEL: fun1:
|
||||
; CHECK: stmg %r5, %r15, 72(%r15)
|
||||
; CHECK-NEXT: aghi %r15, -160
|
||||
; CHECK-NEXT: la %r0, 192(%r15)
|
||||
; CHECK-NEXT: stg %r0, 184(%r15)
|
||||
; CHECK-NEXT: la %r0, 320(%r15)
|
||||
; CHECK-NEXT: stg %r0, 176(%r15)
|
||||
; CHECK-NEXT: mvghi 168(%r15), 0
|
||||
; CHECK-NEXT: mvghi 160(%r15), 3
|
||||
; CHECK-NEXT: lmg %r6, %r15, 240(%r15)
|
||||
; CHECK-NEXT: br %r14
|
||||
entry:
|
||||
%vl = alloca [1 x %struct.__va_list_tag], align 8
|
||||
%0 = bitcast [1 x %struct.__va_list_tag]* %vl to i8*
|
||||
call void @llvm.va_start(i8* nonnull %0)
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #2 = { nounwind "packed-stack"="true" "use-soft-float"="true" "backchain"}
|
||||
define void @fun2(i64 %g0, double %d0, i64 %n, ...) #2 {
|
||||
; CHECK-LABEL: fun2:
|
||||
; CHECK: stmg %r5, %r15, 64(%r15)
|
||||
; CHECK-NEXT: lgr %r1, %r15
|
||||
; CHECK-NEXT: aghi %r15, -168
|
||||
; CHECK-NEXT: stg %r1, 152(%r15)
|
||||
; CHECK-NEXT: la %r0, 192(%r15)
|
||||
; CHECK-NEXT: stg %r0, 184(%r15)
|
||||
; CHECK-NEXT: la %r0, 328(%r15)
|
||||
; CHECK-NEXT: stg %r0, 176(%r15)
|
||||
; CHECK-NEXT: mvghi 168(%r15), 0
|
||||
; CHECK-NEXT: mvghi 160(%r15), 3
|
||||
; CHECK-NEXT: lmg %r6, %r15, 240(%r15)
|
||||
; CHECK-NEXT: br %r14
|
||||
entry:
|
||||
%vl = alloca [1 x %struct.__va_list_tag], align 8
|
||||
%0 = bitcast [1 x %struct.__va_list_tag]* %vl to i8*
|
||||
call void @llvm.va_start(i8* nonnull %0)
|
||||
ret void
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
|
||||
|
||||
; Test lowering of @llvm.frameaddress with packed-stack.
|
||||
|
||||
; With back chain
|
||||
attributes #0 = { nounwind "packed-stack" "backchain" "use-soft-float"="true" }
|
||||
define i8* @fp0() #0 {
|
||||
entry:
|
||||
; CHECK-LABEL: fp0:
|
||||
; CHECK: la %r2, 152(%r15)
|
||||
; CHECK-NEXT: br %r14
|
||||
%0 = tail call i8* @llvm.frameaddress(i32 0)
|
||||
ret i8* %0
|
||||
}
|
||||
|
||||
define i8* @fp0f() #0 {
|
||||
entry:
|
||||
; CHECK-LABEL: fp0f:
|
||||
; CHECK: lgr %r1, %r15
|
||||
; CHECK-NEXT: aghi %r15, -16
|
||||
; CHECK-NEXT: stg %r1, 152(%r15)
|
||||
; CHECK-NEXT: la %r2, 168(%r15)
|
||||
; CHECK-NEXT: aghi %r15, 16
|
||||
; CHECK-NEXT: br %r14
|
||||
%0 = alloca i64, align 8
|
||||
%1 = tail call i8* @llvm.frameaddress(i32 0)
|
||||
ret i8* %1
|
||||
}
|
||||
|
||||
; Without back chain
|
||||
|
||||
attributes #1 = { nounwind "packed-stack" }
|
||||
define i8* @fp1() #1 {
|
||||
entry:
|
||||
; CHECK-LABEL: fp1:
|
||||
; CHECK: lghi %r2, 0
|
||||
; CHECK-NEXT: br %r14
|
||||
%0 = tail call i8* @llvm.frameaddress(i32 0)
|
||||
ret i8* %0
|
||||
}
|
||||
|
||||
define i8* @fp1f() #1 {
|
||||
entry:
|
||||
; CHECK-LABEL: fp1f:
|
||||
; CHECK: aghi %r15, -8
|
||||
; CHECK-NEXT: lghi %r2, 0
|
||||
; CHECK-NEXT: aghi %r15, 8
|
||||
; CHECK-NEXT: br %r14
|
||||
%0 = alloca i64, align 8
|
||||
%1 = tail call i8* @llvm.frameaddress(i32 0)
|
||||
ret i8* %1
|
||||
}
|
||||
|
||||
declare i8* @llvm.frameaddress(i32) nounwind readnone
|
Loading…
Reference in New Issue