Skip to content

Commit 78f5d9c

Browse files
authored
[PATCH] [Xtensa] Implement FrameLowering methods and stack operation lowering. (#92960)
Implement emitPrologue/emitEpilogue methods, determine/spill/restore callee saved registers functionality with test. Also implement lowering of the DYNAMIC_STACKALLOC/STACKSAVE/STACKRESTORE stack operations with tests.
1 parent 8917739 commit 78f5d9c

10 files changed

+404
-14
lines changed

llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp

Lines changed: 221 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@
2222

2323
using namespace llvm;
2424

25-
XtensaFrameLowering::XtensaFrameLowering()
25+
XtensaFrameLowering::XtensaFrameLowering(const XtensaSubtarget &STI)
2626
: TargetFrameLowering(TargetFrameLowering::StackGrowsDown, Align(4), 0,
27-
Align(4)) {}
27+
Align(4)),
28+
STI(STI), TII(*STI.getInstrInfo()), TRI(STI.getRegisterInfo()) {}
2829

2930
bool XtensaFrameLowering::hasFP(const MachineFunction &MF) const {
3031
const MachineFrameInfo &MFI = MF.getFrameInfo();
@@ -33,10 +34,196 @@ bool XtensaFrameLowering::hasFP(const MachineFunction &MF) const {
3334
}
3435

3536
void XtensaFrameLowering::emitPrologue(MachineFunction &MF,
36-
MachineBasicBlock &MBB) const {}
37+
MachineBasicBlock &MBB) const {
38+
assert(&MBB == &MF.front() && "Shrink-wrapping not yet implemented");
39+
MachineFrameInfo &MFI = MF.getFrameInfo();
40+
MachineBasicBlock::iterator MBBI = MBB.begin();
41+
DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
42+
MCRegister SP = Xtensa::SP;
43+
MCRegister FP = TRI->getFrameRegister(MF);
44+
MachineModuleInfo &MMI = MF.getMMI();
45+
const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo();
46+
47+
// First, compute final stack size.
48+
uint64_t StackSize = MFI.getStackSize();
49+
uint64_t PrevStackSize = StackSize;
50+
51+
// Round up StackSize to 16*N
52+
StackSize += (16 - StackSize) & 0xf;
53+
54+
// No need to allocate space on the stack.
55+
if (StackSize == 0 && !MFI.adjustsStack())
56+
return;
57+
58+
// Adjust stack.
59+
TII.adjustStackPtr(SP, -StackSize, MBB, MBBI);
60+
61+
// emit ".cfi_def_cfa_offset StackSize"
62+
unsigned CFIIndex =
63+
MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize));
64+
BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
65+
.addCFIIndex(CFIIndex);
66+
67+
const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
68+
69+
if (!CSI.empty()) {
70+
// Find the instruction past the last instruction that saves a
71+
// callee-saved register to the stack. The callee-saved store
72+
// instructions are placed at the begin of basic block, so
73+
// iterate over instruction sequence and check that
74+
// save instructions are placed correctly.
75+
for (unsigned i = 0, e = CSI.size(); i < e; ++i) {
76+
#ifndef NDEBUG
77+
const CalleeSavedInfo &Info = CSI[i];
78+
int FI = Info.getFrameIdx();
79+
int StoreFI = 0;
80+
81+
// Checking that the instruction is exactly as expected
82+
bool IsStoreInst = false;
83+
if (MBBI->getOpcode() == TargetOpcode::COPY && Info.isSpilledToReg()) {
84+
Register DstReg = MBBI->getOperand(0).getReg();
85+
Register Reg = MBBI->getOperand(1).getReg();
86+
IsStoreInst = (Info.getDstReg() == DstReg) && (Info.getReg() == Reg);
87+
} else {
88+
Register Reg = TII.isStoreToStackSlot(*MBBI, StoreFI);
89+
IsStoreInst = (Reg == Info.getReg()) && (StoreFI == FI);
90+
}
91+
assert(IsStoreInst &&
92+
"Unexpected callee-saved register store instruction");
93+
#endif
94+
++MBBI;
95+
}
96+
97+
// Iterate over list of callee-saved registers and emit .cfi_offset
98+
// directives.
99+
for (const auto &I : CSI) {
100+
int64_t Offset = MFI.getObjectOffset(I.getFrameIdx());
101+
Register Reg = I.getReg();
102+
103+
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
104+
nullptr, MRI->getDwarfRegNum(Reg, 1), Offset));
105+
BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
106+
.addCFIIndex(CFIIndex);
107+
}
108+
}
109+
110+
// if framepointer enabled, set it to point to the stack pointer.
111+
if (hasFP(MF)) {
112+
// Insert instruction "move $fp, $sp" at this location.
113+
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::OR), FP)
114+
.addReg(SP)
115+
.addReg(SP)
116+
.setMIFlag(MachineInstr::FrameSetup);
117+
118+
// emit ".cfi_def_cfa_register $fp"
119+
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfaRegister(
120+
nullptr, MRI->getDwarfRegNum(FP, true)));
121+
BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
122+
.addCFIIndex(CFIIndex);
123+
}
124+
125+
if (StackSize != PrevStackSize) {
126+
MFI.setStackSize(StackSize);
127+
128+
for (int i = MFI.getObjectIndexBegin(); i < MFI.getObjectIndexEnd(); i++) {
129+
if (!MFI.isDeadObjectIndex(i)) {
130+
int64_t SPOffset = MFI.getObjectOffset(i);
131+
132+
if (SPOffset < 0)
133+
MFI.setObjectOffset(i, SPOffset - StackSize + PrevStackSize);
134+
}
135+
}
136+
}
137+
}
37138

