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-exception 6 // 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/MC/MCInstBuilder.h" 21 22 using namespace llvm; 23 24 #define GET_INSTRINFO_CTOR_DTOR 25 #include "LoongArchGenInstrInfo.inc" 26 27 LoongArchInstrInfo::LoongArchInstrInfo(LoongArchSubtarget &STI) 28 : LoongArchGenInstrInfo(LoongArch::ADJCALLSTACKDOWN, 29 LoongArch::ADJCALLSTACKUP), 30 STI(STI) {} 31 32 MCInst LoongArchInstrInfo::getNop() const { 33 return MCInstBuilder(LoongArch::ANDI) 34 .addReg(LoongArch::R0) 35 .addReg(LoongArch::R0) 36 .addImm(0); 37 } 38 39 void LoongArchInstrInfo::copyPhysReg(MachineBasicBlock &MBB, 40 MachineBasicBlock::iterator MBBI, 41 const DebugLoc &DL, MCRegister DstReg, 42 MCRegister SrcReg, bool KillSrc) const { 43 if (LoongArch::GPRRegClass.contains(DstReg, SrcReg)) { 44 BuildMI(MBB, MBBI, DL, get(LoongArch::OR), DstReg) 45 .addReg(SrcReg, getKillRegState(KillSrc)) 46 .addReg(LoongArch::R0); 47 return; 48 } 49 50 // VR->VR copies. 51 if (LoongArch::LSX128RegClass.contains(DstReg, SrcReg)) { 52 BuildMI(MBB, MBBI, DL, get(LoongArch::VORI_B), DstReg) 53 .addReg(SrcReg, getKillRegState(KillSrc)) 54 .addImm(0); 55 return; 56 } 57 58 // XR->XR copies. 59 if (LoongArch::LASX256RegClass.contains(DstReg, SrcReg)) { 60 BuildMI(MBB, MBBI, DL, get(LoongArch::XVORI_B), DstReg) 61 .addReg(SrcReg, getKillRegState(KillSrc)) 62 .addImm(0); 63 return; 64 } 65 66 // GPR->CFR copy. 67 if (LoongArch::CFRRegClass.contains(DstReg) && 68 LoongArch::GPRRegClass.contains(SrcReg)) { 69 BuildMI(MBB, MBBI, DL, get(LoongArch::MOVGR2CF), DstReg) 70 .addReg(SrcReg, getKillRegState(KillSrc)); 71 return; 72 } 73 // CFR->GPR copy. 74 if (LoongArch::GPRRegClass.contains(DstReg) && 75 LoongArch::CFRRegClass.contains(SrcReg)) { 76 BuildMI(MBB, MBBI, DL, get(LoongArch::MOVCF2GR), DstReg) 77 .addReg(SrcReg, getKillRegState(KillSrc)); 78 return; 79 } 80 // CFR->CFR copy. 81 if (LoongArch::CFRRegClass.contains(DstReg, SrcReg)) { 82 BuildMI(MBB, MBBI, DL, get(LoongArch::PseudoCopyCFR), DstReg) 83 .addReg(SrcReg, getKillRegState(KillSrc)); 84 return; 85 } 86 87 // FPR->FPR copies. 88 unsigned Opc; 89 if (LoongArch::FPR32RegClass.contains(DstReg, SrcReg)) { 90 Opc = LoongArch::FMOV_S; 91 } else if (LoongArch::FPR64RegClass.contains(DstReg, SrcReg)) { 92 Opc = LoongArch::FMOV_D; 93 } else if (LoongArch::GPRRegClass.contains(DstReg) && 94 LoongArch::FPR32RegClass.contains(SrcReg)) { 95 // FPR32 -> GPR copies 96 Opc = LoongArch::MOVFR2GR_S; 97 } else if (LoongArch::GPRRegClass.contains(DstReg) && 98 LoongArch::FPR64RegClass.contains(SrcReg)) { 99 // FPR64 -> GPR copies 100 Opc = LoongArch::MOVFR2GR_D; 101 } else { 102 // TODO: support other copies. 103 llvm_unreachable("Impossible reg-to-reg copy"); 104 } 105 106 BuildMI(MBB, MBBI, DL, get(Opc), DstReg) 107 .addReg(SrcReg, getKillRegState(KillSrc)); 108 } 109 110 void LoongArchInstrInfo::storeRegToStackSlot( 111 MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Register SrcReg, 112 bool IsKill, int FI, const TargetRegisterClass *RC, 113 const TargetRegisterInfo *TRI, Register VReg) const { 114 MachineFunction *MF = MBB.getParent(); 115 MachineFrameInfo &MFI = MF->getFrameInfo(); 116 117 unsigned Opcode; 118 if (LoongArch::GPRRegClass.hasSubClassEq(RC)) 119 Opcode = TRI->getRegSizeInBits(LoongArch::GPRRegClass) == 32 120 ? LoongArch::ST_W 121 : LoongArch::ST_D; 122 else if (LoongArch::FPR32RegClass.hasSubClassEq(RC)) 123 Opcode = LoongArch::FST_S; 124 else if (LoongArch::FPR64RegClass.hasSubClassEq(RC)) 125 Opcode = LoongArch::FST_D; 126 else if (LoongArch::LSX128RegClass.hasSubClassEq(RC)) 127 Opcode = LoongArch::VST; 128 else if (LoongArch::LASX256RegClass.hasSubClassEq(RC)) 129 Opcode = LoongArch::XVST; 130 else if (LoongArch::CFRRegClass.hasSubClassEq(RC)) 131 Opcode = LoongArch::PseudoST_CFR; 132 else 133 llvm_unreachable("Can't store this register to stack slot"); 134 135 MachineMemOperand *MMO = MF->getMachineMemOperand( 136 MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOStore, 137 MFI.getObjectSize(FI), MFI.getObjectAlign(FI)); 138 139 BuildMI(MBB, I, DebugLoc(), get(Opcode)) 140 .addReg(SrcReg, getKillRegState(IsKill)) 141 .addFrameIndex(FI) 142 .addImm(0) 143 .addMemOperand(MMO); 144 } 145 146 void LoongArchInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, 147 MachineBasicBlock::iterator I, 148 Register DstReg, int FI, 149 const TargetRegisterClass *RC, 150 const TargetRegisterInfo *TRI, 151 Register VReg) const { 152 MachineFunction *MF = MBB.getParent(); 153 MachineFrameInfo &MFI = MF->getFrameInfo(); 154 155 unsigned Opcode; 156 if (LoongArch::GPRRegClass.hasSubClassEq(RC)) 157 Opcode = TRI->getRegSizeInBits(LoongArch::GPRRegClass) == 32 158 ? LoongArch::LD_W 159 : LoongArch::LD_D; 160 else if (LoongArch::FPR32RegClass.hasSubClassEq(RC)) 161 Opcode = LoongArch::FLD_S; 162 else if (LoongArch::FPR64RegClass.hasSubClassEq(RC)) 163 Opcode = LoongArch::FLD_D; 164 else if (LoongArch::LSX128RegClass.hasSubClassEq(RC)) 165 Opcode = LoongArch::VLD; 166 else if (LoongArch::LASX256RegClass.hasSubClassEq(RC)) 167 Opcode = LoongArch::XVLD; 168 else if (LoongArch::CFRRegClass.hasSubClassEq(RC)) 169 Opcode = LoongArch::PseudoLD_CFR; 170 else 171 llvm_unreachable("Can't load this register from stack slot"); 172 173 MachineMemOperand *MMO = MF->getMachineMemOperand( 174 MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOLoad, 175 MFI.getObjectSize(FI), MFI.getObjectAlign(FI)); 176 177 BuildMI(MBB, I, DebugLoc(), get(Opcode), DstReg) 178 .addFrameIndex(FI) 179 .addImm(0) 180 .addMemOperand(MMO); 181 } 182 183 void LoongArchInstrInfo::movImm(MachineBasicBlock &MBB, 184 MachineBasicBlock::iterator MBBI, 185 const DebugLoc &DL, Register DstReg, 186 uint64_t Val, MachineInstr::MIFlag Flag) const { 187 Register SrcReg = LoongArch::R0; 188 189 if (!STI.is64Bit() && !isInt<32>(Val)) 190 report_fatal_error("Should only materialize 32-bit constants for LA32"); 191 192 auto Seq = LoongArchMatInt::generateInstSeq(Val); 193 assert(!Seq.empty()); 194 195 for (auto &Inst : Seq) { 196 switch (Inst.Opc) { 197 case LoongArch::LU12I_W: 198 BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg) 199 .addImm(Inst.Imm) 200 .setMIFlag(Flag); 201 break; 202 case LoongArch::ADDI_W: 203 case LoongArch::ORI: 204 case LoongArch::LU32I_D: // "rj" is needed due to InstrInfo pattern 205 case LoongArch::LU52I_D: 206 BuildMI(MBB, MBBI, DL, get(Inst.Opc), DstReg) 207 .addReg(SrcReg, RegState::Kill) 208 .addImm(Inst.Imm) 209 .setMIFlag(Flag); 210 break; 211 default: 212 assert(false && "Unknown insn emitted by LoongArchMatInt"); 213 } 214 215 // Only the first instruction has $zero as its source. 216 SrcReg = DstReg; 217 } 218 } 219 220 unsigned LoongArchInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { 221 unsigned Opcode = MI.getOpcode(); 222 223 if (Opcode == TargetOpcode::INLINEASM || 224 Opcode == TargetOpcode::INLINEASM_BR) { 225 const MachineFunction *MF = MI.getParent()->getParent(); 226 const MCAsmInfo *MAI = MF->getTarget().getMCAsmInfo(); 227 return getInlineAsmLength(MI.getOperand(0).getSymbolName(), *MAI); 228 } 229 return MI.getDesc().getSize(); 230 } 231 232 MachineBasicBlock * 233 LoongArchInstrInfo::getBranchDestBlock(const MachineInstr &MI) const { 234 assert(MI.getDesc().isBranch() && "Unexpected opcode!"); 235 // The branch target is always the last operand. 236 return MI.getOperand(MI.getNumExplicitOperands() - 1).getMBB(); 237 } 238 239 static void parseCondBranch(MachineInstr &LastInst, MachineBasicBlock *&Target, 240 SmallVectorImpl<MachineOperand> &Cond) { 241 // Block ends with fall-through condbranch. 242 assert(LastInst.getDesc().isConditionalBranch() && 243 "Unknown conditional branch"); 244 int NumOp = LastInst.getNumExplicitOperands(); 245 Target = LastInst.getOperand(NumOp - 1).getMBB(); 246 247 Cond.push_back(MachineOperand::CreateImm(LastInst.getOpcode())); 248 for (int i = 0; i < NumOp - 1; i++) 249 Cond.push_back(LastInst.getOperand(i)); 250 } 251 252 bool LoongArchInstrInfo::analyzeBranch(MachineBasicBlock &MBB, 253 MachineBasicBlock *&TBB, 254 MachineBasicBlock *&FBB, 255 SmallVectorImpl<MachineOperand> &Cond, 256 bool AllowModify) const { 257 TBB = FBB = nullptr; 258 Cond.clear(); 259 260 // If the block has no terminators, it just falls into the block after it. 261 MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr(); 262 if (I == MBB.end() || !isUnpredicatedTerminator(*I)) 263 return false; 264 265 // Count the number of terminators and find the first unconditional or 266 // indirect branch. 267 MachineBasicBlock::iterator FirstUncondOrIndirectBr = MBB.end(); 268 int NumTerminators = 0; 269 for (auto J = I.getReverse(); J != MBB.rend() && isUnpredicatedTerminator(*J); 270 J++) { 271 NumTerminators++; 272 if (J->getDesc().isUnconditionalBranch() || 273 J->getDesc().isIndirectBranch()) { 274 FirstUncondOrIndirectBr = J.getReverse(); 275 } 276 } 277 278 // If AllowModify is true, we can erase any terminators after 279 // FirstUncondOrIndirectBR. 280 if (AllowModify && FirstUncondOrIndirectBr != MBB.end()) { 281 while (std::next(FirstUncondOrIndirectBr) != MBB.end()) { 282 std::next(FirstUncondOrIndirectBr)->eraseFromParent(); 283 NumTerminators--; 284 } 285 I = FirstUncondOrIndirectBr; 286 } 287 288 // Handle a single unconditional branch. 289 if (NumTerminators == 1 && I->getDesc().isUnconditionalBranch()) { 290 TBB = getBranchDestBlock(*I); 291 return false; 292 } 293 294 // Handle a single conditional branch. 295 if (NumTerminators == 1 && I->getDesc().isConditionalBranch()) { 296 parseCondBranch(*I, TBB, Cond); 297 return false; 298 } 299 300 // Handle a conditional branch followed by an unconditional branch. 301 if (NumTerminators == 2 && std::prev(I)->getDesc().isConditionalBranch() && 302 I->getDesc().isUnconditionalBranch()) { 303 parseCondBranch(*std::prev(I), TBB, Cond); 304 FBB = getBranchDestBlock(*I); 305 return false; 306 } 307 308 // Otherwise, we can't handle this. 309 return true; 310 } 311 312 bool LoongArchInstrInfo::isBranchOffsetInRange(unsigned BranchOp, 313 int64_t BrOffset) const { 314 switch (BranchOp) { 315 default: 316 llvm_unreachable("Unknown branch instruction!"); 317 case LoongArch::BEQ: 318 case LoongArch::BNE: 319 case LoongArch::BLT: 320 case LoongArch::BGE: 321 case LoongArch::BLTU: 322 case LoongArch::BGEU: 323 return isInt<18>(BrOffset); 324 case LoongArch::BEQZ: 325 case LoongArch::BNEZ: 326 case LoongArch::BCEQZ: 327 case LoongArch::BCNEZ: 328 return isInt<23>(BrOffset); 329 case LoongArch::B: 330 case LoongArch::PseudoBR: 331 return isInt<28>(BrOffset); 332 } 333 } 334 335 unsigned LoongArchInstrInfo::removeBranch(MachineBasicBlock &MBB, 336 int *BytesRemoved) const { 337 if (BytesRemoved) 338 *BytesRemoved = 0; 339 MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr(); 340 if (I == MBB.end()) 341 return 0; 342 343 if (!I->getDesc().isBranch()) 344 return 0; 345 346 // Remove the branch. 347 if (BytesRemoved) 348 *BytesRemoved += getInstSizeInBytes(*I); 349 I->eraseFromParent(); 350 351 I = MBB.end(); 352 353 if (I == MBB.begin()) 354 return 1; 355 --I; 356 if (!I->getDesc().isConditionalBranch()) 357 return 1; 358 359 // Remove the branch. 360 if (BytesRemoved) 361 *BytesRemoved += getInstSizeInBytes(*I); 362 I->eraseFromParent(); 363 return 2; 364 } 365 366 // Inserts a branch into the end of the specific MachineBasicBlock, returning 367 // the number of instructions inserted. 368 unsigned LoongArchInstrInfo::insertBranch( 369 MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, 370 ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const { 371 if (BytesAdded) 372 *BytesAdded = 0; 373 374 // Shouldn't be a fall through. 375 assert(TBB && "insertBranch must not be told to insert a fallthrough"); 376 assert(Cond.size() <= 3 && Cond.size() != 1 && 377 "LoongArch branch conditions have at most two components!"); 378 379 // Unconditional branch. 380 if (Cond.empty()) { 381 MachineInstr &MI = *BuildMI(&MBB, DL, get(LoongArch::PseudoBR)).addMBB(TBB); 382 if (BytesAdded) 383 *BytesAdded += getInstSizeInBytes(MI); 384 return 1; 385 } 386 387 // Either a one or two-way conditional branch. 388 MachineInstrBuilder MIB = BuildMI(&MBB, DL, get(Cond[0].getImm())); 389 for (unsigned i = 1; i < Cond.size(); ++i) 390 MIB.add(Cond[i]); 391 MIB.addMBB(TBB); 392 if (BytesAdded) 393 *BytesAdded += getInstSizeInBytes(*MIB); 394 395 // One-way conditional branch. 396 if (!FBB) 397 return 1; 398 399 // Two-way conditional branch. 400 MachineInstr &MI = *BuildMI(&MBB, DL, get(LoongArch::PseudoBR)).addMBB(FBB); 401 if (BytesAdded) 402 *BytesAdded += getInstSizeInBytes(MI); 403 return 2; 404 } 405 406 void LoongArchInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB, 407 MachineBasicBlock &DestBB, 408 MachineBasicBlock &RestoreBB, 409 const DebugLoc &DL, 410 int64_t BrOffset, 411 RegScavenger *RS) const { 412 assert(RS && "RegScavenger required for long branching"); 413 assert(MBB.empty() && 414 "new block should be inserted for expanding unconditional branch"); 415 assert(MBB.pred_size() == 1); 416 417 MachineFunction *MF = MBB.getParent(); 418 MachineRegisterInfo &MRI = MF->getRegInfo(); 419 const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); 420 LoongArchMachineFunctionInfo *LAFI = 421 MF->getInfo<LoongArchMachineFunctionInfo>(); 422 423 if (!isInt<32>(BrOffset)) 424 report_fatal_error( 425 "Branch offsets outside of the signed 32-bit range not supported"); 426 427 Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass); 428 auto II = MBB.end(); 429 430 MachineInstr &PCALAU12I = 431 *BuildMI(MBB, II, DL, get(LoongArch::PCALAU12I), ScratchReg) 432 .addMBB(&DestBB, LoongArchII::MO_PCREL_HI); 433 MachineInstr &ADDI = 434 *BuildMI(MBB, II, DL, 435 get(STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W), 436 ScratchReg) 437 .addReg(ScratchReg) 438 .addMBB(&DestBB, LoongArchII::MO_PCREL_LO); 439 BuildMI(MBB, II, DL, get(LoongArch::PseudoBRIND)) 440 .addReg(ScratchReg, RegState::Kill) 441 .addImm(0); 442 443 RS->enterBasicBlockEnd(MBB); 444 Register Scav = RS->scavengeRegisterBackwards( 445 LoongArch::GPRRegClass, PCALAU12I.getIterator(), /*RestoreAfter=*/false, 446 /*SPAdj=*/0, /*AllowSpill=*/false); 447 if (Scav != LoongArch::NoRegister) 448 RS->setRegUsed(Scav); 449 else { 450 // When there is no scavenged register, it needs to specify a register. 451 // Specify t8 register because it won't be used too often. 452 Scav = LoongArch::R20; 453 int FrameIndex = LAFI->getBranchRelaxationSpillFrameIndex(); 454 if (FrameIndex == -1) 455 report_fatal_error("The function size is incorrectly estimated."); 456 storeRegToStackSlot(MBB, PCALAU12I, Scav, /*IsKill=*/true, FrameIndex, 457 &LoongArch::GPRRegClass, TRI, Register()); 458 TRI->eliminateFrameIndex(std::prev(PCALAU12I.getIterator()), 459 /*SpAdj=*/0, /*FIOperandNum=*/1); 460 PCALAU12I.getOperand(1).setMBB(&RestoreBB); 461 ADDI.getOperand(2).setMBB(&RestoreBB); 462 loadRegFromStackSlot(RestoreBB, RestoreBB.end(), Scav, FrameIndex, 463 &LoongArch::GPRRegClass, TRI, Register()); 464 TRI->eliminateFrameIndex(RestoreBB.back(), 465 /*SpAdj=*/0, /*FIOperandNum=*/1); 466 } 467 MRI.replaceRegWith(ScratchReg, Scav); 468 MRI.clearVirtRegs(); 469 } 470 471 static unsigned getOppositeBranchOpc(unsigned Opc) { 472 switch (Opc) { 473 default: 474 llvm_unreachable("Unrecognized conditional branch"); 475 case LoongArch::BEQ: 476 return LoongArch::BNE; 477 case LoongArch::BNE: 478 return LoongArch::BEQ; 479 case LoongArch::BEQZ: 480 return LoongArch::BNEZ; 481 case LoongArch::BNEZ: 482 return LoongArch::BEQZ; 483 case LoongArch::BCEQZ: 484 return LoongArch::BCNEZ; 485 case LoongArch::BCNEZ: 486 return LoongArch::BCEQZ; 487 case LoongArch::BLT: 488 return LoongArch::BGE; 489 case LoongArch::BGE: 490 return LoongArch::BLT; 491 case LoongArch::BLTU: 492 return LoongArch::BGEU; 493 case LoongArch::BGEU: 494 return LoongArch::BLTU; 495 } 496 } 497 498 bool LoongArchInstrInfo::reverseBranchCondition( 499 SmallVectorImpl<MachineOperand> &Cond) const { 500 assert((Cond.size() && Cond.size() <= 3) && "Invalid branch condition!"); 501 Cond[0].setImm(getOppositeBranchOpc(Cond[0].getImm())); 502 return false; 503 } 504 505 std::pair<unsigned, unsigned> 506 LoongArchInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const { 507 return std::make_pair(TF, 0u); 508 } 509 510 ArrayRef<std::pair<unsigned, const char *>> 511 LoongArchInstrInfo::getSerializableDirectMachineOperandTargetFlags() const { 512 using namespace LoongArchII; 513 // TODO: Add more target flags. 514 static const std::pair<unsigned, const char *> TargetFlags[] = { 515 {MO_CALL, "loongarch-call"}, 516 {MO_CALL_PLT, "loongarch-call-plt"}, 517 {MO_PCREL_HI, "loongarch-pcrel-hi"}, 518 {MO_PCREL_LO, "loongarch-pcrel-lo"}, 519 {MO_PCREL64_LO, "loongarch-pcrel64-lo"}, 520 {MO_PCREL64_HI, "loongarch-pcrel64-hi"}, 521 {MO_GOT_PC_HI, "loongarch-got-pc-hi"}, 522 {MO_GOT_PC_LO, "loongarch-got-pc-lo"}, 523 {MO_GOT_PC64_LO, "loongarch-got-pc64-lo"}, 524 {MO_GOT_PC64_HI, "loongarch-got-pc64-hi"}, 525 {MO_LE_HI, "loongarch-le-hi"}, 526 {MO_LE_LO, "loongarch-le-lo"}, 527 {MO_LE64_LO, "loongarch-le64-lo"}, 528 {MO_LE64_HI, "loongarch-le64-hi"}, 529 {MO_IE_PC_HI, "loongarch-ie-pc-hi"}, 530 {MO_IE_PC_LO, "loongarch-ie-pc-lo"}, 531 {MO_IE_PC64_LO, "loongarch-ie-pc64-lo"}, 532 {MO_IE_PC64_HI, "loongarch-ie-pc64-hi"}, 533 {MO_LD_PC_HI, "loongarch-ld-pc-hi"}, 534 {MO_GD_PC_HI, "loongarch-gd-pc-hi"}}; 535 return ArrayRef(TargetFlags); 536 } 537