aboutsummaryrefslogtreecommitdiff
path: root/llvm
diff options
context:
space:
mode:
authorAndrei Safronov <safronov@espressif.com>2024-06-04 17:44:59 +0300
committerGitHub <noreply@github.com>2024-06-04 16:44:59 +0200
commit78f5d9cdbad2ad6c9857e0ceed99c7c3a40d16d2 (patch)
tree6e678aa92c02b145b366b735a04fd6edea41f43a /llvm
parent8917739b4cb39e6cd2355672ff6e2c140b19aafd (diff)
downloadllvm-78f5d9cdbad2ad6c9857e0ceed99c7c3a40d16d2.zip
llvm-78f5d9cdbad2ad6c9857e0ceed99c7c3a40d16d2.tar.gz
llvm-78f5d9cdbad2ad6c9857e0ceed99c7c3a40d16d2.tar.bz2
[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.
Diffstat (limited to 'llvm')
-rw-r--r--llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp227
-rw-r--r--llvm/lib/Target/Xtensa/XtensaFrameLowering.h24
-rw-r--r--llvm/lib/Target/Xtensa/XtensaISelLowering.cpp49
-rw-r--r--llvm/lib/Target/Xtensa/XtensaISelLowering.h6
-rw-r--r--llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp24
-rw-r--r--llvm/lib/Target/Xtensa/XtensaInstrInfo.h6
-rw-r--r--llvm/lib/Target/Xtensa/XtensaSubtarget.cpp2
-rw-r--r--llvm/test/CodeGen/Xtensa/call.ll12
-rw-r--r--llvm/test/CodeGen/Xtensa/dynamic-alloc.ll26
-rw-r--r--llvm/test/CodeGen/Xtensa/saverestore.ll42
10 files changed, 404 insertions, 14 deletions
diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
index ab37c09..71b1bb6 100644
--- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
@@ -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();
@@ -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(
@@ -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);
+}
diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.h b/llvm/lib/Target/Xtensa/XtensaFrameLowering.h
index 2da88ab1..31c496d 100644
--- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.h
+++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.h
@@ -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;
@@ -29,6 +35,22 @@ public:
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
diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
index 64b996b..6c3258b 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
@@ -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());
}
@@ -534,6 +540,43 @@ 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()) {
@@ -541,6 +584,12 @@ SDValue XtensaTargetLowering::LowerOperation(SDValue Op,
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");
}
diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h
index 077559e..6f6ec39 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h
+++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h
@@ -75,6 +75,12 @@ private:
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;
diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp
index 26d8727..27e1985 100644
--- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp
@@ -48,6 +48,30 @@ XtensaInstrInfo::XtensaInstrInfo(const XtensaSubtarget &STI)
: XtensaGenInstrInfo(Xtensa::ADJCALLSTACKDOWN, Xtensa::ADJCALLSTACKUP),
RI(STI), STI(STI) {}
+Register XtensaInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
+ int &FrameIndex) const {
+ if (MI.getOpcode() == Xtensa::L32I) {
+ if (MI.getOperand(1).isFI() && MI.getOperand(2).isImm() &&
+ MI.getOperand(2).getImm() == 0) {
+ FrameIndex = MI.getOperand(1).getIndex();
+ return MI.getOperand(0).getReg();
+ }
+ }
+ return Register();
+}
+
+Register XtensaInstrInfo::isStoreToStackSlot(const MachineInstr &MI,
+ int &FrameIndex) const {
+ if (MI.getOpcode() == Xtensa::S32I) {
+ if (MI.getOperand(1).isFI() && MI.getOperand(2).isImm() &&
+ MI.getOperand(2).getImm() == 0) {
+ FrameIndex = MI.getOperand(1).getIndex();
+ return MI.getOperand(0).getReg();
+ }
+ }
+ return Register();
+}
+
/// Adjust SP by Amount bytes.
void XtensaInstrInfo::adjustStackPtr(unsigned SP, int64_t Amount,
MachineBasicBlock &MBB,
diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.h b/llvm/lib/Target/Xtensa/XtensaInstrInfo.h
index 1acd314..37f157f 100644
--- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.h
+++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.h
@@ -41,6 +41,12 @@ public:
// Return the XtensaRegisterInfo, which this class owns.
const XtensaRegisterInfo &getRegisterInfo() const { return RI; }
+ Register isLoadFromStackSlot(const MachineInstr &MI,
+ int &FrameIndex) const override;
+
+ Register isStoreToStackSlot(const MachineInstr &MI,
+ int &FrameIndex) const override;
+
void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
const DebugLoc &DL, MCRegister DestReg, MCRegister SrcReg,
bool KillSrc) const override;
diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp
index 10ab92d..d6b1b4b 100644
--- a/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.cpp
@@ -41,4 +41,4 @@ XtensaSubtarget::XtensaSubtarget(const Triple &TT, StringRef CPU, StringRef FS,
const TargetMachine &TM)
: XtensaGenSubtargetInfo(TT, CPU, /*TuneCPU=*/CPU, FS), TargetTriple(TT),
InstrInfo(initializeSubtargetDependencies(CPU, FS)), TLInfo(TM, *this),
- TSInfo(), FrameLowering() {}
+ TSInfo(), FrameLowering(*this) {}
diff --git a/llvm/test/CodeGen/Xtensa/call.ll b/llvm/test/CodeGen/Xtensa/call.ll
index 24c7c4f..921f89a 100644
--- a/llvm/test/CodeGen/Xtensa/call.ll
+++ b/llvm/test/CodeGen/Xtensa/call.ll
@@ -5,11 +5,11 @@ declare i32 @external_function(i32)
define i32 @test_call_external(i32 %a) nounwind {
; CHECK-LABEL: test_call_external:
; CHECK: # %bb.0:
-; CHECK-NEXT: s32i a0, a1, 0
+; CHECK: s32i a0, a1, 0
; CHECK-NEXT: l32r a8, .LCPI0_0
; CHECK-NEXT: callx0 a8
; CHECK-NEXT: l32i a0, a1, 0
-; CHECK-NEXT: ret
+; CHECK: ret
%1 = call i32 @external_function(i32 %a)
ret i32 %1
}
@@ -26,11 +26,11 @@ define i32 @defined_function(i32 %a) nounwind {
define i32 @test_call_defined(i32 %a) nounwind {
; CHECK-LABEL: test_call_defined:
; CHECK: # %bb.0:
-; CHECK-NEXT: s32i a0, a1, 0
+; CHECK: s32i a0, a1, 0
; CHECK-NEXT: l32r a8, .LCPI2_0
; CHECK-NEXT: callx0 a8
; CHECK-NEXT: l32i a0, a1, 0
-; CHECK-NEXT: ret
+; CHECK: ret
%1 = call i32 @defined_function(i32 %a) nounwind
ret i32 %1
}
@@ -38,12 +38,12 @@ define i32 @test_call_defined(i32 %a) nounwind {
define i32 @test_call_indirect(ptr %a, i32 %b) nounwind {
; CHECK-LABEL: test_call_indirect:
; CHECK: # %bb.0:
-; CHECK-NEXT: s32i a0, a1, 0
+; CHECK: s32i a0, a1, 0
; CHECK-NEXT: or a8, a2, a2
; CHECK-NEXT: or a2, a3, a3
; CHECK-NEXT: callx0 a8
; CHECK-NEXT: l32i a0, a1, 0
-; CHECK-NEXT: ret
+; CHECK: ret
%1 = call i32 %a(i32 %b)
ret i32 %1
}
diff --git a/llvm/test/CodeGen/Xtensa/dynamic-alloc.ll b/llvm/test/CodeGen/Xtensa/dynamic-alloc.ll
new file mode 100644
index 0000000..2b28f35
--- /dev/null
+++ b/llvm/test/CodeGen/Xtensa/dynamic-alloc.ll
@@ -0,0 +1,26 @@
+; RUN: llc -mtriple=xtensa -disable-block-placement -verify-machineinstrs < %s \
+; RUN: | FileCheck %s
+
+define ptr @test_simple_alloca(i32 %numelts) {
+; CHECK-LABEL: test_simple_alloca
+; CHECK: addi a8, a1, -16
+; CHECK: or a1, a8, a8
+; CHECK: s32i a15, a1, 0
+; CHECK: or a15, a1, a1
+; CHECK: addi a8, a2, 3
+; CHECK-NEXT: movi a9, -4
+; CHECK-NEXT: and a8, a8, a9
+; CHECK-NEXT: addi a8, a8, 31
+; CHECK-NEXT: movi a9, -32
+; CHECK-NEXT: and a8, a8, a9
+; CHECK-NEXT: sub a1, a1, a8
+; CHECK-NEXT: or a2, a1, a1
+; CHECK-NEXT: or a1, a15, a15
+; CHECK-NEXT: l32i a15, a1, 0
+; CHECK-NEXT: addi a8, a1, 16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: ret
+
+ %addr = alloca i8, i32 %numelts
+ ret ptr %addr
+}
diff --git a/llvm/test/CodeGen/Xtensa/saverestore.ll b/llvm/test/CodeGen/Xtensa/saverestore.ll
new file mode 100644
index 0000000..69c8b16
--- /dev/null
+++ b/llvm/test/CodeGen/Xtensa/saverestore.ll
@@ -0,0 +1,42 @@
+; RUN: llc --mtriple=xtensa < %s | FileCheck %s
+
+declare ptr @llvm.stacksave()
+
+declare void @llvm.stackrestore(ptr)
+
+declare void @use_addr(ptr)
+
+define void @test_saverestore(i64 %n) {
+; CHECK: # %bb.0:
+; CHECK-NEXT: addi a8, a1, -16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK: s32i a0, a1, 8
+; CHECK-NEXT: s32i a12, a1, 4
+; CHECK-NEXT: s32i a15, a1, 0
+; CHECK: or a15, a1, a1
+; CHECK: addi a8, a2, 3
+; CHECK-NEXT: movi a9, -4
+; CHECK-NEXT: and a8, a8, a9
+; CHECK-NEXT: addi a8, a8, 31
+; CHECK-NEXT: movi a9, -32
+; CHECK-NEXT: and a8, a8, a9
+; CHECK-NEXT: or a12, a1, a1
+; CHECK-NEXT: sub a1, a1, a8
+; CHECK-NEXT: or a2, a1, a1
+; CHECK-NEXT: l32r a8, .LCPI0_0
+; CHECK-NEXT: callx0 a8
+; CHECK-NEXT: or a1, a12, a12
+; CHECK-NEXT: or a1, a15, a15
+; CHECK-NEXT: l32i a15, a1, 0
+; CHECK-NEXT: l32i a12, a1, 4
+; CHECK-NEXT: l32i a0, a1, 8
+; CHECK-NEXT: addi a8, a1, 16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: ret
+
+ %sp = call ptr @llvm.stacksave.p0()
+ %addr = alloca i8, i64 %n
+ call void @use_addr(ptr %addr)
+ call void @llvm.stackrestore.p0(ptr %sp)
+ ret void
+}