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