Skip to content

[PATCH] [Xtensa] Implement FrameLowering methods and stack operation lowering. #92960

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
227 changes: 221 additions & 6 deletions llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@

using namespace llvm;

XtensaFrameLowering::XtensaFrameLowering()
XtensaFrameLowering::XtensaFrameLowering(const XtensaSubtarget &STI)
: TargetFrameLowering(TargetFrameLowering::StackGrowsDown, Align(4), 0,
Align(4)) {}
Align(4)),
STI(STI), TII(*STI.getInstrInfo()), TRI(STI.getRegisterInfo()) {}

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

void XtensaFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {}
MachineBasicBlock &MBB) const {
assert(&MBB == &MF.front() && "Shrink-wrapping not yet implemented");
MachineFrameInfo &MFI = MF.getFrameInfo();
MachineBasicBlock::iterator MBBI = MBB.begin();
DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
MCRegister SP = Xtensa::SP;
MCRegister FP = TRI->getFrameRegister(MF);
MachineModuleInfo &MMI = MF.getMMI();
const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo();

// First, compute final stack size.
uint64_t StackSize = MFI.getStackSize();
uint64_t PrevStackSize = StackSize;

// Round up StackSize to 16*N
StackSize += (16 - StackSize) & 0xf;

// No need to allocate space on the stack.
if (StackSize == 0 && !MFI.adjustsStack())
return;

// Adjust stack.
TII.adjustStackPtr(SP, -StackSize, MBB, MBBI);

// emit ".cfi_def_cfa_offset StackSize"
unsigned CFIIndex =
MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize));
BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);

const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();

if (!CSI.empty()) {
// Find the instruction past the last instruction that saves a
// callee-saved register to the stack. The callee-saved store
// instructions are placed at the begin of basic block, so
// iterate over instruction sequence and check that
// save instructions are placed correctly.
for (unsigned i = 0, e = CSI.size(); i < e; ++i) {
#ifndef NDEBUG
const CalleeSavedInfo &Info = CSI[i];
int FI = Info.getFrameIdx();
int StoreFI = 0;

// Checking that the instruction is exactly as expected
bool IsStoreInst = false;
if (MBBI->getOpcode() == TargetOpcode::COPY && Info.isSpilledToReg()) {
Register DstReg = MBBI->getOperand(0).getReg();
Register Reg = MBBI->getOperand(1).getReg();
IsStoreInst = (Info.getDstReg() == DstReg) && (Info.getReg() == Reg);
} else {
Register Reg = TII.isStoreToStackSlot(*MBBI, StoreFI);
IsStoreInst = (Reg == Info.getReg()) && (StoreFI == FI);
}
assert(IsStoreInst &&
"Unexpected callee-saved register store instruction");
#endif
++MBBI;
}

// Iterate over list of callee-saved registers and emit .cfi_offset
// directives.
for (const auto &I : CSI) {
int64_t Offset = MFI.getObjectOffset(I.getFrameIdx());
Register Reg = I.getReg();

unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, MRI->getDwarfRegNum(Reg, 1), Offset));
BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
}
}

// if framepointer enabled, set it to point to the stack pointer.
if (hasFP(MF)) {
// Insert instruction "move $fp, $sp" at this location.
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::OR), FP)
.addReg(SP)
.addReg(SP)
.setMIFlag(MachineInstr::FrameSetup);

// emit ".cfi_def_cfa_register $fp"
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfaRegister(
nullptr, MRI->getDwarfRegNum(FP, true)));
BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
}

if (StackSize != PrevStackSize) {
MFI.setStackSize(StackSize);

for (int i = MFI.getObjectIndexBegin(); i < MFI.getObjectIndexEnd(); i++) {
if (!MFI.isDeadObjectIndex(i)) {
int64_t SPOffset = MFI.getObjectOffset(i);

if (SPOffset < 0)
MFI.setObjectOffset(i, SPOffset - StackSize + PrevStackSize);
}
}
}
}

void XtensaFrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {}
MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
MachineFrameInfo &MFI = MF.getFrameInfo();
DebugLoc DL = MBBI->getDebugLoc();
MCRegister SP = Xtensa::SP;
MCRegister FP = TRI->getFrameRegister(MF);

