Skip to content

Commit 20df35c

Browse files
committed
[Xtensa] Implement windowed call ABI.
Implement base windowed call ABI. By defaullt use rotation window by 8 registers.
1 parent da70881 commit 20df35c

14 files changed

+413
-22
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: 109 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,15 @@
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,
28-
Align(4)),
34+
Align(4)), STI(STI),
2935
TII(*STI.getInstrInfo()), TRI(STI.getRegisterInfo()) {}
3036

3137
bool XtensaFrameLowering::hasFPImpl(const MachineFunction &MF) const {
@@ -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,6 +58,83 @@ void XtensaFrameLowering::emitPrologue(MachineFunction &MF,
5158
// Round up StackSize to 16*N
5259
StackSize += (16 - StackSize) & 0xf;
5360

61+
if (STI.isWinABI()) {
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+
unsigned TmpReg = Xtensa::A8;
74+
75+
const XtensaInstrInfo &TII = *static_cast<const XtensaInstrInfo *>(
76+
MBB.getParent()->getSubtarget().getInstrInfo());
77+
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::ENTRY))
78+
.addReg(SP)
79+
.addImm(MIN_FRAME_SIZE);
80+
TII.loadImmediate(MBB, MBBI, &TmpReg, StackSize - MIN_FRAME_SIZE);
81+
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::SUB), TmpReg)
82+
.addReg(SP)
83+
.addReg(TmpReg);
84+
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::MOVSP), SP).addReg(TmpReg);
85+
}
86+
87+
// Calculate how much is needed to have the correct alignment.
88+
// Change offset to: alignment + difference.
89+
// For example, in case of alignment of 128:
90+
// diff_to_128_aligned_address = (128 - (SP & 127))
91+
// new_offset = SP + diff_to_128_aligned_address
92+
// This is safe to do because we increased the stack size by MaxAlignment.
93+
unsigned Reg, RegMisAlign;
94+
if (MaxAlignment > 32){
95+
TII.loadImmediate(MBB, MBBI, &RegMisAlign, MaxAlignment - 1);
96+
TII.loadImmediate(MBB, MBBI, &Reg, MaxAlignment);
97+
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::AND))
98+
.addReg(RegMisAlign, RegState::Define)
99+
.addReg(FP)
100+
.addReg(RegMisAlign);
101+
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::SUB), RegMisAlign)
102+
.addReg(Reg)
103+
.addReg(RegMisAlign);
104+
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::ADD), SP)
105+
.addReg(SP)
106+
.addReg(RegMisAlign, RegState::Kill);
107+
}
108+
109+
// Store FP register in A8, because FP may be used to pass function
110+
// arguments
111+
if (XtensaFI->isSaveFrameRegister()) {
112+
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::OR), Xtensa::A8)
113+
.addReg(FP)
114+
.addReg(FP);
115+
}
116+
117+
// if framepointer enabled, set it to point to the stack pointer.
118+
if (hasFP(MF)) {
119+
// Insert instruction "move $fp, $sp" at this location.
120+
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::OR), FP)
121+
.addReg(SP)
122+
.addReg(SP)
123+
.setMIFlag(MachineInstr::FrameSetup);
124+
125+
MCCFIInstruction Inst = MCCFIInstruction::cfiDefCfa(
126+
nullptr, MRI->getDwarfRegNum(FP, true), StackSize);
127+
unsigned CFIIndex = MF.addFrameInst(Inst);
128+
BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
129+
.addCFIIndex(CFIIndex);
130+
} else {
131+
// emit ".cfi_def_cfa_offset StackSize"
132+
unsigned CFIIndex = MF.addFrameInst(
133+
MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize));
134+
BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
135+
.addCFIIndex(CFIIndex);
136+
}
137+
} else {
54138
// No need to allocate space on the stack.
55139
if (StackSize == 0 && !MFI.adjustsStack())
56140
return;
@@ -122,6 +206,7 @@ void XtensaFrameLowering::emitPrologue(MachineFunction &MF,
122206
BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
123207
.addCFIIndex(CFIIndex);
124208
}
209+
}
125210

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

280+
if (STI.isWinABI())
281+
return;
282+
186283
// Get the number of bytes from FrameInfo
187284
uint64_t StackSize = MFI.getStackSize();
188285

