tms34010: TI ABI callee frames, arguments and returns
This commit is contained in:
1 parent
11bdccf7f1
commit
a6954059ea
14 files changed
+383
-78
No files matched your search
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
Reference in new issue
Block a user