Skip to content

Commit 89c25c5

Browse files
authored
[Xtensa] Implement windowed register call ABI. (#130001)
Implement base windowed register call ABI. By defaullt use rotation window by 8 registers.
1 parent 5a30794 commit 89c25c5

16 files changed

+565
-128
lines changed

llvm/lib/Target/Xtensa/XtensaCallingConv.td

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,30 @@
99
//===----------------------------------------------------------------------===//
1010

1111
//===----------------------------------------------------------------------===//
12-
// Xtensa return value calling convention
12+
// Xtensa base calling convention
1313
//===----------------------------------------------------------------------===//
14+
// Xtensa return value
1415
def RetCC_Xtensa : CallingConv<[
1516
// First two return values go in a2, a3, a4, a5
1617
CCIfType<[i32], CCAssignToReg<[A2, A3, A4, A5]>>,
1718
CCIfType<[i64], CCAssignToRegWithShadow<[A2, A4], [A3, A5]>>
1819
]>;
1920

21+
// Callee-saved register lists
22+
def CSR_Xtensa : CalleeSavedRegs<(add A0, A12, A13, A14, A15)>;
23+
2024
//===----------------------------------------------------------------------===//
21-
// Callee-saved register lists.
25+
// Xtensa windowed calling convention. Currently by default implemented
26+
// rotation window by 8 registers.
2227
//===----------------------------------------------------------------------===//
28+
// Xtensa return value for 8 registers window
29+
def RetCCW8_Xtensa : CallingConv<[
30+
//First two return values go in a10, a11, a12, a13
31+
CCIfType<[i32], CCAssignToReg<[A10, A11, A12, A13]>>,
32+
CCIfType<[i64], CCAssignToRegWithShadow<[A10, A12], [A11, A13]>>
33+
]>;
2334

24-
def CSR_Xtensa : CalleeSavedRegs<(add A0, A12, A13, A14, A15)>;
35+
// Callee-saved register lists for rotation window by 8 registers
36+
def CSRW8_Xtensa : CalleeSavedRegs<(add)> {
37+
let OtherPreserved = (add A0, SP, A2, A3, A4, A5, A6, A7);
38+
}

llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp

Lines changed: 169 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,16 @@
2323

2424
using namespace llvm;
2525

26+
// Minimum frame = reg save area (4 words) plus static chain (1 word)
27+
// and the total number of words must be a multiple of 128 bits.
28+
// Width of a word, in units (bytes).
29+
#define UNITS_PER_WORD 4
30+
#define MIN_FRAME_SIZE (8 * UNITS_PER_WORD)
31+
2632
XtensaFrameLowering::XtensaFrameLowering(const XtensaSubtarget &STI)
2733
: TargetFrameLowering(TargetFrameLowering::StackGrowsDown, Align(4), 0,
2834
Align(4)),
29-
TII(*STI.getInstrInfo()), TRI(STI.getRegisterInfo()) {}
35+
STI(STI), TII(*STI.getInstrInfo()), TRI(STI.getRegisterInfo()) {}
3036

3137
bool XtensaFrameLowering::hasFPImpl(const MachineFunction &MF) const {
3238
const MachineFrameInfo &MFI = MF.getFrameInfo();
@@ -43,6 +49,7 @@ void XtensaFrameLowering::emitPrologue(MachineFunction &MF,
4349
MCRegister SP = Xtensa::SP;
4450
MCRegister FP = TRI->getFrameRegister(MF);
4551
const MCRegisterInfo *MRI = MF.getContext().getRegisterInfo();
52+
XtensaMachineFunctionInfo *XtensaFI = MF.getInfo<XtensaMachineFunctionInfo>();
4653

4754
// First, compute final stack size.
4855
uint64_t StackSize = MFI.getStackSize();
@@ -51,76 +58,153 @@ void XtensaFrameLowering::emitPrologue(MachineFunction &MF,
5158
// Round up StackSize to 16*N
5259
StackSize += (16 - StackSize) & 0xf;
5360

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;
61+
if (STI.isWindowedABI()) {
62+
StackSize += 32;
63+
uint64_t MaxAlignment = MFI.getMaxAlign().value();
64+
if (MaxAlignment > 32)
65+
StackSize += MaxAlignment;
66+
67+
if (StackSize <= 32760) {
68+
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::ENTRY))
69+
.addReg(SP)
70+
.addImm(StackSize);
71+
} else {
72+
// Use a8 as a temporary since a0-a7 may be live.
73+
MCRegister TmpReg = Xtensa::A8;
74+
75+
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::ENTRY))
76+
.addReg(SP)
77+
.addImm(MIN_FRAME_SIZE);
78+
TII.loadImmediate(MBB, MBBI, &TmpReg, StackSize - MIN_FRAME_SIZE);
79+
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::SUB), TmpReg)
80+
.addReg(SP)
81+
.addReg(TmpReg);
82+
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::MOVSP), SP).addReg(TmpReg);
83+
}
8084

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.asMCReg() &&
87-
Info.getReg() == Reg.asMCReg();
88-
} else {
89-
Register Reg = TII.isStoreToStackSlot(*MBBI, StoreFI);
90-
IsStoreInst = Reg.asMCReg() == Info.getReg() && StoreFI == FI;
91-
}
92-
assert(IsStoreInst &&
93-
"Unexpected callee-saved register store instruction");
94-
#endif
95-
++MBBI;
85+
// Calculate how much is needed to have the correct alignment.
86+
// Change offset to: alignment + difference.
87+
// For example, in case of alignment of 128:
88+
// diff_to_128_aligned_address = (128 - (SP & 127))
89+
// new_offset = SP + diff_to_128_aligned_address
90+
// This is safe to do because we increased the stack size by MaxAlignment.
91+
MCRegister Reg, RegMisAlign;
92+
if (MaxAlignment > 32) {
93+
TII.loadImmediate(MBB, MBBI, &RegMisAlign, MaxAlignment - 1);
94+
TII.loadImmediate(MBB, MBBI, &Reg, MaxAlignment);
95+
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::AND))
96+
.addReg(RegMisAlign, RegState::Define)
97+
.addReg(FP)
98+
.addReg(RegMisAlign);
99+
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::SUB), RegMisAlign)
100+
.addReg(Reg)
101+
.addReg(RegMisAlign);
102+
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::ADD), SP)
103+
.addReg(SP)
104+
.addReg(RegMisAlign, RegState::Kill);
96105
}
97106

