25#define DEBUG_TYPE "loongarch-merge-base-offset"
26#define LoongArch_MERGE_BASE_OFFSET_NAME "LoongArch Merge Base Offset"
75char LoongArchMergeBaseOffsetOpt::ID = 0;
105 if (Hi20.getOpcode() != LoongArch::PCALAU12I)
113 return Op.isGlobal() ||
Op.isCPI() ||
Op.isBlockAddress();
116 if (!isGlobalOrCPIOrBlockAddress(Hi20Op1) || Hi20Op1.getOffset() != 0)
119 Register HiDestReg = Hi20.getOperand(0).getReg();
120 if (!
MRI->hasOneUse(HiDestReg))
124 if (UseInst->getOpcode() != LoongArch::ADD_D) {
126 if ((ST->is64Bit() && Lo12->getOpcode() != LoongArch::ADDI_D) ||
127 (!ST->is64Bit() && Lo12->getOpcode() != LoongArch::ADDI_W))
130 assert(ST->is64Bit());
133 Register LastOp1Reg = Last->getOperand(1).getReg();
134 if (!LastOp1Reg.isVirtual())
136 Hi12 = MRI->getVRegDef(LastOp1Reg);
137 const MachineOperand &Hi12Op2 = Hi12->getOperand(2);
138 if (Hi12Op2.getTargetFlags() != LoongArchII::MO_PCREL64_HI)
140 if (!isGlobalOrCPIOrBlockAddress(Hi12Op2) || Hi12Op2.getOffset() != 0)
142 if (!MRI->hasOneUse(Hi12->getOperand(0).getReg()))
145 Lo20 = MRI->getVRegDef(Hi12->getOperand(1).getReg());
146 const MachineOperand &Lo20Op2 = Lo20->getOperand(2);
147 if (Lo20Op2.getTargetFlags() != LoongArchII::MO_PCREL64_LO)
149 if (!isGlobalOrCPIOrBlockAddress(Lo20Op2) || Lo20Op2.getOffset() != 0)
151 if (!MRI->hasOneUse(Lo20->getOperand(0).getReg()))
154 Lo12 = MRI->getVRegDef(Lo20->getOperand(1).getReg());
155 if (!MRI->hasOneUse(Lo12->getOperand(0).getReg()))
160 assert(Hi20.getOpcode() == LoongArch::PCALAU12I);
162 !(isGlobalOrCPIOrBlockAddress(Lo12Op2) || Lo12Op2.isMCSymbol()) ||
163 Lo12Op2.getOffset() != 0)
166 if (Hi20Op1.isGlobal()) {
167 LLVM_DEBUG(dbgs() <<
" Found lowered global address: "
168 << *Hi20Op1.getGlobal() <<
"\n");
169 }
else if (Hi20Op1.isBlockAddress()) {
170 LLVM_DEBUG(dbgs() <<
" Found lowered basic address: "
171 << *Hi20Op1.getBlockAddress() <<
"\n");
172 }
else if (Hi20Op1.isCPI()) {
173 LLVM_DEBUG(dbgs() <<
" Found lowered constant pool: " << Hi20Op1.getIndex()
194bool LoongArchMergeBaseOffsetOpt::detectFoldable(
MachineInstr &Hi20,
197 if (Hi20.
getOpcode() != LoongArch::LU12I_W)
200 auto isGlobalOrCPI = [](
const MachineOperand &
Op) {
201 return Op.isGlobal() ||
Op.isCPI();
204 const MachineOperand &Hi20Op1 = Hi20.
getOperand(1);
206 !isGlobalOrCPI(Hi20Op1) || Hi20Op1.
getOffset() != 0)
210 if (!
MRI->hasOneUse(HiDestReg))
213 Add = &*
MRI->use_instr_begin(HiDestReg);
214 if ((ST->
is64Bit() &&
Add->getOpcode() != LoongArch::PseudoAddTPRel_D) ||
215 (!ST->
is64Bit() &&
Add->getOpcode() != LoongArch::PseudoAddTPRel_W))
218 if (
Add->getOperand(2).getReg() != LoongArch::R2)
221 const MachineOperand &AddOp3 =
Add->getOperand(3);
223 !(isGlobalOrCPI(AddOp3) || AddOp3.
isMCSymbol()) ||
228 if (!
MRI->hasOneUse(AddDestReg))
231 Lo12 = &*
MRI->use_instr_begin(AddDestReg);
236 const MachineOperand &Lo12Op2 = Lo12->
getOperand(2);
238 !(isGlobalOrCPI(Lo12Op2) || Lo12Op2.
isMCSymbol()) ||
245 }
else if (Hi20Op1.
isCPI()) {
256void LoongArchMergeBaseOffsetOpt::foldOffset(
257 MachineInstr &Hi20, MachineInstr &Lo12, MachineInstr *&Lo20,
258 MachineInstr *&Hi12, MachineInstr *&
Last, MachineInstr &
Tail,
271 if (Hi20.
getOpcode() == LoongArch::LU12I_W)
276 MRI->constrainRegClass(
Def->getOperand(0).getReg(),
277 MRI->getRegClass(
Tail.getOperand(0).getReg()));
278 MRI->replaceRegWith(
Tail.getOperand(0).getReg(),
Def->getOperand(0).getReg());
279 Tail.eraseFromParent();
283 if (Hi20.
getOpcode() == LoongArch::LU12I_W) {
332bool LoongArchMergeBaseOffsetOpt::foldLargeOffset(
333 MachineInstr &Hi20, MachineInstr &Lo12, MachineInstr *&Lo20,
334 MachineInstr *&Hi12, MachineInstr *&
Last, MachineInstr &TailAdd,
337 TailAdd.
getOpcode() == LoongArch::ADD_D) &&
338 "Expected ADD instruction!");
342 SmallVector<MachineInstr *, 4> Instrs;
347 for (
int i = 0; i < 4; i++) {
349 if (
Reg == LoongArch::R0)
356 MachineInstr *Curr =
MRI->getVRegDef(
Reg);
364 case LoongArch::ORI: {
373 case LoongArch::LU12I_W: {
382 case LoongArch::LU32I_D: {
387 Mask ^= 0x000FFFFF00000000ULL;
392 case LoongArch::LU52I_D: {
397 Mask ^= 0xFFF0000000000000ULL;
409 foldOffset(Hi20, Lo12, Lo20, Hi12,
Last, TailAdd,
Offset);
411 for (
auto I : Instrs) {
413 I->eraseFromParent();
419bool LoongArchMergeBaseOffsetOpt::detectAndFoldOffset(MachineInstr &Hi20,
423 MachineInstr *&
Last) {
431 if (!
MRI->hasOneUse(DestReg))
435 MachineInstr &
Tail = *
MRI->use_instr_begin(DestReg);
436 switch (
Tail.getOpcode()) {
438 LLVM_DEBUG(
dbgs() <<
"Don't know how to get offset from this instr:"
441 case LoongArch::ADDI_W:
445 case LoongArch::ADDI_D:
446 case LoongArch::ADDU16I_D: {
449 if (
Tail.getOpcode() == LoongArch::ADDU16I_D)
454 if (
MRI->hasOneUse(TailDestReg)) {
455 MachineInstr &TailTail = *
MRI->use_instr_begin(TailDestReg);
458 if (TailTail.
getOpcode() == LoongArch::ADDI_W ||
459 TailTail.
getOpcode() == LoongArch::ADDI_D) {
462 foldOffset(Hi20, Lo12, Lo20, Hi12,
Last, TailTail,
Offset);
463 Tail.eraseFromParent();
472 case LoongArch::ADD_W:
476 case LoongArch::ADD_D:
478 return foldLargeOffset(Hi20, Lo12, Lo20, Hi12,
Last,
Tail, DestReg);
488 case LoongArch::LD_B:
489 return isLarge ? LoongArch::LDX_B : LoongArch::LD_B;
490 case LoongArch::LD_H:
491 return isLarge ? LoongArch::LDX_H : LoongArch::LD_H;
492 case LoongArch::LD_W:
493 case LoongArch::LDPTR_W:
494 return isLarge ? LoongArch::LDX_W : LoongArch::LD_W;
495 case LoongArch::LD_D:
496 case LoongArch::LDPTR_D:
497 return isLarge ? LoongArch::LDX_D : LoongArch::LD_D;
498 case LoongArch::LD_BU:
499 return isLarge ? LoongArch::LDX_BU : LoongArch::LD_BU;
500 case LoongArch::LD_HU:
501 return isLarge ? LoongArch::LDX_HU : LoongArch::LD_HU;
502 case LoongArch::LD_WU:
503 return isLarge ? LoongArch::LDX_WU : LoongArch::LD_WU;
504 case LoongArch::FLD_S:
505 return isLarge ? LoongArch::FLDX_S : LoongArch::FLD_S;
506 case LoongArch::FLD_D:
507 return isLarge ? LoongArch::FLDX_D : LoongArch::FLD_D;
509 return isLarge ? LoongArch::VLDX : LoongArch::VLD;
510 case LoongArch::XVLD:
511 return isLarge ? LoongArch::XVLDX : LoongArch::XVLD;
512 case LoongArch::VLDREPL_B:
513 return LoongArch::VLDREPL_B;
514 case LoongArch::XVLDREPL_B:
515 return LoongArch::XVLDREPL_B;
516 case LoongArch::ST_B:
517 return isLarge ? LoongArch::STX_B : LoongArch::ST_B;
518 case LoongArch::ST_H:
519 return isLarge ? LoongArch::STX_H : LoongArch::ST_H;
520 case LoongArch::ST_W:
521 case LoongArch::STPTR_W:
522 return isLarge ? LoongArch::STX_W : LoongArch::ST_W;
523 case LoongArch::ST_D:
524 case LoongArch::STPTR_D:
525 return isLarge ? LoongArch::STX_D : LoongArch::ST_D;
526 case LoongArch::FST_S:
527 return isLarge ? LoongArch::FSTX_S : LoongArch::FST_S;
528 case LoongArch::FST_D:
529 return isLarge ? LoongArch::FSTX_D : LoongArch::FST_D;
531 return isLarge ? LoongArch::VSTX : LoongArch::VST;
532 case LoongArch::XVST:
533 return isLarge ? LoongArch::XVSTX : LoongArch::XVST;
539bool LoongArchMergeBaseOffsetOpt::foldIntoMemoryOps(MachineInstr &Hi20,
543 MachineInstr *&
Last) {
588 std::optional<int64_t> CommonOffset;
589 DenseMap<const MachineInstr *, SmallVector<unsigned>>
590 InlineAsmMemoryOpIndexesMap;
591 for (
const MachineInstr &
UseMI :
MRI->use_instructions(DestReg)) {
592 switch (
UseMI.getOpcode()) {
596 case LoongArch::VLDREPL_B:
597 case LoongArch::XVLDREPL_B:
602 case LoongArch::LD_B:
603 case LoongArch::LD_H:
604 case LoongArch::LD_W:
605 case LoongArch::LD_D:
606 case LoongArch::LD_BU:
607 case LoongArch::LD_HU:
608 case LoongArch::LD_WU:
609 case LoongArch::LDPTR_W:
610 case LoongArch::LDPTR_D:
611 case LoongArch::FLD_S:
612 case LoongArch::FLD_D:
614 case LoongArch::XVLD:
615 case LoongArch::ST_B:
616 case LoongArch::ST_H:
617 case LoongArch::ST_W:
618 case LoongArch::ST_D:
619 case LoongArch::STPTR_W:
620 case LoongArch::STPTR_D:
621 case LoongArch::FST_S:
622 case LoongArch::FST_D:
624 case LoongArch::XVST: {
625 if (
UseMI.getOperand(1).isFI())
631 "Expected base address use");
634 if (CommonOffset &&
Offset != CommonOffset)
639 case LoongArch::INLINEASM:
640 case LoongArch::INLINEASM_BR: {
644 SmallVector<unsigned> InlineAsmMemoryOpIndexes;
648 const MachineOperand &FlagsMO =
UseMI.getOperand(
I);
650 if (!FlagsMO.
isImm())
660 for (
unsigned J = 0; J <
NumOps; ++J) {
661 const MachineOperand &MO =
UseMI.getOperand(
I + 1 + J);
669 if (
Flags.getMemoryConstraintID() != InlineAsm::ConstraintCode::m)
672 const MachineOperand &AddrMO =
UseMI.getOperand(
I + 1);
676 const MachineOperand &OffsetMO =
UseMI.getOperand(
I + 2);
677 if (!OffsetMO.
isImm())
682 if (CommonOffset &&
Offset != CommonOffset)
687 InlineAsmMemoryOpIndexesMap.
insert(
688 std::make_pair(&
UseMI, InlineAsmMemoryOpIndexes));
730 if (Hi20.
getOpcode() == LoongArch::PCALAU12I) {
734 }
else if (Hi20.
getOpcode() == LoongArch::LU12I_W) {
736 Add->getOperand(3).setOffset(NewOffset);
741 for (MachineInstr &
UseMI :
743 if (
UseMI.getOpcode() == LoongArch::INLINEASM ||
744 UseMI.getOpcode() == LoongArch::INLINEASM_BR) {
745 auto &InlineAsmMemoryOpIndexes = InlineAsmMemoryOpIndexesMap[&
UseMI];
746 for (
unsigned I : InlineAsmMemoryOpIndexes) {
747 MachineOperand &MO =
UseMI.getOperand(
I + 1);
770 UseMI.removeOperand(2);
771 UseMI.removeOperand(1);
774 UseMI.getOperand(1).setIsKill(
false);
775 UseMI.getOperand(2).setIsKill(
false);
777 UseMI.removeOperand(2);
778 UseMI.addOperand(ImmOp);
784 Last->eraseFromParent();
788 if (Hi20.
getOpcode() == LoongArch::PCALAU12I) {
791 }
else if (Hi20.
getOpcode() == LoongArch::LU12I_W) {
794 Add->getOperand(0).getReg());
800bool LoongArchMergeBaseOffsetOpt::runOnMachineFunction(MachineFunction &Fn) {
806 bool MadeChange =
false;
808 for (MachineBasicBlock &
MBB : Fn) {
810 for (MachineInstr &Hi20 :
MBB) {
811 MachineInstr *Lo12 =
nullptr;
812 MachineInstr *Lo20 =
nullptr;
813 MachineInstr *Hi12 =
nullptr;
814 MachineInstr *
Last =
nullptr;
815 if (Hi20.
getOpcode() == LoongArch::PCALAU12I) {
817 if (!detectFoldable(Hi20, Lo12, Lo20, Hi12,
Last))
819 }
else if (Hi20.
getOpcode() == LoongArch::LU12I_W) {
820 MachineInstr *
Add =
nullptr;
822 if (!detectFoldable(Hi20,
Add, Lo12))
830 MadeChange |= detectAndFoldOffset(Hi20, *Lo12, Lo20, Hi12,
Last);
831 MadeChange |= foldIntoMemoryOps(Hi20, *Lo12, Lo20, Hi12,
Last);
840 return new LoongArchMergeBaseOffsetOpt();
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
const HexagonInstrInfo * TII
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
static unsigned getNewOpc(unsigned Op, bool isLarge)
#define LoongArch_MERGE_BASE_OFFSET_NAME
Promote Memory to Register
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Represent the analysis usage information of a pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
FunctionPass class - This class is used to implement most global optimizations.
const LoongArchInstrInfo * getInstrInfo() const override
LLVM_ABI StringRef getName() const
Return the name of the corresponding LLVM basic block, or an empty string.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
Properties which a MachineFunction may have at a given point in time.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
Register getReg(unsigned Idx) const
Get the register for the operand index.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
LLVM_ABI void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
bool isCPI() const
isCPI - Tests if this is a MO_ConstantPoolIndex operand.
LLVM_ABI void ChangeToMCSymbol(MCSymbol *Sym, unsigned TargetFlags=0)
ChangeToMCSymbol - Replace this operand with a new MC symbol operand.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
LLVM_ABI void ChangeToGA(const GlobalValue *GV, int64_t Offset, unsigned TargetFlags=0)
ChangeToGA - Replace this operand with a new global address operand.
LLVM_ABI void ChangeToBA(const BlockAddress *BA, int64_t Offset, unsigned TargetFlags=0)
ChangeToBA - Replace this operand with a new block address operand.
const BlockAddress * getBlockAddress() const
void setOffset(int64_t Offset)
unsigned getTargetFlags() const
bool isGlobal() const
isGlobal - Tests if this is a MO_GlobalAddress operand.
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
Register getReg() const
getReg - Returns the register number.
void setTargetFlags(unsigned F)
MCSymbol * getMCSymbol() const
@ MO_MCSymbol
MCSymbol reference (for debug/eh info)
@ MO_GlobalAddress
Address of a global value.
@ MO_BlockAddress
Address of a basic block.
int64_t getOffset() const
Return the offset from the symbol in this operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Wrapper class representing virtual and physical registers.
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
void push_back(const T &Elt)
StringRef - Represent a constant reference to a string, i.e.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ Tail
Attemps to make calls as fast as possible while guaranteeing that tail call optimization can always b...
static unsigned getDirectFlags(const MachineOperand &MO)
NodeAddr< DefNode * > Def
This is an optimization pass for GlobalISel generic memory operations.
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
DWARFExpression::Operation Op
constexpr int64_t SignExtend64(uint64_t x)
Sign-extend the number in the bottom B bits of X to a 64-bit integer.
FunctionPass * createLoongArchMergeBaseOffsetOptPass()
Returns an instance of the Merge Base Offset Optimization pass.