// if framepointer enabled, restore the stack pointer.
if (hasFP(MF)) {
// We should place restore stack pointer instruction just before
// sequence of instructions which restores callee-saved registers.
// This sequence is placed at the end of the basic block,
// so we should find first instruction of the sequence.
MachineBasicBlock::iterator I = MBBI;

const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();

// Find the first instruction at the end that restores a callee-saved
// register.
for (unsigned i = 0, e = CSI.size(); i < e; ++i) {
--I;
#ifndef NDEBUG
const CalleeSavedInfo &Info = CSI[i];
int FI = Info.getFrameIdx();
int LoadFI = 0;

// Checking that the instruction is exactly as expected
bool IsRestoreInst = false;
if (I->getOpcode() == TargetOpcode::COPY && Info.isSpilledToReg()) {
Register Reg = I->getOperand(0).getReg();
Register DstReg = I->getOperand(1).getReg();
IsRestoreInst = (Info.getDstReg() == DstReg) && (Info.getReg() == Reg);
} else {
Register Reg = TII.isLoadFromStackSlot(*I, LoadFI);
IsRestoreInst = (Info.getReg() == Reg) && (LoadFI == FI);
}
assert(IsRestoreInst &&
"Unexpected callee-saved register restore instruction");
#endif
}

BuildMI(MBB, I, DL, TII.get(Xtensa::OR), SP).addReg(FP).addReg(FP);
}

// Get the number of bytes from FrameInfo
uint64_t StackSize = MFI.getStackSize();

if (!StackSize)
return;

// Adjust stack.
TII.adjustStackPtr(SP, StackSize, MBB, MBBI);
}

bool XtensaFrameLowering::spillCalleeSavedRegisters(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
MachineFunction *MF = MBB.getParent();
MachineBasicBlock &EntryBlock = *(MF->begin());

for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
// Add the callee-saved register as live-in. Do not add if the register is
// A0 and return address is taken, because it will be implemented in
// method XtensaTargetLowering::LowerRETURNADDR.
// It's killed at the spill, unless the register is RA and return address
// is taken.
Register Reg = CSI[i].getReg();
bool IsA0AndRetAddrIsTaken =
(Reg == Xtensa::A0) && MF->getFrameInfo().isReturnAddressTaken();
if (!IsA0AndRetAddrIsTaken)
EntryBlock.addLiveIn(Reg);

// Insert the spill to the stack frame.
bool IsKill = !IsA0AndRetAddrIsTaken;
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
TII.storeRegToStackSlot(EntryBlock, MI, Reg, IsKill, CSI[i].getFrameIdx(),
RC, TRI, Register());
}

return true;
}

bool XtensaFrameLowering::restoreCalleeSavedRegisters(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
return TargetFrameLowering::restoreCalleeSavedRegisters(MBB, MI, CSI, TRI);
}

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

unsigned SP = Xtensa::SP;
TII.adjustStackPtr(SP, Amount, MBB, I);
TII.adjustStackPtr(Xtensa::SP, Amount, MBB, I);
}

return MBB.erase(I);
}

void XtensaFrameLowering::determineCalleeSaves(MachineFunction &MF,
BitVector &SavedRegs,
RegScavenger *RS) const {
unsigned FP = TRI->getFrameRegister(MF);

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

// Mark $fp as used if function has dedicated frame pointer.
if (hasFP(MF))
SavedRegs.set(FP);
}

void XtensaFrameLowering::processFunctionBeforeFrameFinalized(
MachineFunction &MF, RegScavenger *RS) const {
// Set scavenging frame index if necessary.
MachineFrameInfo &MFI = MF.getFrameInfo();
uint64_t MaxSPOffset = MFI.estimateStackSize(MF);

if (isInt<12>(MaxSPOffset))
return;

const TargetRegisterClass &RC = Xtensa::ARRegClass;
unsigned Size = TRI->getSpillSize(RC);
Align Alignment = TRI->getSpillAlign(RC);
int FI = MF.getFrameInfo().CreateStackObject(Size, Alignment, false);

RS->addScavengingFrameIndex(FI);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure it's safe to do this in determineCalleeSaves. Can you create the emergency scavenging index in processFunctionBeforeFrameFinalized instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved frame index scavenging to processFunctionBeforeFrameFinalized

}
24 changes: 23 additions & 1 deletion llvm/lib/Target/Xtensa/XtensaFrameLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,16 @@
namespace llvm {
class XtensaTargetMachine;
class XtensaSubtarget;
class XtensaInstrInfo;
class XtensaRegisterInfo;

class XtensaFrameLowering : public TargetFrameLowering {
const XtensaSubtarget &STI;
const XtensaInstrInfo &TII;
const XtensaRegisterInfo *TRI;

public:
XtensaFrameLowering();
XtensaFrameLowering(const XtensaSubtarget &STI);

bool hasFP(const MachineFunction &MF) const override;

Expand All @@ -29,6 +35,22 @@ class XtensaFrameLowering : public TargetFrameLowering {
MachineBasicBlock::iterator
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const override;

bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
ArrayRef<CalleeSavedInfo> CSI,
const TargetRegisterInfo *TRI) const override;
bool
restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
MutableArrayRef<CalleeSavedInfo> CSI,
const TargetRegisterInfo *TRI) const override;

void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
RegScavenger *RS) const override;