@@ -199,6 +296,9 @@ bool XtensaFrameLowering::spillCalleeSavedRegisters(
199296
MachineFunction *MF = MBB.getParent();
200297
MachineBasicBlock &EntryBlock = *(MF->begin());
201298

299+
if (STI.isWinABI())
300+
return true;
301+
202302
for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
203303
// Add the callee-saved register as live-in. Do not add if the register is
204304
// A0 and return address is taken, because it will be implemented in
@@ -224,6 +324,8 @@ bool XtensaFrameLowering::spillCalleeSavedRegisters(
224324
bool XtensaFrameLowering::restoreCalleeSavedRegisters(
225325
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
226326
MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
327+
if (STI.isWinABI())
328+
return true;
227329
return TargetFrameLowering::restoreCalleeSavedRegisters(MBB, MI, CSI, TRI);
228330
}
229331

@@ -251,6 +353,10 @@ void XtensaFrameLowering::determineCalleeSaves(MachineFunction &MF,
251353
RegScavenger *RS) const {
252354
unsigned FP = TRI->getFrameRegister(MF);
253355

356+
if (STI.isWinABI()) {
357+
return;
358+
}
359+
254360
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
255361

256362
// Mark $fp as used if function has dedicated frame pointer.

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

llvm/lib/Target/Xtensa/XtensaISelLowering.cpp

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@ static bool isLongCall(const char *str) {
4242
return true;
4343
}
4444

45+
// The calling conventions in XtensaCallingConv.td are described in terms of the
46+
// callee's register window. This function translates registers to the
47+
// corresponding caller window %o register.
48+
static unsigned toCallerWindow(unsigned Reg) {
49+
if (Reg >= Xtensa::A2 && Reg <= Xtensa::A7)
50+
return Reg - Xtensa::A2 + Xtensa::A10;
51+
return Reg;
52+
}
53+
4554
XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
4655
const XtensaSubtarget &STI)
4756
: TargetLowering(TM), Subtarget(STI) {
@@ -339,7 +348,18 @@ SDValue XtensaTargetLowering::LowerFormalArguments(
339348

340349
// Transform the arguments stored on
341350
// physical registers into virtual ones
342-
Register Reg = MF.addLiveIn(VA.getLocReg(), &Xtensa::ARRegClass);
351+
Register Reg = 0;
352+
unsigned FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF);
353+
354+
// Argument passed in FrameReg in WinABI we save in A8 (in emitPrologue),
355+
// so load argument from A8
356+
if (Subtarget.isWinABI() && (VA.getLocReg() == FrameReg)) {
357+
Reg = MF.addLiveIn(Xtensa::A8, &Xtensa::ARRegClass);
358+
XtensaFI->setSaveFrameRegister();
359+
} else {
360+
Reg = MF.addLiveIn(VA.getLocReg(), &Xtensa::ARRegClass);
361+
}
362+
343363
SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, RegVT);
344364

345365
// If this is an 8 or 16-bit value, it has been passed promoted
@@ -538,6 +558,8 @@ XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI,
538558
SDValue Glue;
539559
for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) {
540560
unsigned Reg = RegsToPass[I].first;
561+
if (Subtarget.isWinABI())
562+
Reg = toCallerWindow(Reg);
541563
Chain = DAG.getCopyToReg(Chain, DL, Reg, RegsToPass[I].second, Glue);
542564
Glue = Chain.getValue(1);
543565
}
@@ -587,6 +609,8 @@ XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI,
587609
// known live into the call.
588610
for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) {
589611
unsigned Reg = RegsToPass[I].first;
612+
if (Subtarget.isWinABI())
613+
Reg = toCallerWindow(Reg);
590614
Ops.push_back(DAG.getRegister(Reg, RegsToPass[I].second.getValueType()));
591615
}
592616

@@ -595,7 +619,8 @@ XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI,
595619
Ops.push_back(Glue);
596620

597621
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
598-
Chain = DAG.getNode(XtensaISD::CALL, DL, NodeTys, Ops);
622+
Chain = DAG.getNode(Subtarget.isWinABI() ? XtensaISD::CALLW8 : XtensaISD::CALL,
623+
DL, NodeTys, Ops);
599624
Glue = Chain.getValue(1);
600625

601626
// Mark the end of the call, which is glued to the call itself.
@@ -606,7 +631,8 @@ XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI,
606631
// Assign locations to each value returned by this call.
607632
SmallVector<CCValAssign, 16> RetLocs;
608633
CCState RetCCInfo(CallConv, IsVarArg, MF, RetLocs, *DAG.getContext());
609-
RetCCInfo.AnalyzeCallResult(Ins, RetCC_Xtensa);
634+
RetCCInfo.AnalyzeCallResult(Ins, Subtarget.isWinABI() ? RetCCW8_Xtensa
635+
: RetCC_Xtensa);
610636

