1 //===-- RISCVInstrInfo.cpp - RISCV 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 RISCV implementation of the TargetInstrInfo class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "RISCVInstrInfo.h"
14 #include "RISCV.h"
15 #include "RISCVSubtarget.h"
16 #include "RISCVTargetMachine.h"
17 #include "Utils/RISCVMatInt.h"
18 #include "llvm/ADT/STLExtras.h"
19 #include "llvm/ADT/SmallVector.h"
20 #include "llvm/CodeGen/MachineFunctionPass.h"
21 #include "llvm/CodeGen/MachineInstrBuilder.h"
22 #include "llvm/CodeGen/MachineRegisterInfo.h"
23 #include "llvm/CodeGen/RegisterScavenging.h"
24 #include "llvm/Support/ErrorHandling.h"
25 #include "llvm/Support/TargetRegistry.h"
26 
27 #define GET_INSTRINFO_CTOR_DTOR
28 #include "RISCVGenInstrInfo.inc"
29 
30 using namespace llvm;
31 
32 RISCVInstrInfo::RISCVInstrInfo(RISCVSubtarget &STI)
33     : RISCVGenInstrInfo(RISCV::ADJCALLSTACKDOWN, RISCV::ADJCALLSTACKUP),
34       STI(STI) {}
35 
36 unsigned RISCVInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
37                                              int &FrameIndex) const {
38   switch (MI.getOpcode()) {
39   default:
40     return 0;
41   case RISCV::LB:
42   case RISCV::LBU:
43   case RISCV::LH:
44   case RISCV::LHU:
45   case RISCV::LW:
46   case RISCV::FLW:
47   case RISCV::LWU:
48   case RISCV::LD:
49   case RISCV::FLD:
50     break;
51   }
52 
53   if (MI.getOperand(1).isFI() && MI.getOperand(2).isImm() &&
54       MI.getOperand(2).getImm() == 0) {
55     FrameIndex = MI.getOperand(1).getIndex();
56     return MI.getOperand(0).getReg();
57   }
58 
59   return 0;
60 }
61 
62 unsigned RISCVInstrInfo::isStoreToStackSlot(const MachineInstr &MI,
63                                             int &FrameIndex) const {
64   switch (MI.getOpcode()) {
65   default:
66     return 0;
67   case RISCV::SB:
68   case RISCV::SH:
69   case RISCV::SW:
70   case RISCV::FSW:
71   case RISCV::SD:
72   case RISCV::FSD:
73     break;
74   }
75 
76   if (MI.getOperand(0).isFI() && MI.getOperand(1).isImm() &&
77       MI.getOperand(1).getImm() == 0) {
78     FrameIndex = MI.getOperand(0).getIndex();
79     return MI.getOperand(2).getReg();
80   }
81 
82   return 0;
83 }
84 
85 void RISCVInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
86                                  MachineBasicBlock::iterator MBBI,
87                                  const DebugLoc &DL, MCRegister DstReg,
88                                  MCRegister SrcReg, bool KillSrc) const {
89   if (RISCV::GPRRegClass.contains(DstReg, SrcReg)) {
90     BuildMI(MBB, MBBI, DL, get(RISCV::ADDI), DstReg)
91         .addReg(SrcReg, getKillRegState(KillSrc))
92         .addImm(0);
93     return;
94   }
95 
96   // FPR->FPR copies
97   unsigned Opc;
98   if (RISCV::FPR32RegClass.contains(DstReg, SrcReg))
99     Opc = RISCV::FSGNJ_S;
100   else if (RISCV::FPR64RegClass.contains(DstReg, SrcReg))
101     Opc = RISCV::FSGNJ_D;
102   else
103     llvm_unreachable("Impossible reg-to-reg copy");
104 
105   BuildMI(MBB, MBBI, DL, get(Opc), DstReg)
106       .addReg(SrcReg, getKillRegState(KillSrc))
107       .addReg(SrcReg, getKillRegState(KillSrc));
108 }
109 
110 void RISCVInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
111                                          MachineBasicBlock::iterator I,
112                                          unsigned SrcReg, bool IsKill, int FI,
113                                          const TargetRegisterClass *RC,
114                                          const TargetRegisterInfo *TRI) const {
115   DebugLoc DL;
116   if (I != MBB.end())
117     DL = I->getDebugLoc();
118 
119   unsigned Opcode;
120 
121   if (RISCV::GPRRegClass.hasSubClassEq(RC))
122     Opcode = TRI->getRegSizeInBits(RISCV::GPRRegClass) == 32 ?
123              RISCV::SW : RISCV::SD;
124   else if (RISCV::FPR32RegClass.hasSubClassEq(RC))
125     Opcode = RISCV::FSW;
126   else if (RISCV::FPR64RegClass.hasSubClassEq(RC))
127     Opcode = RISCV::FSD;
128   else
129     llvm_unreachable("Can't store this register to stack slot");
130 
131   BuildMI(MBB, I, DL, get(Opcode))
132       .addReg(SrcReg, getKillRegState(IsKill))
133       .addFrameIndex(FI)
134       .addImm(0);
135 }
136 
137 void RISCVInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
138                                           MachineBasicBlock::iterator I,
139                                           unsigned DstReg, int FI,
140                                           const TargetRegisterClass *RC,
141                                           const TargetRegisterInfo *TRI) const {
142   DebugLoc DL;
143   if (I != MBB.end())
144     DL = I->getDebugLoc();
145 
146   unsigned Opcode;
147 
148   if (RISCV::GPRRegClass.hasSubClassEq(RC))
149     Opcode = TRI->getRegSizeInBits(RISCV::GPRRegClass) == 32 ?
150              RISCV::LW : RISCV::LD;
151   else if (RISCV::FPR32RegClass.hasSubClassEq(RC))
152     Opcode = RISCV::FLW;
153   else if (RISCV::FPR64RegClass.hasSubClassEq(RC))
154     Opcode = RISCV::FLD;
155   else
156     llvm_unreachable("Can't load this register from stack slot");
157 
158   BuildMI(MBB, I, DL, get(Opcode), DstReg).addFrameIndex(FI).addImm(0);
159 }
160 
161 void RISCVInstrInfo::movImm(MachineBasicBlock &MBB,
162                             MachineBasicBlock::iterator MBBI,
163                             const DebugLoc &DL, Register DstReg, uint64_t Val,
164                             MachineInstr::MIFlag Flag) const {
165   MachineFunction *MF = MBB.getParent();
166   MachineRegisterInfo &MRI = MF->getRegInfo();
167   bool IsRV64 = MF->getSubtarget<RISCVSubtarget>().is64Bit();
168   Register SrcReg = RISCV::X0;
169   Register Result = MRI.createVirtualRegister(&RISCV::GPRRegClass);
170   unsigned Num = 0;
171 
172   if (!IsRV64 && !isInt<32>(Val))
173     report_fatal_error("Should only materialize 32-bit constants for RV32");
174 
175   RISCVMatInt::InstSeq Seq;
176   RISCVMatInt::generateInstSeq(Val, IsRV64, Seq);
177   assert(Seq.size() > 0);
178 
179   for (RISCVMatInt::Inst &Inst : Seq) {
180     // Write the final result to DstReg if it's the last instruction in the Seq.
181     // Otherwise, write the result to the temp register.
182     if (++Num == Seq.size())
183       Result = DstReg;
184 
185     if (Inst.Opc == RISCV::LUI) {
186       BuildMI(MBB, MBBI, DL, get(RISCV::LUI), Result)
187           .addImm(Inst.Imm)
188           .setMIFlag(Flag);
189     } else {
190       BuildMI(MBB, MBBI, DL, get(Inst.Opc), Result)
191           .addReg(SrcReg, RegState::Kill)
192           .addImm(Inst.Imm)
193           .setMIFlag(Flag);
194     }
195     // Only the first instruction has X0 as its source.
196     SrcReg = Result;
197   }
198 }
199 
200 // The contents of values added to Cond are not examined outside of
201 // RISCVInstrInfo, giving us flexibility in what to push to it. For RISCV, we
202 // push BranchOpcode, Reg1, Reg2.
203 static void parseCondBranch(MachineInstr &LastInst, MachineBasicBlock *&Target,
204                             SmallVectorImpl<MachineOperand> &Cond) {
205   // Block ends with fall-through condbranch.
206   assert(LastInst.getDesc().isConditionalBranch() &&
207          "Unknown conditional branch");
208   Target = LastInst.getOperand(2).getMBB();
209   Cond.push_back(MachineOperand::CreateImm(LastInst.getOpcode()));
210   Cond.push_back(LastInst.getOperand(0));
211   Cond.push_back(LastInst.getOperand(1));
212 }
213 
214 static unsigned getOppositeBranchOpcode(int Opc) {
215   switch (Opc) {
216   default:
217     llvm_unreachable("Unrecognized conditional branch");
218   case RISCV::BEQ:
219     return RISCV::BNE;
220   case RISCV::BNE:
221     return RISCV::BEQ;
222   case RISCV::BLT:
223     return RISCV::BGE;
224   case RISCV::BGE:
225     return RISCV::BLT;
226   case RISCV::BLTU:
227     return RISCV::BGEU;
228   case RISCV::BGEU:
229     return RISCV::BLTU;
230   }
231 }
232 
233 bool RISCVInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
234                                    MachineBasicBlock *&TBB,
235                                    MachineBasicBlock *&FBB,
236                                    SmallVectorImpl<MachineOperand> &Cond,
237                                    bool AllowModify) const {
238   TBB = FBB = nullptr;
239   Cond.clear();
240 
241   // If the block has no terminators, it just falls into the block after it.
242   MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
243   if (I == MBB.end() || !isUnpredicatedTerminator(*I))
244     return false;
245 
246   // Count the number of terminators and find the first unconditional or
247   // indirect branch.
248   MachineBasicBlock::iterator FirstUncondOrIndirectBr = MBB.end();
249   int NumTerminators = 0;
250   for (auto J = I.getReverse(); J != MBB.rend() && isUnpredicatedTerminator(*J);
251        J++) {
252     NumTerminators++;
253     if (J->getDesc().isUnconditionalBranch() ||
254         J->getDesc().isIndirectBranch()) {
255       FirstUncondOrIndirectBr = J.getReverse();
256     }
257   }
258 
259   // If AllowModify is true, we can erase any terminators after
260   // FirstUncondOrIndirectBR.
261   if (AllowModify && FirstUncondOrIndirectBr != MBB.end()) {
262     while (std::next(FirstUncondOrIndirectBr) != MBB.end()) {
263       std::next(FirstUncondOrIndirectBr)->eraseFromParent();
264       NumTerminators--;
265     }
266     I = FirstUncondOrIndirectBr;
267   }
268 
269   // We can't handle blocks that end in an indirect branch.
270   if (I->getDesc().isIndirectBranch())
271     return true;
272 
273   // We can't handle blocks with more than 2 terminators.
274   if (NumTerminators > 2)
275     return true;
276 
277   // Handle a single unconditional branch.
278   if (NumTerminators == 1 && I->getDesc().isUnconditionalBranch()) {
279     TBB = I->getOperand(0).getMBB();
280     return false;
281   }
282 
283   // Handle a single conditional branch.
284   if (NumTerminators == 1 && I->getDesc().isConditionalBranch()) {
285     parseCondBranch(*I, TBB, Cond);
286     return false;
287   }
288 
289   // Handle a conditional branch followed by an unconditional branch.
290   if (NumTerminators == 2 && std::prev(I)->getDesc().isConditionalBranch() &&
291       I->getDesc().isUnconditionalBranch()) {
292     parseCondBranch(*std::prev(I), TBB, Cond);
293     FBB = I->getOperand(0).getMBB();
294     return false;
295   }
296 
297   // Otherwise, we can't handle this.
298   return true;
299 }
300 
301 unsigned RISCVInstrInfo::removeBranch(MachineBasicBlock &MBB,
302                                       int *BytesRemoved) const {
303   if (BytesRemoved)
304     *BytesRemoved = 0;
305   MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
306   if (I == MBB.end())
307     return 0;
308 
309   if (!I->getDesc().isUnconditionalBranch() &&
310       !I->getDesc().isConditionalBranch())
311     return 0;
312 
313   // Remove the branch.
314   if (BytesRemoved)
315     *BytesRemoved += getInstSizeInBytes(*I);
316   I->eraseFromParent();
317 
318   I = MBB.end();
319 
320   if (I == MBB.begin())
321     return 1;
322   --I;
323   if (!I->getDesc().isConditionalBranch())
324     return 1;
325 
326   // Remove the branch.
327   if (BytesRemoved)
328     *BytesRemoved += getInstSizeInBytes(*I);
329   I->eraseFromParent();
330   return 2;
331 }
332 
333 // Inserts a branch into the end of the specific MachineBasicBlock, returning
334 // the number of instructions inserted.
335 unsigned RISCVInstrInfo::insertBranch(
336     MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB,
337     ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const {
338   if (BytesAdded)
339     *BytesAdded = 0;
340 
341   // Shouldn't be a fall through.
342   assert(TBB && "InsertBranch must not be told to insert a fallthrough");
343   assert((Cond.size() == 3 || Cond.size() == 0) &&
344          "RISCV branch conditions have two components!");
345 
346   // Unconditional branch.
347   if (Cond.empty()) {
348     MachineInstr &MI = *BuildMI(&MBB, DL, get(RISCV::PseudoBR)).addMBB(TBB);
349     if (BytesAdded)
350       *BytesAdded += getInstSizeInBytes(MI);
351     return 1;
352   }
353 
354   // Either a one or two-way conditional branch.
355   unsigned Opc = Cond[0].getImm();
356   MachineInstr &CondMI =
357       *BuildMI(&MBB, DL, get(Opc)).add(Cond[1]).add(Cond[2]).addMBB(TBB);
358   if (BytesAdded)
359     *BytesAdded += getInstSizeInBytes(CondMI);
360 
361   // One-way conditional branch.
362   if (!FBB)
363     return 1;
364 
365   // Two-way conditional branch.
366   MachineInstr &MI = *BuildMI(&MBB, DL, get(RISCV::PseudoBR)).addMBB(FBB);
367   if (BytesAdded)
368     *BytesAdded += getInstSizeInBytes(MI);
369   return 2;
370 }
371 
372 unsigned RISCVInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB,
373                                               MachineBasicBlock &DestBB,
374                                               const DebugLoc &DL,
375                                               int64_t BrOffset,
376                                               RegScavenger *RS) const {
377   assert(RS && "RegScavenger required for long branching");
378   assert(MBB.empty() &&
379          "new block should be inserted for expanding unconditional branch");
380   assert(MBB.pred_size() == 1);
381 
382   MachineFunction *MF = MBB.getParent();
383   MachineRegisterInfo &MRI = MF->getRegInfo();
384   const auto &TM = static_cast<const RISCVTargetMachine &>(MF->getTarget());
385 
386   if (TM.isPositionIndependent())
387     report_fatal_error("Unable to insert indirect branch");
388 
389   if (!isInt<32>(BrOffset))
390     report_fatal_error(
391         "Branch offsets outside of the signed 32-bit range not supported");
392 
393   // FIXME: A virtual register must be used initially, as the register
394   // scavenger won't work with empty blocks (SIInstrInfo::insertIndirectBranch
395   // uses the same workaround).
396   Register ScratchReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);
397   auto II = MBB.end();
398 
399   MachineInstr &LuiMI = *BuildMI(MBB, II, DL, get(RISCV::LUI), ScratchReg)
400                              .addMBB(&DestBB, RISCVII::MO_HI);
401   BuildMI(MBB, II, DL, get(RISCV::PseudoBRIND))
402       .addReg(ScratchReg, RegState::Kill)
403       .addMBB(&DestBB, RISCVII::MO_LO);
404 
405   RS->enterBasicBlockEnd(MBB);
406   unsigned Scav = RS->scavengeRegisterBackwards(RISCV::GPRRegClass,
407                                                 LuiMI.getIterator(), false, 0);
408   MRI.replaceRegWith(ScratchReg, Scav);
409   MRI.clearVirtRegs();
410   RS->setRegUsed(Scav);
411   return 8;
412 }
413 
414 bool RISCVInstrInfo::reverseBranchCondition(
415     SmallVectorImpl<MachineOperand> &Cond) const {
416   assert((Cond.size() == 3) && "Invalid branch condition!");
417   Cond[0].setImm(getOppositeBranchOpcode(Cond[0].getImm()));
418   return false;
419 }
420 
421 MachineBasicBlock *
422 RISCVInstrInfo::getBranchDestBlock(const MachineInstr &MI) const {
423   assert(MI.getDesc().isBranch() && "Unexpected opcode!");
424   // The branch target is always the last operand.
425   int NumOp = MI.getNumExplicitOperands();
426   return MI.getOperand(NumOp - 1).getMBB();
427 }
428 
429 bool RISCVInstrInfo::isBranchOffsetInRange(unsigned BranchOp,
430                                            int64_t BrOffset) const {
431   // Ideally we could determine the supported branch offset from the
432   // RISCVII::FormMask, but this can't be used for Pseudo instructions like
433   // PseudoBR.
434   switch (BranchOp) {
435   default:
436     llvm_unreachable("Unexpected opcode!");
437   case RISCV::BEQ:
438   case RISCV::BNE:
439   case RISCV::BLT:
440   case RISCV::BGE:
441   case RISCV::BLTU:
442   case RISCV::BGEU:
443     return isIntN(13, BrOffset);
444   case RISCV::JAL:
445   case RISCV::PseudoBR:
446     return isIntN(21, BrOffset);
447   }
448 }
449 
450 unsigned RISCVInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
451   unsigned Opcode = MI.getOpcode();
452 
453   switch (Opcode) {
454   default: { return get(Opcode).getSize(); }
455   case TargetOpcode::EH_LABEL:
456   case TargetOpcode::IMPLICIT_DEF:
457   case TargetOpcode::KILL:
458   case TargetOpcode::DBG_VALUE:
459     return 0;
460   case RISCV::PseudoCALLReg:
461   case RISCV::PseudoCALL:
462   case RISCV::PseudoTAIL:
463   case RISCV::PseudoLLA:
464   case RISCV::PseudoLA:
465   case RISCV::PseudoLA_TLS_IE:
466   case RISCV::PseudoLA_TLS_GD:
467     return 8;
468   case TargetOpcode::INLINEASM:
469   case TargetOpcode::INLINEASM_BR: {
470     const MachineFunction &MF = *MI.getParent()->getParent();
471     const auto &TM = static_cast<const RISCVTargetMachine &>(MF.getTarget());
472     return getInlineAsmLength(MI.getOperand(0).getSymbolName(),
473                               *TM.getMCAsmInfo());
474   }
475   }
476 }
477 
478 bool RISCVInstrInfo::isAsCheapAsAMove(const MachineInstr &MI) const {
479   const unsigned Opcode = MI.getOpcode();
480   switch(Opcode) {
481     default:
482       break;
483     case RISCV::ADDI:
484     case RISCV::ORI:
485     case RISCV::XORI:
486       return (MI.getOperand(1).isReg() && MI.getOperand(1).getReg() == RISCV::X0);
487   }
488   return MI.isAsCheapAsAMove();
489 }
490 
491 bool RISCVInstrInfo::verifyInstruction(const MachineInstr &MI,
492                                        StringRef &ErrInfo) const {
493   const MCInstrInfo *MCII = STI.getInstrInfo();
494   MCInstrDesc const &Desc = MCII->get(MI.getOpcode());
495 
496   for (auto &OI : enumerate(Desc.operands())) {
497     unsigned OpType = OI.value().OperandType;
498     if (OpType >= RISCVOp::OPERAND_FIRST_RISCV_IMM &&
499         OpType <= RISCVOp::OPERAND_LAST_RISCV_IMM) {
500       const MachineOperand &MO = MI.getOperand(OI.index());
501       if (MO.isImm()) {
502         int64_t Imm = MO.getImm();
503         bool Ok;
504         switch (OpType) {
505         default:
506           llvm_unreachable("Unexpected operand type");
507         case RISCVOp::OPERAND_UIMM4:
508           Ok = isUInt<4>(Imm);
509           break;
510         case RISCVOp::OPERAND_UIMM5:
511           Ok = isUInt<5>(Imm);
512           break;
513         case RISCVOp::OPERAND_UIMM12:
514           Ok = isUInt<12>(Imm);
515           break;
516         case RISCVOp::OPERAND_SIMM12:
517           Ok = isInt<12>(Imm);
518           break;
519         case RISCVOp::OPERAND_SIMM13_LSB0:
520           Ok = isShiftedInt<12, 1>(Imm);
521           break;
522         case RISCVOp::OPERAND_UIMM20:
523           Ok = isUInt<20>(Imm);
524           break;
525         case RISCVOp::OPERAND_SIMM21_LSB0:
526           Ok = isShiftedInt<20, 1>(Imm);
527           break;
528         case RISCVOp::OPERAND_UIMMLOG2XLEN:
529           if (STI.getTargetTriple().isArch64Bit())
530             Ok = isUInt<6>(Imm);
531           else
532             Ok = isUInt<5>(Imm);
533           break;
534         }
535         if (!Ok) {
536           ErrInfo = "Invalid immediate";
537           return false;
538         }
539       }
540     }
541   }
542 
543   return true;
544 }
545 
546 // Return true if get the base operand, byte offset of an instruction and the
547 // memory width. Width is the size of memory that is being loaded/stored.
548 bool RISCVInstrInfo::getMemOperandWithOffsetWidth(
549     const MachineInstr &LdSt, const MachineOperand *&BaseReg, int64_t &Offset,
550     unsigned &Width, const TargetRegisterInfo *TRI) const {
551   assert(LdSt.mayLoadOrStore() && "Expected a memory operation.");
552 
553   // Here we assume the standard RISC-V ISA, which uses a base+offset
554   // addressing mode. You'll need to relax these conditions to support custom
555   // load/stores instructions.
556   if (LdSt.getNumExplicitOperands() != 3)
557     return false;
558   if (!LdSt.getOperand(1).isReg() || !LdSt.getOperand(2).isImm())
559     return false;
560 
561   if (!LdSt.hasOneMemOperand())
562     return false;
563 
564   Width = (*LdSt.memoperands_begin())->getSize();
565   BaseReg = &LdSt.getOperand(1);
566   Offset = LdSt.getOperand(2).getImm();
567   return true;
568 }
569 
570 bool RISCVInstrInfo::areMemAccessesTriviallyDisjoint(
571     const MachineInstr &MIa, const MachineInstr &MIb) const {
572   assert(MIa.mayLoadOrStore() && "MIa must be a load or store.");
573   assert(MIb.mayLoadOrStore() && "MIb must be a load or store.");
574 
575   if (MIa.hasUnmodeledSideEffects() || MIb.hasUnmodeledSideEffects() ||
576       MIa.hasOrderedMemoryRef() || MIb.hasOrderedMemoryRef())
577     return false;
578 
579   // Retrieve the base register, offset from the base register and width. Width
580   // is the size of memory that is being loaded/stored (e.g. 1, 2, 4).  If
581   // base registers are identical, and the offset of a lower memory access +
582   // the width doesn't overlap the offset of a higher memory access,
583   // then the memory accesses are different.
584   const TargetRegisterInfo *TRI = STI.getRegisterInfo();
585   const MachineOperand *BaseOpA = nullptr, *BaseOpB = nullptr;
586   int64_t OffsetA = 0, OffsetB = 0;
587   unsigned int WidthA = 0, WidthB = 0;
588   if (getMemOperandWithOffsetWidth(MIa, BaseOpA, OffsetA, WidthA, TRI) &&
589       getMemOperandWithOffsetWidth(MIb, BaseOpB, OffsetB, WidthB, TRI)) {
590     if (BaseOpA->isIdenticalTo(*BaseOpB)) {
591       int LowOffset = std::min(OffsetA, OffsetB);
592       int HighOffset = std::max(OffsetA, OffsetB);
593       int LowWidth = (LowOffset == OffsetA) ? WidthA : WidthB;
594       if (LowOffset + LowWidth <= HighOffset)
595         return true;
596     }
597   }
598   return false;
599 }
600 
601 std::pair<unsigned, unsigned>
602 RISCVInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const {
603   const unsigned Mask = RISCVII::MO_DIRECT_FLAG_MASK;
604   return std::make_pair(TF & Mask, TF & ~Mask);
605 }
606 
607 ArrayRef<std::pair<unsigned, const char *>>
608 RISCVInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
609   using namespace RISCVII;
610   static const std::pair<unsigned, const char *> TargetFlags[] = {
611       {MO_CALL, "riscv-call"},
612       {MO_PLT, "riscv-plt"},
613       {MO_LO, "riscv-lo"},
614       {MO_HI, "riscv-hi"},
615       {MO_PCREL_LO, "riscv-pcrel-lo"},
616       {MO_PCREL_HI, "riscv-pcrel-hi"},
617       {MO_GOT_HI, "riscv-got-hi"},
618       {MO_TPREL_LO, "riscv-tprel-lo"},
619       {MO_TPREL_HI, "riscv-tprel-hi"},
620       {MO_TPREL_ADD, "riscv-tprel-add"},
621       {MO_TLS_GOT_HI, "riscv-tls-got-hi"},
622       {MO_TLS_GD_HI, "riscv-tls-gd-hi"}};
623   return makeArrayRef(TargetFlags);
624 }
625