[llvm] Xtensa] Implement windowed call ABI. (PR #130001)
Andrei Safronov via llvm-commits
llvm-commits at lists.llvm.org
Tue Mar 18 02:17:42 PDT 2025
https://github.com/andreisfr updated https://github.com/llvm/llvm-project/pull/130001
>From 20df35c34e0764cf57d7844acee5e99301d2da72 Mon Sep 17 00:00:00 2001
From: Andrei Safronov <safronov at espressif.com>
Date: Thu, 6 Mar 2025 10:27:25 +0300
Subject: [PATCH 1/6] [Xtensa] Implement windowed call ABI.
Implement base windowed call ABI. By defaullt use
rotation window by 8 registers.
---
llvm/lib/Target/Xtensa/XtensaCallingConv.td | 20 +++-
.../lib/Target/Xtensa/XtensaFrameLowering.cpp | 112 +++++++++++++++++-
llvm/lib/Target/Xtensa/XtensaFrameLowering.h | 1 +
llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 47 +++++++-
llvm/lib/Target/Xtensa/XtensaISelLowering.h | 5 +
llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp | 4 +
llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 19 ++-
.../Target/Xtensa/XtensaMachineFunctionInfo.h | 4 +
llvm/lib/Target/Xtensa/XtensaOperators.td | 11 ++
llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp | 13 +-
llvm/lib/Target/Xtensa/XtensaSubtarget.h | 12 +-
llvm/test/CodeGen/Xtensa/aligned_alloc.ll | 32 +++++
.../CodeGen/Xtensa/calling-conv-windowed.ll | 103 ++++++++++++++++
llvm/test/CodeGen/Xtensa/callw.ll | 52 ++++++++
14 files changed, 413 insertions(+), 22 deletions(-)
create mode 100644 llvm/test/CodeGen/Xtensa/aligned_alloc.ll
create mode 100644 llvm/test/CodeGen/Xtensa/calling-conv-windowed.ll
create mode 100644 llvm/test/CodeGen/Xtensa/callw.ll
diff --git a/llvm/lib/Target/Xtensa/XtensaCallingConv.td b/llvm/lib/Target/Xtensa/XtensaCallingConv.td
index a348b4c890b22..092c50947cee8 100644
--- a/llvm/lib/Target/Xtensa/XtensaCallingConv.td
+++ b/llvm/lib/Target/Xtensa/XtensaCallingConv.td
@@ -9,16 +9,30 @@
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
-// Xtensa return value calling convention
+// Xtensa base calling convention
//===----------------------------------------------------------------------===//
+// Xtensa return value
def RetCC_Xtensa : CallingConv<[
// First two return values go in a2, a3, a4, a5
CCIfType<[i32], CCAssignToReg<[A2, A3, A4, A5]>>,
CCIfType<[i64], CCAssignToRegWithShadow<[A2, A4], [A3, A5]>>
]>;
+// Callee-saved register lists
+def CSR_Xtensa : CalleeSavedRegs<(add A0, A12, A13, A14, A15)>;
+
//===----------------------------------------------------------------------===//
-// Callee-saved register lists.
+// Xtensa windowed calling convention. Currently by default implemented
+// rotation window by 8 registers.
//===----------------------------------------------------------------------===//
+// Xtensa return value for 8 registers window
+def RetCCW8_Xtensa : CallingConv<[
+ //First two return values go in a10, a11, a12, a13
+ CCIfType<[i32], CCAssignToReg<[A10, A11, A12, A13]>>,
+ CCIfType<[i64], CCAssignToRegWithShadow<[A10, A12], [A11, A13]>>
+]>;
-def CSR_Xtensa : CalleeSavedRegs<(add A0, A12, A13, A14, A15)>;
+// Callee-saved register lists for rotation window by 8 registers
+def CSRW8_Xtensa : CalleeSavedRegs<(add)> {
+ let OtherPreserved = (add A0, SP, A2, A3, A4, A5, A6, A7);
+}
\ No newline at end of file
diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
index d09aac613f623..338a2bc958498 100644
--- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
@@ -23,9 +23,15 @@
using namespace llvm;
+/* minimum frame = reg save area (4 words) plus static chain (1 word)
+ and the total number of words must be a multiple of 128 bits. */
+/* Width of a word, in units (bytes). */
+#define UNITS_PER_WORD 4
+#define MIN_FRAME_SIZE (8 * UNITS_PER_WORD)
+
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::hasFPImpl(const MachineFunction &MF) const {
@@ -43,6 +49,7 @@ void XtensaFrameLowering::emitPrologue(MachineFunction &MF,
MCRegister SP = Xtensa::SP;
MCRegister FP = TRI->getFrameRegister(MF);
const MCRegisterInfo *MRI = MF.getContext().getRegisterInfo();
+ XtensaMachineFunctionInfo *XtensaFI = MF.getInfo<XtensaMachineFunctionInfo>();
// First, compute final stack size.
uint64_t StackSize = MFI.getStackSize();
@@ -51,6 +58,83 @@ void XtensaFrameLowering::emitPrologue(MachineFunction &MF,
// Round up StackSize to 16*N
StackSize += (16 - StackSize) & 0xf;
+ if (STI.isWinABI()) {
+ StackSize += 32;
+ uint64_t MaxAlignment = MFI.getMaxAlign().value();
+ if(MaxAlignment > 32)
+ StackSize += MaxAlignment;
+
+ if (StackSize <= 32760) {
+ BuildMI(MBB, MBBI, DL, TII.get(Xtensa::ENTRY))
+ .addReg(SP)
+ .addImm(StackSize);
+ } else {
+ /* Use a8 as a temporary since a0-a7 may be live. */
+ unsigned TmpReg = Xtensa::A8;
+
+ const XtensaInstrInfo &TII = *static_cast<const XtensaInstrInfo *>(
+ MBB.getParent()->getSubtarget().getInstrInfo());
+ BuildMI(MBB, MBBI, DL, TII.get(Xtensa::ENTRY))
+ .addReg(SP)
+ .addImm(MIN_FRAME_SIZE);
+ TII.loadImmediate(MBB, MBBI, &TmpReg, StackSize - MIN_FRAME_SIZE);
+ BuildMI(MBB, MBBI, DL, TII.get(Xtensa::SUB), TmpReg)
+ .addReg(SP)
+ .addReg(TmpReg);
+ BuildMI(MBB, MBBI, DL, TII.get(Xtensa::MOVSP), SP).addReg(TmpReg);
+ }
+
+ // Calculate how much is needed to have the correct alignment.
+ // Change offset to: alignment + difference.
+ // For example, in case of alignment of 128:
+ // diff_to_128_aligned_address = (128 - (SP & 127))
+ // new_offset = SP + diff_to_128_aligned_address
+ // This is safe to do because we increased the stack size by MaxAlignment.
+ unsigned Reg, RegMisAlign;
+ if (MaxAlignment > 32){
+ TII.loadImmediate(MBB, MBBI, &RegMisAlign, MaxAlignment - 1);
+ TII.loadImmediate(MBB, MBBI, &Reg, MaxAlignment);
+ BuildMI(MBB, MBBI, DL, TII.get(Xtensa::AND))
+ .addReg(RegMisAlign, RegState::Define)
+ .addReg(FP)
+ .addReg(RegMisAlign);
+ BuildMI(MBB, MBBI, DL, TII.get(Xtensa::SUB), RegMisAlign)
+ .addReg(Reg)
+ .addReg(RegMisAlign);
+ BuildMI(MBB, MBBI, DL, TII.get(Xtensa::ADD), SP)
+ .addReg(SP)
+ .addReg(RegMisAlign, RegState::Kill);
+ }
+
+ // Store FP register in A8, because FP may be used to pass function
+ // arguments
+ if (XtensaFI->isSaveFrameRegister()) {
+ BuildMI(MBB, MBBI, DL, TII.get(Xtensa::OR), Xtensa::A8)
+ .addReg(FP)
+ .addReg(FP);
+ }
+
+ // 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);
+
+ MCCFIInstruction Inst = MCCFIInstruction::cfiDefCfa(
+ nullptr, MRI->getDwarfRegNum(FP, true), StackSize);
+ unsigned CFIIndex = MF.addFrameInst(Inst);
+ BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
+ .addCFIIndex(CFIIndex);
+ } else {
+ // 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);
+ }
+ } else {
// No need to allocate space on the stack.
if (StackSize == 0 && !MFI.adjustsStack())
return;
@@ -122,6 +206,7 @@ void XtensaFrameLowering::emitPrologue(MachineFunction &MF,
BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
}
+ }
if (StackSize != PrevStackSize) {
MFI.setStackSize(StackSize);
@@ -179,10 +264,22 @@ void XtensaFrameLowering::emitEpilogue(MachineFunction &MF,
"Unexpected callee-saved register restore instruction");
#endif
}
-
- BuildMI(MBB, I, DL, TII.get(Xtensa::OR), SP).addReg(FP).addReg(FP);
+ if (STI.isWinABI()) {
+ // In most architectures, we need to explicitly restore the stack pointer
+ // before returning.
+ //
+ // For Xtensa Windowed Register option, it is not needed to explicitly
+ // restore the stack pointer. Reason being is that on function return,
+ // the window of the caller (including the old stack pointer) gets
+ // restored anyways.
+ } else {
+ BuildMI(MBB, I, DL, TII.get(Xtensa::OR), SP).addReg(FP).addReg(FP);
+ }
}
+ if (STI.isWinABI())
+ return;
+
// Get the number of bytes from FrameInfo
uint64_t StackSize = MFI.getStackSize();
@@ -199,6 +296,9 @@ bool XtensaFrameLowering::spillCalleeSavedRegisters(
MachineFunction *MF = MBB.getParent();
MachineBasicBlock &EntryBlock = *(MF->begin());
+ if (STI.isWinABI())
+ return true;
+
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
@@ -224,6 +324,8 @@ bool XtensaFrameLowering::spillCalleeSavedRegisters(
bool XtensaFrameLowering::restoreCalleeSavedRegisters(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
+ if (STI.isWinABI())
+ return true;
return TargetFrameLowering::restoreCalleeSavedRegisters(MBB, MI, CSI, TRI);
}
@@ -251,6 +353,10 @@ void XtensaFrameLowering::determineCalleeSaves(MachineFunction &MF,
RegScavenger *RS) const {
unsigned FP = TRI->getFrameRegister(MF);
+ if (STI.isWinABI()) {
+ return;
+ }
+
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
// Mark $fp as used if function has dedicated frame pointer.
diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.h b/llvm/lib/Target/Xtensa/XtensaFrameLowering.h
index 3f946e1ea730f..f0095b8774154 100644
--- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.h
+++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.h
@@ -18,6 +18,7 @@ class XtensaInstrInfo;
class XtensaRegisterInfo;
class XtensaFrameLowering : public TargetFrameLowering {
+ const XtensaSubtarget &STI;
const XtensaInstrInfo &TII;
const XtensaRegisterInfo *TRI;
diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
index 57f0cbbc36c24..75e8dad388d1e 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
@@ -42,6 +42,15 @@ static bool isLongCall(const char *str) {
return true;
}
+// The calling conventions in XtensaCallingConv.td are described in terms of the
+// callee's register window. This function translates registers to the
+// corresponding caller window %o register.
+static unsigned toCallerWindow(unsigned Reg) {
+ if (Reg >= Xtensa::A2 && Reg <= Xtensa::A7)
+ return Reg - Xtensa::A2 + Xtensa::A10;
+ return Reg;
+}
+
XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
const XtensaSubtarget &STI)
: TargetLowering(TM), Subtarget(STI) {
@@ -339,7 +348,18 @@ SDValue XtensaTargetLowering::LowerFormalArguments(
// Transform the arguments stored on
// physical registers into virtual ones
- Register Reg = MF.addLiveIn(VA.getLocReg(), &Xtensa::ARRegClass);
+ Register Reg = 0;
+ unsigned FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF);
+
+ // Argument passed in FrameReg in WinABI we save in A8 (in emitPrologue),
+ // so load argument from A8
+ if (Subtarget.isWinABI() && (VA.getLocReg() == FrameReg)) {
+ Reg = MF.addLiveIn(Xtensa::A8, &Xtensa::ARRegClass);
+ XtensaFI->setSaveFrameRegister();
+ } else {
+ Reg = MF.addLiveIn(VA.getLocReg(), &Xtensa::ARRegClass);
+ }
+
SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, RegVT);
// If this is an 8 or 16-bit value, it has been passed promoted
@@ -538,6 +558,8 @@ XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI,
SDValue Glue;
for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) {
unsigned Reg = RegsToPass[I].first;
+ if (Subtarget.isWinABI())
+ Reg = toCallerWindow(Reg);
Chain = DAG.getCopyToReg(Chain, DL, Reg, RegsToPass[I].second, Glue);
Glue = Chain.getValue(1);
}
@@ -587,6 +609,8 @@ XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI,
// known live into the call.
for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) {
unsigned Reg = RegsToPass[I].first;
+ if (Subtarget.isWinABI())
+ Reg = toCallerWindow(Reg);
Ops.push_back(DAG.getRegister(Reg, RegsToPass[I].second.getValueType()));
}
@@ -595,7 +619,8 @@ XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI,
Ops.push_back(Glue);
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
- Chain = DAG.getNode(XtensaISD::CALL, DL, NodeTys, Ops);
+ Chain = DAG.getNode(Subtarget.isWinABI() ? XtensaISD::CALLW8 : XtensaISD::CALL,
+ DL, NodeTys, Ops);
Glue = Chain.getValue(1);
// Mark the end of the call, which is glued to the call itself.
@@ -606,7 +631,8 @@ XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI,
// Assign locations to each value returned by this call.
SmallVector<CCValAssign, 16> RetLocs;
CCState RetCCInfo(CallConv, IsVarArg, MF, RetLocs, *DAG.getContext());
- RetCCInfo.AnalyzeCallResult(Ins, RetCC_Xtensa);
+ RetCCInfo.AnalyzeCallResult(Ins, Subtarget.isWinABI() ? RetCCW8_Xtensa
+ : RetCC_Xtensa);
// Copy all of the result registers out of their specified physreg.
for (unsigned I = 0, E = RetLocs.size(); I != E; ++I) {
@@ -648,7 +674,8 @@ XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
SDValue Glue;
// Quick exit for void returns
if (RetLocs.empty())
- return DAG.getNode(XtensaISD::RET, DL, MVT::Other, Chain);
+ return DAG.getNode(Subtarget.isWinABI() ? XtensaISD::RETW
+ : XtensaISD::RET, DL, MVT::Other, Chain);
// Copy the result values into the output registers.
SmallVector<SDValue, 4> RetOps;
@@ -672,7 +699,8 @@ XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
if (Glue.getNode())
RetOps.push_back(Glue);
- return DAG.getNode(XtensaISD::RET, DL, MVT::Other, RetOps);
+ return DAG.getNode(Subtarget.isWinABI() ? XtensaISD::RETW
+ : XtensaISD::RET, DL, MVT::Other, RetOps);
}
static unsigned getBranchOpcode(ISD::CondCode Cond) {
@@ -906,6 +934,9 @@ SDValue XtensaTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
unsigned SPReg = Xtensa::SP;
SDValue SP = DAG.getCopyFromReg(Chain, DL, SPReg, VT);
SDValue NewSP = DAG.getNode(ISD::SUB, DL, VT, SP, SizeRoundUp); // Value
+ if (Subtarget.isWinABI()) {
+ NewSP = DAG.getNode(XtensaISD::MOVSP, DL, MVT::i32, NewSP);
+ }
Chain = DAG.getCopyToReg(SP.getValue(1), DL, SPReg, NewSP); // Output chain
SDValue NewVal = DAG.getCopyFromReg(Chain, DL, SPReg, MVT::i32);
@@ -1230,12 +1261,18 @@ const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const {
return "XtensaISD::BR_JT";
case XtensaISD::CALL:
return "XtensaISD::CALL";
+ case XtensaISD::CALLW8:
+ return "XtensaISD::CALLW8";
case XtensaISD::EXTUI:
return "XtensaISD::EXTUI";
+ case XtensaISD::MOVSP:
+ return "XtensaISD::MOVSP";
case XtensaISD::PCREL_WRAPPER:
return "XtensaISD::PCREL_WRAPPER";
case XtensaISD::RET:
return "XtensaISD::RET";
+ case XtensaISD::RETW:
+ return "XtensaISD::RETW";
case XtensaISD::SELECT_CC:
return "XtensaISD::SELECT_CC";
case XtensaISD::SRCL:
diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h
index a959299d8ca6a..c7d4f41b1f08e 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h
+++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h
@@ -29,16 +29,21 @@ enum {
// is the target address. The arguments start at operand 2.
// There is an optional glue operand at the end.
CALL,
+ // Call with rotation window by 8 registers
+ CALLW8,
// Extract unsigned immediate. Operand 0 is value, operand 1
// is bit position of the field [0..31], operand 2 is bit size
// of the field [1..16]
EXTUI,
+ MOVSP,
+
// Wraps a TargetGlobalAddress that should be loaded using PC-relative
// accesses. Operand 0 is the address.
PCREL_WRAPPER,
RET,
+ RETW,
// Select with condition operator - This selects between a true value and
// a false value (ops #2 and #3) based on the boolean result of comparing
diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp
index da2883e1902ca..788dc992d1d4e 100644
--- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp
@@ -100,9 +100,13 @@ void XtensaInstrInfo::adjustStackPtr(unsigned SP, int64_t Amount,
.addReg(Reg1, RegState::Kill);
}
+ if (STI.isWinABI()) {
+ BuildMI(MBB, I, DL, get(Xtensa::MOVSP), SP).addReg(Reg, RegState::Kill);
+ } else {
BuildMI(MBB, I, DL, get(Xtensa::OR), SP)
.addReg(Reg, RegState::Kill)
.addReg(Reg, RegState::Kill);
+ }
}
void XtensaInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
index 1f397e3ecac35..b41c00738f763 100644
--- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
+++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
@@ -709,22 +709,35 @@ let isCall = 1, Defs = [A0] in {
}
}
+// Windowed call patterns. Currently rotation
+// window by 8 is implemented.
+def : Pat<(Xtensa_callw8 (i32 tglobaladdr:$dst)),
+ (CALL8 tglobaladdr:$dst)>;
+def : Pat<(Xtensa_callw8 (i32 texternalsym:$dst)),
+ (CALL8 texternalsym:$dst)>;
+def : Pat<(Xtensa_callw8 AR:$dst),
+ (CALLX8 AR:$dst)>;
+
def MOVSP : RRR_Inst<0x00, 0x00, 0x00, (outs AR:$t), (ins AR:$s),
- "movsp\t$t, $s", []>, Requires<[HasWindowed]> {
+ "movsp\t$t, $s",
+ [(set AR:$t, (Xtensa_movsp AR:$s))]>,
+ Requires<[HasWindowed]> {
let r = 0x01;
}
let isReturn = 1, isTerminator = 1,
isBarrier = 1, Uses = [A0] in {
def RETW_N : RRRN_Inst<0x0D, (outs), (ins),
- "retw.n", []>, Requires<[HasWindowed, HasDensity]> {
+ "retw.n", [(Xtensa_retw)]>,
+ Requires<[HasWindowed, HasDensity]> {
let r = 0x0F;
let s = 0;
let t = 1;
}
def RETW : CALLX_Inst<0x00, 0x00, 0x00, (outs), (ins),
- "retw", []>, Requires<[HasWindowed]> {
+ "retw", [(Xtensa_retw)]>,
+ Requires<[HasWindowed]> {
let m = 0x2;
let n = 0x1;
let s = 0;
diff --git a/llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.h b/llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.h
index c430562091ba7..bc051d9ca14fa 100644
--- a/llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.h
+++ b/llvm/lib/Target/Xtensa/XtensaMachineFunctionInfo.h
@@ -27,6 +27,7 @@ class XtensaMachineFunctionInfo : public MachineFunctionInfo {
unsigned VarArgsFirstGPR;
int VarArgsOnStackFrameIndex;
int VarArgsInRegsFrameIndex;
+ bool SaveFrameRegister = false;
public:
explicit XtensaMachineFunctionInfo(const Function &F,
@@ -50,6 +51,9 @@ class XtensaMachineFunctionInfo : public MachineFunctionInfo {
// Get and set the frame index of the first stack vararg.
int getVarArgsInRegsFrameIndex() const { return VarArgsInRegsFrameIndex; }
void setVarArgsInRegsFrameIndex(int FI) { VarArgsInRegsFrameIndex = FI; }
+
+ bool isSaveFrameRegister() const { return SaveFrameRegister; }
+ void setSaveFrameRegister() { SaveFrameRegister = true; }
};
} // namespace llvm
diff --git a/llvm/lib/Target/Xtensa/XtensaOperators.td b/llvm/lib/Target/Xtensa/XtensaOperators.td
index 3dd73b44f336a..1fe5c3f64b607 100644
--- a/llvm/lib/Target/Xtensa/XtensaOperators.td
+++ b/llvm/lib/Target/Xtensa/XtensaOperators.td
@@ -31,15 +31,23 @@ def SDT_XtensaSRC : SDTypeProfile<1, 3, [SDTCisVT<0, i32>, SDTCi
def SDT_XtensaEXTUI : SDTypeProfile<1, 3, [SDTCisVT<0, i32>, SDTCisVT<1, i32>,
SDTCisVT<2, i32>, SDTCisVT<3, i32>]>;
+def SDT_XtensaMOVSP : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, SDTCisVT<0, i32>]>;
+
//===----------------------------------------------------------------------===//
// Node definitions
//===----------------------------------------------------------------------===//
def Xtensa_call: SDNode<"XtensaISD::CALL", SDT_XtensaCall,
[SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, SDNPVariadic]>;
+def Xtensa_callw8: SDNode<"XtensaISD::CALLW8", SDT_XtensaCall,
+ [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, SDNPVariadic]>;
+
def Xtensa_ret: SDNode<"XtensaISD::RET", SDTNone,
[SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
+def Xtensa_retw: SDNode<"XtensaISD::RETW", SDTNone,
+ [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
+
def Xtensa_pcrel_wrapper: SDNode<"XtensaISD::PCREL_WRAPPER", SDT_XtensaWrapPtr, []>;
def Xtensa_callseq_start: SDNode<"ISD::CALLSEQ_START", SDT_XtensaCallSeqStart,
@@ -59,3 +67,6 @@ def Xtensa_srcl: SDNode<"XtensaISD::SRCL", SDT_XtensaSRC>;
def Xtensa_srcr: SDNode<"XtensaISD::SRCR", SDT_XtensaSRC>;
def Xtensa_extui: SDNode<"XtensaISD::EXTUI", SDT_XtensaEXTUI>;
+
+def Xtensa_movsp: SDNode<"XtensaISD::MOVSP", SDT_XtensaMOVSP,
+ [SDNPInGlue]>;
diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp
index 4a8bafc540df0..cd8bfa0d4d164 100644
--- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp
@@ -34,13 +34,19 @@ XtensaRegisterInfo::XtensaRegisterInfo(const XtensaSubtarget &STI)
const uint16_t *
XtensaRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
- return CSR_Xtensa_SaveList;
+ if (Subtarget.isWinABI())
+ return CSRW8_Xtensa_SaveList;
+ else
+ return CSR_Xtensa_SaveList;
}
const uint32_t *
XtensaRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
CallingConv::ID) const {
- return CSR_Xtensa_RegMask;
+ if (Subtarget.isWinABI())
+ return CSRW8_Xtensa_RegMask;
+ else
+ return CSR_Xtensa_RegMask;
}
BitVector XtensaRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
@@ -129,5 +135,6 @@ bool XtensaRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
Register XtensaRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
- return TFI->hasFP(MF) ? Xtensa::A15 : Xtensa::SP;
+ return TFI->hasFP(MF) ? (Subtarget.isWinABI() ? Xtensa::A7 : Xtensa::A15)
+ : Xtensa::SP;
}
diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.h b/llvm/lib/Target/Xtensa/XtensaSubtarget.h
index 770f73905b337..b537a72bfe407 100644
--- a/llvm/lib/Target/Xtensa/XtensaSubtarget.h
+++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.h
@@ -30,17 +30,17 @@ class StringRef;
class XtensaSubtarget : public XtensaGenSubtargetInfo {
private:
+// Bool members corresponding to the SubtargetFeatures defined in tablegen
+#define GET_SUBTARGETINFO_MACRO(ATTRIBUTE, DEFAULT, GETTER) \
+ bool ATTRIBUTE = DEFAULT;
+#include "XtensaGenSubtargetInfo.inc"
+
const Triple &TargetTriple;
XtensaInstrInfo InstrInfo;
XtensaTargetLowering TLInfo;
SelectionDAGTargetInfo TSInfo;
XtensaFrameLowering FrameLowering;
-// Bool members corresponding to the SubtargetFeatures defined in tablegen
-#define GET_SUBTARGETINFO_MACRO(ATTRIBUTE, DEFAULT, GETTER) \
- bool ATTRIBUTE = DEFAULT;
-#include "XtensaGenSubtargetInfo.inc"
-
XtensaSubtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS);
public:
@@ -72,6 +72,8 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo {
bool hasBoolean() const { return HasBoolean; }
+ bool isWinABI() const { return hasWindowed(); }
+
// Automatically generated by tblgen.
void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS);
};
diff --git a/llvm/test/CodeGen/Xtensa/aligned_alloc.ll b/llvm/test/CodeGen/Xtensa/aligned_alloc.ll
new file mode 100644
index 0000000000000..ebb24d9272ddc
--- /dev/null
+++ b/llvm/test/CodeGen/Xtensa/aligned_alloc.ll
@@ -0,0 +1,32 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=xtensa -O0 -verify-machineinstrs < %s \
+; RUN: | FileCheck %s -check-prefix=XTENSA
+
+define i8 @loadi8_128(i8 %a) {
+; XTENSA-LABEL: loadi8_128:
+; XTENSA: .cfi_startproc
+; XTENSA-NEXT: # %bb.0:
+; XTENSA-NEXT: addi a8, a1, -128
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: .cfi_def_cfa_offset 128
+; XTENSA-NEXT: s32i a0, a1, 124 # 4-byte Folded Spill
+; XTENSA-NEXT: .cfi_offset a0, -4
+; XTENSA-NEXT: addi a2, a1, 0
+; XTENSA-NEXT: movi a3, 0
+; XTENSA-NEXT: movi a4, 64
+; XTENSA-NEXT: l32r a8, .LCPI0_0
+; XTENSA-NEXT: callx0 a8
+; XTENSA-NEXT: l8ui a2, a1, 0
+; XTENSA-NEXT: l32i a0, a1, 124 # 4-byte Folded Reload
+; XTENSA-NEXT: movi a8, 128
+; XTENSA-NEXT: add a8, a1, a8
+; XTENSA-NEXT: or a1, a8, a8
+; XTENSA-NEXT: ret
+ %aligned = alloca i8, align 128
+ call void @llvm.memset.p0.i64(ptr noundef nonnull align 64 dereferenceable(64) %aligned, i8 0, i64 64, i1 false)
+ %1 = load i8, ptr %aligned, align 128
+ ret i8 %1
+}
+
+; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write)
+declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg)
diff --git a/llvm/test/CodeGen/Xtensa/calling-conv-windowed.ll b/llvm/test/CodeGen/Xtensa/calling-conv-windowed.ll
new file mode 100644
index 0000000000000..27855b1cdf481
--- /dev/null
+++ b/llvm/test/CodeGen/Xtensa/calling-conv-windowed.ll
@@ -0,0 +1,103 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=xtensa -O1 -mattr=+windowed -verify-machineinstrs < %s \
+; RUN: | FileCheck %s -check-prefix=XTENSA
+
+; Check placement of first 6 arguments in registers and 7th argument on stack
+define dso_local i32 @test1(i32 noundef %0, i32 noundef %1, i32 noundef %2, i32 noundef %3, i32 noundef %4, i32 noundef %5, ptr nocapture noundef readonly byval(i32) align 4 %6) {
+; XTENSA-LABEL: test1:
+; XTENSA: .cfi_startproc
+; XTENSA-NEXT: # %bb.0:
+; XTENSA-NEXT: entry a1, 32
+; XTENSA-NEXT: .cfi_def_cfa_offset 32
+; XTENSA-NEXT: add a8, a7, a2
+; XTENSA-NEXT: l32i a9, a1, 32
+; XTENSA-NEXT: add a2, a8, a9
+; XTENSA-NEXT: retw
+ %8 = load i32, ptr %6, align 4
+ %9 = add nsw i32 %5, %0
+ %10 = add nsw i32 %9, %8
+ ret i32 %10
+}
+
+; Check placement of second i64 argument in registers
+define dso_local i32 @test2(i32 noundef %0, i64 noundef %1, i32 noundef %2) {
+; XTENSA-LABEL: test2:
+; XTENSA: .cfi_startproc
+; XTENSA-NEXT: # %bb.0:
+; XTENSA-NEXT: entry a1, 32
+; XTENSA-NEXT: .cfi_def_cfa_offset 32
+; XTENSA-NEXT: add a8, a6, a2
+; XTENSA-NEXT: add a2, a8, a4
+; XTENSA-NEXT: retw
+ %4 = trunc i64 %1 to i32
+ %5 = add nsw i32 %2, %0
+ %6 = add nsw i32 %5, %4
+ ret i32 %6
+}
+
+; Check placement of first argument typeof i8 in register
+define dso_local i32 @test3(i8 noundef signext %0, i64 noundef %1, i32 noundef %2) {
+; XTENSA-LABEL: test3:
+; XTENSA: .cfi_startproc
+; XTENSA-NEXT: # %bb.0:
+; XTENSA-NEXT: entry a1, 32
+; XTENSA-NEXT: .cfi_def_cfa_offset 32
+; XTENSA-NEXT: add a8, a2, a6
+; XTENSA-NEXT: add a2, a8, a4
+; XTENSA-NEXT: retw
+ %4 = trunc i64 %1 to i32
+ %5 = sext i8 %0 to i32
+ %6 = add nsw i32 %5, %2
+ %7 = add nsw i32 %6, %4
+ ret i32 %7
+}
+
+; Check placement of 4th argument typeof i64 on stack
+define dso_local i32 @test4(i8 noundef signext %0, i64 noundef %1, i32 noundef %2, ptr nocapture noundef readonly byval(i64) align 8 %3) {
+; XTENSA-LABEL: test4:
+; XTENSA: .cfi_startproc
+; XTENSA-NEXT: # %bb.0:
+; XTENSA-NEXT: entry a1, 32
+; XTENSA-NEXT: .cfi_def_cfa_offset 32
+; XTENSA-NEXT: add a8, a2, a6
+; XTENSA-NEXT: add a8, a8, a4
+; XTENSA-NEXT: l32i a9, a1, 32
+; XTENSA-NEXT: add a2, a8, a9
+; XTENSA-NEXT: retw
+ %5 = load i64, ptr %3, align 8
+ %6 = trunc i64 %1 to i32
+ %7 = trunc i64 %5 to i32
+ %8 = sext i8 %0 to i32
+ %9 = add nsw i32 %8, %2
+ %10 = add nsw i32 %9, %6
+ %11 = add nsw i32 %10, %7
+ ret i32 %11
+}
+
+; Check placement of 128 bit structure on registers
+define dso_local i32 @test5([4 x i32] %0, i32 noundef %1) {
+; XTENSA-LABEL: test5:
+; XTENSA: .cfi_startproc
+; XTENSA-NEXT: # %bb.0:
+; XTENSA-NEXT: entry a1, 32
+; XTENSA-NEXT: .cfi_def_cfa_offset 32
+; XTENSA-NEXT: add a2, a2, a6
+; XTENSA-NEXT: retw
+ %3 = extractvalue [4 x i32] %0, 0
+ %4 = add nsw i32 %3, %1
+ ret i32 %4
+}
+
+; Check placement of 128 bit structure on stack
+define dso_local i32 @test6(i32 noundef %0, [4 x i32] %1) {
+; XTENSA-LABEL: test6:
+; XTENSA: .cfi_startproc
+; XTENSA-NEXT: # %bb.0:
+; XTENSA-NEXT: entry a1, 32
+; XTENSA-NEXT: .cfi_def_cfa_offset 32
+; XTENSA-NEXT: add a2, a3, a2
+; XTENSA-NEXT: retw
+ %3 = extractvalue [4 x i32] %1, 0
+ %4 = add nsw i32 %3, %0
+ ret i32 %4
+}
diff --git a/llvm/test/CodeGen/Xtensa/callw.ll b/llvm/test/CodeGen/Xtensa/callw.ll
new file mode 100644
index 0000000000000..21549bcf22678
--- /dev/null
+++ b/llvm/test/CodeGen/Xtensa/callw.ll
@@ -0,0 +1,52 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc --mtriple=xtensa -mattr=+windowed < %s | FileCheck %s
+
+declare i32 @external_function(i32)
+
+define i32 @test_call_external(i32 %a) nounwind {
+; CHECK-LABEL: test_call_external:
+; CHECK: # %bb.0:
+; CHECK-NEXT: entry a1, 32
+; CHECK-NEXT: l32r a8, .LCPI0_0
+; CHECK-NEXT: or a10, a2, a2
+; CHECK-NEXT: callx8 a8
+; CHECK-NEXT: or a2, a10, a10
+; CHECK-NEXT: retw
+ %1 = call i32 @external_function(i32 %a)
+ ret i32 %1
+}
+
+define i32 @defined_function(i32 %a) nounwind {
+; CHECK-LABEL: defined_function:
+; CHECK: # %bb.0:
+; CHECK-NEXT: entry a1, 32
+; CHECK-NEXT: addi a2, a2, 1
+; CHECK-NEXT: retw
+ %1 = add i32 %a, 1
+ ret i32 %1
+}
+
+define i32 @test_call_defined(i32 %a) nounwind {
+; CHECK-LABEL: test_call_defined:
+; CHECK: # %bb.0:
+; CHECK-NEXT: entry a1, 32
+; CHECK-NEXT: l32r a8, .LCPI2_0
+; CHECK-NEXT: or a10, a2, a2
+; CHECK-NEXT: callx8 a8
+; CHECK-NEXT: or a2, a10, a10
+; CHECK-NEXT: retw
+ %1 = call i32 @defined_function(i32 %a) nounwind
+ ret i32 %1
+}
+
+define i32 @test_call_indirect(ptr %a, i32 %b) nounwind {
+; CHECK-LABEL: test_call_indirect:
+; CHECK: # %bb.0:
+; CHECK-NEXT: entry a1, 32
+; CHECK-NEXT: or a10, a3, a3
+; CHECK-NEXT: callx8 a2
+; CHECK-NEXT: or a2, a10, a10
+; CHECK-NEXT: retw
+ %1 = call i32 %a(i32 %b)
+ ret i32 %1
+}
>From 637c28726bebc95af652327abc82627934b3f178 Mon Sep 17 00:00:00 2001
From: Andrei Safronov <safronov at espressif.com>
Date: Wed, 12 Mar 2025 02:59:04 +0300
Subject: [PATCH 2/6] [Xtensa] Fix windowed call ABI.
Fixed windowed call ABI test. Code formatting and other minor fixes.
---
llvm/lib/Target/Xtensa/XtensaCallingConv.td | 2 +-
.../lib/Target/Xtensa/XtensaFrameLowering.cpp | 147 +++++++++---------
llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 31 ++--
llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp | 18 +--
llvm/lib/Target/Xtensa/XtensaInstrInfo.h | 4 +-
llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp | 17 +-
llvm/lib/Target/Xtensa/XtensaSubtarget.h | 2 +-
.../CodeGen/Xtensa/calling-conv-windowed.ll | 66 ++++----
8 files changed, 143 insertions(+), 144 deletions(-)
diff --git a/llvm/lib/Target/Xtensa/XtensaCallingConv.td b/llvm/lib/Target/Xtensa/XtensaCallingConv.td
index 092c50947cee8..2c48f8f86cafb 100644
--- a/llvm/lib/Target/Xtensa/XtensaCallingConv.td
+++ b/llvm/lib/Target/Xtensa/XtensaCallingConv.td
@@ -35,4 +35,4 @@ def RetCCW8_Xtensa : CallingConv<[
// Callee-saved register lists for rotation window by 8 registers
def CSRW8_Xtensa : CalleeSavedRegs<(add)> {
let OtherPreserved = (add A0, SP, A2, A3, A4, A5, A6, A7);
-}
\ No newline at end of file
+}
diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
index 338a2bc958498..44a240386511a 100644
--- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
@@ -23,9 +23,9 @@
using namespace llvm;
-/* minimum frame = reg save area (4 words) plus static chain (1 word)
- and the total number of words must be a multiple of 128 bits. */
-/* Width of a word, in units (bytes). */
+// Minimum frame = reg save area (4 words) plus static chain (1 word)
+// and the total number of words must be a multiple of 128 bits.
+// Width of a word, in units (bytes).
#define UNITS_PER_WORD 4
#define MIN_FRAME_SIZE (8 * UNITS_PER_WORD)
@@ -58,7 +58,7 @@ void XtensaFrameLowering::emitPrologue(MachineFunction &MF,
// Round up StackSize to 16*N
StackSize += (16 - StackSize) & 0xf;
- if (STI.isWinABI()) {
+ if (STI.isWindowedABI()) {
StackSize += 32;
uint64_t MaxAlignment = MFI.getMaxAlign().value();
if(MaxAlignment > 32)
@@ -69,8 +69,8 @@ void XtensaFrameLowering::emitPrologue(MachineFunction &MF,
.addReg(SP)
.addImm(StackSize);
} else {
- /* Use a8 as a temporary since a0-a7 may be live. */
- unsigned TmpReg = Xtensa::A8;
+ // Use a8 as a temporary since a0-a7 may be live.
+ MCRegister TmpReg = Xtensa::A8;
const XtensaInstrInfo &TII = *static_cast<const XtensaInstrInfo *>(
MBB.getParent()->getSubtarget().getInstrInfo());
@@ -90,7 +90,7 @@ void XtensaFrameLowering::emitPrologue(MachineFunction &MF,
// diff_to_128_aligned_address = (128 - (SP & 127))
// new_offset = SP + diff_to_128_aligned_address
// This is safe to do because we increased the stack size by MaxAlignment.
- unsigned Reg, RegMisAlign;
+ MCRegister Reg, RegMisAlign;
if (MaxAlignment > 32){
TII.loadImmediate(MBB, MBBI, &RegMisAlign, MaxAlignment - 1);
TII.loadImmediate(MBB, MBBI, &Reg, MaxAlignment);
@@ -135,79 +135,80 @@ void XtensaFrameLowering::emitPrologue(MachineFunction &MF,
.addCFIIndex(CFIIndex);
}
} else {
- // No need to allocate space on the stack.
- if (StackSize == 0 && !MFI.adjustsStack())
- return;
+ // 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) {
+ // 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;
+ 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.asMCReg() &&
+ Info.getReg() == Reg.asMCReg();
+ } else {
+ Register Reg = TII.isStoreToStackSlot(*MBBI, StoreFI);
+ IsStoreInst = Reg.asMCReg() == Info.getReg() && StoreFI == FI;
+ }
+ assert(IsStoreInst &&
+ "Unexpected callee-saved register store instruction");
+#endif
+ ++MBBI;
+ }
- // 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.asMCReg() &&
- Info.getReg() == Reg.asMCReg();
- } else {
- Register Reg = TII.isStoreToStackSlot(*MBBI, StoreFI);
- IsStoreInst = Reg.asMCReg() == Info.getReg() && StoreFI == FI;
+ // Iterate over list of callee-saved registers and emit .cfi_offset
+ // directives.
+ for (const auto &I : CSI) {
+ int64_t Offset = MFI.getObjectOffset(I.getFrameIdx());
+ MCRegister 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);
}
- 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());
- MCRegister Reg = I.getReg();
+ // 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);
- unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
- nullptr, MRI->getDwarfRegNum(Reg, 1), Offset));
+ // 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 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);
@@ -264,7 +265,7 @@ void XtensaFrameLowering::emitEpilogue(MachineFunction &MF,
"Unexpected callee-saved register restore instruction");
#endif
}
- if (STI.isWinABI()) {
+ if (STI.isWindowedABI()) {
// In most architectures, we need to explicitly restore the stack pointer
// before returning.
//
@@ -277,7 +278,7 @@ void XtensaFrameLowering::emitEpilogue(MachineFunction &MF,
}
}
- if (STI.isWinABI())
+ if (STI.isWindowedABI())
return;
// Get the number of bytes from FrameInfo
@@ -296,7 +297,7 @@ bool XtensaFrameLowering::spillCalleeSavedRegisters(
MachineFunction *MF = MBB.getParent();
MachineBasicBlock &EntryBlock = *(MF->begin());
- if (STI.isWinABI())
+ if (STI.isWindowedABI())
return true;
for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
@@ -324,7 +325,7 @@ bool XtensaFrameLowering::spillCalleeSavedRegisters(
bool XtensaFrameLowering::restoreCalleeSavedRegisters(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
- if (STI.isWinABI())
+ if (STI.isWindowedABI())
return true;
return TargetFrameLowering::restoreCalleeSavedRegisters(MBB, MI, CSI, TRI);
}
@@ -353,7 +354,7 @@ void XtensaFrameLowering::determineCalleeSaves(MachineFunction &MF,
RegScavenger *RS) const {
unsigned FP = TRI->getFrameRegister(MF);
- if (STI.isWinABI()) {
+ if (STI.isWindowedABI()) {
return;
}
diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
index 75e8dad388d1e..c4aa513d9ca40 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
@@ -349,11 +349,11 @@ SDValue XtensaTargetLowering::LowerFormalArguments(
// Transform the arguments stored on
// physical registers into virtual ones
Register Reg = 0;
- unsigned FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF);
+ MCRegister FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF);
- // Argument passed in FrameReg in WinABI we save in A8 (in emitPrologue),
- // so load argument from A8
- if (Subtarget.isWinABI() && (VA.getLocReg() == FrameReg)) {
+ // Argument passed in FrameReg in Windowed ABI we save in A8 (in
+ // emitPrologue), so load argument from A8
+ if (Subtarget.isWindowedABI() && (VA.getLocReg() == FrameReg)) {
Reg = MF.addLiveIn(Xtensa::A8, &Xtensa::ARRegClass);
XtensaFI->setSaveFrameRegister();
} else {
@@ -558,7 +558,7 @@ XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI,
SDValue Glue;
for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) {
unsigned Reg = RegsToPass[I].first;
- if (Subtarget.isWinABI())
+ if (Subtarget.isWindowedABI())
Reg = toCallerWindow(Reg);
Chain = DAG.getCopyToReg(Chain, DL, Reg, RegsToPass[I].second, Glue);
Glue = Chain.getValue(1);
@@ -609,7 +609,7 @@ XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI,
// known live into the call.
for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) {
unsigned Reg = RegsToPass[I].first;
- if (Subtarget.isWinABI())
+ if (Subtarget.isWindowedABI())
Reg = toCallerWindow(Reg);
Ops.push_back(DAG.getRegister(Reg, RegsToPass[I].second.getValueType()));
}
@@ -619,7 +619,8 @@ XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI,
Ops.push_back(Glue);
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
- Chain = DAG.getNode(Subtarget.isWinABI() ? XtensaISD::CALLW8 : XtensaISD::CALL,
+ Chain = DAG.getNode(Subtarget.isWindowedABI() ? XtensaISD::CALLW8
+ : XtensaISD::CALL,
DL, NodeTys, Ops);
Glue = Chain.getValue(1);
@@ -631,8 +632,8 @@ XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI,
// Assign locations to each value returned by this call.
SmallVector<CCValAssign, 16> RetLocs;
CCState RetCCInfo(CallConv, IsVarArg, MF, RetLocs, *DAG.getContext());
- RetCCInfo.AnalyzeCallResult(Ins, Subtarget.isWinABI() ? RetCCW8_Xtensa
- : RetCC_Xtensa);
+ RetCCInfo.AnalyzeCallResult(Ins, Subtarget.isWindowedABI() ? RetCCW8_Xtensa
+ : RetCC_Xtensa);
// Copy all of the result registers out of their specified physreg.
for (unsigned I = 0, E = RetLocs.size(); I != E; ++I) {
@@ -674,8 +675,9 @@ XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
SDValue Glue;
// Quick exit for void returns
if (RetLocs.empty())
- return DAG.getNode(Subtarget.isWinABI() ? XtensaISD::RETW
- : XtensaISD::RET, DL, MVT::Other, Chain);
+ return DAG.getNode(Subtarget.isWindowedABI() ? XtensaISD::RETW
+ : XtensaISD::RET,
+ DL, MVT::Other, Chain);
// Copy the result values into the output registers.
SmallVector<SDValue, 4> RetOps;
@@ -699,8 +701,9 @@ XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
if (Glue.getNode())
RetOps.push_back(Glue);
- return DAG.getNode(Subtarget.isWinABI() ? XtensaISD::RETW
- : XtensaISD::RET, DL, MVT::Other, RetOps);
+ return DAG.getNode(Subtarget.isWindowedABI() ? XtensaISD::RETW
+ : XtensaISD::RET,
+ DL, MVT::Other, RetOps);
}
static unsigned getBranchOpcode(ISD::CondCode Cond) {
@@ -934,7 +937,7 @@ SDValue XtensaTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
unsigned SPReg = Xtensa::SP;
SDValue SP = DAG.getCopyFromReg(Chain, DL, SPReg, VT);
SDValue NewSP = DAG.getNode(ISD::SUB, DL, VT, SP, SizeRoundUp); // Value
- if (Subtarget.isWinABI()) {
+ if (Subtarget.isWindowedABI()) {
NewSP = DAG.getNode(XtensaISD::MOVSP, DL, MVT::i32, NewSP);
}
Chain = DAG.getCopyToReg(SP.getValue(1), DL, SPReg, NewSP); // Output chain
diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp
index 788dc992d1d4e..005532b864c41 100644
--- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp
@@ -76,7 +76,7 @@ Register XtensaInstrInfo::isStoreToStackSlot(const MachineInstr &MI,
}
/// Adjust SP by Amount bytes.
-void XtensaInstrInfo::adjustStackPtr(unsigned SP, int64_t Amount,
+void XtensaInstrInfo::adjustStackPtr(MCRegister SP, int64_t Amount,
MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc();
@@ -88,25 +88,25 @@ void XtensaInstrInfo::adjustStackPtr(unsigned SP, int64_t Amount,
const TargetRegisterClass *RC = &Xtensa::ARRegClass;
// create virtual reg to store immediate
- unsigned Reg = RegInfo.createVirtualRegister(RC);
+ MCRegister Reg = RegInfo.createVirtualRegister(RC);
if (isInt<8>(Amount)) { // addi sp, sp, amount
BuildMI(MBB, I, DL, get(Xtensa::ADDI), Reg).addReg(SP).addImm(Amount);
} else { // Expand immediate that doesn't fit in 8-bit.
- unsigned Reg1;
+ MCRegister Reg1;
loadImmediate(MBB, I, &Reg1, Amount);
BuildMI(MBB, I, DL, get(Xtensa::ADD), Reg)
.addReg(SP)
.addReg(Reg1, RegState::Kill);
}
- if (STI.isWinABI()) {
+ if (STI.isWindowedABI()) {
BuildMI(MBB, I, DL, get(Xtensa::MOVSP), SP).addReg(Reg, RegState::Kill);
} else {
- BuildMI(MBB, I, DL, get(Xtensa::OR), SP)
- .addReg(Reg, RegState::Kill)
- .addReg(Reg, RegState::Kill);
- }
+ BuildMI(MBB, I, DL, get(Xtensa::OR), SP)
+ .addReg(Reg, RegState::Kill)
+ .addReg(Reg, RegState::Kill);
+ }
}
void XtensaInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
@@ -160,7 +160,7 @@ void XtensaInstrInfo::getLoadStoreOpcodes(const TargetRegisterClass *RC,
void XtensaInstrInfo::loadImmediate(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
- unsigned *Reg, int64_t Value) const {
+ MCRegister *Reg, int64_t Value) const {
DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo();
const TargetRegisterClass *RC = &Xtensa::ARRegClass;
diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.h b/llvm/lib/Target/Xtensa/XtensaInstrInfo.h
index 9bb2114427146..1808cb36d8a9b 100644
--- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.h
+++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.h
@@ -35,7 +35,7 @@ class XtensaInstrInfo : public XtensaGenInstrInfo {
public:
XtensaInstrInfo(const XtensaSubtarget &STI);
- void adjustStackPtr(unsigned SP, int64_t Amount, MachineBasicBlock &MBB,
+ void adjustStackPtr(MCRegister SP, int64_t Amount, MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const;
unsigned getInstSizeInBytes(const MachineInstr &MI) const override;
@@ -73,7 +73,7 @@ class XtensaInstrInfo : public XtensaGenInstrInfo {
// Emit code before MBBI in MI to move immediate value Value into
// physical register Reg.
void loadImmediate(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
- unsigned *Reg, int64_t Value) const;
+ MCRegister *Reg, int64_t Value) const;
bool
reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp
index cd8bfa0d4d164..74633050861c2 100644
--- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp
@@ -34,19 +34,14 @@ XtensaRegisterInfo::XtensaRegisterInfo(const XtensaSubtarget &STI)
const uint16_t *
XtensaRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
- if (Subtarget.isWinABI())
- return CSRW8_Xtensa_SaveList;
- else
- return CSR_Xtensa_SaveList;
+ return Subtarget.isWindowedABI() ? CSRW8_Xtensa_SaveList
+ : CSR_Xtensa_SaveList;
}
const uint32_t *
XtensaRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
CallingConv::ID) const {
- if (Subtarget.isWinABI())
- return CSRW8_Xtensa_RegMask;
- else
- return CSR_Xtensa_RegMask;
+ return Subtarget.isWindowedABI() ? CSRW8_Xtensa_RegMask : CSR_Xtensa_RegMask;
}
BitVector XtensaRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
@@ -88,7 +83,7 @@ bool XtensaRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
// 4. Locations for eh data registers.
// Everything else is referenced relative to whatever register
// getFrameRegister() returns.
- unsigned FrameReg;
+ MCRegister FrameReg;
if ((FrameIndex >= MinCSFI && FrameIndex <= MaxCSFI))
FrameReg = Xtensa::SP;
else
@@ -113,7 +108,7 @@ bool XtensaRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
MachineBasicBlock &MBB = *MI.getParent();
DebugLoc DL = II->getDebugLoc();
unsigned ADD = Xtensa::ADD;
- unsigned Reg;
+ MCRegister Reg;
const XtensaInstrInfo &TII = *static_cast<const XtensaInstrInfo *>(
MBB.getParent()->getSubtarget().getInstrInfo());
@@ -135,6 +130,6 @@ bool XtensaRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
Register XtensaRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
- return TFI->hasFP(MF) ? (Subtarget.isWinABI() ? Xtensa::A7 : Xtensa::A15)
+ return TFI->hasFP(MF) ? (Subtarget.isWindowedABI() ? Xtensa::A7 : Xtensa::A15)
: Xtensa::SP;
}
diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.h b/llvm/lib/Target/Xtensa/XtensaSubtarget.h
index b537a72bfe407..05c0c07e93a96 100644
--- a/llvm/lib/Target/Xtensa/XtensaSubtarget.h
+++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.h
@@ -72,7 +72,7 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo {
bool hasBoolean() const { return HasBoolean; }
- bool isWinABI() const { return hasWindowed(); }
+ bool isWindowedABI() const { return hasWindowed(); }
// Automatically generated by tblgen.
void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS);
diff --git a/llvm/test/CodeGen/Xtensa/calling-conv-windowed.ll b/llvm/test/CodeGen/Xtensa/calling-conv-windowed.ll
index 27855b1cdf481..2b6b018019c52 100644
--- a/llvm/test/CodeGen/Xtensa/calling-conv-windowed.ll
+++ b/llvm/test/CodeGen/Xtensa/calling-conv-windowed.ll
@@ -3,7 +3,7 @@
; RUN: | FileCheck %s -check-prefix=XTENSA
; Check placement of first 6 arguments in registers and 7th argument on stack
-define dso_local i32 @test1(i32 noundef %0, i32 noundef %1, i32 noundef %2, i32 noundef %3, i32 noundef %4, i32 noundef %5, ptr nocapture noundef readonly byval(i32) align 4 %6) {
+define dso_local i32 @test1(i32 noundef %a, i32 noundef %b, i32 noundef %c, i32 noundef %d, i32 noundef %e, i32 noundef %f, ptr nocapture noundef readonly byval(i32) align 4 %p) {
; XTENSA-LABEL: test1:
; XTENSA: .cfi_startproc
; XTENSA-NEXT: # %bb.0:
@@ -13,14 +13,14 @@ define dso_local i32 @test1(i32 noundef %0, i32 noundef %1, i32 noundef %2, i32
; XTENSA-NEXT: l32i a9, a1, 32
; XTENSA-NEXT: add a2, a8, a9
; XTENSA-NEXT: retw
- %8 = load i32, ptr %6, align 4
- %9 = add nsw i32 %5, %0
- %10 = add nsw i32 %9, %8
- ret i32 %10
+ %l = load i32, ptr %p, align 4
+ %sum = add nsw i32 %f, %a
+ %1 = add nsw i32 %sum, %l
+ ret i32 %1
}
; Check placement of second i64 argument in registers
-define dso_local i32 @test2(i32 noundef %0, i64 noundef %1, i32 noundef %2) {
+define dso_local i32 @test2(i32 noundef %a, i64 noundef %b, i32 noundef %c) {
; XTENSA-LABEL: test2:
; XTENSA: .cfi_startproc
; XTENSA-NEXT: # %bb.0:
@@ -29,14 +29,14 @@ define dso_local i32 @test2(i32 noundef %0, i64 noundef %1, i32 noundef %2) {
; XTENSA-NEXT: add a8, a6, a2
; XTENSA-NEXT: add a2, a8, a4
; XTENSA-NEXT: retw
- %4 = trunc i64 %1 to i32
- %5 = add nsw i32 %2, %0
- %6 = add nsw i32 %5, %4
- ret i32 %6
+ %tr = trunc i64 %b to i32
+ %sum = add nsw i32 %c, %a
+ %1 = add nsw i32 %sum, %tr
+ ret i32 %1
}
; Check placement of first argument typeof i8 in register
-define dso_local i32 @test3(i8 noundef signext %0, i64 noundef %1, i32 noundef %2) {
+define dso_local i32 @test3(i8 noundef signext %a, i64 noundef %b, i32 noundef %c) {
; XTENSA-LABEL: test3:
; XTENSA: .cfi_startproc
; XTENSA-NEXT: # %bb.0:
@@ -45,15 +45,15 @@ define dso_local i32 @test3(i8 noundef signext %0, i64 noundef %1, i32 noundef %
; XTENSA-NEXT: add a8, a2, a6
; XTENSA-NEXT: add a2, a8, a4
; XTENSA-NEXT: retw
- %4 = trunc i64 %1 to i32
- %5 = sext i8 %0 to i32
- %6 = add nsw i32 %5, %2
- %7 = add nsw i32 %6, %4
- ret i32 %7
+ %tr = trunc i64 %b to i32
+ %se = sext i8 %a to i32
+ %sum = add nsw i32 %se, %c
+ %1 = add nsw i32 %sum, %tr
+ ret i32 %1
}
; Check placement of 4th argument typeof i64 on stack
-define dso_local i32 @test4(i8 noundef signext %0, i64 noundef %1, i32 noundef %2, ptr nocapture noundef readonly byval(i64) align 8 %3) {
+define dso_local i32 @test4(i8 noundef signext %a, i64 noundef %b, i32 noundef %c, ptr nocapture noundef readonly byval(i64) align 8 %p) {
; XTENSA-LABEL: test4:
; XTENSA: .cfi_startproc
; XTENSA-NEXT: # %bb.0:
@@ -64,18 +64,18 @@ define dso_local i32 @test4(i8 noundef signext %0, i64 noundef %1, i32 noundef %
; XTENSA-NEXT: l32i a9, a1, 32
; XTENSA-NEXT: add a2, a8, a9
; XTENSA-NEXT: retw
- %5 = load i64, ptr %3, align 8
- %6 = trunc i64 %1 to i32
- %7 = trunc i64 %5 to i32
- %8 = sext i8 %0 to i32
- %9 = add nsw i32 %8, %2
- %10 = add nsw i32 %9, %6
- %11 = add nsw i32 %10, %7
- ret i32 %11
+ %l = load i64, ptr %p, align 8
+ %tr1 = trunc i64 %b to i32
+ %tr2 = trunc i64 %l to i32
+ %se = sext i8 %a to i32
+ %sum1 = add nsw i32 %se, %c
+ %sum2 = add nsw i32 %sum1, %tr1
+ %1 = add nsw i32 %sum2, %tr2
+ ret i32 %1
}
; Check placement of 128 bit structure on registers
-define dso_local i32 @test5([4 x i32] %0, i32 noundef %1) {
+define dso_local i32 @test5([4 x i32] %a, i32 noundef %b) {
; XTENSA-LABEL: test5:
; XTENSA: .cfi_startproc
; XTENSA-NEXT: # %bb.0:
@@ -83,13 +83,13 @@ define dso_local i32 @test5([4 x i32] %0, i32 noundef %1) {
; XTENSA-NEXT: .cfi_def_cfa_offset 32
; XTENSA-NEXT: add a2, a2, a6
; XTENSA-NEXT: retw
- %3 = extractvalue [4 x i32] %0, 0
- %4 = add nsw i32 %3, %1
- ret i32 %4
+ %ev = extractvalue [4 x i32] %a, 0
+ %1 = add nsw i32 %ev, %b
+ ret i32 %1
}
; Check placement of 128 bit structure on stack
-define dso_local i32 @test6(i32 noundef %0, [4 x i32] %1) {
+define dso_local i32 @test6(i32 noundef %a, [4 x i32] %b) {
; XTENSA-LABEL: test6:
; XTENSA: .cfi_startproc
; XTENSA-NEXT: # %bb.0:
@@ -97,7 +97,7 @@ define dso_local i32 @test6(i32 noundef %0, [4 x i32] %1) {
; XTENSA-NEXT: .cfi_def_cfa_offset 32
; XTENSA-NEXT: add a2, a3, a2
; XTENSA-NEXT: retw
- %3 = extractvalue [4 x i32] %1, 0
- %4 = add nsw i32 %3, %0
- ret i32 %4
+ %ev = extractvalue [4 x i32] %b, 0
+ %1 = add nsw i32 %ev, %a
+ ret i32 %1
}
>From ef88051434b4ff211e24a234e255fd56d35c770a Mon Sep 17 00:00:00 2001
From: Andrei Safronov <safronov at espressif.com>
Date: Wed, 12 Mar 2025 12:24:45 +0300
Subject: [PATCH 3/6] [Xtensa] Minor code formatting.
---
llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
index 44a240386511a..33c57e504b363 100644
--- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
@@ -31,8 +31,8 @@ using namespace llvm;
XtensaFrameLowering::XtensaFrameLowering(const XtensaSubtarget &STI)
: TargetFrameLowering(TargetFrameLowering::StackGrowsDown, Align(4), 0,
- Align(4)), STI(STI),
- TII(*STI.getInstrInfo()), TRI(STI.getRegisterInfo()) {}
+ Align(4)),
+ STI(STI), TII(*STI.getInstrInfo()), TRI(STI.getRegisterInfo()) {}
bool XtensaFrameLowering::hasFPImpl(const MachineFunction &MF) const {
const MachineFrameInfo &MFI = MF.getFrameInfo();
@@ -61,7 +61,7 @@ void XtensaFrameLowering::emitPrologue(MachineFunction &MF,
if (STI.isWindowedABI()) {
StackSize += 32;
uint64_t MaxAlignment = MFI.getMaxAlign().value();
- if(MaxAlignment > 32)
+ if (MaxAlignment > 32)
StackSize += MaxAlignment;
if (StackSize <= 32760) {
@@ -91,7 +91,7 @@ void XtensaFrameLowering::emitPrologue(MachineFunction &MF,
// new_offset = SP + diff_to_128_aligned_address
// This is safe to do because we increased the stack size by MaxAlignment.
MCRegister Reg, RegMisAlign;
- if (MaxAlignment > 32){
+ if (MaxAlignment > 32) {
TII.loadImmediate(MBB, MBBI, &RegMisAlign, MaxAlignment - 1);
TII.loadImmediate(MBB, MBBI, &Reg, MaxAlignment);
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::AND))
>From 1293a26788b7c6a1a60a1f0cb2145e4a1350e543 Mon Sep 17 00:00:00 2001
From: Andrei Safronov <safronov at espressif.com>
Date: Wed, 12 Mar 2025 12:51:03 +0300
Subject: [PATCH 4/6] [Xtensa] Fix XtensaFrameLowering implementation.
---
llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp | 5 -----
1 file changed, 5 deletions(-)
diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
index 33c57e504b363..3ff30f05ad780 100644
--- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
@@ -72,8 +72,6 @@ void XtensaFrameLowering::emitPrologue(MachineFunction &MF,
// Use a8 as a temporary since a0-a7 may be live.
MCRegister TmpReg = Xtensa::A8;
- const XtensaInstrInfo &TII = *static_cast<const XtensaInstrInfo *>(
- MBB.getParent()->getSubtarget().getInstrInfo());
BuildMI(MBB, MBBI, DL, TII.get(Xtensa::ENTRY))
.addReg(SP)
.addImm(MIN_FRAME_SIZE);
@@ -334,9 +332,6 @@ bool XtensaFrameLowering::restoreCalleeSavedRegisters(
MachineBasicBlock::iterator XtensaFrameLowering::eliminateCallFramePseudoInstr(
MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
- const XtensaInstrInfo &TII =
- *static_cast<const XtensaInstrInfo *>(MF.getSubtarget().getInstrInfo());
-
if (!hasReservedCallFrame(MF)) {
int64_t Amount = I->getOperand(0).getImm();
>From 5d43d83375cc08690622af53c1b77e33abb796bb Mon Sep 17 00:00:00 2001
From: Andrei Safronov <safronov at espressif.com>
Date: Sat, 15 Mar 2025 16:56:20 +0300
Subject: [PATCH 5/6] [Xtensa] Implement Windowed ABI for STACKRESTORE.
---
llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp | 2 +-
llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 14 ++++++++++----
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
index 3ff30f05ad780..cf9a2a052978d 100644
--- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
@@ -347,7 +347,7 @@ MachineBasicBlock::iterator XtensaFrameLowering::eliminateCallFramePseudoInstr(
void XtensaFrameLowering::determineCalleeSaves(MachineFunction &MF,
BitVector &SavedRegs,
RegScavenger *RS) const {
- unsigned FP = TRI->getFrameRegister(MF);
+ MCRegister FP = TRI->getFrameRegister(MF);
if (STI.isWindowedABI()) {
return;
diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
index c4aa513d9ca40..93cb7a679be06 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
@@ -895,8 +895,14 @@ SDValue XtensaTargetLowering::LowerSTACKSAVE(SDValue Op,
SDValue XtensaTargetLowering::LowerSTACKRESTORE(SDValue Op,
SelectionDAG &DAG) const {
- return DAG.getCopyToReg(Op.getOperand(0), SDLoc(Op), Xtensa::SP,
- Op.getOperand(1));
+ if (Subtarget.isWindowedABI()) {
+ SDValue NewSP =
+ DAG.getNode(XtensaISD::MOVSP, SDLoc(Op), MVT::i32, Op.getOperand(1));
+ return DAG.getCopyToReg(Op.getOperand(0), SDLoc(Op), Xtensa::SP, NewSP);
+ } else {
+ return DAG.getCopyToReg(Op.getOperand(0), SDLoc(Op), Xtensa::SP,
+ Op.getOperand(1));
+ }
}
SDValue XtensaTargetLowering::LowerFRAMEADDR(SDValue Op,
@@ -915,7 +921,7 @@ SDValue XtensaTargetLowering::LowerFRAMEADDR(SDValue Op,
EVT VT = Op.getValueType();
SDLoc DL(Op);
- Register FrameRegister = Subtarget.getRegisterInfo()->getFrameRegister(MF);
+ MCRegister FrameRegister = Subtarget.getRegisterInfo()->getFrameRegister(MF);
SDValue FrameAddr =
DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameRegister, VT);
return FrameAddr;
@@ -934,7 +940,7 @@ SDValue XtensaTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
SDValue SizeRoundUp = DAG.getNode(ISD::AND, DL, VT, SizeTmp,
DAG.getSignedConstant(~31, DL, MVT::i32));
- unsigned SPReg = Xtensa::SP;
+ MCRegister SPReg = Xtensa::SP;
SDValue SP = DAG.getCopyFromReg(Chain, DL, SPReg, VT);
SDValue NewSP = DAG.getNode(ISD::SUB, DL, VT, SP, SizeRoundUp); // Value
if (Subtarget.isWindowedABI()) {
>From 5bbdb8a67ae4cf978cd45297b85090bea1f0b8f4 Mon Sep 17 00:00:00 2001
From: Andrei Safronov <safronov at espressif.com>
Date: Tue, 18 Mar 2025 11:56:50 +0300
Subject: [PATCH 6/6] [Xtensa] Add test for STACKRESTORE. Fix SP update.
Implemented MOVSP_P pseudo operation for SP register update in
STACKRESTORE and DYNAMIC_STACKALLOC lowerinng.
---
llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 30 +++++--
llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 11 ++-
llvm/lib/Target/Xtensa/XtensaOperators.td | 4 +-
llvm/test/CodeGen/Xtensa/saverestore.ll | 84 +++++++++++++------
4 files changed, 89 insertions(+), 40 deletions(-)
diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
index 93cb7a679be06..93837ca321e08 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
@@ -895,14 +895,16 @@ SDValue XtensaTargetLowering::LowerSTACKSAVE(SDValue Op,
SDValue XtensaTargetLowering::LowerSTACKRESTORE(SDValue Op,
SelectionDAG &DAG) const {
+ SDValue Chain = Op.getOperand(0);
+ SDValue NewSP = Op.getOperand(1);
+
if (Subtarget.isWindowedABI()) {
- SDValue NewSP =
- DAG.getNode(XtensaISD::MOVSP, SDLoc(Op), MVT::i32, Op.getOperand(1));
- return DAG.getCopyToReg(Op.getOperand(0), SDLoc(Op), Xtensa::SP, NewSP);
- } else {
- return DAG.getCopyToReg(Op.getOperand(0), SDLoc(Op), Xtensa::SP,
- Op.getOperand(1));
+ return DAG.getNode(XtensaISD::MOVSP, SDLoc(Op), MVT::Other, Chain,
+ DAG.getRegister(Xtensa::SP, NewSP.getValueType()),
+ NewSP);
}
+
+ return DAG.getCopyToReg(Chain, SDLoc(Op), Xtensa::SP, NewSP);
}
SDValue XtensaTargetLowering::LowerFRAMEADDR(SDValue Op,
@@ -944,9 +946,11 @@ SDValue XtensaTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
SDValue SP = DAG.getCopyFromReg(Chain, DL, SPReg, VT);
SDValue NewSP = DAG.getNode(ISD::SUB, DL, VT, SP, SizeRoundUp); // Value
if (Subtarget.isWindowedABI()) {
- NewSP = DAG.getNode(XtensaISD::MOVSP, DL, MVT::i32, NewSP);
+ Chain = DAG.getNode(XtensaISD::MOVSP, SDLoc(Op), MVT::Other, SP.getValue(1),
+ DAG.getRegister(SPReg, NewSP.getValueType()), NewSP);
+ } else {
+ Chain = DAG.getCopyToReg(SP.getValue(1), DL, SPReg, NewSP); // Output chain
}
- Chain = DAG.getCopyToReg(SP.getValue(1), DL, SPReg, NewSP); // Output chain
SDValue NewVal = DAG.getCopyFromReg(Chain, DL, SPReg, MVT::i32);
Chain = NewVal.getValue(1);
@@ -1385,6 +1389,16 @@ MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter(
}
return MBB;
}
+ case Xtensa::MOVSP_P: {
+ MachineOperand SP = MI.getOperand(0);
+ MachineOperand NewSP = MI.getOperand(1);
+
+ BuildMI(*MBB, MI, DL, TII.get(Xtensa::MOVSP), SP.getReg())
+ .addReg(NewSP.getReg());
+ MI.eraseFromParent();
+
+ return MBB;
+ }
default:
llvm_unreachable("Unexpected instr type to insert");
}
diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
index b41c00738f763..631cf4bd73a6c 100644
--- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
+++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
@@ -719,12 +719,17 @@ def : Pat<(Xtensa_callw8 AR:$dst),
(CALLX8 AR:$dst)>;
def MOVSP : RRR_Inst<0x00, 0x00, 0x00, (outs AR:$t), (ins AR:$s),
- "movsp\t$t, $s",
- [(set AR:$t, (Xtensa_movsp AR:$s))]>,
- Requires<[HasWindowed]> {
+ "movsp\t$t, $s", []>, Requires<[HasWindowed]> {
let r = 0x01;
}
+// Use this pseudo operation instead of getCopyToReg function to
+// update SP register.
+let usesCustomInserter = 1, Predicates = [HasWindowed] in {
+ def MOVSP_P : Pseudo<(outs), (ins AR:$t, AR:$s),
+ "!movsp_p\t$t, $s", [(Xtensa_movsp AR:$t, AR:$s)]>;
+}
+
let isReturn = 1, isTerminator = 1,
isBarrier = 1, Uses = [A0] in {
def RETW_N : RRRN_Inst<0x0D, (outs), (ins),
diff --git a/llvm/lib/Target/Xtensa/XtensaOperators.td b/llvm/lib/Target/Xtensa/XtensaOperators.td
index 1fe5c3f64b607..1e92d90d191e2 100644
--- a/llvm/lib/Target/Xtensa/XtensaOperators.td
+++ b/llvm/lib/Target/Xtensa/XtensaOperators.td
@@ -31,7 +31,7 @@ def SDT_XtensaSRC : SDTypeProfile<1, 3, [SDTCisVT<0, i32>, SDTCi
def SDT_XtensaEXTUI : SDTypeProfile<1, 3, [SDTCisVT<0, i32>, SDTCisVT<1, i32>,
SDTCisVT<2, i32>, SDTCisVT<3, i32>]>;
-def SDT_XtensaMOVSP : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, SDTCisVT<0, i32>]>;
+def SDT_XtensaMOVSP : SDTypeProfile<0, 2, [SDTCisSameAs<0, 1>, SDTCisVT<0, i32>]>;
//===----------------------------------------------------------------------===//
// Node definitions
@@ -69,4 +69,4 @@ def Xtensa_srcr: SDNode<"XtensaISD::SRCR", SDT_XtensaSRC>;
def Xtensa_extui: SDNode<"XtensaISD::EXTUI", SDT_XtensaEXTUI>;
def Xtensa_movsp: SDNode<"XtensaISD::MOVSP", SDT_XtensaMOVSP,
- [SDNPInGlue]>;
+ [SDNPHasChain, SDNPSideEffect, SDNPInGlue]>;
diff --git a/llvm/test/CodeGen/Xtensa/saverestore.ll b/llvm/test/CodeGen/Xtensa/saverestore.ll
index 69c8b16ab601d..82c0dab1a680a 100644
--- a/llvm/test/CodeGen/Xtensa/saverestore.ll
+++ b/llvm/test/CodeGen/Xtensa/saverestore.ll
@@ -1,4 +1,6 @@
-; RUN: llc --mtriple=xtensa < %s | FileCheck %s
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc --mtriple=xtensa < %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc --mtriple=xtensa --mattr=+windowed < %s | FileCheck -check-prefixes=CHECK-WINDOWED %s
declare ptr @llvm.stacksave()
@@ -7,32 +9,60 @@ 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
+; CHECK-LABEL: test_saverestore:
+; CHECK: .cfi_startproc
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: addi a8, a1, -16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: .cfi_def_cfa_offset 16
+; CHECK-NEXT: s32i a0, a1, 8 # 4-byte Folded Spill
+; CHECK-NEXT: s32i a12, a1, 4 # 4-byte Folded Spill
+; CHECK-NEXT: s32i a15, a1, 0 # 4-byte Folded Spill
+; CHECK-NEXT: .cfi_offset a0, -4
+; CHECK-NEXT: .cfi_offset a12, -8
+; CHECK-NEXT: .cfi_offset a15, -12
+; CHECK-NEXT: or a15, a1, a1
+; CHECK-NEXT: .cfi_def_cfa_register a15
+; CHECK-NEXT: 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 # 4-byte Folded Reload
+; CHECK-NEXT: l32i a12, a1, 4 # 4-byte Folded Reload
+; CHECK-NEXT: l32i a0, a1, 8 # 4-byte Folded Reload
+; CHECK-NEXT: addi a8, a1, 16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: ret
+;
+; CHECK-WINDOWED-LABEL: test_saverestore:
+; CHECK-WINDOWED: .cfi_startproc
+; CHECK-WINDOWED-NEXT: # %bb.0:
+; CHECK-WINDOWED-NEXT: entry a1, 32
+; CHECK-WINDOWED-NEXT: or a7, a1, a1
+; CHECK-WINDOWED-NEXT: .cfi_def_cfa a7, 32
+; CHECK-WINDOWED-NEXT: addi a8, a2, 3
+; CHECK-WINDOWED-NEXT: movi a9, -4
+; CHECK-WINDOWED-NEXT: and a8, a8, a9
+; CHECK-WINDOWED-NEXT: addi a8, a8, 31
+; CHECK-WINDOWED-NEXT: movi a9, -32
+; CHECK-WINDOWED-NEXT: and a8, a8, a9
+; CHECK-WINDOWED-NEXT: or a6, a1, a1
+; CHECK-WINDOWED-NEXT: sub a8, a1, a8
+; CHECK-WINDOWED-NEXT: movsp a1, a8
+; CHECK-WINDOWED-NEXT: or a10, a1, a1
+; CHECK-WINDOWED-NEXT: l32r a8, .LCPI0_0
+; CHECK-WINDOWED-NEXT: callx8 a8
+; CHECK-WINDOWED-NEXT: movsp a1, a6
+; CHECK-WINDOWED-NEXT: retw
%sp = call ptr @llvm.stacksave.p0()
%addr = alloca i8, i64 %n
More information about the llvm-commits
mailing list