38139
void XtensaFrameLowering::emitEpilogue(MachineFunction &MF,
39-
MachineBasicBlock &MBB) const {}
140+
MachineBasicBlock &MBB) const {
141+
MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
142+
MachineFrameInfo &MFI = MF.getFrameInfo();
143+
DebugLoc DL = MBBI->getDebugLoc();
144+
MCRegister SP = Xtensa::SP;
145+
MCRegister FP = TRI->getFrameRegister(MF);
146+
147+
// if framepointer enabled, restore the stack pointer.
148+
if (hasFP(MF)) {
149+
// We should place restore stack pointer instruction just before
150+
// sequence of instructions which restores callee-saved registers.
151+
// This sequence is placed at the end of the basic block,
152+
// so we should find first instruction of the sequence.
153+
MachineBasicBlock::iterator I = MBBI;
154+
155+
const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
156+
157+
// Find the first instruction at the end that restores a callee-saved
158+
// register.
159+
for (unsigned i = 0, e = CSI.size(); i < e; ++i) {
160+
--I;
161+
#ifndef NDEBUG
162+
const CalleeSavedInfo &Info = CSI[i];
163+
int FI = Info.getFrameIdx();
164+
int LoadFI = 0;
165+
166+
// Checking that the instruction is exactly as expected
167+
bool IsRestoreInst = false;
168+
if (I->getOpcode() == TargetOpcode::COPY && Info.isSpilledToReg()) {
169+
Register Reg = I->getOperand(0).getReg();
170+
Register DstReg = I->getOperand(1).getReg();
171+
IsRestoreInst = (Info.getDstReg() == DstReg) && (Info.getReg() == Reg);
172+
} else {
173+
Register Reg = TII.isLoadFromStackSlot(*I, LoadFI);
174+
IsRestoreInst = (Info.getReg() == Reg) && (LoadFI == FI);
175+
}
176+
assert(IsRestoreInst &&
177+
"Unexpected callee-saved register restore instruction");
178+
#endif
179+
}
180+
181+
BuildMI(MBB, I, DL, TII.get(Xtensa::OR), SP).addReg(FP).addReg(FP);
182+
}
183+
184+
// Get the number of bytes from FrameInfo
185+
uint64_t StackSize = MFI.getStackSize();
186+
187+
if (!StackSize)
188+
return;
189+
190+
// Adjust stack.
191+
TII.adjustStackPtr(SP, StackSize, MBB, MBBI);
192+
}
193+
194+
bool XtensaFrameLowering::spillCalleeSavedRegisters(
195+
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
196+
ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
197+
MachineFunction *MF = MBB.getParent();
198+
MachineBasicBlock &EntryBlock = *(MF->begin());
199+
200+
for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
201+
// Add the callee-saved register as live-in. Do not add if the register is
202+
// A0 and return address is taken, because it will be implemented in
203+
// method XtensaTargetLowering::LowerRETURNADDR.
204+
// It's killed at the spill, unless the register is RA and return address
205+
// is taken.
206+
Register Reg = CSI[i].getReg();
207+
bool IsA0AndRetAddrIsTaken =
208+
(Reg == Xtensa::A0) && MF->getFrameInfo().isReturnAddressTaken();
209+
if (!IsA0AndRetAddrIsTaken)
210+
EntryBlock.addLiveIn(Reg);
211+
212+
// Insert the spill to the stack frame.
213+
bool IsKill = !IsA0AndRetAddrIsTaken;
214+
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
215+
TII.storeRegToStackSlot(EntryBlock, MI, Reg, IsKill, CSI[i].getFrameIdx(),
216+
RC, TRI, Register());
217+
}
218+
219+
return true;
220+
}
221+
222+
bool XtensaFrameLowering::restoreCalleeSavedRegisters(
223+
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
224+
MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
225+
return TargetFrameLowering::restoreCalleeSavedRegisters(MBB, MI, CSI, TRI);
226+
}
40227

