Path: blob/main/contrib/llvm-project/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
35267 views
//=- LoongArchInstrInfo.cpp - LoongArch Instruction Information -*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file contains the LoongArch implementation of the TargetInstrInfo class.9//10//===----------------------------------------------------------------------===//1112#include "LoongArchInstrInfo.h"13#include "LoongArch.h"14#include "LoongArchMachineFunctionInfo.h"15#include "LoongArchRegisterInfo.h"16#include "MCTargetDesc/LoongArchMCTargetDesc.h"17#include "MCTargetDesc/LoongArchMatInt.h"18#include "llvm/CodeGen/RegisterScavenging.h"19#include "llvm/MC/MCInstBuilder.h"2021using namespace llvm;2223#define GET_INSTRINFO_CTOR_DTOR24#include "LoongArchGenInstrInfo.inc"2526LoongArchInstrInfo::LoongArchInstrInfo(LoongArchSubtarget &STI)27: LoongArchGenInstrInfo(LoongArch::ADJCALLSTACKDOWN,28LoongArch::ADJCALLSTACKUP),29STI(STI) {}3031MCInst LoongArchInstrInfo::getNop() const {32return MCInstBuilder(LoongArch::ANDI)33.addReg(LoongArch::R0)34.addReg(LoongArch::R0)35.addImm(0);36}3738void LoongArchInstrInfo::copyPhysReg(MachineBasicBlock &MBB,39MachineBasicBlock::iterator MBBI,40const DebugLoc &DL, MCRegister DstReg,41MCRegister SrcReg, bool KillSrc) const {42if (LoongArch::GPRRegClass.contains(DstReg, SrcReg)) {43BuildMI(MBB, MBBI, DL, get(LoongArch::OR), DstReg)44.addReg(SrcReg, getKillRegState(KillSrc))45.addReg(LoongArch::R0);46return;47}4849// VR->VR copies.50if (LoongArch::LSX128RegClass.contains(DstReg, SrcReg)) {51BuildMI(MBB, MBBI, DL, get(LoongArch::VORI_B), DstReg)52.addReg(SrcReg, getKillRegState(KillSrc))53.addImm(0);54return;55}5657// XR->XR copies.58if (LoongArch::LASX256RegClass.contains(DstReg, SrcReg)) {59BuildMI(MBB, MBBI, DL, get(LoongArch::XVORI_B), DstReg)60.addReg(SrcReg, getKillRegState(KillSrc))61.addImm(0);62return;63}6465// GPR->CFR copy.66if (LoongArch::CFRRegClass.contains(DstReg) &&67LoongArch::GPRRegClass.contains(SrcReg)) {68BuildMI(MBB, MBBI, DL, get(LoongArch::MOVGR2CF), DstReg)69.addReg(SrcReg, getKillRegState(KillSrc));70return;71}72// CFR->GPR copy.73if (LoongArch::GPRRegClass.contains(DstReg) &&74LoongArch::CFRRegClass.contains(SrcReg)) {75BuildMI(MBB, MBBI, DL, get(LoongArch::MOVCF2GR), DstReg)76.addReg(SrcReg, getKillRegState(KillSrc));77return;78}79// CFR->CFR copy.80if (LoongArch::CFRRegClass.contains(DstReg, SrcReg)) {81BuildMI(MBB, MBBI, DL, get(LoongArch::PseudoCopyCFR), DstReg)82.addReg(SrcReg, getKillRegState(KillSrc));83return;84}8586// FPR->FPR copies.87unsigned Opc;88if (LoongArch::FPR32RegClass.contains(DstReg, SrcReg)) {89Opc = LoongArch::FMOV_S;90} else if (LoongArch::FPR64RegClass.contains(DstReg, SrcReg)) {91Opc = LoongArch::FMOV_D;92} else if (LoongArch::GPRRegClass.contains(DstReg) &&93LoongArch::FPR32RegClass.contains(SrcReg)) {94// FPR32 -> GPR copies95Opc = LoongArch::MOVFR2GR_S;96} else if (LoongArch::GPRRegClass.contains(DstReg) &&97LoongArch::FPR64RegClass.contains(SrcReg)) {98// FPR64 -> GPR copies99Opc = LoongArch::MOVFR2GR_D;100} else {101// TODO: support other copies.102llvm_unreachable("Impossible reg-to-reg copy");103}104105BuildMI(MBB, MBBI, DL, get(Opc), DstReg)106.addReg(SrcReg, getKillRegState(KillSrc));107}108109void LoongArchInstrInfo::storeRegToStackSlot(110MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Register SrcReg,111bool IsKill, int FI, const TargetRegisterClass *RC,112const TargetRegisterInfo *TRI, Register VReg) const {113MachineFunction *MF = MBB.getParent();114MachineFrameInfo &MFI = MF->getFrameInfo();115116unsigned Opcode;117if (LoongArch::GPRRegClass.hasSubClassEq(RC))118Opcode = TRI->getRegSizeInBits(LoongArch::GPRRegClass) == 32119? LoongArch::ST_W120: LoongArch::ST_D;121else if (LoongArch::FPR32RegClass.hasSubClassEq(RC))122Opcode = LoongArch::FST_S;123else if (LoongArch::FPR64RegClass.hasSubClassEq(RC))124Opcode = LoongArch::FST_D;125else if (LoongArch::LSX128RegClass.hasSubClassEq(RC))126Opcode = LoongArch::VST;127else if (LoongArch::LASX256RegClass.hasSubClassEq(RC))128Opcode = LoongArch::XVST;129else if (LoongArch::CFRRegClass.hasSubClassEq(RC))130Opcode = LoongArch::PseudoST_CFR;131else132llvm_unreachable("Can't store this register to stack slot");133134MachineMemOperand *MMO = MF->getMachineMemOperand(135MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOStore,136MFI.getObjectSize(FI), MFI.getObjectAlign(FI));137138BuildMI(MBB, I, DebugLoc(), get(Opcode))139.addReg(SrcReg, getKillRegState(IsKill))140.addFrameIndex(FI)141.addImm(0)142.addMemOperand(MMO);143}144145void LoongArchInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,146MachineBasicBlock::iterator I,147Register DstReg, int FI,148const TargetRegisterClass *RC,149const TargetRegisterInfo *TRI,150Register VReg) const {151MachineFunction *MF = MBB.getParent();152MachineFrameInfo &MFI = MF->getFrameInfo();153154unsigned Opcode;155if (LoongArch::GPRRegClass.hasSubClassEq(RC))156Opcode = TRI->getRegSizeInBits(LoongArch::GPRRegClass) == 32157? LoongArch::LD_W158: LoongArch::LD_D;159else if (LoongArch::FPR32RegClass.hasSubClassEq(RC))160Opcode = LoongArch::FLD_S;161else if (LoongArch::FPR64RegClass.hasSubClassEq(RC))162Opcode = LoongArch::FLD_D;163else if (LoongArch::LSX128RegClass.hasSubClassEq(RC))164Opcode = LoongArch::VLD;165else if (LoongArch::LASX256RegClass.hasSubClassEq(RC))166Opcode = LoongArch::XVLD;167else if (LoongArch::CFRRegClass.hasSubClassEq(RC))168Opcode = LoongArch::PseudoLD_CFR;169else170llvm_unreachable("Can't load this register from stack slot");171172MachineMemOperand *MMO = MF->getMachineMemOperand(173MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOLoad,174MFI.getObjectSize(FI), MFI.getObjectAlign(FI));175176BuildMI(MBB, I, DebugLoc(), get(Opcode), DstReg)177.addFrameIndex(FI)178.addImm(0)179.addMemOperand(MMO);180}181182void LoongArchInstrInfo::movImm(MachineBasicBlock &MBB,183MachineBasicBlock::iterator MBBI,184const DebugLoc &DL, Register DstReg,185uint64_t Val, MachineInstr::MIFlag Flag) const {186Register SrcReg = LoongArch::R0;187188if (!STI.is64Bit() && !isInt<32>(Val))189report_fatal_error("Should only materialize 32-bit constants for LA32");190191auto Seq = LoongArchMatInt::generateInstSeq(Val);192assert(!Seq.empty());193194for (auto &Inst : Seq) {195switch (Inst.Opc) {196case LoongArch::LU12I_W:197BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg)198.addImm(Inst.Imm)199.setMIFlag(Flag);200break;201case LoongArch::ADDI_W:202case LoongArch::ORI:203case LoongArch::LU32I_D: // "rj" is needed due to InstrInfo pattern204case LoongArch::LU52I_D:205BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg)206.addReg(SrcReg, RegState::Kill)207.addImm(Inst.Imm)208.setMIFlag(Flag);209break;210default:211assert(false && "Unknown insn emitted by LoongArchMatInt");212}213214// Only the first instruction has $zero as its source.215SrcReg = DstReg;216}217}218219unsigned LoongArchInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {220unsigned Opcode = MI.getOpcode();221222if (Opcode == TargetOpcode::INLINEASM ||223Opcode == TargetOpcode::INLINEASM_BR) {224const MachineFunction *MF = MI.getParent()->getParent();225const MCAsmInfo *MAI = MF->getTarget().getMCAsmInfo();226return getInlineAsmLength(MI.getOperand(0).getSymbolName(), *MAI);227}228return MI.getDesc().getSize();229}230231bool LoongArchInstrInfo::isAsCheapAsAMove(const MachineInstr &MI) const {232const unsigned Opcode = MI.getOpcode();233switch (Opcode) {234default:235break;236case LoongArch::ADDI_D:237case LoongArch::ORI:238case LoongArch::XORI:239return (MI.getOperand(1).isReg() &&240MI.getOperand(1).getReg() == LoongArch::R0) ||241(MI.getOperand(2).isImm() && MI.getOperand(2).getImm() == 0);242}243return MI.isAsCheapAsAMove();244}245246MachineBasicBlock *247LoongArchInstrInfo::getBranchDestBlock(const MachineInstr &MI) const {248assert(MI.getDesc().isBranch() && "Unexpected opcode!");249// The branch target is always the last operand.250return MI.getOperand(MI.getNumExplicitOperands() - 1).getMBB();251}252253static void parseCondBranch(MachineInstr &LastInst, MachineBasicBlock *&Target,254SmallVectorImpl<MachineOperand> &Cond) {255// Block ends with fall-through condbranch.256assert(LastInst.getDesc().isConditionalBranch() &&257"Unknown conditional branch");258int NumOp = LastInst.getNumExplicitOperands();259Target = LastInst.getOperand(NumOp - 1).getMBB();260261Cond.push_back(MachineOperand::CreateImm(LastInst.getOpcode()));262for (int i = 0; i < NumOp - 1; i++)263Cond.push_back(LastInst.getOperand(i));264}265266bool LoongArchInstrInfo::analyzeBranch(MachineBasicBlock &MBB,267MachineBasicBlock *&TBB,268MachineBasicBlock *&FBB,269SmallVectorImpl<MachineOperand> &Cond,270bool AllowModify) const {271TBB = FBB = nullptr;272Cond.clear();273274// If the block has no terminators, it just falls into the block after it.275MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();276if (I == MBB.end() || !isUnpredicatedTerminator(*I))277return false;278279// Count the number of terminators and find the first unconditional or280// indirect branch.281MachineBasicBlock::iterator FirstUncondOrIndirectBr = MBB.end();282int NumTerminators = 0;283for (auto J = I.getReverse(); J != MBB.rend() && isUnpredicatedTerminator(*J);284J++) {285NumTerminators++;286if (J->getDesc().isUnconditionalBranch() ||287J->getDesc().isIndirectBranch()) {288FirstUncondOrIndirectBr = J.getReverse();289}290}291292// If AllowModify is true, we can erase any terminators after293// FirstUncondOrIndirectBR.294if (AllowModify && FirstUncondOrIndirectBr != MBB.end()) {295while (std::next(FirstUncondOrIndirectBr) != MBB.end()) {296std::next(FirstUncondOrIndirectBr)->eraseFromParent();297NumTerminators--;298}299I = FirstUncondOrIndirectBr;300}301302// Handle a single unconditional branch.303if (NumTerminators == 1 && I->getDesc().isUnconditionalBranch()) {304TBB = getBranchDestBlock(*I);305return false;306}307308// Handle a single conditional branch.309if (NumTerminators == 1 && I->getDesc().isConditionalBranch()) {310parseCondBranch(*I, TBB, Cond);311return false;312}313314// Handle a conditional branch followed by an unconditional branch.315if (NumTerminators == 2 && std::prev(I)->getDesc().isConditionalBranch() &&316I->getDesc().isUnconditionalBranch()) {317parseCondBranch(*std::prev(I), TBB, Cond);318FBB = getBranchDestBlock(*I);319return false;320}321322// Otherwise, we can't handle this.323return true;324}325326bool LoongArchInstrInfo::isBranchOffsetInRange(unsigned BranchOp,327int64_t BrOffset) const {328switch (BranchOp) {329default:330llvm_unreachable("Unknown branch instruction!");331case LoongArch::BEQ:332case LoongArch::BNE:333case LoongArch::BLT:334case LoongArch::BGE:335case LoongArch::BLTU:336case LoongArch::BGEU:337return isInt<18>(BrOffset);338case LoongArch::BEQZ:339case LoongArch::BNEZ:340case LoongArch::BCEQZ:341case LoongArch::BCNEZ:342return isInt<23>(BrOffset);343case LoongArch::B:344case LoongArch::PseudoBR:345return isInt<28>(BrOffset);346}347}348349unsigned LoongArchInstrInfo::removeBranch(MachineBasicBlock &MBB,350int *BytesRemoved) const {351if (BytesRemoved)352*BytesRemoved = 0;353MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();354if (I == MBB.end())355return 0;356357if (!I->getDesc().isBranch())358return 0;359360// Remove the branch.361if (BytesRemoved)362*BytesRemoved += getInstSizeInBytes(*I);363I->eraseFromParent();364365I = MBB.end();366367if (I == MBB.begin())368return 1;369--I;370if (!I->getDesc().isConditionalBranch())371return 1;372373// Remove the branch.374if (BytesRemoved)375*BytesRemoved += getInstSizeInBytes(*I);376I->eraseFromParent();377return 2;378}379380// Inserts a branch into the end of the specific MachineBasicBlock, returning381// the number of instructions inserted.382unsigned LoongArchInstrInfo::insertBranch(383MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB,384ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const {385if (BytesAdded)386*BytesAdded = 0;387388// Shouldn't be a fall through.389assert(TBB && "insertBranch must not be told to insert a fallthrough");390assert(Cond.size() <= 3 && Cond.size() != 1 &&391"LoongArch branch conditions have at most two components!");392393// Unconditional branch.394if (Cond.empty()) {395MachineInstr &MI = *BuildMI(&MBB, DL, get(LoongArch::PseudoBR)).addMBB(TBB);396if (BytesAdded)397*BytesAdded += getInstSizeInBytes(MI);398return 1;399}400401// Either a one or two-way conditional branch.402MachineInstrBuilder MIB = BuildMI(&MBB, DL, get(Cond[0].getImm()));403for (unsigned i = 1; i < Cond.size(); ++i)404MIB.add(Cond[i]);405MIB.addMBB(TBB);406if (BytesAdded)407*BytesAdded += getInstSizeInBytes(*MIB);408409// One-way conditional branch.410if (!FBB)411return 1;412413// Two-way conditional branch.414MachineInstr &MI = *BuildMI(&MBB, DL, get(LoongArch::PseudoBR)).addMBB(FBB);415if (BytesAdded)416*BytesAdded += getInstSizeInBytes(MI);417return 2;418}419420void LoongArchInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB,421MachineBasicBlock &DestBB,422MachineBasicBlock &RestoreBB,423const DebugLoc &DL,424int64_t BrOffset,425RegScavenger *RS) const {426assert(RS && "RegScavenger required for long branching");427assert(MBB.empty() &&428"new block should be inserted for expanding unconditional branch");429assert(MBB.pred_size() == 1);430431MachineFunction *MF = MBB.getParent();432MachineRegisterInfo &MRI = MF->getRegInfo();433const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();434LoongArchMachineFunctionInfo *LAFI =435MF->getInfo<LoongArchMachineFunctionInfo>();436437if (!isInt<32>(BrOffset))438report_fatal_error(439"Branch offsets outside of the signed 32-bit range not supported");440441Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);442auto II = MBB.end();443444MachineInstr &PCALAU12I =445*BuildMI(MBB, II, DL, get(LoongArch::PCALAU12I), ScratchReg)446.addMBB(&DestBB, LoongArchII::MO_PCREL_HI);447MachineInstr &ADDI =448*BuildMI(MBB, II, DL,449get(STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W),450ScratchReg)451.addReg(ScratchReg)452.addMBB(&DestBB, LoongArchII::MO_PCREL_LO);453BuildMI(MBB, II, DL, get(LoongArch::PseudoBRIND))454.addReg(ScratchReg, RegState::Kill)455.addImm(0);456457RS->enterBasicBlockEnd(MBB);458Register Scav = RS->scavengeRegisterBackwards(459LoongArch::GPRRegClass, PCALAU12I.getIterator(), /*RestoreAfter=*/false,460/*SPAdj=*/0, /*AllowSpill=*/false);461if (Scav != LoongArch::NoRegister)462RS->setRegUsed(Scav);463else {464// When there is no scavenged register, it needs to specify a register.465// Specify t8 register because it won't be used too often.466Scav = LoongArch::R20;467int FrameIndex = LAFI->getBranchRelaxationSpillFrameIndex();468if (FrameIndex == -1)469report_fatal_error("The function size is incorrectly estimated.");470storeRegToStackSlot(MBB, PCALAU12I, Scav, /*IsKill=*/true, FrameIndex,471&LoongArch::GPRRegClass, TRI, Register());472TRI->eliminateFrameIndex(std::prev(PCALAU12I.getIterator()),473/*SpAdj=*/0, /*FIOperandNum=*/1);474PCALAU12I.getOperand(1).setMBB(&RestoreBB);475ADDI.getOperand(2).setMBB(&RestoreBB);476loadRegFromStackSlot(RestoreBB, RestoreBB.end(), Scav, FrameIndex,477&LoongArch::GPRRegClass, TRI, Register());478TRI->eliminateFrameIndex(RestoreBB.back(),479/*SpAdj=*/0, /*FIOperandNum=*/1);480}481MRI.replaceRegWith(ScratchReg, Scav);482MRI.clearVirtRegs();483}484485static unsigned getOppositeBranchOpc(unsigned Opc) {486switch (Opc) {487default:488llvm_unreachable("Unrecognized conditional branch");489case LoongArch::BEQ:490return LoongArch::BNE;491case LoongArch::BNE:492return LoongArch::BEQ;493case LoongArch::BEQZ:494return LoongArch::BNEZ;495case LoongArch::BNEZ:496return LoongArch::BEQZ;497case LoongArch::BCEQZ:498return LoongArch::BCNEZ;499case LoongArch::BCNEZ:500return LoongArch::BCEQZ;501case LoongArch::BLT:502return LoongArch::BGE;503case LoongArch::BGE:504return LoongArch::BLT;505case LoongArch::BLTU:506return LoongArch::BGEU;507case LoongArch::BGEU:508return LoongArch::BLTU;509}510}511512bool LoongArchInstrInfo::reverseBranchCondition(513SmallVectorImpl<MachineOperand> &Cond) const {514assert((Cond.size() && Cond.size() <= 3) && "Invalid branch condition!");515Cond[0].setImm(getOppositeBranchOpc(Cond[0].getImm()));516return false;517}518519std::pair<unsigned, unsigned>520LoongArchInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const {521return std::make_pair(TF, 0u);522}523524ArrayRef<std::pair<unsigned, const char *>>525LoongArchInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {526using namespace LoongArchII;527// TODO: Add more target flags.528static const std::pair<unsigned, const char *> TargetFlags[] = {529{MO_CALL, "loongarch-call"},530{MO_CALL_PLT, "loongarch-call-plt"},531{MO_PCREL_HI, "loongarch-pcrel-hi"},532{MO_PCREL_LO, "loongarch-pcrel-lo"},533{MO_PCREL64_LO, "loongarch-pcrel64-lo"},534{MO_PCREL64_HI, "loongarch-pcrel64-hi"},535{MO_GOT_PC_HI, "loongarch-got-pc-hi"},536{MO_GOT_PC_LO, "loongarch-got-pc-lo"},537{MO_GOT_PC64_LO, "loongarch-got-pc64-lo"},538{MO_GOT_PC64_HI, "loongarch-got-pc64-hi"},539{MO_LE_HI, "loongarch-le-hi"},540{MO_LE_LO, "loongarch-le-lo"},541{MO_LE64_LO, "loongarch-le64-lo"},542{MO_LE64_HI, "loongarch-le64-hi"},543{MO_IE_PC_HI, "loongarch-ie-pc-hi"},544{MO_IE_PC_LO, "loongarch-ie-pc-lo"},545{MO_IE_PC64_LO, "loongarch-ie-pc64-lo"},546{MO_IE_PC64_HI, "loongarch-ie-pc64-hi"},547{MO_DESC_PC_HI, "loongarch-desc-pc-hi"},548{MO_DESC_PC_LO, "loongarch-desc-pc-lo"},549{MO_DESC64_PC_LO, "loongarch-desc64-pc-lo"},550{MO_DESC64_PC_HI, "loongarch-desc64-pc-hi"},551{MO_DESC_LD, "loongarch-desc-ld"},552{MO_DESC_CALL, "loongarch-desc-call"},553{MO_LD_PC_HI, "loongarch-ld-pc-hi"},554{MO_GD_PC_HI, "loongarch-gd-pc-hi"}};555return ArrayRef(TargetFlags);556}557558// Returns true if this is the sext.w pattern, addi.w rd, rs, 0.559bool LoongArch::isSEXT_W(const MachineInstr &MI) {560return MI.getOpcode() == LoongArch::ADDI_W && MI.getOperand(1).isReg() &&561MI.getOperand(2).isImm() && MI.getOperand(2).getImm() == 0;562}563564565