98-
// Iterate over list of callee-saved registers and emit .cfi_offset
99-
// directives.
100-
for (const auto &I : CSI) {
101-
int64_t Offset = MFI.getObjectOffset(I.getFrameIdx());
102-
MCRegister Reg = I.getReg();
107+
// Store FP register in A8, because FP may be used to pass function
108+
// arguments
109+
if (XtensaFI->isSaveFrameRegister()) {
110+
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::OR), Xtensa::A8)
111+
.addReg(FP)
112+
.addReg(FP);
113+
}
103114

104-
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
105-
nullptr, MRI->getDwarfRegNum(Reg, 1), Offset));
115+
// if framepointer enabled, set it to point to the stack pointer.
116+
if (hasFP(MF)) {
117+
// Insert instruction "move $fp, $sp" at this location.
118+
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::OR), FP)
119+
.addReg(SP)
120+
.addReg(SP)
121+
.setMIFlag(MachineInstr::FrameSetup);
122+
123+
MCCFIInstruction Inst = MCCFIInstruction::cfiDefCfa(
124+
nullptr, MRI->getDwarfRegNum(FP, true), StackSize);
125+
unsigned CFIIndex = MF.addFrameInst(Inst);
126+
BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
127+
.addCFIIndex(CFIIndex);
128+
} else {
129+
// emit ".cfi_def_cfa_offset StackSize"
130+
unsigned CFIIndex = MF.addFrameInst(
131+
MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize));
106132
BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
107133
.addCFIIndex(CFIIndex);
108134
}
109-
}
135+
} else {
136+
// No need to allocate space on the stack.
137+
if (StackSize == 0 && !MFI.adjustsStack())
138+
return;
110139

111-
// if framepointer enabled, set it to point to the stack pointer.
112-
if (hasFP(MF)) {
113-
// Insert instruction "move $fp, $sp" at this location.
114-
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::OR), FP)
115-
.addReg(SP)
116-
.addReg(SP)
117-
.setMIFlag(MachineInstr::FrameSetup);
118-
119-
// emit ".cfi_def_cfa_register $fp"
120-
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfaRegister(
121-
nullptr, MRI->getDwarfRegNum(FP, true)));
140+
// Adjust stack.
141+
TII.adjustStackPtr(SP, -StackSize, MBB, MBBI);
142+
143+
// emit ".cfi_def_cfa_offset StackSize"
144+
unsigned CFIIndex =
145+
MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize));
122146
BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
123147
.addCFIIndex(CFIIndex);
148+
149+
const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
150+
151+
if (!CSI.empty()) {
152+
// Find the instruction past the last instruction that saves a
153+
// callee-saved register to the stack. The callee-saved store
154+
// instructions are placed at the begin of basic block, so
155+
// iterate over instruction sequence and check that
156+
// save instructions are placed correctly.
157+
for (unsigned i = 0, e = CSI.size(); i < e; ++i) {
158+
#ifndef NDEBUG
159+
const CalleeSavedInfo &Info = CSI[i];
160+
int FI = Info.getFrameIdx();
161+
int StoreFI = 0;
162+
163+
// Checking that the instruction is exactly as expected
164+
bool IsStoreInst = false;
165+
if (MBBI->getOpcode() == TargetOpcode::COPY && Info.isSpilledToReg()) {
166+
Register DstReg = MBBI->getOperand(0).getReg();
167+
Register Reg = MBBI->getOperand(1).getReg();
168+
IsStoreInst = Info.getDstReg() == DstReg.asMCReg() &&
169+
Info.getReg() == Reg.asMCReg();
170+
} else {
171+
Register Reg = TII.isStoreToStackSlot(*MBBI, StoreFI);
172+
IsStoreInst = Reg.asMCReg() == Info.getReg() && StoreFI == FI;
173+
}
174+
assert(IsStoreInst &&
175+
"Unexpected callee-saved register store instruction");
176+
#endif
177+
++MBBI;
178+
}
179+
180+
// Iterate over list of callee-saved registers and emit .cfi_offset
181+
// directives.
182+
for (const auto &I : CSI) {
183+
int64_t Offset = MFI.getObjectOffset(I.getFrameIdx());
184+
MCRegister Reg = I.getReg();
185+
186+
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
187+
nullptr, MRI->getDwarfRegNum(Reg, 1), Offset));
188+
BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
189+
.addCFIIndex(CFIIndex);
190+
}
191+
}
192+
193+
// if framepointer enabled, set it to point to the stack pointer.
194+
if (hasFP(MF)) {
195+
// Insert instruction "move $fp, $sp" at this location.
196+
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::OR), FP)
197+
.addReg(SP)
198+
.addReg(SP)
199+
.setMIFlag(MachineInstr::FrameSetup);
200+
201+
// emit ".cfi_def_cfa_register $fp"
202+
unsigned CFIIndex =
203+
MF.addFrameInst(MCCFIInstruction::createDefCfaRegister(
204+
nullptr, MRI->getDwarfRegNum(FP, true)));
205+
BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
206+
.addCFIIndex(CFIIndex);
207+
}
124208
}
125209

