//===-- 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 &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 &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 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 &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; } unsigned 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; } unsigned 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(); 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(); 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) 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(); 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()); } } }