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