Skip to content

Commit 316fb85

Browse files
committed
[PATCH] [Xtensa] Implement FrameLowering methods and stack operations lowering.
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 253c28f commit 316fb85

File tree

7 files changed

+320
-8
lines changed

7 files changed

+320
-8
lines changed

llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp

Lines changed: 178 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,158 @@ bool XtensaFrameLowering::hasFP(const MachineFunction &MF) const {
3333
}
3434

3535
void XtensaFrameLowering::emitPrologue(MachineFunction &MF,
36-
MachineBasicBlock &MBB) const {}
36+
MachineBasicBlock &MBB) const {
37+
assert(&MBB == &MF.front() && "Shrink-wrapping not yet implemented");
38+
MachineFrameInfo &MFI = MF.getFrameInfo();
39+
const XtensaRegisterInfo *RegInfo = static_cast<const XtensaRegisterInfo *>(
40+
MF.getSubtarget().getRegisterInfo());
41+
const XtensaInstrInfo &TII =
42+
*static_cast<const XtensaInstrInfo *>(MF.getSubtarget().getInstrInfo());
43+
MachineBasicBlock::iterator MBBI = MBB.begin();
44+
DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
45+
unsigned SP = Xtensa::SP;
46+
unsigned FP = RegInfo->getFrameRegister(MF);
47+
MachineModuleInfo &MMI = MF.getMMI();
48+
const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo();
49+
50+
// First, compute final stack size.
51+
uint64_t StackSize = MFI.getStackSize();
52+
uint64_t PrevStackSize = StackSize;
53+
54+
// Round up StackSize to 16*N
55+
StackSize += (16 - StackSize) & 0xf;
56+
57+
// No need to allocate space on the stack.
58+
if (StackSize == 0 && !MFI.adjustsStack())
59+
return;
60+
61+
// Adjust stack.
62+
TII.adjustStackPtr(SP, -StackSize, MBB, MBBI);
63+
64+
// emit ".cfi_def_cfa_offset StackSize"
65+
unsigned CFIIndex =
66+
MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize));
67+
BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
68+
.addCFIIndex(CFIIndex);
69+
70+
const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
71+
72+
if (CSI.size()) {
73+
// Find the instruction past the last instruction that saves a
74+
// callee-saved register to the stack.
75+
for (unsigned i = 0; i < CSI.size(); ++i)
76+
++MBBI;
77+
78+
// Iterate over list of callee-saved registers and emit .cfi_offset
79+
// directives.
80+
for (const auto &I : CSI) {
81+
int64_t Offset = MFI.getObjectOffset(I.getFrameIdx());
82+
Register Reg = I.getReg();
83+
84+
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
85+
nullptr, MRI->getDwarfRegNum(Reg, 1), Offset));
86+
BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
87+
.addCFIIndex(CFIIndex);
88+
}
89+
}
90+
91+
// if framepointer enabled, set it to point to the stack pointer.
92+
if (hasFP(MF)) {
93+
// Insert instruction "move $fp, $sp" at this location.
94+
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::OR), FP)
95+
.addReg(SP)
96+
.addReg(SP)
97+
.setMIFlag(MachineInstr::FrameSetup);
98+
99+
// emit ".cfi_def_cfa_register $fp"
100+
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfaRegister(
101+
nullptr, MRI->getDwarfRegNum(FP, true)));
102+
BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
103+
.addCFIIndex(CFIIndex);
104+
}
105+
106+
if (StackSize != PrevStackSize) {
107+
MFI.setStackSize(StackSize);
108+
109+
for (int i = MFI.getObjectIndexBegin(); i < MFI.getObjectIndexEnd(); i++) {
110+
if (!MFI.isDeadObjectIndex(i)) {
111+
int64_t SPOffset = MFI.getObjectOffset(i);
112+
113+
if (SPOffset < 0)
114+
MFI.setObjectOffset(i, SPOffset - StackSize + PrevStackSize);
115+
}
116+
}
117+
}
118+
}
37119

