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 bool LoongArchInstrInfo::isAsCheapAsAMove(const MachineInstr &MI) const { 233 const unsigned Opcode = MI.getOpcode(); 234 switch (Opcode) { 235 default: 236 break; 237 case LoongArch::ADDI_D: 238 case LoongArch::ORI: 239 case LoongArch::XORI: 240 return (MI.getOperand(1).isReg() && 241 MI.getOperand(1).getReg() == LoongArch::R0) || 242 (MI.getOperand(2).isImm() && MI.getOperand(2).getImm() == 0); 243 } 244 return MI.isAsCheapAsAMove(); 245 } 246 247 MachineBasicBlock * 248 LoongArchInstrInfo::getBranchDestBlock(const MachineInstr &MI) const { 249 assert(MI.getDesc().isBranch() && "Unexpected opcode!"); 250 // The branch target is always the last operand. 251 return MI.getOperand(MI.getNumExplicitOperands() - 1).getMBB(); 252 } 253 254 static void parseCondBranch(MachineInstr &LastInst, MachineBasicBlock *&Target, 255 SmallVectorImpl<MachineOperand> &Cond) { 256 // Block ends with fall-through condbranch. 257 assert(LastInst.getDesc().isConditionalBranch() && 258 "Unknown conditional branch"); 259 int NumOp = LastInst.getNumExplicitOperands(); 260 Target = LastInst.getOperand(NumOp - 1).getMBB(); 261 262 Cond.push_back(MachineOperand::CreateImm(LastInst.getOpcode())); 263 for (int i = 0; i < NumOp - 1; i++) 264 Cond.push_back(LastInst.getOperand(i)); 265 } 266 267 bool LoongArchInstrInfo::analyzeBranch(MachineBasicBlock &MBB, 268 MachineBasicBlock *&TBB, 269 MachineBasicBlock *&FBB, 270 SmallVectorImpl<MachineOperand> &Cond, 271 bool AllowModify) const { 272 TBB = FBB = nullptr; 273 Cond.clear(); 274 275 // If the block has no terminators, it just falls into the block after it. 276 MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr(); 277 if (I == MBB.end() || !isUnpredicatedTerminator(*I)) 278 return false; 279 280 // Count the number of terminators and find the first unconditional or 281 // indirect branch. 282 MachineBasicBlock::iterator FirstUncondOrIndirectBr = MBB.end(); 283 int NumTerminators = 0; 284 for (auto J = I.getReverse(); J != MBB.rend() && isUnpredicatedTerminator(*J); 285 J++) { 286 NumTerminators++; 287 if (J->getDesc().isUnconditionalBranch() || 288 J->getDesc().isIndirectBranch()) { 289 FirstUncondOrIndirectBr = J.getReverse(); 290 } 291 } 292 293 // If AllowModify is true, we can erase any terminators after 294 // FirstUncondOrIndirectBR. 295 if (AllowModify && FirstUncondOrIndirectBr != MBB.end()) { 296 while (std::next(FirstUncondOrIndirectBr) != MBB.end()) { 297 std::next(FirstUncondOrIndirectBr)->eraseFromParent(); 298 NumTerminators--; 299 } 300 I = FirstUncondOrIndirectBr; 301 } 302 303 // Handle a single unconditional branch. 304 if (NumTerminators == 1 && I->getDesc().isUnconditionalBranch()) { 305 TBB = getBranchDestBlock(*I); 306 return false; 307 } 308 309 // Handle a single conditional branch. 310 if (NumTerminators == 1 && I->getDesc().isConditionalBranch()) { 311 parseCondBranch(*I, TBB, Cond); 312 return false; 313 } 314 315 // Handle a conditional branch followed by an unconditional branch. 316 if (NumTerminators == 2 && std::prev(I)->getDesc().isConditionalBranch() && 317 I->getDesc().isUnconditionalBranch()) { 318 parseCondBranch(*std::prev(I), TBB, Cond); 319 FBB = getBranchDestBlock(*I); 320 return false; 321 } 322 323 // Otherwise, we can't handle this. 324 return true; 325 } 326 327 bool LoongArchInstrInfo::isBranchOffsetInRange(unsigned BranchOp, 328 int64_t BrOffset) const { 329 switch (BranchOp) { 330 default: 331 llvm_unreachable("Unknown branch instruction!"); 332 case LoongArch::BEQ: 333 case LoongArch::BNE: 334 case LoongArch::BLT: 335 case LoongArch::BGE: 336 case LoongArch::BLTU: 337 case LoongArch::BGEU: 338 return isInt<18>(BrOffset); 339 case LoongArch::BEQZ: 340 case LoongArch::BNEZ: 341 case LoongArch::BCEQZ: 342 case LoongArch::BCNEZ: 343 return isInt<23>(BrOffset); 344 case LoongArch::B: 345 case LoongArch::PseudoBR: 346 return isInt<28>(BrOffset); 347 } 348 } 349 350 unsigned LoongArchInstrInfo::removeBranch(MachineBasicBlock &MBB, 351 int *BytesRemoved) const { 352 if (BytesRemoved) 353 *BytesRemoved = 0; 354 MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr(); 355 if (I == MBB.end()) 356 return 0; 357 358 if (!I->getDesc().isBranch()) 359 return 0; 360 361 // Remove the branch. 362 if (BytesRemoved) 363 *BytesRemoved += getInstSizeInBytes(*I); 364 I->eraseFromParent(); 365 366 I = MBB.end(); 367 368 if (I == MBB.begin()) 369 return 1; 370 --I; 371 if (!I->getDesc().isConditionalBranch()) 372 return 1; 373 374 // Remove the branch. 375 if (BytesRemoved) 376 *BytesRemoved += getInstSizeInBytes(*I); 377 I->eraseFromParent(); 378 return 2; 379 } 380 381 // Inserts a branch into the end of the specific MachineBasicBlock, returning 382 // the number of instructions inserted. 383 unsigned LoongArchInstrInfo::insertBranch( 384 MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, 385 ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const { 386 if (BytesAdded) 387 *BytesAdded = 0; 388 389 // Shouldn't be a fall through. 390 assert(TBB && "insertBranch must not be told to insert a fallthrough"); 391 assert(Cond.size() <= 3 && Cond.size() != 1 && 392 "LoongArch branch conditions have at most two components!"); 393 394 // Unconditional branch. 395 if (Cond.empty()) { 396 MachineInstr &MI = *BuildMI(&MBB, DL, get(LoongArch::PseudoBR)).addMBB(TBB); 397 if (BytesAdded) 398 *BytesAdded += getInstSizeInBytes(MI); 399 return 1; 400 } 401 402 // Either a one or two-way conditional branch. 403 MachineInstrBuilder MIB = BuildMI(&MBB, DL, get(Cond[0].getImm())); 404 for (unsigned i = 1; i < Cond.size(); ++i) 405 MIB.add(Cond[i]); 406 MIB.addMBB(TBB); 407 if (BytesAdded) 408 *BytesAdded += getInstSizeInBytes(*MIB); 409 410 // One-way conditional branch. 411 if (!FBB) 412 return 1; 413 414 // Two-way conditional branch. 415 MachineInstr &MI = *BuildMI(&MBB, DL, get(LoongArch::PseudoBR)).addMBB(FBB); 416 if (BytesAdded) 417 *BytesAdded += getInstSizeInBytes(MI); 418 return 2; 419 } 420 421 void LoongArchInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB, 422 MachineBasicBlock &DestBB, 423 MachineBasicBlock &RestoreBB, 424 const DebugLoc &DL, 425 int64_t BrOffset, 426 RegScavenger *RS) const { 427 assert(RS && "RegScavenger required for long branching"); 428 assert(MBB.empty() && 429 "new block should be inserted for expanding unconditional branch"); 430 assert(MBB.pred_size() == 1); 431 432 MachineFunction *MF = MBB.getParent(); 433 MachineRegisterInfo &MRI = MF->getRegInfo(); 434 const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); 435 LoongArchMachineFunctionInfo *LAFI = 436 MF->getInfo<LoongArchMachineFunctionInfo>(); 437 438 if (!isInt<32>(BrOffset)) 439 report_fatal_error( 440 "Branch offsets outside of the signed 32-bit range not supported"); 441 442 Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass); 443 auto II = MBB.end(); 444 445 MachineInstr &PCALAU12I = 446 *BuildMI(MBB, II, DL, get(LoongArch::PCALAU12I), ScratchReg) 447 .addMBB(&DestBB, LoongArchII::MO_PCREL_HI); 448 MachineInstr &ADDI = 449 *BuildMI(MBB, II, DL, 450 get(STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W), 451 ScratchReg) 452 .addReg(ScratchReg) 453 .addMBB(&DestBB, LoongArchII::MO_PCREL_LO); 454 BuildMI(MBB, II, DL, get(LoongArch::PseudoBRIND)) 455 .addReg(ScratchReg, RegState::Kill) 456 .addImm(0); 457 458 RS->enterBasicBlockEnd(MBB); 459 Register Scav = RS->scavengeRegisterBackwards( 460 LoongArch::GPRRegClass, PCALAU12I.getIterator(), /*RestoreAfter=*/false, 461 /*SPAdj=*/0, /*AllowSpill=*/false); 462 if (Scav != LoongArch::NoRegister) 463 RS->setRegUsed(Scav); 464 else { 465 // When there is no scavenged register, it needs to specify a register. 466 // Specify t8 register because it won't be used too often. 467 Scav = LoongArch::R20; 468 int FrameIndex = LAFI->getBranchRelaxationSpillFrameIndex(); 469 if (FrameIndex == -1) 470 report_fatal_error("The function size is incorrectly estimated."); 471 storeRegToStackSlot(MBB, PCALAU12I, Scav, /*IsKill=*/true, FrameIndex, 472 &LoongArch::GPRRegClass, TRI, Register()); 473 TRI->eliminateFrameIndex(std::prev(PCALAU12I.getIterator()), 474 /*SpAdj=*/0, /*FIOperandNum=*/1); 475 PCALAU12I.getOperand(1).setMBB(&RestoreBB); 476 ADDI.getOperand(2).setMBB(&RestoreBB); 477 loadRegFromStackSlot(RestoreBB, RestoreBB.end(), Scav, FrameIndex, 478 &LoongArch::GPRRegClass, TRI, Register()); 479 TRI->eliminateFrameIndex(RestoreBB.back(), 480 /*SpAdj=*/0, /*FIOperandNum=*/1); 481 } 482 MRI.replaceRegWith(ScratchReg, Scav); 483 MRI.clearVirtRegs(); 484 } 485 486 static unsigned getOppositeBranchOpc(unsigned Opc) { 487 switch (Opc) { 488 default: 489 llvm_unreachable("Unrecognized conditional branch"); 490 case LoongArch::BEQ: 491 return LoongArch::BNE; 492 case LoongArch::BNE: 493 return LoongArch::BEQ; 494 case LoongArch::BEQZ: 495 return LoongArch::BNEZ; 496 case LoongArch::BNEZ: 497 return LoongArch::BEQZ; 498 case LoongArch::BCEQZ: 499 return LoongArch::BCNEZ; 500 case LoongArch::BCNEZ: 501 return LoongArch::BCEQZ; 502 case LoongArch::BLT: 503 return LoongArch::BGE; 504 case LoongArch::BGE: 505 return LoongArch::BLT; 506 case LoongArch::BLTU: 507 return LoongArch::BGEU; 508 case LoongArch::BGEU: 509 return LoongArch::BLTU; 510 } 511 } 512 513 bool LoongArchInstrInfo::reverseBranchCondition( 514 SmallVectorImpl<MachineOperand> &Cond) const { 515 assert((Cond.size() && Cond.size() <= 3) && "Invalid branch condition!"); 516 Cond[0].setImm(getOppositeBranchOpc(Cond[0].getImm())); 517 return false; 518 } 519 520 std::pair<unsigned, unsigned> 521 LoongArchInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const { 522 return std::make_pair(TF, 0u); 523 } 524 525 ArrayRef<std::pair<unsigned, const char *>> 526 LoongArchInstrInfo::getSerializableDirectMachineOperandTargetFlags() const { 527 using namespace LoongArchII; 528 // TODO: Add more target flags. 529 static const std::pair<unsigned, const char *> TargetFlags[] = { 530 {MO_CALL, "loongarch-call"}, 531 {MO_CALL_PLT, "loongarch-call-plt"}, 532 {MO_PCREL_HI, "loongarch-pcrel-hi"}, 533 {MO_PCREL_LO, "loongarch-pcrel-lo"}, 534 {MO_PCREL64_LO, "loongarch-pcrel64-lo"}, 535 {MO_PCREL64_HI, "loongarch-pcrel64-hi"}, 536 {MO_GOT_PC_HI, "loongarch-got-pc-hi"}, 537 {MO_GOT_PC_LO, "loongarch-got-pc-lo"}, 538 {MO_GOT_PC64_LO, "loongarch-got-pc64-lo"}, 539 {MO_GOT_PC64_HI, "loongarch-got-pc64-hi"}, 540 {MO_LE_HI, "loongarch-le-hi"}, 541 {MO_LE_LO, "loongarch-le-lo"}, 542 {MO_LE64_LO, "loongarch-le64-lo"}, 543 {MO_LE64_HI, "loongarch-le64-hi"}, 544 {MO_IE_PC_HI, "loongarch-ie-pc-hi"}, 545 {MO_IE_PC_LO, "loongarch-ie-pc-lo"}, 546 {MO_IE_PC64_LO, "loongarch-ie-pc64-lo"}, 547 {MO_IE_PC64_HI, "loongarch-ie-pc64-hi"}, 548 {MO_DESC_PC_HI, "loongarch-desc-pc-hi"}, 549 {MO_DESC_PC_LO, "loongarch-desc-pc-lo"}, 550 {MO_DESC64_PC_LO, "loongarch-desc64-pc-lo"}, 551 {MO_DESC64_PC_HI, "loongarch-desc64-pc-hi"}, 552 {MO_DESC_LD, "loongarch-desc-ld"}, 553 {MO_DESC_CALL, "loongarch-desc-call"}, 554 {MO_LD_PC_HI, "loongarch-ld-pc-hi"}, 555 {MO_GD_PC_HI, "loongarch-gd-pc-hi"}}; 556 return ArrayRef(TargetFlags); 557 } 558 559 // Returns true if this is the sext.w pattern, addi.w rd, rs, 0. 560 bool LoongArch::isSEXT_W(const MachineInstr &MI) { 561 return MI.getOpcode() == LoongArch::ADDI_W && MI.getOperand(1).isReg() && 562 MI.getOperand(2).isImm() && MI.getOperand(2).getImm() == 0; 563 } 564