922 lines · cpp
1//=- LoongArchInstrInfo.cpp - LoongArch Instruction Information -*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file contains the LoongArch implementation of the TargetInstrInfo class.10//11//===----------------------------------------------------------------------===//12 13#include "LoongArchInstrInfo.h"14#include "LoongArch.h"15#include "LoongArchMachineFunctionInfo.h"16#include "LoongArchRegisterInfo.h"17#include "MCTargetDesc/LoongArchMCTargetDesc.h"18#include "MCTargetDesc/LoongArchMatInt.h"19#include "llvm/CodeGen/RegisterScavenging.h"20#include "llvm/CodeGen/StackMaps.h"21#include "llvm/MC/MCInstBuilder.h"22 23using namespace llvm;24 25#define GET_INSTRINFO_CTOR_DTOR26#include "LoongArchGenInstrInfo.inc"27 28LoongArchInstrInfo::LoongArchInstrInfo(const LoongArchSubtarget &STI)29 : LoongArchGenInstrInfo(STI, RegInfo, LoongArch::ADJCALLSTACKDOWN,30 LoongArch::ADJCALLSTACKUP),31 RegInfo(STI.getHwMode()), STI(STI) {}32 33MCInst LoongArchInstrInfo::getNop() const {34 return MCInstBuilder(LoongArch::ANDI)35 .addReg(LoongArch::R0)36 .addReg(LoongArch::R0)37 .addImm(0);38}39 40void LoongArchInstrInfo::copyPhysReg(MachineBasicBlock &MBB,41 MachineBasicBlock::iterator MBBI,42 const DebugLoc &DL, Register DstReg,43 Register SrcReg, bool KillSrc,44 bool RenamableDest,45 bool RenamableSrc) const {46 if (LoongArch::GPRRegClass.contains(DstReg, SrcReg)) {47 BuildMI(MBB, MBBI, DL, get(LoongArch::OR), DstReg)48 .addReg(SrcReg, getKillRegState(KillSrc))49 .addReg(LoongArch::R0);50 return;51 }52 53 // VR->VR copies.54 if (LoongArch::LSX128RegClass.contains(DstReg, SrcReg)) {55 BuildMI(MBB, MBBI, DL, get(LoongArch::VORI_B), DstReg)56 .addReg(SrcReg, getKillRegState(KillSrc))57 .addImm(0);58 return;59 }60 61 // XR->XR copies.62 if (LoongArch::LASX256RegClass.contains(DstReg, SrcReg)) {63 BuildMI(MBB, MBBI, DL, get(LoongArch::XVORI_B), DstReg)64 .addReg(SrcReg, getKillRegState(KillSrc))65 .addImm(0);66 return;67 }68 69 // GPR->CFR copy.70 if (LoongArch::CFRRegClass.contains(DstReg) &&71 LoongArch::GPRRegClass.contains(SrcReg)) {72 BuildMI(MBB, MBBI, DL, get(LoongArch::MOVGR2CF), DstReg)73 .addReg(SrcReg, getKillRegState(KillSrc));74 return;75 }76 // CFR->GPR copy.77 if (LoongArch::GPRRegClass.contains(DstReg) &&78 LoongArch::CFRRegClass.contains(SrcReg)) {79 BuildMI(MBB, MBBI, DL, get(LoongArch::MOVCF2GR), DstReg)80 .addReg(SrcReg, getKillRegState(KillSrc));81 return;82 }83 // CFR->CFR copy.84 if (LoongArch::CFRRegClass.contains(DstReg, SrcReg)) {85 BuildMI(MBB, MBBI, DL, get(LoongArch::PseudoCopyCFR), DstReg)86 .addReg(SrcReg, getKillRegState(KillSrc));87 return;88 }89 90 // FPR->FPR copies.91 unsigned Opc;92 if (LoongArch::FPR32RegClass.contains(DstReg, SrcReg)) {93 Opc = LoongArch::FMOV_S;94 } else if (LoongArch::FPR64RegClass.contains(DstReg, SrcReg)) {95 Opc = LoongArch::FMOV_D;96 } else if (LoongArch::GPRRegClass.contains(DstReg) &&97 LoongArch::FPR32RegClass.contains(SrcReg)) {98 // FPR32 -> GPR copies99 Opc = LoongArch::MOVFR2GR_S;100 } else if (LoongArch::GPRRegClass.contains(DstReg) &&101 LoongArch::FPR64RegClass.contains(SrcReg)) {102 // FPR64 -> GPR copies103 Opc = LoongArch::MOVFR2GR_D;104 } else {105 // TODO: support other copies.106 llvm_unreachable("Impossible reg-to-reg copy");107 }108 109 BuildMI(MBB, MBBI, DL, get(Opc), DstReg)110 .addReg(SrcReg, getKillRegState(KillSrc));111}112 113void LoongArchInstrInfo::storeRegToStackSlot(114 MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Register SrcReg,115 bool IsKill, int FI, const TargetRegisterClass *RC,116 117 Register VReg, MachineInstr::MIFlag Flags) const {118 MachineFunction *MF = MBB.getParent();119 MachineFrameInfo &MFI = MF->getFrameInfo();120 121 unsigned Opcode;122 if (LoongArch::GPRRegClass.hasSubClassEq(RC))123 Opcode = TRI.getRegSizeInBits(LoongArch::GPRRegClass) == 32124 ? LoongArch::ST_W125 : LoongArch::ST_D;126 else if (LoongArch::FPR32RegClass.hasSubClassEq(RC))127 Opcode = LoongArch::FST_S;128 else if (LoongArch::FPR64RegClass.hasSubClassEq(RC))129 Opcode = LoongArch::FST_D;130 else if (LoongArch::LSX128RegClass.hasSubClassEq(RC))131 Opcode = LoongArch::VST;132 else if (LoongArch::LASX256RegClass.hasSubClassEq(RC))133 Opcode = LoongArch::XVST;134 else if (LoongArch::CFRRegClass.hasSubClassEq(RC))135 Opcode = LoongArch::PseudoST_CFR;136 else137 llvm_unreachable("Can't store this register to stack slot");138 139 MachineMemOperand *MMO = MF->getMachineMemOperand(140 MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOStore,141 MFI.getObjectSize(FI), MFI.getObjectAlign(FI));142 143 BuildMI(MBB, I, DebugLoc(), get(Opcode))144 .addReg(SrcReg, getKillRegState(IsKill))145 .addFrameIndex(FI)146 .addImm(0)147 .addMemOperand(MMO);148}149 150void LoongArchInstrInfo::loadRegFromStackSlot(151 MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Register DstReg,152 int FI, const TargetRegisterClass *RC, Register VReg,153 MachineInstr::MIFlag Flags) const {154 MachineFunction *MF = MBB.getParent();155 MachineFrameInfo &MFI = MF->getFrameInfo();156 DebugLoc DL;157 if (I != MBB.end())158 DL = I->getDebugLoc();159 160 unsigned Opcode;161 if (LoongArch::GPRRegClass.hasSubClassEq(RC))162 Opcode = RegInfo.getRegSizeInBits(LoongArch::GPRRegClass) == 32163 ? LoongArch::LD_W164 : LoongArch::LD_D;165 else if (LoongArch::FPR32RegClass.hasSubClassEq(RC))166 Opcode = LoongArch::FLD_S;167 else if (LoongArch::FPR64RegClass.hasSubClassEq(RC))168 Opcode = LoongArch::FLD_D;169 else if (LoongArch::LSX128RegClass.hasSubClassEq(RC))170 Opcode = LoongArch::VLD;171 else if (LoongArch::LASX256RegClass.hasSubClassEq(RC))172 Opcode = LoongArch::XVLD;173 else if (LoongArch::CFRRegClass.hasSubClassEq(RC))174 Opcode = LoongArch::PseudoLD_CFR;175 else176 llvm_unreachable("Can't load this register from stack slot");177 178 MachineMemOperand *MMO = MF->getMachineMemOperand(179 MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOLoad,180 MFI.getObjectSize(FI), MFI.getObjectAlign(FI));181 182 BuildMI(MBB, I, DL, get(Opcode), DstReg)183 .addFrameIndex(FI)184 .addImm(0)185 .addMemOperand(MMO);186}187 188void LoongArchInstrInfo::movImm(MachineBasicBlock &MBB,189 MachineBasicBlock::iterator MBBI,190 const DebugLoc &DL, Register DstReg,191 uint64_t Val, MachineInstr::MIFlag Flag) const {192 Register SrcReg = LoongArch::R0;193 194 if (!STI.is64Bit() && !isInt<32>(Val))195 report_fatal_error("Should only materialize 32-bit constants for LA32");196 197 auto Seq = LoongArchMatInt::generateInstSeq(Val);198 assert(!Seq.empty());199 200 for (auto &Inst : Seq) {201 switch (Inst.Opc) {202 case LoongArch::LU12I_W:203 BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg)204 .addImm(Inst.Imm)205 .setMIFlag(Flag);206 break;207 case LoongArch::ADDI_W:208 case LoongArch::ORI:209 case LoongArch::LU32I_D: // "rj" is needed due to InstrInfo pattern210 case LoongArch::LU52I_D:211 BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg)212 .addReg(SrcReg, RegState::Kill)213 .addImm(Inst.Imm)214 .setMIFlag(Flag);215 break;216 case LoongArch::BSTRINS_D:217 BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg)218 .addReg(SrcReg, RegState::Kill)219 .addReg(SrcReg, RegState::Kill)220 .addImm(Inst.Imm >> 32)221 .addImm(Inst.Imm & 0xFF)222 .setMIFlag(Flag);223 break;224 default:225 assert(false && "Unknown insn emitted by LoongArchMatInt");226 }227 228 // Only the first instruction has $zero as its source.229 SrcReg = DstReg;230 }231}232 233unsigned LoongArchInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {234 unsigned Opcode = MI.getOpcode();235 236 if (Opcode == TargetOpcode::INLINEASM ||237 Opcode == TargetOpcode::INLINEASM_BR) {238 const MachineFunction *MF = MI.getParent()->getParent();239 const MCAsmInfo *MAI = MF->getTarget().getMCAsmInfo();240 return getInlineAsmLength(MI.getOperand(0).getSymbolName(), *MAI);241 }242 243 unsigned NumBytes = 0;244 const MCInstrDesc &Desc = MI.getDesc();245 246 // Size should be preferably set in247 // llvm/lib/Target/LoongArch/LoongArch*InstrInfo.td (default case).248 // Specific cases handle instructions of variable sizes.249 switch (Desc.getOpcode()) {250 default:251 return Desc.getSize();252 case TargetOpcode::STATEPOINT:253 NumBytes = StatepointOpers(&MI).getNumPatchBytes();254 assert(NumBytes % 4 == 0 && "Invalid number of NOP bytes requested!");255 // No patch bytes means a normal call inst (i.e. `bl`) is emitted.256 if (NumBytes == 0)257 NumBytes = 4;258 break;259 }260 return NumBytes;261}262 263bool LoongArchInstrInfo::isAsCheapAsAMove(const MachineInstr &MI) const {264 const unsigned Opcode = MI.getOpcode();265 switch (Opcode) {266 default:267 break;268 case LoongArch::ADDI_D:269 case LoongArch::ORI:270 case LoongArch::XORI:271 return (MI.getOperand(1).isReg() &&272 MI.getOperand(1).getReg() == LoongArch::R0) ||273 (MI.getOperand(2).isImm() && MI.getOperand(2).getImm() == 0);274 }275 return MI.isAsCheapAsAMove();276}277 278MachineBasicBlock *279LoongArchInstrInfo::getBranchDestBlock(const MachineInstr &MI) const {280 assert(MI.getDesc().isBranch() && "Unexpected opcode!");281 // The branch target is always the last operand.282 return MI.getOperand(MI.getNumExplicitOperands() - 1).getMBB();283}284 285static void parseCondBranch(MachineInstr &LastInst, MachineBasicBlock *&Target,286 SmallVectorImpl<MachineOperand> &Cond) {287 // Block ends with fall-through condbranch.288 assert(LastInst.getDesc().isConditionalBranch() &&289 "Unknown conditional branch");290 int NumOp = LastInst.getNumExplicitOperands();291 Target = LastInst.getOperand(NumOp - 1).getMBB();292 293 Cond.push_back(MachineOperand::CreateImm(LastInst.getOpcode()));294 for (int i = 0; i < NumOp - 1; i++)295 Cond.push_back(LastInst.getOperand(i));296}297 298bool LoongArchInstrInfo::analyzeBranch(MachineBasicBlock &MBB,299 MachineBasicBlock *&TBB,300 MachineBasicBlock *&FBB,301 SmallVectorImpl<MachineOperand> &Cond,302 bool AllowModify) const {303 TBB = FBB = nullptr;304 Cond.clear();305 306 // If the block has no terminators, it just falls into the block after it.307 MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();308 if (I == MBB.end() || !isUnpredicatedTerminator(*I))309 return false;310 311 // Count the number of terminators and find the first unconditional or312 // indirect branch.313 MachineBasicBlock::iterator FirstUncondOrIndirectBr = MBB.end();314 int NumTerminators = 0;315 for (auto J = I.getReverse(); J != MBB.rend() && isUnpredicatedTerminator(*J);316 J++) {317 NumTerminators++;318 if (J->getDesc().isUnconditionalBranch() ||319 J->getDesc().isIndirectBranch()) {320 FirstUncondOrIndirectBr = J.getReverse();321 }322 }323 324 // If AllowModify is true, we can erase any terminators after325 // FirstUncondOrIndirectBR.326 if (AllowModify && FirstUncondOrIndirectBr != MBB.end()) {327 while (std::next(FirstUncondOrIndirectBr) != MBB.end()) {328 std::next(FirstUncondOrIndirectBr)->eraseFromParent();329 NumTerminators--;330 }331 I = FirstUncondOrIndirectBr;332 }333 334 // Handle a single unconditional branch.335 if (NumTerminators == 1 && I->getDesc().isUnconditionalBranch()) {336 TBB = getBranchDestBlock(*I);337 return false;338 }339 340 // Handle a single conditional branch.341 if (NumTerminators == 1 && I->getDesc().isConditionalBranch()) {342 parseCondBranch(*I, TBB, Cond);343 return false;344 }345 346 // Handle a conditional branch followed by an unconditional branch.347 if (NumTerminators == 2 && std::prev(I)->getDesc().isConditionalBranch() &&348 I->getDesc().isUnconditionalBranch()) {349 parseCondBranch(*std::prev(I), TBB, Cond);350 FBB = getBranchDestBlock(*I);351 return false;352 }353 354 // Otherwise, we can't handle this.355 return true;356}357 358bool LoongArchInstrInfo::isBranchOffsetInRange(unsigned BranchOp,359 int64_t BrOffset) const {360 switch (BranchOp) {361 default:362 llvm_unreachable("Unknown branch instruction!");363 case LoongArch::BEQ:364 case LoongArch::BNE:365 case LoongArch::BLT:366 case LoongArch::BGE:367 case LoongArch::BLTU:368 case LoongArch::BGEU:369 return isInt<18>(BrOffset);370 case LoongArch::BEQZ:371 case LoongArch::BNEZ:372 case LoongArch::BCEQZ:373 case LoongArch::BCNEZ:374 return isInt<23>(BrOffset);375 case LoongArch::B:376 case LoongArch::PseudoBR:377 return isInt<28>(BrOffset);378 }379}380 381bool LoongArchInstrInfo::isSafeToMove(const MachineInstr &MI,382 const MachineBasicBlock *MBB,383 const MachineFunction &MF) const {384 auto MII = MI.getIterator();385 auto MIE = MBB->end();386 387 // According to psABI v2.30:388 //389 // https://github.com/loongson/la-abi-specs/releases/tag/v2.30390 //391 // The following instruction patterns are prohibited from being reordered:392 //393 // * pcalau12i $a0, %pc_hi20(s)394 // addi.d $a1, $zero, %pc_lo12(s)395 // lu32i.d $a1, %pc64_lo20(s)396 // lu52i.d $a1, $a1, %pc64_hi12(s)397 //398 // * pcalau12i $a0, %got_pc_hi20(s) | %ld_pc_hi20(s) | %gd_pc_hi20(s)399 // addi.d $a1, $zero, %got_pc_lo12(s)400 // lu32i.d $a1, %got64_pc_lo20(s)401 // lu52i.d $a1, $a1, %got64_pc_hi12(s)402 //403 // * pcalau12i $a0, %ie_pc_hi20(s)404 // addi.d $a1, $zero, %ie_pc_lo12(s)405 // lu32i.d $a1, %ie64_pc_lo20(s)406 // lu52i.d $a1, $a1, %ie64_pc_hi12(s)407 //408 // * pcalau12i $a0, %desc_pc_hi20(s)409 // addi.d $a1, $zero, %desc_pc_lo12(s)410 // lu32i.d $a1, %desc64_pc_lo20(s)411 // lu52i.d $a1, $a1, %desc64_pc_hi12(s)412 //413 // For simplicity, only pcalau12i and lu52i.d are marked as scheduling414 // boundaries, and the instructions between them are guaranteed to be415 // ordered according to data dependencies.416 switch (MI.getOpcode()) {417 case LoongArch::PCALAU12I: {418 auto AddI = std::next(MII);419 if (AddI == MIE || AddI->getOpcode() != LoongArch::ADDI_D)420 break;421 auto Lu32I = std::next(AddI);422 if (Lu32I == MIE || Lu32I->getOpcode() != LoongArch::LU32I_D)423 break;424 auto MO0 = MI.getOperand(1).getTargetFlags();425 auto MO1 = AddI->getOperand(2).getTargetFlags();426 auto MO2 = Lu32I->getOperand(2).getTargetFlags();427 if (MO0 == LoongArchII::MO_PCREL_HI && MO1 == LoongArchII::MO_PCREL_LO &&428 MO2 == LoongArchII::MO_PCREL64_LO)429 return false;430 if ((MO0 == LoongArchII::MO_GOT_PC_HI || MO0 == LoongArchII::MO_LD_PC_HI ||431 MO0 == LoongArchII::MO_GD_PC_HI) &&432 MO1 == LoongArchII::MO_GOT_PC_LO && MO2 == LoongArchII::MO_GOT_PC64_LO)433 return false;434 if (MO0 == LoongArchII::MO_IE_PC_HI && MO1 == LoongArchII::MO_IE_PC_LO &&435 MO2 == LoongArchII::MO_IE_PC64_LO)436 return false;437 if (MO0 == LoongArchII::MO_DESC_PC_HI &&438 MO1 == LoongArchII::MO_DESC_PC_LO &&439 MO2 == LoongArchII::MO_DESC64_PC_LO)440 return false;441 break;442 }443 case LoongArch::LU52I_D: {444 auto MO = MI.getOperand(2).getTargetFlags();445 if (MO == LoongArchII::MO_PCREL64_HI || MO == LoongArchII::MO_GOT_PC64_HI ||446 MO == LoongArchII::MO_IE_PC64_HI || MO == LoongArchII::MO_DESC64_PC_HI)447 return false;448 break;449 }450 default:451 break;452 }453 454 const auto &STI = MF.getSubtarget<LoongArchSubtarget>();455 if (STI.hasFeature(LoongArch::FeatureRelax)) {456 // When linker relaxation enabled, the following instruction patterns are457 // prohibited from being reordered:458 //459 // * pcalau12i $a0, %pc_hi20(s)460 // addi.w/d $a0, $a0, %pc_lo12(s)461 //462 // * pcalau12i $a0, %got_pc_hi20(s)463 // ld.w/d $a0, $a0, %got_pc_lo12(s)464 //465 // * pcalau12i $a0, %ld_pc_hi20(s) | %gd_pc_hi20(s)466 // addi.w/d $a0, $a0, %got_pc_lo12(s)467 //468 // * pcalau12i $a0, %desc_pc_hi20(s)469 // addi.w/d $a0, $a0, %desc_pc_lo12(s)470 // ld.w/d $ra, $a0, %desc_ld(s)471 // jirl $ra, $ra, %desc_call(s)472 unsigned AddiOp = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;473 unsigned LdOp = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;474 switch (MI.getOpcode()) {475 case LoongArch::PCALAU12I: {476 auto MO0 = LoongArchII::getDirectFlags(MI.getOperand(1));477 auto SecondOp = std::next(MII);478 if (MO0 == LoongArchII::MO_DESC_PC_HI) {479 if (SecondOp == MIE || SecondOp->getOpcode() != AddiOp)480 break;481 auto Ld = std::next(SecondOp);482 if (Ld == MIE || Ld->getOpcode() != LdOp)483 break;484 auto MO1 = LoongArchII::getDirectFlags(SecondOp->getOperand(2));485 auto MO2 = LoongArchII::getDirectFlags(Ld->getOperand(2));486 if (MO1 == LoongArchII::MO_DESC_PC_LO && MO2 == LoongArchII::MO_DESC_LD)487 return false;488 break;489 }490 if (SecondOp == MIE ||491 (SecondOp->getOpcode() != AddiOp && SecondOp->getOpcode() != LdOp))492 break;493 auto MO1 = LoongArchII::getDirectFlags(SecondOp->getOperand(2));494 if (MO0 == LoongArchII::MO_PCREL_HI && SecondOp->getOpcode() == AddiOp &&495 MO1 == LoongArchII::MO_PCREL_LO)496 return false;497 if (MO0 == LoongArchII::MO_GOT_PC_HI && SecondOp->getOpcode() == LdOp &&498 MO1 == LoongArchII::MO_GOT_PC_LO)499 return false;500 if ((MO0 == LoongArchII::MO_LD_PC_HI ||501 MO0 == LoongArchII::MO_GD_PC_HI) &&502 SecondOp->getOpcode() == AddiOp && MO1 == LoongArchII::MO_GOT_PC_LO)503 return false;504 break;505 }506 case LoongArch::ADDI_W:507 case LoongArch::ADDI_D: {508 auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));509 if (MO == LoongArchII::MO_PCREL_LO || MO == LoongArchII::MO_GOT_PC_LO)510 return false;511 break;512 }513 case LoongArch::LD_W:514 case LoongArch::LD_D: {515 auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));516 if (MO == LoongArchII::MO_GOT_PC_LO)517 return false;518 break;519 }520 case LoongArch::PseudoDESC_CALL: {521 auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));522 if (MO == LoongArchII::MO_DESC_CALL)523 return false;524 break;525 }526 default:527 break;528 }529 }530 531 return true;532}533 534bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,535 const MachineBasicBlock *MBB,536 const MachineFunction &MF) const {537 if (TargetInstrInfo::isSchedulingBoundary(MI, MBB, MF))538 return true;539 540 if (!isSafeToMove(MI, MBB, MF))541 return true;542 543 return false;544}545 546unsigned LoongArchInstrInfo::removeBranch(MachineBasicBlock &MBB,547 int *BytesRemoved) const {548 if (BytesRemoved)549 *BytesRemoved = 0;550 MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();551 if (I == MBB.end())552 return 0;553 554 if (!I->getDesc().isBranch())555 return 0;556 557 // Remove the branch.558 if (BytesRemoved)559 *BytesRemoved += getInstSizeInBytes(*I);560 I->eraseFromParent();561 562 I = MBB.end();563 564 if (I == MBB.begin())565 return 1;566 --I;567 if (!I->getDesc().isConditionalBranch())568 return 1;569 570 // Remove the branch.571 if (BytesRemoved)572 *BytesRemoved += getInstSizeInBytes(*I);573 I->eraseFromParent();574 return 2;575}576 577// Inserts a branch into the end of the specific MachineBasicBlock, returning578// the number of instructions inserted.579unsigned LoongArchInstrInfo::insertBranch(580 MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB,581 ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const {582 if (BytesAdded)583 *BytesAdded = 0;584 585 // Shouldn't be a fall through.586 assert(TBB && "insertBranch must not be told to insert a fallthrough");587 assert(Cond.size() <= 3 && Cond.size() != 1 &&588 "LoongArch branch conditions have at most two components!");589 590 // Unconditional branch.591 if (Cond.empty()) {592 MachineInstr &MI = *BuildMI(&MBB, DL, get(LoongArch::PseudoBR)).addMBB(TBB);593 if (BytesAdded)594 *BytesAdded += getInstSizeInBytes(MI);595 return 1;596 }597 598 // Either a one or two-way conditional branch.599 MachineInstrBuilder MIB = BuildMI(&MBB, DL, get(Cond[0].getImm()));600 for (unsigned i = 1; i < Cond.size(); ++i)601 MIB.add(Cond[i]);602 MIB.addMBB(TBB);603 if (BytesAdded)604 *BytesAdded += getInstSizeInBytes(*MIB);605 606 // One-way conditional branch.607 if (!FBB)608 return 1;609 610 // Two-way conditional branch.611 MachineInstr &MI = *BuildMI(&MBB, DL, get(LoongArch::PseudoBR)).addMBB(FBB);612 if (BytesAdded)613 *BytesAdded += getInstSizeInBytes(MI);614 return 2;615}616 617void LoongArchInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB,618 MachineBasicBlock &DestBB,619 MachineBasicBlock &RestoreBB,620 const DebugLoc &DL,621 int64_t BrOffset,622 RegScavenger *RS) const {623 assert(RS && "RegScavenger required for long branching");624 assert(MBB.empty() &&625 "new block should be inserted for expanding unconditional branch");626 assert(MBB.pred_size() == 1);627 628 MachineFunction *MF = MBB.getParent();629 MachineRegisterInfo &MRI = MF->getRegInfo();630 const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();631 LoongArchMachineFunctionInfo *LAFI =632 MF->getInfo<LoongArchMachineFunctionInfo>();633 634 if (!isInt<32>(BrOffset))635 report_fatal_error(636 "Branch offsets outside of the signed 32-bit range not supported");637 638 Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);639 auto II = MBB.end();640 641 MachineInstr &PCALAU12I =642 *BuildMI(MBB, II, DL, get(LoongArch::PCALAU12I), ScratchReg)643 .addMBB(&DestBB, LoongArchII::MO_PCREL_HI);644 MachineInstr &ADDI =645 *BuildMI(MBB, II, DL,646 get(STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W),647 ScratchReg)648 .addReg(ScratchReg)649 .addMBB(&DestBB, LoongArchII::MO_PCREL_LO);650 BuildMI(MBB, II, DL, get(LoongArch::PseudoBRIND))651 .addReg(ScratchReg, RegState::Kill)652 .addImm(0);653 654 RS->enterBasicBlockEnd(MBB);655 Register Scav = RS->scavengeRegisterBackwards(656 LoongArch::GPRRegClass, PCALAU12I.getIterator(), /*RestoreAfter=*/false,657 /*SPAdj=*/0, /*AllowSpill=*/false);658 if (Scav != LoongArch::NoRegister)659 RS->setRegUsed(Scav);660 else {661 // When there is no scavenged register, it needs to specify a register.662 // Specify t8 register because it won't be used too often.663 Scav = LoongArch::R20;664 int FrameIndex = LAFI->getBranchRelaxationSpillFrameIndex();665 if (FrameIndex == -1)666 report_fatal_error("The function size is incorrectly estimated.");667 storeRegToStackSlot(MBB, PCALAU12I, Scav, /*IsKill=*/true, FrameIndex,668 &LoongArch::GPRRegClass, Register());669 TRI->eliminateFrameIndex(std::prev(PCALAU12I.getIterator()),670 /*SpAdj=*/0, /*FIOperandNum=*/1);671 PCALAU12I.getOperand(1).setMBB(&RestoreBB);672 ADDI.getOperand(2).setMBB(&RestoreBB);673 loadRegFromStackSlot(RestoreBB, RestoreBB.end(), Scav, FrameIndex,674 &LoongArch::GPRRegClass, Register());675 TRI->eliminateFrameIndex(RestoreBB.back(),676 /*SpAdj=*/0, /*FIOperandNum=*/1);677 }678 MRI.replaceRegWith(ScratchReg, Scav);679 MRI.clearVirtRegs();680}681 682static unsigned getOppositeBranchOpc(unsigned Opc) {683 switch (Opc) {684 default:685 llvm_unreachable("Unrecognized conditional branch");686 case LoongArch::BEQ:687 return LoongArch::BNE;688 case LoongArch::BNE:689 return LoongArch::BEQ;690 case LoongArch::BEQZ:691 return LoongArch::BNEZ;692 case LoongArch::BNEZ:693 return LoongArch::BEQZ;694 case LoongArch::BCEQZ:695 return LoongArch::BCNEZ;696 case LoongArch::BCNEZ:697 return LoongArch::BCEQZ;698 case LoongArch::BLT:699 return LoongArch::BGE;700 case LoongArch::BGE:701 return LoongArch::BLT;702 case LoongArch::BLTU:703 return LoongArch::BGEU;704 case LoongArch::BGEU:705 return LoongArch::BLTU;706 }707}708 709bool LoongArchInstrInfo::reverseBranchCondition(710 SmallVectorImpl<MachineOperand> &Cond) const {711 assert((Cond.size() && Cond.size() <= 3) && "Invalid branch condition!");712 Cond[0].setImm(getOppositeBranchOpc(Cond[0].getImm()));713 return false;714}715 716std::pair<unsigned, unsigned>717LoongArchInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const {718 const unsigned Mask = LoongArchII::MO_DIRECT_FLAG_MASK;719 return std::make_pair(TF & Mask, TF & ~Mask);720}721 722ArrayRef<std::pair<unsigned, const char *>>723LoongArchInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {724 using namespace LoongArchII;725 // TODO: Add more target flags.726 static const std::pair<unsigned, const char *> TargetFlags[] = {727 {MO_CALL, "loongarch-call"},728 {MO_CALL_PLT, "loongarch-call-plt"},729 {MO_PCREL_HI, "loongarch-pcrel-hi"},730 {MO_PCREL_LO, "loongarch-pcrel-lo"},731 {MO_PCREL64_LO, "loongarch-pcrel64-lo"},732 {MO_PCREL64_HI, "loongarch-pcrel64-hi"},733 {MO_GOT_PC_HI, "loongarch-got-pc-hi"},734 {MO_GOT_PC_LO, "loongarch-got-pc-lo"},735 {MO_GOT_PC64_LO, "loongarch-got-pc64-lo"},736 {MO_GOT_PC64_HI, "loongarch-got-pc64-hi"},737 {MO_LE_HI, "loongarch-le-hi"},738 {MO_LE_LO, "loongarch-le-lo"},739 {MO_LE64_LO, "loongarch-le64-lo"},740 {MO_LE64_HI, "loongarch-le64-hi"},741 {MO_IE_PC_HI, "loongarch-ie-pc-hi"},742 {MO_IE_PC_LO, "loongarch-ie-pc-lo"},743 {MO_IE_PC64_LO, "loongarch-ie-pc64-lo"},744 {MO_IE_PC64_HI, "loongarch-ie-pc64-hi"},745 {MO_LD_PC_HI, "loongarch-ld-pc-hi"},746 {MO_GD_PC_HI, "loongarch-gd-pc-hi"},747 {MO_CALL36, "loongarch-call36"},748 {MO_DESC_PC_HI, "loongarch-desc-pc-hi"},749 {MO_DESC_PC_LO, "loongarch-desc-pc-lo"},750 {MO_DESC64_PC_LO, "loongarch-desc64-pc-lo"},751 {MO_DESC64_PC_HI, "loongarch-desc64-pc-hi"},752 {MO_DESC_LD, "loongarch-desc-ld"},753 {MO_DESC_CALL, "loongarch-desc-call"},754 {MO_LE_HI_R, "loongarch-le-hi-r"},755 {MO_LE_ADD_R, "loongarch-le-add-r"},756 {MO_LE_LO_R, "loongarch-le-lo-r"}};757 return ArrayRef(TargetFlags);758}759 760ArrayRef<std::pair<unsigned, const char *>>761LoongArchInstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const {762 using namespace LoongArchII;763 static const std::pair<unsigned, const char *> TargetFlags[] = {764 {MO_RELAX, "loongarch-relax"}};765 return ArrayRef(TargetFlags);766}767 768bool LoongArchInstrInfo::canFoldIntoAddrMode(const MachineInstr &MemI,769 Register Reg,770 const MachineInstr &AddrI,771 ExtAddrMode &AM) const {772 enum MemIOffsetType {773 Imm14Shift2,774 Imm12,775 Imm11Shift1,776 Imm10Shift2,777 Imm9Shift3,778 Imm8,779 Imm8Shift1,780 Imm8Shift2,781 Imm8Shift3782 };783 784 MemIOffsetType OT;785 switch (MemI.getOpcode()) {786 default:787 return false;788 case LoongArch::LDPTR_W:789 case LoongArch::LDPTR_D:790 case LoongArch::STPTR_W:791 case LoongArch::STPTR_D:792 OT = Imm14Shift2;793 break;794 case LoongArch::LD_B:795 case LoongArch::LD_H:796 case LoongArch::LD_W:797 case LoongArch::LD_D:798 case LoongArch::LD_BU:799 case LoongArch::LD_HU:800 case LoongArch::LD_WU:801 case LoongArch::ST_B:802 case LoongArch::ST_H:803 case LoongArch::ST_W:804 case LoongArch::ST_D:805 case LoongArch::FLD_S:806 case LoongArch::FLD_D:807 case LoongArch::FST_S:808 case LoongArch::FST_D:809 case LoongArch::VLD:810 case LoongArch::VST:811 case LoongArch::XVLD:812 case LoongArch::XVST:813 case LoongArch::VLDREPL_B:814 case LoongArch::XVLDREPL_B:815 OT = Imm12;816 break;817 case LoongArch::VLDREPL_H:818 case LoongArch::XVLDREPL_H:819 OT = Imm11Shift1;820 break;821 case LoongArch::VLDREPL_W:822 case LoongArch::XVLDREPL_W:823 OT = Imm10Shift2;824 break;825 case LoongArch::VLDREPL_D:826 case LoongArch::XVLDREPL_D:827 OT = Imm9Shift3;828 break;829 case LoongArch::VSTELM_B:830 case LoongArch::XVSTELM_B:831 OT = Imm8;832 break;833 case LoongArch::VSTELM_H:834 case LoongArch::XVSTELM_H:835 OT = Imm8Shift1;836 break;837 case LoongArch::VSTELM_W:838 case LoongArch::XVSTELM_W:839 OT = Imm8Shift2;840 break;841 case LoongArch::VSTELM_D:842 case LoongArch::XVSTELM_D:843 OT = Imm8Shift3;844 break;845 }846 847 if (MemI.getOperand(0).getReg() == Reg)848 return false;849 850 if ((AddrI.getOpcode() != LoongArch::ADDI_W &&851 AddrI.getOpcode() != LoongArch::ADDI_D) ||852 !AddrI.getOperand(1).isReg() || !AddrI.getOperand(2).isImm())853 return false;854 855 int64_t OldOffset = MemI.getOperand(2).getImm();856 int64_t Disp = AddrI.getOperand(2).getImm();857 int64_t NewOffset = OldOffset + Disp;858 if (!STI.is64Bit())859 NewOffset = SignExtend64<32>(NewOffset);860 861 if (!(OT == Imm14Shift2 && isShiftedInt<14, 2>(NewOffset) && STI.hasUAL()) &&862 !(OT == Imm12 && isInt<12>(NewOffset)) &&863 !(OT == Imm11Shift1 && isShiftedInt<11, 1>(NewOffset)) &&864 !(OT == Imm10Shift2 && isShiftedInt<10, 2>(NewOffset)) &&865 !(OT == Imm9Shift3 && isShiftedInt<9, 3>(NewOffset)) &&866 !(OT == Imm8 && isInt<8>(NewOffset)) &&867 !(OT == Imm8Shift1 && isShiftedInt<8, 1>(NewOffset)) &&868 !(OT == Imm8Shift2 && isShiftedInt<8, 2>(NewOffset)) &&869 !(OT == Imm8Shift3 && isShiftedInt<8, 3>(NewOffset)))870 return false;871 872 AM.BaseReg = AddrI.getOperand(1).getReg();873 AM.ScaledReg = 0;874 AM.Scale = 0;875 AM.Displacement = NewOffset;876 AM.Form = ExtAddrMode::Formula::Basic;877 return true;878}879 880MachineInstr *881LoongArchInstrInfo::emitLdStWithAddr(MachineInstr &MemI,882 const ExtAddrMode &AM) const {883 const DebugLoc &DL = MemI.getDebugLoc();884 MachineBasicBlock &MBB = *MemI.getParent();885 886 assert(AM.ScaledReg == 0 && AM.Scale == 0 &&887 "Addressing mode not supported for folding");888 889 unsigned MemIOp = MemI.getOpcode();890 switch (MemIOp) {891 default:892 return BuildMI(MBB, MemI, DL, get(MemIOp))893 .addReg(MemI.getOperand(0).getReg(),894 MemI.mayLoad() ? RegState::Define : 0)895 .addReg(AM.BaseReg)896 .addImm(AM.Displacement)897 .setMemRefs(MemI.memoperands())898 .setMIFlags(MemI.getFlags());899 case LoongArch::VSTELM_B:900 case LoongArch::VSTELM_H:901 case LoongArch::VSTELM_W:902 case LoongArch::VSTELM_D:903 case LoongArch::XVSTELM_B:904 case LoongArch::XVSTELM_H:905 case LoongArch::XVSTELM_W:906 case LoongArch::XVSTELM_D:907 return BuildMI(MBB, MemI, DL, get(MemIOp))908 .addReg(MemI.getOperand(0).getReg(), 0)909 .addReg(AM.BaseReg)910 .addImm(AM.Displacement)911 .addImm(MemI.getOperand(3).getImm())912 .setMemRefs(MemI.memoperands())913 .setMIFlags(MemI.getFlags());914 }915}916 917// Returns true if this is the sext.w pattern, addi.w rd, rs, 0.918bool LoongArch::isSEXT_W(const MachineInstr &MI) {919 return MI.getOpcode() == LoongArch::ADDI_W && MI.getOperand(1).isReg() &&920 MI.getOperand(2).isImm() && MI.getOperand(2).getImm() == 0;921}922