41228
// Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions
42229
MachineBasicBlock::iterator XtensaFrameLowering::eliminateCallFramePseudoInstr(
@@ -51,9 +238,37 @@ MachineBasicBlock::iterator XtensaFrameLowering::eliminateCallFramePseudoInstr(
51238
if (I->getOpcode() == Xtensa::ADJCALLSTACKDOWN)
52239
Amount = -Amount;
53240

54-
unsigned SP = Xtensa::SP;
55-
TII.adjustStackPtr(SP, Amount, MBB, I);
241+
TII.adjustStackPtr(Xtensa::SP, Amount, MBB, I);
56242
}
57243

58244
return MBB.erase(I);
59245
}
246+
247+
void XtensaFrameLowering::determineCalleeSaves(MachineFunction &MF,
248+
BitVector &SavedRegs,
249+
RegScavenger *RS) const {
250+
unsigned FP = TRI->getFrameRegister(MF);
251+
252+
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
253+
254+
// Mark $fp as used if function has dedicated frame pointer.
255+
if (hasFP(MF))
256+
SavedRegs.set(FP);
257+
}
258+
259+
void XtensaFrameLowering::processFunctionBeforeFrameFinalized(
260+
MachineFunction &MF, RegScavenger *RS) const {
261+
// Set scavenging frame index if necessary.
262+
MachineFrameInfo &MFI = MF.getFrameInfo();
263+
uint64_t MaxSPOffset = MFI.estimateStackSize(MF);
264+
265+
if (isInt<12>(MaxSPOffset))
266+
return;
267+
268+
const TargetRegisterClass &RC = Xtensa::ARRegClass;
269+
unsigned Size = TRI->getSpillSize(RC);
270+
Align Alignment = TRI->getSpillAlign(RC);
271+
int FI = MF.getFrameInfo().CreateStackObject(Size, Alignment, false);
272+
273+
RS->addScavengingFrameIndex(FI);
274+
}

llvm/lib/Target/Xtensa/XtensaFrameLowering.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,16 @@
1414
namespace llvm {
1515
class XtensaTargetMachine;
1616
class XtensaSubtarget;
17+
class XtensaInstrInfo;
18+
class XtensaRegisterInfo;
1719

1820
class XtensaFrameLowering : public TargetFrameLowering {
21+
const XtensaSubtarget &STI;
22+
const XtensaInstrInfo &TII;
23+
const XtensaRegisterInfo *TRI;
24+
1925
public:
20-
XtensaFrameLowering();
26+
XtensaFrameLowering(const XtensaSubtarget &STI);
2127

2228
bool hasFP(const MachineFunction &MF) const override;
2329

@@ -29,6 +35,22 @@ class XtensaFrameLowering : public TargetFrameLowering {
2935
MachineBasicBlock::iterator
3036
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
3137
MachineBasicBlock::iterator I) const override;
38+
39+
bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
40+
MachineBasicBlock::iterator MI,
41+
ArrayRef<CalleeSavedInfo> CSI,
42+
const TargetRegisterInfo *TRI) const override;
43+
bool
44+
restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
45+
MachineBasicBlock::iterator MI,
46+
MutableArrayRef<CalleeSavedInfo> CSI,
47+
const TargetRegisterInfo *TRI) const override;
48+
49+
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
50+
RegScavenger *RS) const override;
51+
52+
void processFunctionBeforeFrameFinalized(MachineFunction &MF,
53+
RegScavenger *RS) const override;
3254
};
3355

3456
} // namespace llvm

