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