//===-- CSKYInstrInfo.h - CSKY Instruction Information --------*- C++ -*---===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file contains the CSKY implementation of the TargetInstrInfo class.
//
//===----------------------------------------------------------------------===//
#include "CSKYInstrInfo.h"
#include "CSKYConstantPoolValue.h"
#include "CSKYMachineFunctionInfo.h"
#include "CSKYTargetMachine.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/MC/MCContext.h"
#define DEBUG_TYPE "csky-instr-info"
using namespace llvm;
#define GET_INSTRINFO_CTOR_DTOR
#include "CSKYGenInstrInfo.inc"
CSKYInstrInfo::CSKYInstrInfo(CSKYSubtarget &STI)
: CSKYGenInstrInfo(CSKY::ADJCALLSTACKDOWN, CSKY::ADJCALLSTACKUP), STI(STI) {
v2sf = STI.hasFPUv2SingleFloat();
v2df = STI.hasFPUv2DoubleFloat();
v3sf = STI.hasFPUv3SingleFloat();
v3df = STI.hasFPUv3DoubleFloat();
}
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, uint64_t Val,
MachineInstr::MIFlag Flag) const {
if (!isInt<32>(Val))
report_fatal_error("Should only materialize 32-bit constants.");
MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
Register DstReg;
if (STI.hasE2()) {
DstReg = MRI.createVirtualRegister(&CSKY::GPRRegClass);
if (isUInt<16>(Val)) {
BuildMI(MBB, MBBI, DL, get(CSKY::MOVI32), DstReg)
.addImm(Val & 0xFFFF)
.setMIFlags(Flag);
} else if (isShiftedUInt<16, 16>(Val)) {
BuildMI(MBB, MBBI, DL, get(CSKY::MOVIH32), DstReg)
.addImm((Val >> 16) & 0xFFFF)
.setMIFlags(Flag);
} else {
BuildMI(MBB, MBBI, DL, get(CSKY::MOVIH32), DstReg)
.addImm((Val >> 16) & 0xFFFF)
.setMIFlags(Flag);
BuildMI(MBB, MBBI, DL, get(CSKY::ORI32), DstReg)
.addReg(DstReg)
.addImm(Val & 0xFFFF)
.setMIFlags(Flag);
}
} else {
DstReg = MRI.createVirtualRegister(&CSKY::mGPRRegClass);
if (isUInt<8>(Val)) {
BuildMI(MBB, MBBI, DL, get(CSKY::MOVI16), DstReg)
.addImm(Val & 0xFF)
.setMIFlags(Flag);
} else if (isUInt<16>(Val)) {
BuildMI(MBB, MBBI, DL, get(CSKY::MOVI16), DstReg)
.addImm((Val >> 8) & 0xFF)
.setMIFlags(Flag);
BuildMI(MBB, MBBI, DL, get(CSKY::LSLI16), DstReg)
.addReg(DstReg)
.addImm(8)
.setMIFlags(Flag);
if ((Val & 0xFF) != 0)
BuildMI(MBB, MBBI, DL, get(CSKY::ADDI16), DstReg)
.addReg(DstReg)
.addImm(Val & 0xFF)
.setMIFlags(Flag);
} else if (isUInt<24>(Val)) {
BuildMI(MBB, MBBI, DL, get(CSKY::MOVI16), DstReg)
.addImm((Val >> 16) & 0xFF)
.setMIFlags(Flag);
BuildMI(MBB, MBBI, DL, get(CSKY::LSLI16), DstReg)
.addReg(DstReg)
.addImm(8)
.setMIFlags(Flag);
if (((Val >> 8) & 0xFF) != 0)
BuildMI(MBB, MBBI, DL, get(CSKY::ADDI16), DstReg)
.addReg(DstReg)
.addImm((Val >> 8) & 0xFF)
.setMIFlags(Flag);
BuildMI(MBB, MBBI, DL, get(CSKY::LSLI16), DstReg)
.addReg(DstReg)
.addImm(8)
.setMIFlags(Flag);
if ((Val & 0xFF) != 0)
BuildMI(MBB, MBBI, DL, get(CSKY::ADDI16), DstReg)
.addReg(DstReg)
.addImm(Val & 0xFF)
.setMIFlags(Flag);
} else {
BuildMI(MBB, MBBI, DL, get(CSKY::MOVI16), DstReg)
.addImm((Val >> 24) & 0xFF)
.setMIFlags(Flag);
BuildMI(MBB, MBBI, DL, get(CSKY::LSLI16), DstReg)
.addReg(DstReg)
.addImm(8)
.setMIFlags(Flag);
if (((Val >> 16) & 0xFF) != 0)
BuildMI(MBB, MBBI, DL, get(CSKY::ADDI16), DstReg)
.addReg(DstReg)
.addImm((Val >> 16) & 0xFF)
.setMIFlags(Flag);
BuildMI(MBB, MBBI, DL, get(CSKY::LSLI16), DstReg)
.addReg(DstReg)
.addImm(8)
.setMIFlags(Flag);
if (((Val >> 8) & 0xFF) != 0)
BuildMI(MBB, MBBI, DL, get(CSKY::ADDI16), DstReg)
.addReg(DstReg)
.addImm((Val >> 8) & 0xFF)
.setMIFlags(Flag);
BuildMI(MBB, MBBI, DL, get(CSKY::LSLI16), DstReg)
.addReg(DstReg)
.addImm(8)
.setMIFlags(Flag);
if ((Val & 0xFF) != 0)
BuildMI(MBB, MBBI, DL, get(CSKY::ADDI16), DstReg)
.addReg(DstReg)
.addImm(Val & 0xFF)
.setMIFlags(Flag);
}
}
return DstReg;
}
Register CSKYInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
int &FrameIndex) const {
switch (MI.getOpcode()) {
default:
return 0;
case CSKY::LD16B:
case CSKY::LD16H:
case CSKY::LD16W:
case CSKY::LD32B:
case CSKY::LD32BS:
case CSKY::LD32H:
case CSKY::LD32HS:
case CSKY::LD32W:
case CSKY::FLD_S:
case CSKY::FLD_D:
case CSKY::f2FLD_S:
case CSKY::f2FLD_D:
case CSKY::RESTORE_CARRY:
break;
}
if (MI.getOperand(1).isFI() && MI.getOperand(2).isImm() &&
MI.getOperand(2).getImm() == 0) {
FrameIndex = MI.getOperand(1).getIndex();
return MI.getOperand(0).getReg();
}
return 0;
}
Register CSKYInstrInfo::isStoreToStackSlot(const MachineInstr &MI,
int &FrameIndex) const {
switch (MI.getOpcode()) {
default:
return 0;
case CSKY::ST16B:
case CSKY::ST16H:
case CSKY::ST16W:
case CSKY::ST32B:
case CSKY::ST32H:
case CSKY::ST32W:
case CSKY::FST_S:
case CSKY::FST_D:
case CSKY::f2FST_S:
case CSKY::f2FST_D:
case CSKY::SPILL_CARRY:
break;
}
if (MI.getOperand(1).isFI() && MI.getOperand(2).isImm() &&
MI.getOperand(2).getImm() == 0) {
FrameIndex = MI.getOperand(1).getIndex();
return MI.getOperand(0).getReg();
}
return 0;
}
void CSKYInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
Register SrcReg, bool IsKill, int FI,
const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI,
Register VReg) const {
DebugLoc DL;
if (I != MBB.end())
DL = I->getDebugLoc();
MachineFunction &MF = *MBB.getParent();
CSKYMachineFunctionInfo *CFI = MF.getInfo<CSKYMachineFunctionInfo>();
MachineFrameInfo &MFI = MF.getFrameInfo();
unsigned Opcode = 0;
if (CSKY::GPRRegClass.hasSubClassEq(RC)) {
Opcode = CSKY::ST32W; // Optimize for 16bit
} else if (CSKY::CARRYRegClass.hasSubClassEq(RC)) {
Opcode = CSKY::SPILL_CARRY;
CFI->setSpillsCR();
} else if (v2sf && CSKY::sFPR32RegClass.hasSubClassEq(RC))
Opcode = CSKY::FST_S;
else if (v2df && CSKY::sFPR64RegClass.hasSubClassEq(RC))
Opcode = CSKY::FST_D;
else if (v3sf && CSKY::FPR32RegClass.hasSubClassEq(RC))
Opcode = CSKY::f2FST_S;
else if (v3df && CSKY::FPR64RegClass.hasSubClassEq(RC))
Opcode = CSKY::f2FST_D;
else {
llvm_unreachable("Unknown RegisterClass");
}
MachineMemOperand *MMO = MF.getMachineMemOperand(
MachinePointerInfo::getFixedStack(MF, FI), MachineMemOperand::MOStore,
MFI.getObjectSize(FI), MFI.getObjectAlign(FI));
BuildMI(MBB, I, DL, get(Opcode))
.addReg(SrcReg, getKillRegState(IsKill))
.addFrameIndex(FI)
.addImm(0)
.addMemOperand(MMO);
}
void CSKYInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
Register DestReg, int FI,
const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI,
Register VReg) const {
DebugLoc DL;
if (I != MBB.end())
DL = I->getDebugLoc();
MachineFunction &MF = *MBB.getParent();
CSKYMachineFunctionInfo *CFI = MF.getInfo<CSKYMachineFunctionInfo>();
MachineFrameInfo &MFI = MF.getFrameInfo();
unsigned Opcode = 0;
if (CSKY::GPRRegClass.hasSubClassEq(RC)) {
Opcode = CSKY::LD32W;
} else if (CSKY::CARRYRegClass.hasSubClassEq(RC)) {
Opcode = CSKY::RESTORE_CARRY;
CFI->setSpillsCR();
} else if (v2sf && CSKY::sFPR32RegClass.hasSubClassEq(RC))
Opcode = CSKY::FLD_S;
else if (v2df && CSKY::sFPR64RegClass.hasSubClassEq(RC))
Opcode = CSKY::FLD_D;
else if (v3sf && CSKY::FPR32RegClass.hasSubClassEq(RC))
Opcode = CSKY::f2FLD_S;
else if (v3df && CSKY::FPR64RegClass.hasSubClassEq(RC))
Opcode = CSKY::f2FLD_D;
else {
llvm_unreachable("Unknown RegisterClass");
}
MachineMemOperand *MMO = MF.getMachineMemOperand(
MachinePointerInfo::getFixedStack(MF, FI), MachineMemOperand::MOLoad,
MFI.getObjectSize(FI), MFI.getObjectAlign(FI));
BuildMI(MBB, I, DL, get(Opcode), DestReg)
.addFrameIndex(FI)
.addImm(0)
.addMemOperand(MMO);
}
void CSKYInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
const DebugLoc &DL, MCRegister DestReg,
MCRegister SrcReg, bool KillSrc,
bool RenamableDest, bool RenamableSrc) const {
if (CSKY::GPRRegClass.contains(SrcReg) &&
CSKY::CARRYRegClass.contains(DestReg)) {
if (STI.hasE2()) {
BuildMI(MBB, I, DL, get(CSKY::BTSTI32), DestReg)
.addReg(SrcReg, getKillRegState(KillSrc))
.addImm(0);
} else {
assert(SrcReg < CSKY::R8);
BuildMI(MBB, I, DL, get(CSKY::BTSTI16), DestReg)
.addReg(SrcReg, getKillRegState(KillSrc))
.addImm(0);
}
return;
}
if (CSKY::CARRYRegClass.contains(SrcReg) &&
CSKY::GPRRegClass.contains(DestReg)) {
if (STI.hasE2()) {
BuildMI(MBB, I, DL, get(CSKY::MVC32), DestReg)
.addReg(SrcReg, getKillRegState(KillSrc));
} else {
assert(DestReg < CSKY::R16);
assert(DestReg < CSKY::R8);
BuildMI(MBB, I, DL, get(CSKY::MOVI16), DestReg).addImm(0);
BuildMI(MBB, I, DL, get(CSKY::ADDC16))
.addReg(DestReg, RegState::Define)
.addReg(SrcReg, RegState::Define)
.addReg(DestReg, getKillRegState(true))
.addReg(DestReg, getKillRegState(true))
.addReg(SrcReg, getKillRegState(true));
BuildMI(MBB, I, DL, get(CSKY::BTSTI16))
.addReg(SrcReg, RegState::Define | getDeadRegState(KillSrc))
.addReg(DestReg)
.addImm(0);
}
return;
}
unsigned Opcode = 0;
if (CSKY::GPRRegClass.contains(DestReg, SrcReg))
Opcode = STI.hasE2() ? CSKY::MOV32 : CSKY::MOV16;
else if (v2sf && CSKY::sFPR32RegClass.contains(DestReg, SrcReg))
Opcode = CSKY::FMOV_S;
else if (v3sf && CSKY::FPR32RegClass.contains(DestReg, SrcReg))
Opcode = CSKY::f2FMOV_S;
else if (v2df && CSKY::sFPR64RegClass.contains(DestReg, SrcReg))
Opcode = CSKY::FMOV_D;
else if (v3df && CSKY::FPR64RegClass.contains(DestReg, SrcReg))
Opcode = CSKY::f2FMOV_D;
else if (v2sf && CSKY::sFPR32RegClass.contains(SrcReg) &&
CSKY::GPRRegClass.contains(DestReg))
Opcode = CSKY::FMFVRL;
else if (v3sf && CSKY::FPR32RegClass.contains(SrcReg) &&
CSKY::GPRRegClass.contains(DestReg))
Opcode = CSKY::f2FMFVRL;
else if (v2df && CSKY::sFPR64RegClass.contains(SrcReg) &&
CSKY::GPRRegClass.contains(DestReg))
Opcode = CSKY::FMFVRL_D;
else if (v3df && CSKY::FPR64RegClass.contains(SrcReg) &&
CSKY::GPRRegClass.contains(DestReg))
Opcode = CSKY::f2FMFVRL_D;
else if (v2sf && CSKY::GPRRegClass.contains(SrcReg) &&
CSKY::sFPR32RegClass.contains(DestReg))
Opcode = CSKY::FMTVRL;
else if (v3sf && CSKY::GPRRegClass.contains(SrcReg) &&
CSKY::FPR32RegClass.contains(DestReg))
Opcode = CSKY::f2FMTVRL;
else if (v2df && CSKY::GPRRegClass.contains(SrcReg) &&
CSKY::sFPR64RegClass.contains(DestReg))
Opcode = CSKY::FMTVRL_D;
else if (v3df && CSKY::GPRRegClass.contains(SrcReg) &&
CSKY::FPR64RegClass.contains(DestReg))
Opcode = CSKY::f2FMTVRL_D;
else {
LLVM_DEBUG(dbgs() << "src = " << SrcReg << ", dst = " << DestReg);
LLVM_DEBUG(I->dump());
llvm_unreachable("Unknown RegisterClass");
}
BuildMI(MBB, I, DL, get(Opcode), DestReg)
.addReg(SrcReg, getKillRegState(KillSrc));
}
Register CSKYInstrInfo::getGlobalBaseReg(MachineFunction &MF) const {
CSKYMachineFunctionInfo *CFI = MF.getInfo<CSKYMachineFunctionInfo>();
MachineConstantPool *MCP = MF.getConstantPool();
MachineRegisterInfo &MRI = MF.getRegInfo();
Register GlobalBaseReg = CFI->getGlobalBaseReg();
if (GlobalBaseReg != 0)
return GlobalBaseReg;
// Insert a pseudo instruction to set the GlobalBaseReg into the first
// MBB of the function
MachineBasicBlock &FirstMBB = MF.front();
MachineBasicBlock::iterator MBBI = FirstMBB.begin();
DebugLoc DL;
CSKYConstantPoolValue *CPV = CSKYConstantPoolSymbol::Create(
Type::getInt32Ty(MF.getFunction().getContext()), "_GLOBAL_OFFSET_TABLE_",
0, CSKYCP::ADDR);
unsigned CPI = MCP->getConstantPoolIndex(CPV, Align(4));
MachineMemOperand *MO =
MF.getMachineMemOperand(MachinePointerInfo::getConstantPool(MF),
MachineMemOperand::MOLoad, 4, Align(4));
BuildMI(FirstMBB, MBBI, DL, get(CSKY::LRW32), CSKY::R28)
.addConstantPoolIndex(CPI)
.addMemOperand(MO);
GlobalBaseReg = MRI.createVirtualRegister(&CSKY::GPRRegClass);
BuildMI(FirstMBB, MBBI, DL, get(TargetOpcode::COPY), GlobalBaseReg)
.addReg(CSKY::R28);
CFI->setGlobalBaseReg(GlobalBaseReg);
return GlobalBaseReg;
}
unsigned CSKYInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
switch (MI.getOpcode()) {
default:
return MI.getDesc().getSize();
case CSKY::CONSTPOOL_ENTRY:
return MI.getOperand(2).getImm();
case CSKY::SPILL_CARRY:
case CSKY::RESTORE_CARRY:
case CSKY::PseudoTLSLA32:
return 8;
case TargetOpcode::INLINEASM_BR:
case TargetOpcode::INLINEASM: {
const MachineFunction *MF = MI.getParent()->getParent();
const char *AsmStr = MI.getOperand(0).getSymbolName();
return getInlineAsmLength(AsmStr, *MF->getTarget().getMCAsmInfo());
}
}
}