llvm/lib/Target/Xtensa/XtensaISelLowering.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
7878

7979
setOperationAction(ISD::ConstantPool, PtrVT, Custom);
8080

81+
// Implement custom stack allocations
82+
setOperationAction(ISD::DYNAMIC_STACKALLOC, PtrVT, Custom);
83+
// Implement custom stack save and restore
84+
setOperationAction(ISD::STACKSAVE, MVT::Other, Custom);
85+
setOperationAction(ISD::STACKRESTORE, MVT::Other, Custom);
86+
8187
// Compute derived properties from the register classes
8288
computeRegisterProperties(STI.getRegisterInfo());
8389
}
@@ -534,13 +540,56 @@ SDValue XtensaTargetLowering::LowerConstantPool(ConstantPoolSDNode *CP,
534540
return getAddrPCRel(Result, DAG);
535541
}
536542

543+
SDValue XtensaTargetLowering::LowerSTACKSAVE(SDValue Op,
544+
SelectionDAG &DAG) const {
545+
return DAG.getCopyFromReg(Op.getOperand(0), SDLoc(Op), Xtensa::SP,
546+
Op.getValueType());
547+
}
548+
549+
SDValue XtensaTargetLowering::LowerSTACKRESTORE(SDValue Op,
550+
SelectionDAG &DAG) const {
551+
return DAG.getCopyToReg(Op.getOperand(0), SDLoc(Op), Xtensa::SP,
552+
Op.getOperand(1));
553+
}
554+
555+
SDValue XtensaTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
556+
SelectionDAG &DAG) const {
557+
SDValue Chain = Op.getOperand(0); // Legalize the chain.
558+
SDValue Size = Op.getOperand(1); // Legalize the size.
559+
EVT VT = Size->getValueType(0);
560+
SDLoc DL(Op);
561+
562+
// Round up Size to 32
563+
SDValue SizeTmp =
564+
DAG.getNode(ISD::ADD, DL, VT, Size, DAG.getConstant(31, DL, MVT::i32));
565+
SDValue SizeRoundUp = DAG.getNode(ISD::AND, DL, VT, SizeTmp,
566+
DAG.getConstant(~31, DL, MVT::i32));
567+
568+
unsigned SPReg = Xtensa::SP;
569+
SDValue SP = DAG.getCopyFromReg(Chain, DL, SPReg, VT);
570+
SDValue NewSP = DAG.getNode(ISD::SUB, DL, VT, SP, SizeRoundUp); // Value
571+
Chain = DAG.getCopyToReg(SP.getValue(1), DL, SPReg, NewSP); // Output chain
572+
573+
SDValue NewVal = DAG.getCopyFromReg(Chain, DL, SPReg, MVT::i32);
574+
Chain = NewVal.getValue(1);
575+
576+
SDValue Ops[2] = {NewVal, Chain};
577+
return DAG.getMergeValues(Ops, DL);
578+
}
579+
537580
SDValue XtensaTargetLowering::LowerOperation(SDValue Op,
538581
SelectionDAG &DAG) const {
539582
switch (Op.getOpcode()) {
540583
case ISD::Constant:
541584
return LowerImmediate(Op, DAG);
542585
case ISD::ConstantPool:
543586
return LowerConstantPool(cast<ConstantPoolSDNode>(Op), DAG);
587+
case ISD::STACKSAVE:
588+
return LowerSTACKSAVE(Op, DAG);
589+
case ISD::STACKRESTORE:
590+
return LowerSTACKRESTORE(Op, DAG);
591+
case ISD::DYNAMIC_STACKALLOC:
592+
return LowerDYNAMIC_STACKALLOC(Op, DAG);
544593
default:
545594
report_fatal_error("Unexpected node to lower");
546595
}

llvm/lib/Target/Xtensa/XtensaISelLowering.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ class XtensaTargetLowering : public TargetLowering {
7575

7676
SDValue LowerConstantPool(ConstantPoolSDNode *CP, SelectionDAG &DAG) const;
7777

78+
SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;
79+
80+
SDValue LowerSTACKSAVE(SDValue Op, SelectionDAG &DAG) const;
81+
82+
SDValue LowerSTACKRESTORE(SDValue Op, SelectionDAG &DAG) const;
83+
7884
SDValue getAddrPCRel(SDValue Op, SelectionDAG &DAG) const;
7985

8086
CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool IsVarArg) const;

0 commit comments

Comments
 (0)