38120
void XtensaFrameLowering::emitEpilogue(MachineFunction &MF,
39-
MachineBasicBlock &MBB) const {}
121+
MachineBasicBlock &MBB) const {
122+
MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
123+
MachineFrameInfo &MFI = MF.getFrameInfo();
124+
const XtensaRegisterInfo *RegInfo = static_cast<const XtensaRegisterInfo *>(
125+
MF.getSubtarget().getRegisterInfo());
126+
const XtensaInstrInfo &TII =
127+
*static_cast<const XtensaInstrInfo *>(MF.getSubtarget().getInstrInfo());
128+
DebugLoc DL = MBBI->getDebugLoc();
129+
unsigned SP = Xtensa::SP;
130+
unsigned FP = RegInfo->getFrameRegister(MF);
131+
132+
// if framepointer enabled, restore the stack pointer.
133+
if (hasFP(MF)) {
134+
// Find the first instruction that restores a callee-saved register.
135+
MachineBasicBlock::iterator I = MBBI;
136+
137+
for (unsigned i = 0; i < MFI.getCalleeSavedInfo().size(); ++i)
138+
--I;
139+
140+
BuildMI(MBB, I, DL, TII.get(Xtensa::OR), SP).addReg(FP).addReg(FP);
141+
}
142+
143+
// Get the number of bytes from FrameInfo
144+
uint64_t StackSize = MFI.getStackSize();
145+
146+
if (!StackSize)
147+
return;
148+
149+
// Adjust stack.
150+
TII.adjustStackPtr(SP, StackSize, MBB, MBBI);
151+
}
152+
153+
bool XtensaFrameLowering::spillCalleeSavedRegisters(
154+
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
155+
ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
156+
MachineFunction *MF = MBB.getParent();
157+
158+
MachineBasicBlock &EntryBlock = *(MF->begin());
159+
const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
160+
161+
for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
162+
// Add the callee-saved register as live-in. Do not add if the register is
163+
// A0 and return address is taken, because it will be implemented in
164+
// method XtensaTargetLowering::LowerRETURNADDR.
165+
// It's killed at the spill, unless the register is RA and return address
166+
// is taken.
167+
Register Reg = CSI[i].getReg();
168+
bool IsA0AndRetAddrIsTaken =
169+
(Reg == Xtensa::A0) && MF->getFrameInfo().isReturnAddressTaken();
170+
if (!IsA0AndRetAddrIsTaken)
171+
EntryBlock.addLiveIn(Reg);
172+
173+
// Insert the spill to the stack frame.
174+
bool IsKill = !IsA0AndRetAddrIsTaken;
175+
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
176+
TII.storeRegToStackSlot(EntryBlock, MI, Reg, IsKill, CSI[i].getFrameIdx(),
177+
RC, TRI, Register());
178+
}
179+
180+
return true;
181+
}
182+
183+
bool XtensaFrameLowering::restoreCalleeSavedRegisters(
184+
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
185+
MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
186+
return TargetFrameLowering::restoreCalleeSavedRegisters(MBB, MI, CSI, TRI);
187+
}
40188

41189
// Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions
42190
MachineBasicBlock::iterator XtensaFrameLowering::eliminateCallFramePseudoInstr(
@@ -57,3 +205,31 @@ MachineBasicBlock::iterator XtensaFrameLowering::eliminateCallFramePseudoInstr(
57205

58206
return MBB.erase(I);
59207
}
208+
209+
void XtensaFrameLowering::determineCalleeSaves(MachineFunction &MF,
210+
BitVector &SavedRegs,
211+
RegScavenger *RS) const {
212+
MachineFrameInfo &MFI = MF.getFrameInfo();
213+
const XtensaRegisterInfo *RegInfo = static_cast<const XtensaRegisterInfo *>(
214+
MF.getSubtarget().getRegisterInfo());
215+
unsigned FP = RegInfo->getFrameRegister(MF);
216+
217+
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
218+
219+
// Mark $fp as used if function has dedicated frame pointer.
220+
if (hasFP(MF))
221+
SavedRegs.set(FP);
222+
223+
// Set scavenging frame index if necessary.
224+
uint64_t MaxSPOffset = MFI.estimateStackSize(MF);
225+
226+
if (isInt<12>(MaxSPOffset))
227+
return;
228+
229+
const TargetRegisterClass &RC = Xtensa::ARRegClass;
230+
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
231+
unsigned Size = TRI->getSpillSize(RC);
232+
Align Alignment = TRI->getSpillAlign(RC);
233+
int FI = MF.getFrameInfo().CreateStackObject(Size, Alignment, false);
234+
RS->addScavengingFrameIndex(FI);
235+
}

llvm/lib/Target/Xtensa/XtensaFrameLowering.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,19 @@ class XtensaFrameLowering : public TargetFrameLowering {
2929
MachineBasicBlock::iterator
3030
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
3131
MachineBasicBlock::iterator I) const override;
32+
33+
bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
34+
MachineBasicBlock::iterator MI,
35+
ArrayRef<CalleeSavedInfo> CSI,
36+
const TargetRegisterInfo *TRI) const override;
37+
bool
38+
restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
39+
MachineBasicBlock::iterator MI,
40+
MutableArrayRef<CalleeSavedInfo> CSI,
41+
const TargetRegisterInfo *TRI) const override;
42+
43+
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
44+
RegScavenger *RS) const override;
3245
};
3346

