From a6954059ea324947be2def7b967d0fb3077ce831 Mon Sep 17 00:00:00 2001 From: arti Date: Wed, 11 Nov 2026 15:43:40 +0000 Subject: [PATCH] tms34010: TI ABI callee frames, arguments and returns --- llvm/lib/Target/TMS34010/TMS34010.td | 1 + .../Target/TMS34010/TMS34010CallingConv.td | 25 ++++++ .../Target/TMS34010/TMS34010FrameLowering.cpp | 87 ++++++++++++++++++- .../Target/TMS34010/TMS34010FrameLowering.h | 29 ++++++- .../Target/TMS34010/TMS34010ISelDAGToDAG.cpp | 18 ++-- .../Target/TMS34010/TMS34010ISelLowering.cpp | 87 +++++++++---------- .../lib/Target/TMS34010/TMS34010InstrInfo.cpp | 51 ++++++++++- llvm/lib/Target/TMS34010/TMS34010InstrInfo.h | 2 + llvm/lib/Target/TMS34010/TMS34010InstrInfo.td | 80 ++++++++++++++++- .../Target/TMS34010/TMS34010RegisterInfo.cpp | 51 +++++++++-- .../Target/TMS34010/TMS34010RegisterInfo.h | 3 + .../Target/TMS34010/TMS34010RegisterInfo.td | 17 +++- llvm/test/CodeGen/TMS34010/m2-args-locals.ll | 6 +- llvm/test/CodeGen/TMS34010/m2-args.ll | 4 + 14 files changed, 383 insertions(+), 78 deletions(-) create mode 100644 llvm/lib/Target/TMS34010/TMS34010CallingConv.td diff --git a/llvm/lib/Target/TMS34010/TMS34010.td b/llvm/lib/Target/TMS34010/TMS34010.td index d9b22efbbc02..c57969592910 100644 --- a/llvm/lib/Target/TMS34010/TMS34010.td +++ b/llvm/lib/Target/TMS34010/TMS34010.td @@ -13,6 +13,7 @@ include "llvm/Target/Target.td" include "TMS34010RegisterInfo.td" +include "TMS34010CallingConv.td" include "TMS34010InstrInfo.td" defm : RemapAllTargetPseudoPointerOperands; diff --git a/llvm/lib/Target/TMS34010/TMS34010CallingConv.td b/llvm/lib/Target/TMS34010/TMS34010CallingConv.td new file mode 100644 index 000000000000..e09f9bf46805 --- /dev/null +++ b/llvm/lib/Target/TMS34010/TMS34010CallingConv.td @@ -0,0 +1,25 @@ +//===-- TMS34010CallingConv.td - TMS34010 calling conventions -*- tablegen -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// M2 implements the TI ABI directly in TMS34010ISelLowering.cpp: every +// explicit argument is pushed on the program stack (A14) and a scalar return +// value is delivered in A8. CC_TMS34010 therefore has no register arguments +// and no register returns; the definition below documents that contract. The +// C calling convention is lowered identically. +// +//===----------------------------------------------------------------------===// + +def CC_TMS34010 : CallingConv<[ + // No arguments are assigned to registers. See LowerFormalArguments. + // No return values are assigned to registers. See LowerReturn. +]>; + +// Callee-saved registers: A0-A7 and A9-A12. A13 is reserved and saved by the +// prologue/epilogue; A8, A14 and A15 are ABI registers that are not preserved. +def CSR_TMS34010 : CalleeSavedRegs<(add A0, A1, A2, A3, A4, A5, A6, A7, + A9, A10, A11, A12)>; diff --git a/llvm/lib/Target/TMS34010/TMS34010FrameLowering.cpp b/llvm/lib/Target/TMS34010/TMS34010FrameLowering.cpp index 8e033f397a6a..56da90f2529f 100644 --- a/llvm/lib/Target/TMS34010/TMS34010FrameLowering.cpp +++ b/llvm/lib/Target/TMS34010/TMS34010FrameLowering.cpp @@ -5,14 +5,97 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +// +// The TI ABI splits the frame across two stacks: +// +// - the program stack (A14/STK) holds explicit arguments and locals; +// - the system stack (A15/SP) holds the return address and saved registers. +// +// The prologue keeps the caller's FP and the used callee-saved registers on +// the system stack, then points FP (A13) at the incoming program stack and +// allocates the local frame above it. Each register is saved with its own +// MOVE push, which is ABI-identical to one MMTM slot. +// +//===----------------------------------------------------------------------===// #include "TMS34010FrameLowering.h" -#include "llvm/Support/ErrorHandling.h" +#include "TMS34010.h" +#include "TMS34010InstrInfo.h" +#include "TMS34010Subtarget.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" using namespace llvm; StackOffset TMS34010FrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI, Register &FrameReg) const { - report_fatal_error("M1 has no stack frame", false); + const MachineFrameInfo &MFI = MF.getFrameInfo(); + + // Incoming arguments live below the frame pointer; locals live between FP + // and FP + StackSize. All TMS34010 addresses are bit addresses, so the + // byte-based frame offsets are scaled by eight. + int64_t OffsetBytes = MFI.getObjectOffset(FI); + if (!MFI.isFixedObjectIndex(FI)) + OffsetBytes += MFI.getStackSize(); + + FrameReg = TMS34010::A13; + return StackOffset::getFixed(OffsetBytes * 8); +} + +void TMS34010FrameLowering::emitPrologue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + MachineFrameInfo &MFI = MF.getFrameInfo(); + const TMS34010InstrInfo &TII = *STI.getInstrInfo(); + + MachineBasicBlock::iterator MBBI = MBB.begin(); + DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + + // The field-size invariant comes first so that every frame access below is + // a 32-bit access. + BuildMI(MBB, MBBI, DL, TII.get(TMS34010::SETF32)); + + // Save the caller's frame pointer, then the used callee-saved registers. + BuildMI(MBB, MBBI, DL, TII.get(TMS34010::PUSH32)).addReg(TMS34010::A13); + for (const CalleeSavedInfo &CSI : MFI.getCalleeSavedInfo()) + BuildMI(MBB, MBBI, DL, TII.get(TMS34010::PUSH32)).addReg(CSI.getReg()); + + // FP = STK, then allocate the local frame. + BuildMI(MBB, MBBI, DL, TII.get(TMS34010::SETFP)); + + int64_t FrameBits = MFI.getStackSize() * 8; + if (FrameBits) + BuildMI(MBB, MBBI, DL, TII.get(TMS34010::ADDSTK)).addImm(FrameBits); +} + +void TMS34010FrameLowering::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + MachineFrameInfo &MFI = MF.getFrameInfo(); + const TMS34010InstrInfo &TII = *STI.getInstrInfo(); + + MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator(); + assert(MBBI != MBB.end() && MBBI->getOpcode() == TMS34010::RETS && + "the TMS34010 epilogue must precede RETS"); + DebugLoc DL = MBBI->getDebugLoc(); + + const std::vector &CSI = MFI.getCalleeSavedInfo(); + unsigned NumSaved = 1 + CSI.size(); // FP plus the callee-saved registers. + + if (MF.getFunction().arg_size() != 0) { + // The caller pushed the explicit arguments on the program stack and saved + // its old STK below the return address: SP + (NumSaved + 1) * 32. + BuildMI(MBB, MBBI, DL, TII.get(TMS34010::LOADSTK)) + .addImm((NumSaved + 1) * 32); + } else { + int64_t FrameBits = MFI.getStackSize() * 8; + if (FrameBits) + BuildMI(MBB, MBBI, DL, TII.get(TMS34010::ADDSTK)).addImm(-FrameBits); + } + + // Restore the callee-saved registers in reverse order, then the old FP. + for (const CalleeSavedInfo &CI : llvm::reverse(CSI)) + BuildMI(MBB, MBBI, DL, TII.get(TMS34010::POP32), CI.getReg()); + BuildMI(MBB, MBBI, DL, TII.get(TMS34010::POP32), TMS34010::A13); } diff --git a/llvm/lib/Target/TMS34010/TMS34010FrameLowering.h b/llvm/lib/Target/TMS34010/TMS34010FrameLowering.h index 93fd829d7b08..620fb9062f4f 100644 --- a/llvm/lib/Target/TMS34010/TMS34010FrameLowering.h +++ b/llvm/lib/Target/TMS34010/TMS34010FrameLowering.h @@ -21,16 +21,39 @@ public: : TargetFrameLowering(StackGrowsDown, Align(2), 0), STI(STI) {} void emitPrologue(MachineFunction &MF, - MachineBasicBlock &MBB) const override {} + MachineBasicBlock &MBB) const override; void emitEpilogue(MachineFunction &MF, - MachineBasicBlock &MBB) const override {} + MachineBasicBlock &MBB) const override; StackOffset getFrameIndexReference(const MachineFunction &MF, int FI, Register &FrameReg) const override; + // The prologue and epilogue save and restore the ABI registers themselves, + // on the system stack, so PEI must not allocate program-frame spill slots or + // emit its own spill/restore instructions. + bool assignCalleeSavedSpillSlots( + MachineFunction &MF, const TargetRegisterInfo *TRI, + std::vector &CSI) const override { + return true; + } + + bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + ArrayRef CSI, + const TargetRegisterInfo *TRI) const override { + return true; + } + + bool restoreCalleeSavedRegisters( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, + MutableArrayRef CSI, + const TargetRegisterInfo *TRI) const override { + return true; + } + protected: - bool hasFPImpl(const MachineFunction &MF) const override { return false; } + bool hasFPImpl(const MachineFunction &MF) const override { return true; } private: const TMS34010Subtarget &STI; diff --git a/llvm/lib/Target/TMS34010/TMS34010ISelDAGToDAG.cpp b/llvm/lib/Target/TMS34010/TMS34010ISelDAGToDAG.cpp index ab1f3e265891..ffe8163ea360 100644 --- a/llvm/lib/Target/TMS34010/TMS34010ISelDAGToDAG.cpp +++ b/llvm/lib/Target/TMS34010/TMS34010ISelDAGToDAG.cpp @@ -69,15 +69,15 @@ void TMS34010DAGToDAGISel::Select(SDNode *N) { return; } - // M1 has no stack. Any frame index means an alloca or a spill reached - // instruction selection, which is outside the M1 contract. Check the - // operands too: the frame index is usually an operand of a load/store that - // would otherwise fail to select before its operand is visited. - if (N->getOpcode() == ISD::FrameIndex) - report_fatal_error("M1 has no stack frame", false); - for (const SDValue &Op : N->op_values()) - if (Op.getOpcode() == ISD::FrameIndex) - report_fatal_error("M1 has no stack frame", false); + // A frame index becomes a GETFI pseudo with the frame index as its offset + // operand. eliminateFrameIndex later replaces that operand with the + // FP-relative bit offset and expandPostRAPseudo expands it to MOVEFP + ADDI. + if (N->getOpcode() == ISD::FrameIndex) { + int FI = cast(N)->getIndex(); + SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32); + CurDAG->SelectNodeTo(N, TMS34010::GETFI, MVT::i32, TFI); + return; + } SelectCode(N); } diff --git a/llvm/lib/Target/TMS34010/TMS34010ISelLowering.cpp b/llvm/lib/Target/TMS34010/TMS34010ISelLowering.cpp index 4a68b6598f4f..32946b88db24 100644 --- a/llvm/lib/Target/TMS34010/TMS34010ISelLowering.cpp +++ b/llvm/lib/Target/TMS34010/TMS34010ISelLowering.cpp @@ -10,9 +10,8 @@ #include "TMS34010.h" #include "TMS34010Subtarget.h" #include "TMS34010TargetMachine.h" -#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/IR/Function.h" #include "llvm/Support/ErrorHandling.h" @@ -46,53 +45,45 @@ SDValue TMS34010TargetLowering::LowerFormalArguments( const SmallVectorImpl &Ins, const SDLoc &DL, SelectionDAG &DAG, SmallVectorImpl &InVals) const { MachineFunction &MF = DAG.getMachineFunction(); - MachineRegisterInfo &RegInfo = MF.getRegInfo(); + MachineFrameInfo &MFI = MF.getFrameInfo(); const Function &F = MF.getFunction(); + (void)CallConv; + // Validate the IR signature before legalization can split or promote it. // Checking only the legalized MVT lets an i64 or an aggregate arrive as // several i32 pieces and be silently accepted (and miscompiled). - if (F.isVarArg()) - report_fatal_error("M1 does not support varargs", false); + if (F.isVarArg() || IsVarArg) + report_fatal_error("M2 does not support varargs", false); for (const Argument &Arg : F.args()) { Type *Ty = Arg.getType(); - if (!Ty->isIntegerTy(32) && !Ty->isIntegerTy(16) && - !Ty->isIntegerTy(8) && !Ty->isPointerTy()) - report_fatal_error( - "M1 supports only i32, i8, i16 and pointer arguments", false); + if (!Ty->isIntegerTy(32) && !Ty->isPointerTy()) + report_fatal_error("M2 supports only i32 and pointer arguments", false); } - static const MCPhysReg ArgRegs[] = {TMS34010::A0, TMS34010::A1, TMS34010::A2, - TMS34010::A3}; - - if (Ins.size() > std::size(ArgRegs)) - report_fatal_error("M1 supports at most four register arguments", false); - - SmallVector ArgLocs; - CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); - + // Every explicit argument is passed on the program stack. Argument i lives + // one 32-bit slot below FP for each preceding argument, so its fixed object + // is at byte offset -(i + 1) * 4 (bit offset -(i + 1) * 32 after frame + // elimination). for (unsigned i = 0, e = Ins.size(); i != e; ++i) { const ISD::InputArg &In = Ins[i]; if (In.Flags.isSRet() || In.Flags.isByVal() || In.Flags.isInReg() || In.Flags.isNest() || In.Flags.isReturned()) report_fatal_error( - "M1 supports only plain register arguments " + "M2 supports only plain arguments " "(no sret/byval/inreg/nest/returned)", false); - MVT VT = In.VT; - if (VT != MVT::i32) - report_fatal_error( - "M1 supports only 32-bit scalar and pointer arguments", false); - CCInfo.addLoc( - CCValAssign::getReg(i, VT, ArgRegs[i], VT, CCValAssign::Full)); - } + if (In.VT != MVT::i32) + report_fatal_error("M2 supports only i32 and pointer arguments", false); - for (const CCValAssign &VA : ArgLocs) { - Register VReg = RegInfo.createVirtualRegister(&TMS34010::ARegsRegClass); - RegInfo.addLiveIn(VA.getLocReg(), VReg); - InVals.push_back( - DAG.getCopyFromReg(Chain, DL, VReg, VA.getLocVT())); + int FI = MFI.CreateFixedObject(4, -static_cast(i + 1) * 4, true); + SDValue FIN = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); + SDValue Load = + DAG.getLoad(MVT::i32, DL, Chain, FIN, + MachinePointerInfo::getFixedStack(MF, FI), Align(2)); + Chain = Load.getValue(1); + InVals.push_back(Load); } return Chain; @@ -101,7 +92,7 @@ SDValue TMS34010TargetLowering::LowerFormalArguments( SDValue TMS34010TargetLowering::LowerCall( TargetLowering::CallLoweringInfo &CLI, SmallVectorImpl &InVals) const { - report_fatal_error("M1 has no calls; M2 adds the TI ABI", false); + report_fatal_error("M2 call lowering is Task 3", false); } bool TMS34010TargetLowering::CanLowerReturn( @@ -109,11 +100,11 @@ bool TMS34010TargetLowering::CanLowerReturn( const SmallVectorImpl &Outs, LLVMContext &Context, const Type *RetTy) const { // Returning false here makes SelectionDAG demote the return value to an - // sret pointer, silently changing the signature to something M1 cannot + // sret pointer, silently changing the signature to something M2 cannot // lower either. Reject unsupported returns loudly instead. if (RetTy->isVoidTy() || RetTy->isIntegerTy(32) || RetTy->isPointerTy()) return true; - report_fatal_error("M1 supports only void/i32/pointer returns", false); + report_fatal_error("M2 supports only void/i32/pointer returns", false); } SDValue TMS34010TargetLowering::LowerReturn( @@ -121,18 +112,24 @@ SDValue TMS34010TargetLowering::LowerReturn( const SmallVectorImpl &Outs, const SmallVectorImpl &OutVals, const SDLoc &DL, SelectionDAG &DAG) const { - if (Outs.empty()) - return DAG.getNode(TMS34010ISD::RET_GLUE, DL, MVT::Other, Chain); + MachineFunction &MF = DAG.getMachineFunction(); - if (Outs.size() != 1 || Outs[0].VT != MVT::i32) - report_fatal_error("M1 supports only void/i32/pointer returns", false); + (void)CallConv; + (void)IsVarArg; - SDValue Glue; - Chain = DAG.getCopyToReg(Chain, DL, TMS34010::A0, OutVals[0], Glue); - Glue = Chain.getValue(1); + // A scalar result is returned in A8. A8 is an implicit use of RETS, so the + // copy stays live through the terminator. + if (!Outs.empty()) { + if (Outs.size() != 1 || Outs[0].VT != MVT::i32) + report_fatal_error("M2 supports only void/i32/pointer returns", false); + Chain = DAG.getCopyToReg(Chain, DL, TMS34010::A8, OutVals[0]); + } - SmallVector RetOps(1, Chain); - RetOps.push_back(DAG.getRegister(TMS34010::A0, MVT::i32)); - RetOps.push_back(Glue); - return DAG.getNode(TMS34010ISD::RET_GLUE, DL, MVT::Other, RetOps); + // RETS must pop the caller's argument words: 2 when the function has + // explicit arguments, 0 otherwise. The value depends on the signature, so + // emit RETS as a machine node instead of a pattern with a fixed immediate. + unsigned N = MF.getFunction().arg_size() != 0 ? 2 : 0; + SDValue NVal = DAG.getTargetConstant(N, DL, MVT::i32); + return SDValue( + DAG.getMachineNode(TMS34010::RETS, DL, MVT::Other, NVal, Chain), 0); } diff --git a/llvm/lib/Target/TMS34010/TMS34010InstrInfo.cpp b/llvm/lib/Target/TMS34010/TMS34010InstrInfo.cpp index ee27ed18c368..706bae8f6748 100644 --- a/llvm/lib/Target/TMS34010/TMS34010InstrInfo.cpp +++ b/llvm/lib/Target/TMS34010/TMS34010InstrInfo.cpp @@ -9,7 +9,9 @@ #include "TMS34010InstrInfo.h" #include "TMS34010.h" #include "TMS34010Subtarget.h" +#include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Support/ErrorHandling.h" using namespace llvm; @@ -26,7 +28,7 @@ void TMS34010InstrInfo::copyPhysReg(MachineBasicBlock &MBB, Register SrcReg, bool KillSrc, bool RenamableDest, bool RenamableSrc) const { - if (!TMS34010::ARegsRegClass.contains(DestReg, SrcReg)) + if (!TMS34010::ARegsAllRegClass.contains(DestReg, SrcReg)) llvm_unreachable("Impossible reg-to-reg copy"); BuildMI(MBB, I, DL, get(TMS34010::MOVE), DestReg) @@ -37,12 +39,55 @@ void TMS34010InstrInfo::storeRegToStackSlot( MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, Register SrcReg, bool isKill, int FrameIndex, const TargetRegisterClass *RC, Register VReg, MachineInstr::MIFlag Flags) const { - report_fatal_error("M1 has no stack frame", false); + MachineFunction &MF = *MBB.getParent(); + MachineRegisterInfo &RegInfo = MF.getRegInfo(); + DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc() : DebugLoc(); + + // GETFI materialises the spill slot's address into a virtual A register; it + // is expanded to MOVEFP + ADDI after frame elimination. + Register Addr = RegInfo.createVirtualRegister(&TMS34010::ARegsRegClass); + BuildMI(MBB, MI, DL, get(TMS34010::GETFI), Addr) + .addFrameIndex(FrameIndex) + .setMIFlag(Flags); + BuildMI(MBB, MI, DL, get(TMS34010::MOVE32Store)) + .addReg(SrcReg, getKillRegState(isKill)) + .addReg(Addr, RegState::Kill) + .setMIFlag(Flags); } void TMS34010InstrInfo::loadRegFromStackSlot( MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, Register DestReg, int FrameIdx, const TargetRegisterClass *RC, Register VReg, unsigned SubReg, MachineInstr::MIFlag Flags) const { - report_fatal_error("M1 has no stack frame", false); + MachineFunction &MF = *MBB.getParent(); + MachineRegisterInfo &RegInfo = MF.getRegInfo(); + DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc() : DebugLoc(); + + Register Addr = RegInfo.createVirtualRegister(&TMS34010::ARegsRegClass); + BuildMI(MBB, MI, DL, get(TMS34010::GETFI), Addr) + .addFrameIndex(FrameIdx) + .setMIFlag(Flags); + BuildMI(MBB, MI, DL, get(TMS34010::MOVE32Load), DestReg) + .addReg(Addr, RegState::Kill) + .setMIFlag(Flags); +} + +bool TMS34010InstrInfo::expandPostRAPseudo(MachineInstr &MI) const { + if (MI.getOpcode() != TMS34010::GETFI) + return false; + + MachineBasicBlock &MBB = *MI.getParent(); + DebugLoc DL = MI.getDebugLoc(); + Register DstReg = MI.getOperand(0).getReg(); + int64_t Offset = MI.getOperand(1).getImm(); + + // The frame index has already been replaced by the FP-relative bit offset. + BuildMI(MBB, MI, DL, get(TMS34010::MOVEFP), DstReg); + if (Offset) + BuildMI(MBB, MI, DL, get(TMS34010::ADDI), DstReg) + .addReg(DstReg) + .addImm(Offset); + + MI.eraseFromParent(); + return true; } diff --git a/llvm/lib/Target/TMS34010/TMS34010InstrInfo.h b/llvm/lib/Target/TMS34010/TMS34010InstrInfo.h index 56ea5f3a330b..45f25ab1594f 100644 --- a/llvm/lib/Target/TMS34010/TMS34010InstrInfo.h +++ b/llvm/lib/Target/TMS34010/TMS34010InstrInfo.h @@ -43,6 +43,8 @@ public: Register VReg, unsigned SubReg = 0, MachineInstr::MIFlag Flags = MachineInstr::NoFlags) const override; + + bool expandPostRAPseudo(MachineInstr &MI) const override; }; } // namespace llvm diff --git a/llvm/lib/Target/TMS34010/TMS34010InstrInfo.td b/llvm/lib/Target/TMS34010/TMS34010InstrInfo.td index dca2adc8fcd3..09a8837aceb6 100644 --- a/llvm/lib/Target/TMS34010/TMS34010InstrInfo.td +++ b/llvm/lib/Target/TMS34010/TMS34010InstrInfo.td @@ -64,8 +64,10 @@ def MOVI : TMS34010Inst<(outs ARegs:$dst), (ins i32imm:$imm), let Inst{47-32} = imm{31-16}; } -// MOVE Rs, Rd: 0100 11MS SSSR DDDD -def MOVE : TMS34010Inst<(outs ARegs:$dst), (ins ARegs:$src), +// MOVE Rs, Rd: 0100 11MS SSSR DDDD. Any A register may be copied, including +// the reserved A8/A13; these copies are emitted directly, not selected from a +// pattern. +def MOVE : TMS34010Inst<(outs ARegsAll:$dst), (ins ARegsAll:$src), "MOVE $src, $dst", []> { bits<5> src; bits<5> dst; @@ -173,14 +175,84 @@ def RETS : TMS34010Inst<(outs), (ins i32imm:$n), "RETS $n", []> { let isReturn = 1; let isTerminator = 1; let isBarrier = 1; + // N is 2 when the function has explicit arguments and 0 otherwise. The + // value depends on the signature, so LowerReturn emits this instruction as + // a machine node rather than through a pattern. + let Uses = [A8]; bits<5> n; let Inst{15-9} = 0b0000100; let Inst{8-5} = 0b1011; let Inst{4-0} = n; } +// Push/pop on the system stack (A15/SP). The CPU predecrements and +// postincrements by one 32-bit slot, so each is ABI-identical to one MMTM/MMFM +// slot. MMTM/MMFM is a later code-size optimisation. +def PUSH32 : TMS34010Inst<(outs), (ins ARegsAll:$src), + "MOVE $src, -*SP, 1", []> { + let mayStore = 1; + let Uses = [A15]; + let Defs = [A15]; +} + +def POP32 : TMS34010Inst<(outs ARegsAll:$dst), (ins), + "MOVE *SP+, $dst, 1", []> { + let mayLoad = 1; + let Uses = [A15]; + let Defs = [A15]; +} + +// Push one 32-bit argument on the program stack (A14/STK). +def PUSHARG : TMS34010Inst<(outs), (ins ARegs:$src), + "MOVE $src, *A14+, 1", []> { + let mayStore = 1; + let Uses = [A14]; + let Defs = [A14]; +} + +// FP = STK, and the program-stack frame adjustment (negative to deallocate). +def SETFP : TMS34010Inst<(outs), (ins), "MOVE A14, A13", []> { + let Uses = [A14]; + let Defs = [A13]; +} + +def ADDSTK : TMS34010Inst<(outs), (ins i32imm:$imm), "ADDI $imm, A14", []> { + let Uses = [A14]; + let Defs = [A14]; +} + +// Materialise a frame address; the base is the reserved FP, so this is not +// the allocatable-register MOVE pattern. +def MOVEFP : TMS34010Inst<(outs ARegs:$dst), (ins), "MOVE A13, $dst", []> { + let Uses = [A13]; +} + +// Read the caller's saved old STK from the system stack into A14. +def LOADSTK : TMS34010Inst<(outs), (ins i32imm:$off), + "MOVE *SP($off), A14, 1", []> { + let mayLoad = 1; + let Uses = [A15]; + let Defs = [A14]; +} + +// The ABI's field-size invariant. No operands; side-effecting. +def SETF32 : TMS34010Inst<(outs), (ins), "SETF 32, 0, 1", []> { + let hasSideEffects = 1; +} + +// Direct ROM/local call; the target is a symbol or bit address. +def CALLA : TMS34010Inst<(outs), (ins i32imm:$target), "CALLA $target", []> { + let isCall = 1; + let Uses = [A14]; + let Defs = [A8]; +} + +// Frame-index materialisation: the base is implicitly A13; expanded after +// frame elimination to MOVEFP dst ; ADDI off, dst +def GETFI : TMS34010Inst<(outs ARegs:$dst), (ins i32imm:$off), "# GETFI", []> { + let isPseudo = 1; +} + def NOP : TMS34010Inst<(outs), (ins), "NOP", []> { let Inst{15-0} = 0x0300; } - -def : Pat<(TMS34010retglue), (RETS 0)>; diff --git a/llvm/lib/Target/TMS34010/TMS34010RegisterInfo.cpp b/llvm/lib/Target/TMS34010/TMS34010RegisterInfo.cpp index 6752691c864c..42e30f12698f 100644 --- a/llvm/lib/Target/TMS34010/TMS34010RegisterInfo.cpp +++ b/llvm/lib/Target/TMS34010/TMS34010RegisterInfo.cpp @@ -12,6 +12,7 @@ #include "TMS34010Subtarget.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/TargetFrameLowering.h" using namespace llvm; @@ -22,13 +23,36 @@ TMS34010RegisterInfo::TMS34010RegisterInfo() : TMS34010GenRegisterInfo(TMS34010: const MCPhysReg * TMS34010RegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { - static const MCPhysReg Empty[] = {0}; - return Empty; + // A13 is reserved by the ABI, so PEI cannot list it here; the prologue and + // epilogue save and restore it explicitly. + return CSR_TMS34010_SaveList; +} + +const uint32_t *TMS34010RegisterInfo::getCallPreservedMask( + const MachineFunction &MF, CallingConv::ID CC) const { + // CC_TMS34010 is documented in TMS34010CallingConv.td and lowered directly; + // like the C convention it preserves only A0-A7 and A9-A12 across a call. + (void)MF; + (void)CC; + return CSR_TMS34010_RegMask; } BitVector TMS34010RegisterInfo::getReservedRegs(const MachineFunction &MF) const { - return BitVector(getNumRegs()); + BitVector Reserved(getNumRegs()); + + // A8 is the return-value register, A13 the frame pointer, A14 the program + // stack pointer and A15 the system stack pointer. + Reserved.set(TMS34010::A8); + Reserved.set(TMS34010::A13); + Reserved.set(TMS34010::A14); + Reserved.set(TMS34010::A15); + + // The B file is reserved for a later task. + for (unsigned Reg = TMS34010::B0; Reg <= TMS34010::B15; ++Reg) + Reserved.set(Reg); + + return Reserved; } const TargetRegisterClass * @@ -39,14 +63,27 @@ TMS34010RegisterInfo::getPointerRegClass(unsigned Kind) const { bool TMS34010RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, unsigned FIOperandNum, RegScavenger *RS) const { - MachineFunction &MF = *II->getParent()->getParent(); + MachineInstr &MI = *II; + MachineFunction &MF = *MI.getParent()->getParent(); + + assert(MI.getOpcode() == TMS34010::GETFI && + "only GETFI carries a frame index in M2"); + (void)SPAdj; + (void)RS; + Register FrameReg; - getFrameLowering(MF)->getFrameIndexReference( - MF, II->getOperand(FIOperandNum).getIndex(), FrameReg); + StackOffset Offset = getFrameLowering(MF)->getFrameIndexReference( + MF, MI.getOperand(FIOperandNum).getIndex(), FrameReg); + assert(Offset.getScalable() == 0 && "scalable stack offsets are unsupported"); + assert(FrameReg == TMS34010::A13 && "the frame base is always A13"); + + // GETFI is expanded after frame elimination into MOVEFP dst ; ADDI off, dst + // with the FP-relative bit offset as an immediate. + MI.getOperand(FIOperandNum).ChangeToImmediate(Offset.getFixed()); return false; } Register TMS34010RegisterInfo::getFrameRegister(const MachineFunction &MF) const { - return TMS34010::A14; + return TMS34010::A13; } diff --git a/llvm/lib/Target/TMS34010/TMS34010RegisterInfo.h b/llvm/lib/Target/TMS34010/TMS34010RegisterInfo.h index 6b673e22400f..1336d0ec473a 100644 --- a/llvm/lib/Target/TMS34010/TMS34010RegisterInfo.h +++ b/llvm/lib/Target/TMS34010/TMS34010RegisterInfo.h @@ -22,6 +22,9 @@ public: const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override; + const uint32_t *getCallPreservedMask(const MachineFunction &MF, + CallingConv::ID CC) const override; + BitVector getReservedRegs(const MachineFunction &MF) const override; const TargetRegisterClass * diff --git a/llvm/lib/Target/TMS34010/TMS34010RegisterInfo.td b/llvm/lib/Target/TMS34010/TMS34010RegisterInfo.td index 506b8793d996..df217988844d 100644 --- a/llvm/lib/Target/TMS34010/TMS34010RegisterInfo.td +++ b/llvm/lib/Target/TMS34010/TMS34010RegisterInfo.td @@ -13,7 +13,10 @@ class TMS34010Reg num, string n> : Register { let DwarfNumbers = [num]; } -// The A file holds the general-purpose registers. M1 only allocates A0-A7. +// The A file holds the general-purpose registers. A8 (return value), A13 +// (frame pointer), A14 (program-stack pointer) and A15 (system-stack pointer) +// are reserved by the ABI and are deliberately left out of the allocatable +// class. def A0 : TMS34010Reg<0, "A0">; def A1 : TMS34010Reg<1, "A1">; def A2 : TMS34010Reg<2, "A2">; @@ -50,7 +53,17 @@ def B14 : TMS34010Reg<30, "B14">; def B15 : TMS34010Reg<31, "B15">; def ARegs : RegisterClass<"TMS34010", [i32], 32, - (add A0, A1, A2, A3, A4, A5, A6, A7)>; + (add A0, A1, A2, A3, A4, A5, A6, A7, + A9, A10, A11, A12)>; + +// ARegsAll names every A register. It is used only as the operand class of +// the frame and system-stack instructions, which need to name the reserved +// FP/STK/SP registers explicitly; it is never allocated. +def ARegsAll : RegisterClass<"TMS34010", [i32], 32, + (add A0, A1, A2, A3, A4, A5, A6, A7, + A8, A9, A10, A11, A12, A13, A14, A15)> { + let isAllocatable = 0; +} def BRegs : RegisterClass<"TMS34010", [i32], 32, (add B0, B1, B2, B3, B4, B5, B6, B7, diff --git a/llvm/test/CodeGen/TMS34010/m2-args-locals.ll b/llvm/test/CodeGen/TMS34010/m2-args-locals.ll index 637fa8826756..6de781145603 100644 --- a/llvm/test/CodeGen/TMS34010/m2-args-locals.ll +++ b/llvm/test/CodeGen/TMS34010/m2-args-locals.ll @@ -1,9 +1,9 @@ ; RUN: llc -march=tms34010 -O0 -filetype=asm < %s | FileCheck %s define i32 @mix(i32 %a) { entry: - %x = alloca i32 - store i32 %a, ptr %x - %v = load i32, ptr %x + %x = alloca i32, align 4 + store volatile i32 %a, ptr %x + %v = load volatile i32, ptr %x ret i32 %v } ; CHECK-LABEL: _mix: diff --git a/llvm/test/CodeGen/TMS34010/m2-args.ll b/llvm/test/CodeGen/TMS34010/m2-args.ll index fbff1fe27dfa..f41f16f401a1 100644 --- a/llvm/test/CodeGen/TMS34010/m2-args.ll +++ b/llvm/test/CodeGen/TMS34010/m2-args.ll @@ -5,8 +5,12 @@ entry: ret i32 %r } ; CHECK-LABEL: _add2: +; CHECK: SETF 32, 0, 1 +; CHECK: MOVE A13, -*SP, 1 ; CHECK-DAG: MOVE A13, A{{[0-9]+}} ; CHECK-DAG: ADDI -32, A{{[0-9]+}} ; CHECK-DAG: ADDI -64, A{{[0-9]+}} ; CHECK: MOVE {{A[0-9]+}}, A8 +; CHECK: MOVE *SP(128), A14, 1 +; CHECK: MOVE *SP+, A13, 1 ; CHECK: RETS 2