[CSKY] Add codegen of select/br/cmp instruction and some frame lowering infra

Add basic integer codegen of select/br/cmp instruction. It also includes frame lowering code
such as prologue/epilogue.
This commit is contained in:
Zi Xuan Wu 2021-12-30 16:10:22 +08:00
parent c6c19a77e3
commit 9566cf16ad
11 changed files with 9488 additions and 2 deletions

View File

@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "CSKYFrameLowering.h"
#include "CSKYMachineFunctionInfo.h"
#include "CSKYSubtarget.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
@ -46,12 +47,555 @@ bool CSKYFrameLowering::hasBP(const MachineFunction &MF) const {
return MFI.hasVarSizedObjects();
}
// Determines the size of the frame and maximum call frame size.
void CSKYFrameLowering::determineFrameLayout(MachineFunction &MF) const {
MachineFrameInfo &MFI = MF.getFrameInfo();
const CSKYRegisterInfo *RI = STI.getRegisterInfo();
// Get the number of bytes to allocate from the FrameInfo.
uint64_t FrameSize = MFI.getStackSize();
// Get the alignment.
Align StackAlign = getStackAlign();
if (RI->hasStackRealignment(MF)) {
Align MaxStackAlign = std::max(StackAlign, MFI.getMaxAlign());
FrameSize += (MaxStackAlign.value() - StackAlign.value());
StackAlign = MaxStackAlign;
}
// Set Max Call Frame Size
uint64_t MaxCallSize = alignTo(MFI.getMaxCallFrameSize(), StackAlign);
MFI.setMaxCallFrameSize(MaxCallSize);
// Make sure the frame is aligned.
FrameSize = alignTo(FrameSize, StackAlign);
// Update frame info.
MFI.setStackSize(FrameSize);
}
void CSKYFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
// FIXME: Implement this when we have function calls
CSKYMachineFunctionInfo *CFI = MF.getInfo<CSKYMachineFunctionInfo>();
MachineFrameInfo &MFI = MF.getFrameInfo();
const CSKYRegisterInfo *RI = STI.getRegisterInfo();
const CSKYInstrInfo *TII = STI.getInstrInfo();
MachineBasicBlock::iterator MBBI = MBB.begin();
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
const MachineRegisterInfo &MRI = MF.getRegInfo();
Register FPReg = getFPReg(STI);
Register SPReg = CSKY::R14;
Register BPReg = getBPReg(STI);
// Debug location must be unknown since the first debug location is used
// to determine the end of the prologue.
DebugLoc DL;
if (MF.getFunction().hasFnAttribute("interrupt"))
BuildMI(MBB, MBBI, DL, TII->get(CSKY::NIE));
// Determine the correct frame layout
determineFrameLayout(MF);
// FIXME (note copied from Lanai): This appears to be overallocating. Needs
// investigation. Get the number of bytes to allocate from the FrameInfo.
uint64_t StackSize = MFI.getStackSize();
// Early exit if there is no need to allocate on the stack
if (StackSize == 0 && !MFI.adjustsStack())
return;
const auto &CSI = MFI.getCalleeSavedInfo();
unsigned spillAreaSize = CFI->getCalleeSaveAreaSize();
uint64_t ActualSize = spillAreaSize + CFI->getVarArgsSaveSize();
// First part stack allocation.
adjustReg(MBB, MBBI, DL, SPReg, SPReg, -(static_cast<int64_t>(ActualSize)),
MachineInstr::NoFlags);
// Emit ".cfi_def_cfa_offset FirstSPAdjustAmount"
unsigned CFIIndex =
MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, ActualSize));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
// The frame pointer is callee-saved, and code has been generated for us to
// save it to the stack. We need to skip over the storing of callee-saved
// registers as the frame pointer must be modified after it has been saved
// to the stack, not before.
// FIXME: assumes exactly one instruction is used to save each callee-saved
// register.
std::advance(MBBI, CSI.size());
// Iterate over list of callee-saved registers and emit .cfi_offset
// directives.
for (const auto &Entry : CSI) {
int64_t Offset = MFI.getObjectOffset(Entry.getFrameIdx());
Register Reg = Entry.getReg();
unsigned Num = TRI->getRegSizeInBits(Reg, MRI) / 32;
for (unsigned i = 0; i < Num; i++) {
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, RI->getDwarfRegNum(Reg, true) + i, Offset + i * 4));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
}
}
// Generate new FP.
if (hasFP(MF)) {
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::COPY), FPReg)
.addReg(SPReg)
.setMIFlag(MachineInstr::FrameSetup);
// Emit ".cfi_def_cfa_register $fp"
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfaRegister(
nullptr, RI->getDwarfRegNum(FPReg, true)));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
// Second part stack allocation.
adjustReg(MBB, MBBI, DL, SPReg, SPReg,
-(static_cast<int64_t>(StackSize - ActualSize)),
MachineInstr::NoFlags);
// Realign Stack
const CSKYRegisterInfo *RI = STI.getRegisterInfo();
if (RI->hasStackRealignment(MF)) {
Align MaxAlignment = MFI.getMaxAlign();
const CSKYInstrInfo *TII = STI.getInstrInfo();
if (STI.hasE2() && isUInt<12>(~(-(int)MaxAlignment.value()))) {
BuildMI(MBB, MBBI, DL, TII->get(CSKY::ANDNI32), SPReg)
.addReg(SPReg)
.addImm(~(-(int)MaxAlignment.value()));
} else {
unsigned ShiftAmount = Log2(MaxAlignment);
if (STI.hasE2()) {
Register VR =
MF.getRegInfo().createVirtualRegister(&CSKY::GPRRegClass);
BuildMI(MBB, MBBI, DL, TII->get(CSKY::LSRI32), VR)
.addReg(SPReg)
.addImm(ShiftAmount);
BuildMI(MBB, MBBI, DL, TII->get(CSKY::LSLI32), SPReg)
.addReg(VR)
.addImm(ShiftAmount);
} else {
Register VR =
MF.getRegInfo().createVirtualRegister(&CSKY::mGPRRegClass);
BuildMI(MBB, MBBI, DL, TII->get(CSKY::MOV16), VR).addReg(SPReg);
BuildMI(MBB, MBBI, DL, TII->get(CSKY::LSRI16), VR)
.addReg(VR)
.addImm(ShiftAmount);
BuildMI(MBB, MBBI, DL, TII->get(CSKY::LSLI16), VR)
.addReg(VR)
.addImm(ShiftAmount);
BuildMI(MBB, MBBI, DL, TII->get(CSKY::MOV16), SPReg).addReg(VR);
}
}
}
// FP will be used to restore the frame in the epilogue, so we need
// another base register BP to record SP after re-alignment. SP will
// track the current stack after allocating variable sized objects.
if (hasBP(MF)) {
// move BP, SP
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::COPY), BPReg).addReg(SPReg);
}
} else {
adjustReg(MBB, MBBI, DL, SPReg, SPReg,
-(static_cast<int64_t>(StackSize - ActualSize)),
MachineInstr::NoFlags);
// Emit ".cfi_def_cfa_offset StackSize"
unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::cfiDefCfaOffset(nullptr, MFI.getStackSize()));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
}
}
void CSKYFrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
// FIXME: Implement this when we have function calls
CSKYMachineFunctionInfo *CFI = MF.getInfo<CSKYMachineFunctionInfo>();
MachineFrameInfo &MFI = MF.getFrameInfo();
Register FPReg = getFPReg(STI);
Register SPReg = CSKY::R14;
// Get the insert location for the epilogue. If there were no terminators in
// the block, get the last instruction.
MachineBasicBlock::iterator MBBI = MBB.end();
DebugLoc DL;
if (!MBB.empty()) {
MBBI = MBB.getFirstTerminator();
if (MBBI == MBB.end())
MBBI = MBB.getLastNonDebugInstr();
DL = MBBI->getDebugLoc();
// If this is not a terminator, the actual insert location should be after
// the last instruction.
if (!MBBI->isTerminator())
MBBI = std::next(MBBI);
}
const auto &CSI = MFI.getCalleeSavedInfo();
uint64_t StackSize = MFI.getStackSize();
uint64_t ActualSize =
CFI->getCalleeSaveAreaSize() + CFI->getVarArgsSaveSize();
// Skip to before the restores of callee-saved registers
// FIXME: assumes exactly one instruction is used to restore each
// callee-saved register.
auto LastFrameDestroy = MBBI;
if (!CSI.empty())
LastFrameDestroy = std::prev(MBBI, CSI.size());
if (hasFP(MF)) {
const CSKYInstrInfo *TII = STI.getInstrInfo();
BuildMI(MBB, LastFrameDestroy, DL, TII->get(TargetOpcode::COPY), SPReg)
.addReg(FPReg)
.setMIFlag(MachineInstr::NoFlags);
} else {
adjustReg(MBB, LastFrameDestroy, DL, SPReg, SPReg, (StackSize - ActualSize),
MachineInstr::FrameDestroy);
}
adjustReg(MBB, MBBI, DL, SPReg, SPReg, ActualSize,
MachineInstr::FrameDestroy);
}
static unsigned estimateRSStackSizeLimit(MachineFunction &MF,
const CSKYSubtarget &STI) {
unsigned Limit = (1 << 12) - 1;
for (auto &MBB : MF) {
for (auto &MI : MBB) {
if (MI.isDebugInstr())
continue;
for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) {
if (!MI.getOperand(i).isFI())
continue;
if (MI.getOpcode() == CSKY::SPILL_CARRY ||
MI.getOpcode() == CSKY::RESTORE_CARRY ||
MI.getOpcode() == CSKY::STORE_PAIR ||
MI.getOpcode() == CSKY::LOAD_PAIR) {
Limit = std::min(Limit, ((1U << 12) - 1) * 4);
break;
}
if (MI.getOpcode() == CSKY::ADDI32) {
Limit = std::min(Limit, (1U << 12));
break;
}
if (MI.getOpcode() == CSKY::ADDI16XZ) {
Limit = std::min(Limit, (1U << 3));
break;
}
// ADDI16 will not require an extra register,
// it can reuse the destination.
if (MI.getOpcode() == CSKY::ADDI16)
break;
// Otherwise check the addressing mode.
switch (MI.getDesc().TSFlags & CSKYII::AddrModeMask) {
default:
LLVM_DEBUG(MI.dump());
llvm_unreachable(
"Unhandled addressing mode in stack size limit calculation");
case CSKYII::AddrMode32B:
Limit = std::min(Limit, (1U << 12) - 1);
break;
case CSKYII::AddrMode32H:
Limit = std::min(Limit, ((1U << 12) - 1) * 2);
break;
case CSKYII::AddrMode32WD:
Limit = std::min(Limit, ((1U << 12) - 1) * 4);
break;
case CSKYII::AddrMode16B:
Limit = std::min(Limit, (1U << 5) - 1);
break;
case CSKYII::AddrMode16H:
Limit = std::min(Limit, ((1U << 5) - 1) * 2);
break;
case CSKYII::AddrMode16W:
Limit = std::min(Limit, ((1U << 5) - 1) * 4);
break;
case CSKYII::AddrMode32SDF:
Limit = std::min(Limit, ((1U << 8) - 1) * 4);
break;
}
break; // At most one FI per instruction
}
}
}
return Limit;
}
void CSKYFrameLowering::determineCalleeSaves(MachineFunction &MF,
BitVector &SavedRegs,
RegScavenger *RS) const {
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
CSKYMachineFunctionInfo *CFI = MF.getInfo<CSKYMachineFunctionInfo>();
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
const MachineRegisterInfo &MRI = MF.getRegInfo();
MachineFrameInfo &MFI = MF.getFrameInfo();
if (hasFP(MF))
SavedRegs.set(CSKY::R8);
// Mark BP as used if function has dedicated base pointer.
if (hasBP(MF))
SavedRegs.set(CSKY::R7);
// If interrupt is enabled and there are calls in the handler,
// unconditionally save all Caller-saved registers and
// all FP registers, regardless whether they are used.
if (MF.getFunction().hasFnAttribute("interrupt") && MFI.hasCalls()) {
static const MCPhysReg CSRegs[] = {CSKY::R0, CSKY::R1, CSKY::R2, CSKY::R3,
CSKY::R12, CSKY::R13, 0};
for (unsigned i = 0; CSRegs[i]; ++i)
SavedRegs.set(CSRegs[i]);
if (STI.hasHighRegisters()) {
static const MCPhysReg CSHRegs[] = {CSKY::R18, CSKY::R19, CSKY::R20,
CSKY::R21, CSKY::R22, CSKY::R23,
CSKY::R24, CSKY::R25, 0};
for (unsigned i = 0; CSHRegs[i]; ++i)
SavedRegs.set(CSHRegs[i]);
}
static const MCPhysReg CSF32Regs[] = {
CSKY::F8_32, CSKY::F9_32, CSKY::F10_32,
CSKY::F11_32, CSKY::F12_32, CSKY::F13_32,
CSKY::F14_32, CSKY::F15_32, 0};
static const MCPhysReg CSF64Regs[] = {
CSKY::F8_64, CSKY::F9_64, CSKY::F10_64,
CSKY::F11_64, CSKY::F12_64, CSKY::F13_64,
CSKY::F14_64, CSKY::F15_64, 0};
const MCPhysReg *FRegs = NULL;
if (STI.hasFPUv2DoubleFloat() || STI.hasFPUv3DoubleFloat())
FRegs = CSF64Regs;
else if (STI.hasFPUv2SingleFloat() || STI.hasFPUv3SingleFloat())
FRegs = CSF32Regs;
if (FRegs != NULL) {
const MCPhysReg *Regs = MF.getRegInfo().getCalleeSavedRegs();
for (unsigned i = 0; Regs[i]; ++i)
if (CSKY::FPR32RegClass.contains(Regs[i]) ||
CSKY::FPR64RegClass.contains(Regs[i])) {
unsigned x = 0;
for (; FRegs[x]; ++x)
if (FRegs[x] == Regs[i])
break;
if (FRegs[x] == 0)
SavedRegs.set(Regs[i]);
}
}
}
CFI->setLRIsSpilled(SavedRegs.test(CSKY::R15));
unsigned CSStackSize = 0;
for (unsigned Reg : SavedRegs.set_bits()) {
auto RegSize = TRI->getRegSizeInBits(Reg, MRI) / 8;
CSStackSize += RegSize;
}
CFI->setCalleeSaveAreaSize(CSStackSize);
uint64_t Limit = estimateRSStackSizeLimit(MF, STI);
bool BigFrame = (MFI.estimateStackSize(MF) + CSStackSize >= Limit);
if (BigFrame || CFI->isCRSpilled() || !STI.hasE2()) {
const TargetRegisterClass *RC = &CSKY::GPRRegClass;
unsigned size = TRI->getSpillSize(*RC);
Align align = TRI->getSpillAlign(*RC);
RS->addScavengingFrameIndex(MFI.CreateStackObject(size, align, false));
}
}
// Not preserve stack space within prologue for outgoing variables when the
// function contains variable size objects and let eliminateCallFramePseudoInstr
// preserve stack space for it.
bool CSKYFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
return !MF.getFrameInfo().hasVarSizedObjects();
}
bool CSKYFrameLowering::spillCalleeSavedRegisters(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
if (CSI.empty())
return true;
MachineFunction *MF = MBB.getParent();
const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
DebugLoc DL;
if (MI != MBB.end() && !MI->isDebugInstr())
DL = MI->getDebugLoc();
for (auto &CS : CSI) {
// Insert the spill to the stack frame.
Register Reg = CS.getReg();
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
TII.storeRegToStackSlot(MBB, MI, Reg, true, CS.getFrameIdx(), RC, TRI);
}
return true;
}
bool CSKYFrameLowering::restoreCalleeSavedRegisters(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
if (CSI.empty())
return true;
MachineFunction *MF = MBB.getParent();
const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
DebugLoc DL;
if (MI != MBB.end() && !MI->isDebugInstr())
DL = MI->getDebugLoc();
for (auto &CS : reverse(CSI)) {
Register Reg = CS.getReg();
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
TII.loadRegFromStackSlot(MBB, MI, Reg, CS.getFrameIdx(), RC, TRI);
assert(MI != MBB.begin() && "loadRegFromStackSlot didn't insert any code!");
}
return true;
}
// Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions.
MachineBasicBlock::iterator CSKYFrameLowering::eliminateCallFramePseudoInstr(
MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI) const {
Register SPReg = CSKY::R14;
DebugLoc DL = MI->getDebugLoc();
if (!hasReservedCallFrame(MF)) {
// If space has not been reserved for a call frame, ADJCALLSTACKDOWN and
// ADJCALLSTACKUP must be converted to instructions manipulating the stack
// pointer. This is necessary when there is a variable length stack
// allocation (e.g. alloca), which means it's not possible to allocate
// space for outgoing arguments from within the function prologue.
int64_t Amount = MI->getOperand(0).getImm();
if (Amount != 0) {
// Ensure the stack remains aligned after adjustment.
Amount = alignSPAdjust(Amount);
if (MI->getOpcode() == CSKY::ADJCALLSTACKDOWN)
Amount = -Amount;
adjustReg(MBB, MI, DL, SPReg, SPReg, Amount, MachineInstr::NoFlags);
}
}
return MBB.erase(MI);
}
void CSKYFrameLowering::adjustReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
const DebugLoc &DL, Register DestReg,
Register SrcReg, int64_t Val,
MachineInstr::MIFlag Flag) const {
const CSKYInstrInfo *TII = STI.getInstrInfo();
if (DestReg == SrcReg && Val == 0)
return;
// TODO: Add 16-bit instruction support with immediate num
if (STI.hasE2() && isUInt<12>(std::abs(Val) - 1)) {
BuildMI(MBB, MBBI, DL, TII->get(Val < 0 ? CSKY::SUBI32 : CSKY::ADDI32),
DestReg)
.addReg(SrcReg)
.addImm(std::abs(Val))
.setMIFlag(Flag);
} else if (!STI.hasE2() && isShiftedUInt<7, 2>(std::abs(Val))) {
BuildMI(MBB, MBBI, DL,
TII->get(Val < 0 ? CSKY::SUBI16SPSP : CSKY::ADDI16SPSP), CSKY::R14)
.addReg(CSKY::R14, RegState::Kill)
.addImm(std::abs(Val))
.setMIFlag(Flag);
} else {
unsigned Op = 0;
if (STI.hasE2()) {
Op = Val < 0 ? CSKY::SUBU32 : CSKY::ADDU32;
} else {
assert(SrcReg == DestReg);
Op = Val < 0 ? CSKY::SUBU16XZ : CSKY::ADDU16XZ;
}
Register ScratchReg = TII->movImm(MBB, MBBI, DL, std::abs(Val), Flag);
BuildMI(MBB, MBBI, DL, TII->get(Op), DestReg)
.addReg(SrcReg)
.addReg(ScratchReg, RegState::Kill)
.setMIFlag(Flag);
}
}
StackOffset
CSKYFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
Register &FrameReg) const {
const CSKYMachineFunctionInfo *CFI = MF.getInfo<CSKYMachineFunctionInfo>();
const MachineFrameInfo &MFI = MF.getFrameInfo();
const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo();
const auto &CSI = MFI.getCalleeSavedInfo();
int MinCSFI = 0;
int MaxCSFI = -1;
int Offset = MFI.getObjectOffset(FI) + MFI.getOffsetAdjustment();
if (CSI.size()) {
MinCSFI = CSI[0].getFrameIdx();
MaxCSFI = CSI[CSI.size() - 1].getFrameIdx();
}
if (FI >= MinCSFI && FI <= MaxCSFI) {
FrameReg = CSKY::R14;
Offset += CFI->getVarArgsSaveSize() + CFI->getCalleeSaveAreaSize();
} else if (RI->hasStackRealignment(MF)) {
assert(hasFP(MF));
if (!MFI.isFixedObjectIndex(FI)) {
FrameReg = hasBP(MF) ? getBPReg(STI) : CSKY::R14;
Offset += MFI.getStackSize();
} else {
FrameReg = getFPReg(STI);
Offset += CFI->getVarArgsSaveSize() + CFI->getCalleeSaveAreaSize();
}
} else {
if (MFI.isFixedObjectIndex(FI) && hasFP(MF)) {
FrameReg = getFPReg(STI);
Offset += CFI->getVarArgsSaveSize() + CFI->getCalleeSaveAreaSize();
} else {
FrameReg = hasBP(MF) ? getBPReg(STI) : CSKY::R14;
Offset += MFI.getStackSize();
}
}
return StackOffset::getFixed(Offset);
}

