123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488 |
- //=- LoongArchInstrInfo.cpp - LoongArch 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 LoongArch implementation of the TargetInstrInfo class.
- //
- //===----------------------------------------------------------------------===//
- #include "LoongArchInstrInfo.h"
- #include "LoongArch.h"
- #include "LoongArchMachineFunctionInfo.h"
- #include "LoongArchRegisterInfo.h"
- #include "MCTargetDesc/LoongArchMCTargetDesc.h"
- #include "MCTargetDesc/LoongArchMatInt.h"
- #include "llvm/CodeGen/RegisterScavenging.h"
- using namespace llvm;
- #define GET_INSTRINFO_CTOR_DTOR
- #include "LoongArchGenInstrInfo.inc"
- LoongArchInstrInfo::LoongArchInstrInfo(LoongArchSubtarget &STI)
- : LoongArchGenInstrInfo(LoongArch::ADJCALLSTACKDOWN,
- LoongArch::ADJCALLSTACKUP),
- STI(STI) {}
- void LoongArchInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
- MachineBasicBlock::iterator MBBI,
- const DebugLoc &DL, MCRegister DstReg,
- MCRegister SrcReg, bool KillSrc) const {
- if (LoongArch::GPRRegClass.contains(DstReg, SrcReg)) {
- BuildMI(MBB, MBBI, DL, get(LoongArch::OR), DstReg)
- .addReg(SrcReg, getKillRegState(KillSrc))
- .addReg(LoongArch::R0);
- return;
- }
- // GPR->CFR copy.
- if (LoongArch::CFRRegClass.contains(DstReg) &&
- LoongArch::GPRRegClass.contains(SrcReg)) {
- BuildMI(MBB, MBBI, DL, get(LoongArch::MOVGR2CF), DstReg)
- .addReg(SrcReg, getKillRegState(KillSrc));
- return;
- }
- // CFR->GPR copy.
- if (LoongArch::GPRRegClass.contains(DstReg) &&
- LoongArch::CFRRegClass.contains(SrcReg)) {
- BuildMI(MBB, MBBI, DL, get(LoongArch::MOVCF2GR), DstReg)
- .addReg(SrcReg, getKillRegState(KillSrc));
- return;
- }
- // FPR->FPR copies.
- unsigned Opc;
- if (LoongArch::FPR32RegClass.contains(DstReg, SrcReg)) {
- Opc = LoongArch::FMOV_S;
- } else if (LoongArch::FPR64RegClass.contains(DstReg, SrcReg)) {
- Opc = LoongArch::FMOV_D;
- } else {
- // TODO: support other copies.
- llvm_unreachable("Impossible reg-to-reg copy");
- }
- BuildMI(MBB, MBBI, DL, get(Opc), DstReg)
- .addReg(SrcReg, getKillRegState(KillSrc));
- }
- void LoongArchInstrInfo::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();
- MachineFrameInfo &MFI = MF->getFrameInfo();
- unsigned Opcode;
- if (LoongArch::GPRRegClass.hasSubClassEq(RC))
- Opcode = TRI->getRegSizeInBits(LoongArch::GPRRegClass) == 32
- ? LoongArch::ST_W
- : LoongArch::ST_D;
- else if (LoongArch::FPR32RegClass.hasSubClassEq(RC))
- Opcode = LoongArch::FST_S;
- else if (LoongArch::FPR64RegClass.hasSubClassEq(RC))
- Opcode = LoongArch::FST_D;
- else if (LoongArch::CFRRegClass.hasSubClassEq(RC))
- Opcode = LoongArch::PseudoST_CFR;
- else
- llvm_unreachable("Can't store this register to stack slot");
- 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 LoongArchInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
- MachineBasicBlock::iterator I,
- Register DstReg, int FI,
- const TargetRegisterClass *RC,
- const TargetRegisterInfo *TRI,
- Register VReg) const {
- DebugLoc DL;
- if (I != MBB.end())
- DL = I->getDebugLoc();
- MachineFunction *MF = MBB.getParent();
- MachineFrameInfo &MFI = MF->getFrameInfo();
- unsigned Opcode;
- if (LoongArch::GPRRegClass.hasSubClassEq(RC))
- Opcode = TRI->getRegSizeInBits(LoongArch::GPRRegClass) == 32
- ? LoongArch::LD_W
- : LoongArch::LD_D;
- else if (LoongArch::FPR32RegClass.hasSubClassEq(RC))
- Opcode = LoongArch::FLD_S;
- else if (LoongArch::FPR64RegClass.hasSubClassEq(RC))
- Opcode = LoongArch::FLD_D;
- else if (LoongArch::CFRRegClass.hasSubClassEq(RC))
- Opcode = LoongArch::PseudoLD_CFR;
- else
- llvm_unreachable("Can't load this register from stack slot");
- MachineMemOperand *MMO = MF->getMachineMemOperand(
- MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOLoad,
- MFI.getObjectSize(FI), MFI.getObjectAlign(FI));
- BuildMI(MBB, I, DL, get(Opcode), DstReg)
- .addFrameIndex(FI)
- .addImm(0)
- .addMemOperand(MMO);
- }
- void LoongArchInstrInfo::movImm(MachineBasicBlock &MBB,
- MachineBasicBlock::iterator MBBI,
- const DebugLoc &DL, Register DstReg,
- uint64_t Val, MachineInstr::MIFlag Flag) const {
- Register SrcReg = LoongArch::R0;
- if (!STI.is64Bit() && !isInt<32>(Val))
- report_fatal_error("Should only materialize 32-bit constants for LA32");
- auto Seq = LoongArchMatInt::generateInstSeq(Val);
- assert(!Seq.empty());
- for (auto &Inst : Seq) {
- switch (Inst.Opc) {
- case LoongArch::LU12I_W:
- BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg)
- .addImm(Inst.Imm)
- .setMIFlag(Flag);
- break;
- case LoongArch::ADDI_W:
- case LoongArch::ORI:
- case LoongArch::LU32I_D: // "rj" is needed due to InstrInfo pattern
- case LoongArch::LU52I_D:
- BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg)
- .addReg(SrcReg, RegState::Kill)
- .addImm(Inst.Imm)
- .setMIFlag(Flag);
- break;
- default:
- assert(false && "Unknown insn emitted by LoongArchMatInt");
- }
- // Only the first instruction has $zero as its source.
- SrcReg = DstReg;
- }
- }
- unsigned LoongArchInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
- unsigned Opcode = MI.getOpcode();
- if (Opcode == TargetOpcode::INLINEASM ||
- Opcode == TargetOpcode::INLINEASM_BR) {
- const MachineFunction *MF = MI.getParent()->getParent();
- const MCAsmInfo *MAI = MF->getTarget().getMCAsmInfo();
- return getInlineAsmLength(MI.getOperand(0).getSymbolName(), *MAI);
- }
- return MI.getDesc().getSize();
- }
- MachineBasicBlock *
- LoongArchInstrInfo::getBranchDestBlock(const MachineInstr &MI) const {
- assert(MI.getDesc().isBranch() && "Unexpected opcode!");
- // The branch target is always the last operand.
- return MI.getOperand(MI.getNumExplicitOperands() - 1).getMBB();
- }
- static void parseCondBranch(MachineInstr &LastInst, MachineBasicBlock *&Target,
- SmallVectorImpl<MachineOperand> &Cond) {
- // Block ends with fall-through condbranch.
- assert(LastInst.getDesc().isConditionalBranch() &&
- "Unknown conditional branch");
- int NumOp = LastInst.getNumExplicitOperands();
- Target = LastInst.getOperand(NumOp - 1).getMBB();
- Cond.push_back(MachineOperand::CreateImm(LastInst.getOpcode()));
- for (int i = 0; i < NumOp - 1; i++)
- Cond.push_back(LastInst.getOperand(i));
- }
- bool LoongArchInstrInfo::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;
- }
- // 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;
- }
- bool LoongArchInstrInfo::isBranchOffsetInRange(unsigned BranchOp,
- int64_t BrOffset) const {
- switch (BranchOp) {
- default:
- llvm_unreachable("Unknown branch instruction!");
- case LoongArch::BEQ:
- case LoongArch::BNE:
- case LoongArch::BLT:
- case LoongArch::BGE:
- case LoongArch::BLTU:
- case LoongArch::BGEU:
- return isInt<18>(BrOffset);
- case LoongArch::BEQZ:
- case LoongArch::BNEZ:
- case LoongArch::BCEQZ:
- case LoongArch::BCNEZ:
- return isInt<23>(BrOffset);
- case LoongArch::B:
- case LoongArch::PseudoBR:
- return isInt<28>(BrOffset);
- }
- }
- unsigned LoongArchInstrInfo::removeBranch(MachineBasicBlock &MBB,
- int *BytesRemoved) const {
- if (BytesRemoved)
- *BytesRemoved = 0;
- MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
- if (I == MBB.end())
- return 0;
- if (!I->getDesc().isBranch())
- 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;
- }
- // Inserts a branch into the end of the specific MachineBasicBlock, returning
- // the number of instructions inserted.
- unsigned LoongArchInstrInfo::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() <= 3 && Cond.size() != 1 &&
- "LoongArch branch conditions have at most two components!");
- // Unconditional branch.
- if (Cond.empty()) {
- MachineInstr &MI = *BuildMI(&MBB, DL, get(LoongArch::PseudoBR)).addMBB(TBB);
- if (BytesAdded)
- *BytesAdded += getInstSizeInBytes(MI);
- return 1;
- }
- // Either a one or two-way conditional branch.
- MachineInstrBuilder MIB = BuildMI(&MBB, DL, get(Cond[0].getImm()));
- for (unsigned i = 1; i < Cond.size(); ++i)
- MIB.add(Cond[i]);
- MIB.addMBB(TBB);
- if (BytesAdded)
- *BytesAdded += getInstSizeInBytes(*MIB);
- // One-way conditional branch.
- if (!FBB)
- return 1;
- // Two-way conditional branch.
- MachineInstr &MI = *BuildMI(&MBB, DL, get(LoongArch::PseudoBR)).addMBB(FBB);
- if (BytesAdded)
- *BytesAdded += getInstSizeInBytes(MI);
- return 2;
- }
- void LoongArchInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB,
- MachineBasicBlock &DestBB,
- MachineBasicBlock &RestoreBB,
- const DebugLoc &DL,
- int64_t BrOffset,
- RegScavenger *RS) const {
- assert(RS && "RegScavenger required for long branching");
- assert(MBB.empty() &&
- "new block should be inserted for expanding unconditional branch");
- assert(MBB.pred_size() == 1);
- MachineFunction *MF = MBB.getParent();
- MachineRegisterInfo &MRI = MF->getRegInfo();
- const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
- LoongArchMachineFunctionInfo *LAFI =
- MF->getInfo<LoongArchMachineFunctionInfo>();
- if (!isInt<32>(BrOffset))
- report_fatal_error(
- "Branch offsets outside of the signed 32-bit range not supported");
- Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
- auto II = MBB.end();
- MachineInstr &PCALAU12I =
- *BuildMI(MBB, II, DL, get(LoongArch::PCALAU12I), ScratchReg)
- .addMBB(&DestBB, LoongArchII::MO_PCREL_HI);
- MachineInstr &ADDI =
- *BuildMI(MBB, II, DL,
- get(STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W),
- ScratchReg)
- .addReg(ScratchReg)
- .addMBB(&DestBB, LoongArchII::MO_PCREL_LO);
- BuildMI(MBB, II, DL, get(LoongArch::PseudoBRIND))
- .addReg(ScratchReg, RegState::Kill)
- .addImm(0);
- RS->enterBasicBlockEnd(MBB);
- Register Scav = RS->scavengeRegisterBackwards(
- LoongArch::GPRRegClass, PCALAU12I.getIterator(), /*RestoreAfter=*/false,
- /*SPAdj=*/0, /*AllowSpill=*/false);
- if (Scav != LoongArch::NoRegister)
- RS->setRegUsed(Scav);
- else {
- // When there is no scavenged register, it needs to specify a register.
- // Specify t8 register because it won't be used too often.
- Scav = LoongArch::R20;
- int FrameIndex = LAFI->getBranchRelaxationSpillFrameIndex();
- if (FrameIndex == -1)
- report_fatal_error("The function size is incorrectly estimated.");
- storeRegToStackSlot(MBB, PCALAU12I, Scav, /*IsKill=*/true, FrameIndex,
- &LoongArch::GPRRegClass, TRI, Register());
- TRI->eliminateFrameIndex(std::prev(PCALAU12I.getIterator()),
- /*SpAdj=*/0, /*FIOperandNum=*/1);
- PCALAU12I.getOperand(1).setMBB(&RestoreBB);
- ADDI.getOperand(2).setMBB(&RestoreBB);
- loadRegFromStackSlot(RestoreBB, RestoreBB.end(), Scav, FrameIndex,
- &LoongArch::GPRRegClass, TRI, Register());
- TRI->eliminateFrameIndex(RestoreBB.back(),
- /*SpAdj=*/0, /*FIOperandNum=*/1);
- }
- MRI.replaceRegWith(ScratchReg, Scav);
- MRI.clearVirtRegs();
- }
- static unsigned getOppositeBranchOpc(unsigned Opc) {
- switch (Opc) {
- default:
- llvm_unreachable("Unrecognized conditional branch");
- case LoongArch::BEQ:
- return LoongArch::BNE;
- case LoongArch::BNE:
- return LoongArch::BEQ;
- case LoongArch::BEQZ:
- return LoongArch::BNEZ;
- case LoongArch::BNEZ:
- return LoongArch::BEQZ;
- case LoongArch::BCEQZ:
- return LoongArch::BCNEZ;
- case LoongArch::BCNEZ:
- return LoongArch::BCEQZ;
- case LoongArch::BLT:
- return LoongArch::BGE;
- case LoongArch::BGE:
- return LoongArch::BLT;
- case LoongArch::BLTU:
- return LoongArch::BGEU;
- case LoongArch::BGEU:
- return LoongArch::BLTU;
- }
- }
- bool LoongArchInstrInfo::reverseBranchCondition(
- SmallVectorImpl<MachineOperand> &Cond) const {
- assert((Cond.size() && Cond.size() <= 3) && "Invalid branch condition!");
- Cond[0].setImm(getOppositeBranchOpc(Cond[0].getImm()));
- return false;
- }
- std::pair<unsigned, unsigned>
- LoongArchInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const {
- return std::make_pair(TF, 0u);
- }
- ArrayRef<std::pair<unsigned, const char *>>
- LoongArchInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
- using namespace LoongArchII;
- // TODO: Add more target flags.
- static const std::pair<unsigned, const char *> TargetFlags[] = {
- {MO_CALL, "loongarch-call"},
- {MO_CALL_PLT, "loongarch-call-plt"},
- {MO_PCREL_HI, "loongarch-pcrel-hi"},
- {MO_PCREL_LO, "loongarch-pcrel-lo"},
- {MO_GOT_PC_HI, "loongarch-got-pc-hi"},
- {MO_GOT_PC_LO, "loongarch-got-pc-lo"},
- {MO_LE_HI, "loongarch-le-hi"},
- {MO_LE_LO, "loongarch-le-lo"},
- {MO_IE_PC_HI, "loongarch-ie-pc-hi"},
- {MO_IE_PC_LO, "loongarch-ie-pc-lo"},
- {MO_LD_PC_HI, "loongarch-ld-pc-hi"},
- {MO_GD_PC_HI, "loongarch-gd-pc-hi"}};
- return ArrayRef(TargetFlags);
- }
|