void processFunctionBeforeFrameFinalized(MachineFunction &MF,
RegScavenger *RS) const override;
};

} // namespace llvm
Expand Down
49 changes: 49 additions & 0 deletions llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,

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

// Implement custom stack allocations
setOperationAction(ISD::DYNAMIC_STACKALLOC, PtrVT, Custom);
// Implement custom stack save and restore
setOperationAction(ISD::STACKSAVE, MVT::Other, Custom);
setOperationAction(ISD::STACKRESTORE, MVT::Other, Custom);

// Compute derived properties from the register classes
computeRegisterProperties(STI.getRegisterInfo());
}
Expand Down Expand Up @@ -534,13 +540,56 @@ SDValue XtensaTargetLowering::LowerConstantPool(ConstantPoolSDNode *CP,
return getAddrPCRel(Result, DAG);
}

SDValue XtensaTargetLowering::LowerSTACKSAVE(SDValue Op,
SelectionDAG &DAG) const {
return DAG.getCopyFromReg(Op.getOperand(0), SDLoc(Op), Xtensa::SP,
Op.getValueType());
}

SDValue XtensaTargetLowering::LowerSTACKRESTORE(SDValue Op,
SelectionDAG &DAG) const {
return DAG.getCopyToReg(Op.getOperand(0), SDLoc(Op), Xtensa::SP,
Op.getOperand(1));
}

SDValue XtensaTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
SelectionDAG &DAG) const {
SDValue Chain = Op.getOperand(0); // Legalize the chain.
SDValue Size = Op.getOperand(1); // Legalize the size.
EVT VT = Size->getValueType(0);
SDLoc DL(Op);

// Round up Size to 32
SDValue SizeTmp =
DAG.getNode(ISD::ADD, DL, VT, Size, DAG.getConstant(31, DL, MVT::i32));
SDValue SizeRoundUp = DAG.getNode(ISD::AND, DL, VT, SizeTmp,
DAG.getConstant(~31, DL, MVT::i32));

unsigned SPReg = Xtensa::SP;
SDValue SP = DAG.getCopyFromReg(Chain, DL, SPReg, VT);
SDValue NewSP = DAG.getNode(ISD::SUB, DL, VT, SP, SizeRoundUp); // Value
Chain = DAG.getCopyToReg(SP.getValue(1), DL, SPReg, NewSP); // Output chain

SDValue NewVal = DAG.getCopyFromReg(Chain, DL, SPReg, MVT::i32);
Chain = NewVal.getValue(1);

SDValue Ops[2] = {NewVal, Chain};
return DAG.getMergeValues(Ops, DL);
}

SDValue XtensaTargetLowering::LowerOperation(SDValue Op,
SelectionDAG &DAG) const {
switch (Op.getOpcode()) {
case ISD::Constant:
return LowerImmediate(Op, DAG);
case ISD::ConstantPool:
return LowerConstantPool(cast<ConstantPoolSDNode>(Op), DAG);
case ISD::STACKSAVE:
return LowerSTACKSAVE(Op, DAG);
case ISD::STACKRESTORE:
return LowerSTACKRESTORE(Op, DAG);
case ISD::DYNAMIC_STACKALLOC:
return LowerDYNAMIC_STACKALLOC(Op, DAG);
default:
report_fatal_error("Unexpected node to lower");
}
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/Target/Xtensa/XtensaISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ class XtensaTargetLowering : public TargetLowering {

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

SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;

SDValue LowerSTACKSAVE(SDValue Op, SelectionDAG &DAG) const;

SDValue LowerSTACKRESTORE(SDValue Op, SelectionDAG &DAG) const;

SDValue getAddrPCRel(SDValue Op, SelectionDAG &DAG) const;

CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool IsVarArg) const;
Expand Down
Loading
Loading