View File

@ -21,6 +21,11 @@ class CSKYSubtarget;
class CSKYFrameLowering : public TargetFrameLowering {
const CSKYSubtarget &STI;
void determineFrameLayout(MachineFunction &MF) const;
void adjustReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
const DebugLoc &DL, Register DestReg, Register SrcReg,
int64_t Val, MachineInstr::MIFlag Flag) const;
public:
explicit CSKYFrameLowering(const CSKYSubtarget &STI)
: TargetFrameLowering(StackGrowsDown,
@ -31,8 +36,39 @@ public:
void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
Register &FrameReg) const override;
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
RegScavenger *RS) const override;
bool assignCalleeSavedSpillSlots(
MachineFunction &MF, const TargetRegisterInfo *TRI,
std::vector<CalleeSavedInfo> &CSI) const override {
std::reverse(CSI.begin(), CSI.end());
return false;
}
bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
ArrayRef<CalleeSavedInfo> CSI,
const TargetRegisterInfo *TRI) const override;
bool
restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
MutableArrayRef<CalleeSavedInfo> CSI,
const TargetRegisterInfo *TRI) const override;
bool hasFP(const MachineFunction &MF) const override;
bool hasBP(const MachineFunction &MF) const;
bool hasReservedCallFrame(const MachineFunction &MF) const override;
MachineBasicBlock::iterator
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI) const override;
};
} // namespace llvm
#endif