611637
// Copy all of the result registers out of their specified physreg.
612638
for (unsigned I = 0, E = RetLocs.size(); I != E; ++I) {
@@ -648,7 +674,8 @@ XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
648674
SDValue Glue;
649675
// Quick exit for void returns
650676
if (RetLocs.empty())
651-
return DAG.getNode(XtensaISD::RET, DL, MVT::Other, Chain);
677+
return DAG.getNode(Subtarget.isWinABI() ? XtensaISD::RETW
678+
: XtensaISD::RET, DL, MVT::Other, Chain);
652679

653680
// Copy the result values into the output registers.
654681
SmallVector<SDValue, 4> RetOps;
@@ -672,7 +699,8 @@ XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
672699
if (Glue.getNode())
673700
RetOps.push_back(Glue);
674701

675-
return DAG.getNode(XtensaISD::RET, DL, MVT::Other, RetOps);
702+
return DAG.getNode(Subtarget.isWinABI() ? XtensaISD::RETW
703+
: XtensaISD::RET, DL, MVT::Other, RetOps);
676704
}
677705

678706
static unsigned getBranchOpcode(ISD::CondCode Cond) {
@@ -906,6 +934,9 @@ SDValue XtensaTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
906934
unsigned SPReg = Xtensa::SP;
907935
SDValue SP = DAG.getCopyFromReg(Chain, DL, SPReg, VT);
908936
SDValue NewSP = DAG.getNode(ISD::SUB, DL, VT, SP, SizeRoundUp); // Value
937+
if (Subtarget.isWinABI()) {
938+
NewSP = DAG.getNode(XtensaISD::MOVSP, DL, MVT::i32, NewSP);
939+
}
909940
Chain = DAG.getCopyToReg(SP.getValue(1), DL, SPReg, NewSP); // Output chain
910941

911942
SDValue NewVal = DAG.getCopyFromReg(Chain, DL, SPReg, MVT::i32);
@@ -1230,12 +1261,18 @@ const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const {
12301261
return "XtensaISD::BR_JT";
12311262
case XtensaISD::CALL:
12321263
return "XtensaISD::CALL";
1264+
case XtensaISD::CALLW8:
1265+
return "XtensaISD::CALLW8";
12331266
case XtensaISD::EXTUI:
12341267
return "XtensaISD::EXTUI";
1268+
case XtensaISD::MOVSP:
1269+
return "XtensaISD::MOVSP";
12351270
case XtensaISD::PCREL_WRAPPER:
12361271
return "XtensaISD::PCREL_WRAPPER";
12371272
case XtensaISD::RET:
12381273
return "XtensaISD::RET";
1274+
case XtensaISD::RETW:
1275+
return "XtensaISD::RETW";
12391276
case XtensaISD::SELECT_CC:
12401277
return "XtensaISD::SELECT_CC";
12411278
case XtensaISD::SRCL:

llvm/lib/Target/Xtensa/XtensaISelLowering.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,21 @@ enum {
2929
// is the target address. The arguments start at operand 2.
3030
// There is an optional glue operand at the end.
3131
CALL,
32+
// Call with rotation window by 8 registers
33+
CALLW8,
3234

3335
// Extract unsigned immediate. Operand 0 is value, operand 1
3436
// is bit position of the field [0..31], operand 2 is bit size
3537
// of the field [1..16]
3638
EXTUI,
3739

40+
MOVSP,
41+
3842
// Wraps a TargetGlobalAddress that should be loaded using PC-relative
3943
// accesses. Operand 0 is the address.
4044
PCREL_WRAPPER,
4145
RET,
46+
RETW,
4247

4348
// Select with condition operator - This selects between a true value and
4449
// a false value (ops #2 and #3) based on the boolean result of comparing

llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,13 @@ void XtensaInstrInfo::adjustStackPtr(unsigned SP, int64_t Amount,
100100
.addReg(Reg1, RegState::Kill);
101101
}
102102

103+
if (STI.isWinABI()) {
104+
BuildMI(MBB, I, DL, get(Xtensa::MOVSP), SP).addReg(Reg, RegState::Kill);
105+
} else {
103106
BuildMI(MBB, I, DL, get(Xtensa::OR), SP)
104107
.addReg(Reg, RegState::Kill)
105108
.addReg(Reg, RegState::Kill);
109+
}
106110
}
107111

108112
void XtensaInstrInfo::copyPhysReg(MachineBasicBlock &MBB,

0 commit comments

Comments
 (0)