126210
if (StackSize != PrevStackSize) {
@@ -179,10 +263,22 @@ void XtensaFrameLowering::emitEpilogue(MachineFunction &MF,
179263
"Unexpected callee-saved register restore instruction");
180264
#endif
181265
}
182-
183-
BuildMI(MBB, I, DL, TII.get(Xtensa::OR), SP).addReg(FP).addReg(FP);
266+
if (STI.isWindowedABI()) {
267+
// In most architectures, we need to explicitly restore the stack pointer
268+
// before returning.
269+
//
270+
// For Xtensa Windowed Register option, it is not needed to explicitly
271+
// restore the stack pointer. Reason being is that on function return,
272+
// the window of the caller (including the old stack pointer) gets
273+
// restored anyways.
274+
} else {
275+
BuildMI(MBB, I, DL, TII.get(Xtensa::OR), SP).addReg(FP).addReg(FP);
276+
}
184277
}
185278

279+
if (STI.isWindowedABI())
280+
return;
281+
186282
// Get the number of bytes from FrameInfo
187283
uint64_t StackSize = MFI.getStackSize();
188284

@@ -199,6 +295,9 @@ bool XtensaFrameLowering::spillCalleeSavedRegisters(
199295
MachineFunction *MF = MBB.getParent();
200296
MachineBasicBlock &EntryBlock = *(MF->begin());
201297

298+
if (STI.isWindowedABI())
299+
return true;
300+
202301
for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
203302
// Add the callee-saved register as live-in. Do not add if the register is
204303
// A0 and return address is taken, because it will be implemented in
@@ -224,16 +323,15 @@ bool XtensaFrameLowering::spillCalleeSavedRegisters(
224323
bool XtensaFrameLowering::restoreCalleeSavedRegisters(
225324
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
226325
MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
326+
if (STI.isWindowedABI())
327+
return true;
227328
return TargetFrameLowering::restoreCalleeSavedRegisters(MBB, MI, CSI, TRI);
228329
}
229330

230331
// Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions
231332
MachineBasicBlock::iterator XtensaFrameLowering::eliminateCallFramePseudoInstr(
232333
MachineFunction &MF, MachineBasicBlock &MBB,
233334
MachineBasicBlock::iterator I) const {
234-
const XtensaInstrInfo &TII =
235-
*static_cast<const XtensaInstrInfo *>(MF.getSubtarget().getInstrInfo());
236-
237335
if (!hasReservedCallFrame(MF)) {
238336
int64_t Amount = I->getOperand(0).getImm();
239337

@@ -249,7 +347,11 @@ MachineBasicBlock::iterator XtensaFrameLowering::eliminateCallFramePseudoInstr(
249347
void XtensaFrameLowering::determineCalleeSaves(MachineFunction &MF,
250348
BitVector &SavedRegs,
251349
RegScavenger *RS) const {
252-
unsigned FP = TRI->getFrameRegister(MF);
350+
MCRegister FP = TRI->getFrameRegister(MF);
351+
352+
if (STI.isWindowedABI()) {
353+
return;
354+
}
253355

254356
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
255357

llvm/lib/Target/Xtensa/XtensaFrameLowering.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class XtensaInstrInfo;
1818
class XtensaRegisterInfo;
1919

2020
class XtensaFrameLowering : public TargetFrameLowering {
21+
const XtensaSubtarget &STI;
2122
const XtensaInstrInfo &TII;
2223
const XtensaRegisterInfo *TRI;
2324

0 commit comments

Comments
 (0)