View File

@ -68,6 +68,17 @@ void CSKYDAGToDAGISel::Select(SDNode *N) {
case ISD::SUBCARRY:
IsSelected = selectSubCarry(N);
break;
case ISD::FrameIndex: {
SDValue Imm = CurDAG->getTargetConstant(0, Dl, MVT::i32);
int FI = cast<FrameIndexSDNode>(N)->getIndex();
SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32);
ReplaceNode(N, CurDAG->getMachineNode(Subtarget->hasE2() ? CSKY::ADDI32
: CSKY::ADDI16XZ,
Dl, MVT::i32, TFI, Imm));
IsSelected = true;
break;
}
}
if (IsSelected)

View File

@ -53,6 +53,9 @@ CSKYTargetLowering::CSKYTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand);
setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand);
setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand);
setOperationAction(ISD::SELECT_CC, MVT::i32, Expand);
setOperationAction(ISD::BR_CC, MVT::i32, Expand);
setOperationAction(ISD::BR_JT, MVT::Other, Expand);
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand);
setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);

View File

@ -26,6 +26,195 @@ CSKYInstrInfo::CSKYInstrInfo(CSKYSubtarget &STI)
: CSKYGenInstrInfo(CSKY::ADJCALLSTACKDOWN, CSKY::ADJCALLSTACKUP), STI(STI) {
}
static void parseCondBranch(MachineInstr &LastInst, MachineBasicBlock *&Target,
SmallVectorImpl<MachineOperand> &Cond) {
// Block ends with fall-through condbranch.
assert(LastInst.getDesc().isConditionalBranch() &&
"Unknown conditional branch");
Target = LastInst.getOperand(1).getMBB();
Cond.push_back(MachineOperand::CreateImm(LastInst.getOpcode()));
Cond.push_back(LastInst.getOperand(0));
}
bool CSKYInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
MachineBasicBlock *&TBB,
MachineBasicBlock *&FBB,
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify) const {
TBB = FBB = nullptr;
Cond.clear();
// If the block has no terminators, it just falls into the block after it.
MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
if (I == MBB.end() || !isUnpredicatedTerminator(*I))
return false;
// Count the number of terminators and find the first unconditional or
// indirect branch.
MachineBasicBlock::iterator FirstUncondOrIndirectBr = MBB.end();
int NumTerminators = 0;
for (auto J = I.getReverse(); J != MBB.rend() && isUnpredicatedTerminator(*J);
J++) {
NumTerminators++;
if (J->getDesc().isUnconditionalBranch() ||
J->getDesc().isIndirectBranch()) {
FirstUncondOrIndirectBr = J.getReverse();
}
}
// If AllowModify is true, we can erase any terminators after
// FirstUncondOrIndirectBR.
if (AllowModify && FirstUncondOrIndirectBr != MBB.end()) {
while (std::next(FirstUncondOrIndirectBr) != MBB.end()) {
std::next(FirstUncondOrIndirectBr)->eraseFromParent();
NumTerminators--;
}
I = FirstUncondOrIndirectBr;
}
// We can't handle blocks that end in an indirect branch.
if (I->getDesc().isIndirectBranch())
return true;
// We can't handle blocks with more than 2 terminators.
if (NumTerminators > 2)
return true;
// Handle a single unconditional branch.
if (NumTerminators == 1 && I->getDesc().isUnconditionalBranch()) {
TBB = getBranchDestBlock(*I);
return false;
}
// Handle a single conditional branch.
if (NumTerminators == 1 && I->getDesc().isConditionalBranch()) {
parseCondBranch(*I, TBB, Cond);
return false;
}
// Handle a conditional branch followed by an unconditional branch.
if (NumTerminators == 2 && std::prev(I)->getDesc().isConditionalBranch() &&
I->getDesc().isUnconditionalBranch()) {
parseCondBranch(*std::prev(I), TBB, Cond);
FBB = getBranchDestBlock(*I);
return false;
}
// Otherwise, we can't handle this.
return true;
}
unsigned CSKYInstrInfo::removeBranch(MachineBasicBlock &MBB,
int *BytesRemoved) const {
if (BytesRemoved)
*BytesRemoved = 0;
MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
if (I == MBB.end())
return 0;
if (!I->getDesc().isUnconditionalBranch() &&
!I->getDesc().isConditionalBranch())
return 0;
// Remove the branch.
if (BytesRemoved)
*BytesRemoved += getInstSizeInBytes(*I);
I->eraseFromParent();
I = MBB.end();
if (I == MBB.begin())
return 1;
--I;
if (!I->getDesc().isConditionalBranch())
return 1;
// Remove the branch.
if (BytesRemoved)
*BytesRemoved += getInstSizeInBytes(*I);
I->eraseFromParent();
return 2;
}
MachineBasicBlock *
CSKYInstrInfo::getBranchDestBlock(const MachineInstr &MI) const {
assert(MI.getDesc().isBranch() && "Unexpected opcode!");
// The branch target is always the last operand.
int NumOp = MI.getNumExplicitOperands();
assert(MI.getOperand(NumOp - 1).isMBB() && "Expected MBB!");
return MI.getOperand(NumOp - 1).getMBB();
}
unsigned CSKYInstrInfo::insertBranch(
MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB,
ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const {
if (BytesAdded)
*BytesAdded = 0;
// Shouldn't be a fall through.
assert(TBB && "insertBranch must not be told to insert a fallthrough");
assert((Cond.size() == 2 || Cond.size() == 0) &&
"CSKY branch conditions have two components!");
// Unconditional branch.
if (Cond.empty()) {
MachineInstr &MI = *BuildMI(&MBB, DL, get(CSKY::BR32)).addMBB(TBB);
if (BytesAdded)
*BytesAdded += getInstSizeInBytes(MI);
return 1;
}
// Either a one or two-way conditional branch.
unsigned Opc = Cond[0].getImm();
MachineInstr &CondMI = *BuildMI(&MBB, DL, get(Opc)).add(Cond[1]).addMBB(TBB);
if (BytesAdded)
*BytesAdded += getInstSizeInBytes(CondMI);
// One-way conditional branch.
if (!FBB)
return 1;
// Two-way conditional branch.
MachineInstr &MI = *BuildMI(&MBB, DL, get(CSKY::BR32)).addMBB(FBB);
if (BytesAdded)
*BytesAdded += getInstSizeInBytes(MI);
return 2;
}
static unsigned getOppositeBranchOpc(unsigned Opcode) {
switch (Opcode) {
default:
llvm_unreachable("Unknown conditional branch!");
case CSKY::BT32:
return CSKY::BF32;
case CSKY::BT16:
return CSKY::BF16;
case CSKY::BF32:
return CSKY::BT32;
case CSKY::BF16:
return CSKY::BT16;
case CSKY::BHZ32:
return CSKY::BLSZ32;
case CSKY::BHSZ32:
return CSKY::BLZ32;
case CSKY::BLZ32:
return CSKY::BHSZ32;
case CSKY::BLSZ32:
return CSKY::BHZ32;
case CSKY::BNEZ32:
return CSKY::BEZ32;
case CSKY::BEZ32:
return CSKY::BNEZ32;
}
}
bool CSKYInstrInfo::reverseBranchCondition(
SmallVectorImpl<MachineOperand> &Cond) const {
assert((Cond.size() == 2) && "Invalid branch condition!");
Cond[0].setImm(getOppositeBranchOpc(Cond[0].getImm()));
return false;
}
Register CSKYInstrInfo::movImm(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
const DebugLoc &DL, int64_t Val,

View File

@ -50,6 +50,24 @@ public:
const DebugLoc &DL, MCRegister DestReg, MCRegister SrcReg,
bool KillSrc) const override;
unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
const DebugLoc &DL,
int *BytesAdded = nullptr) const override;
bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
MachineBasicBlock *&FBB,
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify = false) const override;
unsigned removeBranch(MachineBasicBlock &MBB,
int *BytesRemoved = nullptr) const override;
bool
reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
MachineBasicBlock *getBranchDestBlock(const MachineInstr &MI) const override;
// Materializes the given integer Val into DstReg.
Register movImm(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
const DebugLoc &DL, int64_t Val,

View File

@ -1057,6 +1057,153 @@ let Predicates = [iHas2E3] in {
def : Pat<(and GPR:$src, 65535), (ZEXT32 GPR:$src, 15, 0)>;
}
// Branch Patterns.
let Predicates = [iHasE2] in {
def : Pat<(brcond CARRY:$ca, bb:$imm16),
(BT32 CARRY:$ca, bb:$imm16)>;
def : Pat<(brcond (i32 (setne GPR:$rs1, uimm16:$rs2)), bb:$imm16),
(BT32 (CMPNEI32 GPR:$rs1, uimm16:$rs2), bb:$imm16)>;
def : Pat<(brcond (i32 (seteq GPR:$rs1, uimm16:$rs2)), bb:$imm16),
(BF32 (CMPNEI32 GPR:$rs1, uimm16:$rs2), bb:$imm16)>;
def : Pat<(brcond (i32 (setuge GPR:$rs1, oimm16:$rs2)), bb:$imm16),
(BT32 (CMPHSI32 GPR:$rs1, oimm16:$rs2), bb:$imm16)>;
def : Pat<(brcond (i32 (setult GPR:$rs1, oimm16:$rs2)), bb:$imm16),
(BF32 (CMPHSI32 GPR:$rs1, oimm16:$rs2), bb:$imm16)>;
def : Pat<(brcond (i32 (setlt GPR:$rs1, oimm16:$rs2)), bb:$imm16),
(BT32 (CMPLTI32 GPR:$rs1, oimm16:$rs2), bb:$imm16)>;
def : Pat<(brcond (i32 (setge GPR:$rs1, oimm16:$rs2)), bb:$imm16),
(BF32 (CMPLTI32 GPR:$rs1, oimm16:$rs2), bb:$imm16)>;
}
let Predicates = [iHas2E3] in {
def : Pat<(brcond (i32 (setne GPR:$rs1, GPR:$rs2)), bb:$imm16),
(BT32 (CMPNE32 GPR:$rs1, GPR:$rs2), bb:$imm16)>;
def : Pat<(brcond (i32 (seteq GPR:$rs1, GPR:$rs2)), bb:$imm16),
(BF32 (CMPNE32 GPR:$rs1, GPR:$rs2), bb:$imm16)>;
def : Pat<(brcond (i32 (setuge GPR:$rs1, GPR:$rs2)), bb:$imm16),
(BT32 (CMPHS32 GPR:$rs1, GPR:$rs2), bb:$imm16)>;
def : Pat<(brcond (i32 (setule GPR:$rs1, GPR:$rs2)), bb:$imm16),
(BT32 (CMPHS32 GPR:$rs2, GPR:$rs1), bb:$imm16)>;
def : Pat<(brcond (i32 (setult GPR:$rs1, GPR:$rs2)), bb:$imm16),
(BF32 (CMPHS32 GPR:$rs1, GPR:$rs2), bb:$imm16)>;
def : Pat<(brcond (i32 (setugt GPR:$rs1, GPR:$rs2)), bb:$imm16),
(BF32 (CMPHS32 GPR:$rs2, GPR:$rs1), bb:$imm16)>;
def : Pat<(brcond (i32 (setlt GPR:$rs1, GPR:$rs2)), bb:$imm16),
(BT32 (CMPLT32 GPR:$rs1, GPR:$rs2), bb:$imm16)>;
def : Pat<(brcond (i32 (setgt GPR:$rs1, GPR:$rs2)), bb:$imm16),
(BT32 (CMPLT32 GPR:$rs2, GPR:$rs1), bb:$imm16)>;
def : Pat<(brcond (i32 (setge GPR:$rs1, GPR:$rs2)), bb:$imm16),
(BF32 (CMPLT32 GPR:$rs1, GPR:$rs2), bb:$imm16)>;
def : Pat<(brcond (i32 (setle GPR:$rs1, GPR:$rs2)), bb:$imm16),
(BF32 (CMPLT32 GPR:$rs2, GPR:$rs1), bb:$imm16)>;
def : Pat<(brcond (i32 (seteq GPR:$rs1, (i32 0))), bb:$imm16),
(BEZ32 GPR:$rs1, bb:$imm16)>;
def : Pat<(brcond (i32 (setne GPR:$rs1, (i32 0))), bb:$imm16),
(BNEZ32 GPR:$rs1, bb:$imm16)>;
def : Pat<(brcond (i32 (setlt GPR:$rs1, (i32 0))), bb:$imm16),
(BLZ32 GPR:$rs1, bb:$imm16)>;
def : Pat<(brcond (i32 (setge GPR:$rs1, (i32 0))), bb:$imm16),
(BHSZ32 GPR:$rs1, bb:$imm16)>;
def : Pat<(brcond (i32 (setgt GPR:$rs1, (i32 0))), bb:$imm16),
(BHZ32 GPR:$rs1, bb:$imm16)>;
def : Pat<(brcond (i32 (setle GPR:$rs1, (i32 0))), bb:$imm16),
(BLSZ32 GPR:$rs1, bb:$imm16)>;
}
// Compare Patterns.
let Predicates = [iHas2E3] in {
def : Pat<(setne GPR:$rs1, GPR:$rs2),
(CMPNE32 GPR:$rs1, GPR:$rs2)>;
def : Pat<(i32 (seteq GPR:$rs1, GPR:$rs2)),
(MVCV32 (CMPNE32 GPR:$rs1, GPR:$rs2))>;
def : Pat<(setuge GPR:$rs1, GPR:$rs2),
(CMPHS32 GPR:$rs1, GPR:$rs2)>;
def : Pat<(setule GPR:$rs1, GPR:$rs2),
(CMPHS32 GPR:$rs2, GPR:$rs1)>;
def : Pat<(i32 (setult GPR:$rs1, GPR:$rs2)),
(MVCV32 (CMPHS32 GPR:$rs1, GPR:$rs2))>;
def : Pat<(i32 (setugt GPR:$rs1, GPR:$rs2)),
(MVCV32 (CMPHS32 GPR:$rs2, GPR:$rs1))>;
def : Pat<(setlt GPR:$rs1, GPR:$rs2),
(CMPLT32 GPR:$rs1, GPR:$rs2)>;
def : Pat<(setgt GPR:$rs1, GPR:$rs2),
(CMPLT32 GPR:$rs2, GPR:$rs1)>;
def : Pat<(i32 (setge GPR:$rs1, GPR:$rs2)),
(MVCV32 (CMPLT32 GPR:$rs1, GPR:$rs2))>;
def : Pat<(i32 (setle GPR:$rs1, GPR:$rs2)),
(MVCV32 (CMPLT32 GPR:$rs2, GPR:$rs1))>;
}
let Predicates = [iHasE2] in {
def : Pat<(setne GPR:$rs1, uimm16:$rs2),
(CMPNEI32 GPR:$rs1, uimm16:$rs2)>;
let Predicates = [iHas2E3] in
def : Pat<(i32 (seteq GPR:$rs1, uimm16:$rs2)),
(MVCV32 (CMPNEI32 GPR:$rs1, uimm16:$rs2))>;
def : Pat<(setuge GPR:$rs1, oimm16:$rs2),
(CMPHSI32 GPR:$rs1, oimm16:$rs2)>;
let Predicates = [iHas2E3] in
def : Pat<(i32 (setult GPR:$rs1, oimm16:$rs2)),
(MVCV32 (CMPHSI32 GPR:$rs1, oimm16:$rs2))>;
def : Pat<(setlt GPR:$rs1, oimm16:$rs2),
(CMPLTI32 GPR:$rs1, oimm16:$rs2)>;
let Predicates = [iHas2E3] in
def : Pat<(i32 (setge GPR:$rs1, oimm16:$rs2)),
(MVCV32 (CMPLTI32 GPR:$rs1, oimm16:$rs2))>;
}
// Select Patterns.
let Predicates = [iHasE2] in {
def : Pat<(select CARRY:$ca, GPR:$rx, GPR:$false),
(MOVT32 CARRY:$ca, GPR:$rx, GPR:$false)>;
def : Pat<(select (and CARRY:$ca, 1), GPR:$rx, GPR:$false),
(MOVT32 CARRY:$ca, GPR:$rx, GPR:$false)>;
def : Pat<(select (i32 (setne GPR:$rs1, GPR:$rs2)), GPR:$rx, GPR:$false),
(MOVT32 (CMPNE32 GPR:$rs1, GPR:$rs2), GPR:$rx, GPR:$false)>;
def : Pat<(select (i32 (setne GPR:$rs1, uimm16:$rs2)), GPR:$rx, GPR:$false),
(MOVT32 (CMPNEI32 GPR:$rs1, uimm16:$rs2), GPR:$rx, GPR:$false)>;
def : Pat<(select (i32 (seteq GPR:$rs1, GPR:$rs2)), GPR:$rx, GPR:$false),
(MOVF32 (CMPNE32 GPR:$rs1, GPR:$rs2), GPR:$rx, GPR:$false)>;
def : Pat<(select (i32 (seteq GPR:$rs1, uimm16:$rs2)), GPR:$rx, GPR:$false),
(MOVF32 (CMPNEI32 GPR:$rs1, uimm16:$rs2), GPR:$rx, GPR:$false)>;
def : Pat<(select (i32 (setuge GPR:$rs1, GPR:$rs2)), GPR:$rx, GPR:$false),
(MOVT32 (CMPHS32 GPR:$rs1, GPR:$rs2), GPR:$rx, GPR:$false)>;
def : Pat<(select (i32 (setuge GPR:$rs1, oimm16:$rs2)), GPR:$rx, GPR:$false),
(MOVT32 (CMPHSI32 GPR:$rs1, oimm16:$rs2), GPR:$rx, GPR:$false)>;
def : Pat<(select (i32 (setule GPR:$rs1, GPR:$rs2)), GPR:$rx, GPR:$false),
(MOVT32 (CMPHS32 GPR:$rs2, GPR:$rs1), GPR:$rx, GPR:$false)>;
def : Pat<(select (i32 (setult GPR:$rs1, GPR:$rs2)), GPR:$rx, GPR:$false),
(MOVF32 (CMPHS32 GPR:$rs1, GPR:$rs2), GPR:$rx, GPR:$false)>;
def : Pat<(select (i32 (setult GPR:$rs1, oimm16:$rs2)), GPR:$rx, GPR:$false),
(MOVF32 (CMPHSI32 GPR:$rs1, oimm16:$rs2), GPR:$rx, GPR:$false)>;
def : Pat<(select (i32 (setugt GPR:$rs1, GPR:$rs2)), GPR:$rx, GPR:$false),
(MOVF32 (CMPHS32 GPR:$rs2, GPR:$rs1), GPR:$rx, GPR:$false)>;
def : Pat<(select (i32 (setlt GPR:$rs1, GPR:$rs2)), GPR:$rx, GPR:$false),
(MOVT32 (CMPLT32 GPR:$rs1, GPR:$rs2), GPR:$rx, GPR:$false)>;
def : Pat<(select (i32 (setlt GPR:$rs1, oimm16:$rs2)), GPR:$rx, GPR:$false),
(MOVT32 (CMPLTI32 GPR:$rs1, oimm16:$rs2), GPR:$rx, GPR:$false)>;
def : Pat<(select (i32 (setgt GPR:$rs1, GPR:$rs2)), GPR:$rx, GPR:$false),
(MOVT32 (CMPLT32 GPR:$rs2, GPR:$rs1), GPR:$rx, GPR:$false)>;
def : Pat<(select (i32 (setge GPR:$rs1, GPR:$rs2)), GPR:$rx, GPR:$false),
(MOVF32 (CMPLT32 GPR:$rs1, GPR:$rs2), GPR:$rx, GPR:$false)>;
def : Pat<(select (i32 (setge GPR:$rs1, oimm16:$rs2)), GPR:$rx, GPR:$false),
(MOVF32 (CMPLTI32 GPR:$rs1, oimm16:$rs2), GPR:$rx, GPR:$false)>;
def : Pat<(select (i32 (setle GPR:$rs1, GPR:$rs2)), GPR:$rx, GPR:$false),
(MOVF32 (CMPLT32 GPR:$rs2, GPR:$rs1), GPR:$rx, GPR:$false)>;
def : Pat<(select CARRY:$ca, GPR:$rx, GPR:$false),
(ISEL32 CARRY:$ca, GPR:$rx, GPR:$false)>;
def : Pat<(select (and CARRY:$ca, 1), GPR:$rx, GPR:$false),
(ISEL32 CARRY:$ca, GPR:$rx, GPR:$false)>;
}
// Constant materialize patterns.
let Predicates = [iHasE2] in
def : Pat<(i32 imm:$imm),

View File

@ -22,4 +22,6 @@ CSKYMCAsmInfo::CSKYMCAsmInfo(const Triple &TargetTriple) {
AlignmentIsInBytes = false;
SupportsDebugInformation = true;
CommentString = "#";
ExceptionsType = ExceptionHandling::DwarfCFI;
}

3650
llvm/test/CodeGen/CSKY/br.ll Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff