tms34010: TI ABI callee frames, arguments and returns

This commit is contained in:
arti committed 2026-11-11 15:53:28 +00:00
1 parent 11bdccf7f1
commit a6954059ea
14 files changed
+383 -78

No files matched your search

+1
View File
@@ -13,6 +13,7 @@
include "llvm/Target/Target.td"
include "TMS34010RegisterInfo.td"
include "TMS34010CallingConv.td"
include "TMS34010InstrInfo.td"
defm : RemapAllTargetPseudoPointerOperands<ARegs>;
@@ -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)>;
@@ -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<CalleeSavedInfo> &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);
}
@@ -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<CalleeSavedInfo> &CSI) const override {
return true;
}
bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
ArrayRef<CalleeSavedInfo> CSI,
const TargetRegisterInfo *TRI) const override {
return true;
}
bool restoreCalleeSavedRegisters(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
MutableArrayRef<CalleeSavedInfo> 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;
@@ -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<FrameIndexSDNode>(N)->getIndex();
SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32);
CurDAG->SelectNodeTo(N, TMS34010::GETFI, MVT::i32, TFI);
return;
}
SelectCode(N);
}
@@ -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<ISD::InputArg> &Ins, const SDLoc &DL,
SelectionDAG &DAG, SmallVectorImpl<SDValue> &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<CCValAssign, 4> 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<int64_t>(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<SDValue> &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<ISD::OutputArg> &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<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &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<SDValue, 3> 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);
}
+48 -3
View File
@@ -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;
}
@@ -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
+76 -4
View File
@@ -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)>;
@@ -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;
}
@@ -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 *
@@ -13,7 +13,10 @@ class TMS34010Reg<bits<5> num, string n> : Register<n> {
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,
+3 -3
View File
@@ -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:
+4
View File
@@ -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