3447
} // 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+
unsigned SP = Xtensa::SP;
546+
return DAG.getCopyFromReg(Op.getOperand(0), SDLoc(Op), SP, Op.getValueType());
547+
}
548+
549+
SDValue XtensaTargetLowering::LowerSTACKRESTORE(SDValue Op,
550+
SelectionDAG &DAG) const {
551+
unsigned SP = Xtensa::SP;
552+
return DAG.getCopyToReg(Op.getOperand(0), SDLoc(Op), SP, 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 =
566+
DAG.getNode(ISD::AND, DL, VT, SizeTmp, 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;

llvm/test/CodeGen/Xtensa/call.ll

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ declare i32 @external_function(i32)
55
define i32 @test_call_external(i32 %a) nounwind {
66
; CHECK-LABEL: test_call_external:
77
; CHECK: # %bb.0:
8-
; CHECK-NEXT: s32i a0, a1, 0
8+
; CHECK: s32i a0, a1, 0
99
; CHECK-NEXT: l32r a8, .LCPI0_0
1010
; CHECK-NEXT: callx0 a8
1111
; CHECK-NEXT: l32i a0, a1, 0
12-
; CHECK-NEXT: ret
12+
; CHECK: ret
1313
%1 = call i32 @external_function(i32 %a)
1414
ret i32 %1
1515
}
@@ -26,24 +26,24 @@ define i32 @defined_function(i32 %a) nounwind {
2626
define i32 @test_call_defined(i32 %a) nounwind {
2727
; CHECK-LABEL: test_call_defined:
2828
; CHECK: # %bb.0:
29-
; CHECK-NEXT: s32i a0, a1, 0
29+
; CHECK: s32i a0, a1, 0
3030
; CHECK-NEXT: l32r a8, .LCPI2_0
3131
; CHECK-NEXT: callx0 a8
3232
; CHECK-NEXT: l32i a0, a1, 0
33-
; CHECK-NEXT: ret
33+
; CHECK: ret
3434
%1 = call i32 @defined_function(i32 %a) nounwind
3535
ret i32 %1
3636
}
3737

3838
define i32 @test_call_indirect(ptr %a, i32 %b) nounwind {
3939
; CHECK-LABEL: test_call_indirect:
4040
; CHECK: # %bb.0:
41-
; CHECK-NEXT: s32i a0, a1, 0
41+
; CHECK: s32i a0, a1, 0
4242
; CHECK-NEXT: or a8, a2, a2
4343
; CHECK-NEXT: or a2, a3, a3
4444
; CHECK-NEXT: callx0 a8
4545
; CHECK-NEXT: l32i a0, a1, 0
46-
; CHECK-NEXT: ret
46+
; CHECK: ret
4747
%1 = call i32 %a(i32 %b)
4848
ret i32 %1
4949
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
; RUN: llc -mtriple=xtensa -disable-block-placement -verify-machineinstrs < %s \
2+
; RUN: | FileCheck %s
3+
4+
define ptr @test_simple_alloca(i32 %numelts) {
5+
; CHECK-LABEL: test_simple_alloca
6+
; CHECK: addi a8, a1, -16
7+
; CHECK: or a1, a8, a8
8+
; CHECK: s32i a15, a1, 0
9+
; CHECK: or a15, a1, a1
10+
; CHECK: addi a8, a2, 3
11+
; CHECK-NEXT: movi a9, -4
12+
; CHECK-NEXT: and a8, a8, a9
13+
; CHECK-NEXT: addi a8, a8, 31
14+
; CHECK-NEXT: movi a9, -32
15+
; CHECK-NEXT: and a8, a8, a9
16+
; CHECK-NEXT: sub a1, a1, a8
17+
; CHECK-NEXT: or a2, a1, a1
18+
; CHECK-NEXT: or a1, a15, a15
19+
; CHECK-NEXT: l32i a15, a1, 0
20+
; CHECK-NEXT: addi a8, a1, 16
21+
; CHECK-NEXT: or a1, a8, a8
22+
; CHECK-NEXT: ret
23+
24+
%addr = alloca i8, i32 %numelts
25+
ret ptr %addr
26+
}

0 commit comments

Comments
 (0)