25#define DEBUG_TYPE "loongarch-merge-base-offset"
26#define LoongArch_MERGE_BASE_OFFSET_NAME "LoongArch Merge Base Offset"
75char LoongArchMergeBaseOffsetOpt::ID = 0;
79static
inline bool isPCAddLo(
unsigned Flags) {
113bool LoongArchMergeBaseOffsetOpt::detectFoldable(
MachineInstr &Hi20,
118 if (Hi20.
getOpcode() != LoongArch::PCALAU12I &&
119 Hi20.
getOpcode() != LoongArch::PCADDU12I)
122 const MachineOperand &Hi20Op1 = Hi20.
getOperand(1);
127 auto isGlobalOrCPIOrBlockAddress = [](
const MachineOperand &
Op) {
128 return Op.isGlobal() ||
Op.isCPI() ||
Op.isBlockAddress();
131 if (!isGlobalOrCPIOrBlockAddress(Hi20Op1) || Hi20Op1.
getOffset() != 0)
135 if (!
MRI->hasOneUse(HiDestReg))
138 MachineInstr *UseInst = &*
MRI->use_instr_begin(HiDestReg);
139 if (UseInst->
getOpcode() != LoongArch::ADD_D) {
151 Hi12 =
MRI->getVRegDef(LastOp1Reg);
152 const MachineOperand &Hi12Op2 = Hi12->
getOperand(2);
155 if (!isGlobalOrCPIOrBlockAddress(Hi12Op2) || Hi12Op2.
getOffset() != 0)
161 const MachineOperand &Lo20Op2 = Lo20->
getOperand(2);
164 if (!isGlobalOrCPIOrBlockAddress(Lo20Op2) || Lo20Op2.
getOffset() != 0)
174 const MachineOperand &Lo12Op2 = Lo12->
getOperand(2);
176 Hi20.
getOpcode() == LoongArch::PCADDU12I);
179 !(isGlobalOrCPIOrBlockAddress(Lo12Op2) || Lo12Op2.
isMCSymbol()) ||
189 }
else if (Hi20Op1.
isCPI()) {
211bool LoongArchMergeBaseOffsetOpt::detectFoldable(MachineInstr &Hi20,
213 MachineInstr *&Lo12) {
214 if (Hi20.
getOpcode() != LoongArch::LU12I_W)
217 auto isGlobalOrCPI = [](
const MachineOperand &
Op) {
218 return Op.isGlobal() ||
Op.isCPI();
221 const MachineOperand &Hi20Op1 = Hi20.
getOperand(1);
223 !isGlobalOrCPI(Hi20Op1) || Hi20Op1.
getOffset() != 0)
227 if (!
MRI->hasOneUse(HiDestReg))
230 Add = &*
MRI->use_instr_begin(HiDestReg);
231 if ((ST->
is64Bit() &&
Add->getOpcode() != LoongArch::PseudoAddTPRel_D) ||
232 (!ST->
is64Bit() &&
Add->getOpcode() != LoongArch::PseudoAddTPRel_W))
235 if (
Add->getOperand(2).getReg() != LoongArch::R2)
238 const MachineOperand &AddOp3 =
Add->getOperand(3);
240 !(isGlobalOrCPI(AddOp3) || AddOp3.
isMCSymbol()) ||
245 if (!
MRI->hasOneUse(AddDestReg))
248 Lo12 = &*
MRI->use_instr_begin(AddDestReg);
253 const MachineOperand &Lo12Op2 = Lo12->
getOperand(2);
255 !(isGlobalOrCPI(Lo12Op2) || Lo12Op2.
isMCSymbol()) ||
262 }
else if (Hi20Op1.
isCPI()) {
273void LoongArchMergeBaseOffsetOpt::foldOffset(
274 MachineInstr &Hi20, MachineInstr &Lo12, MachineInstr *&Lo20,
275 MachineInstr *&Hi12, MachineInstr *&
Last, MachineInstr &
Tail,
290 if (Hi20.
getOpcode() == LoongArch::LU12I_W)
295 MRI->constrainRegClass(
Def->getOperand(0).getReg(),
296 MRI->getRegClass(
Tail.getOperand(0).getReg()));
297 MRI->replaceRegWith(
Tail.getOperand(0).getReg(),
Def->getOperand(0).getReg());
298 Tail.eraseFromParent();
302 if (Hi20.
getOpcode() == LoongArch::LU12I_W) {
351bool LoongArchMergeBaseOffsetOpt::foldLargeOffset(
352 MachineInstr &Hi20, MachineInstr &Lo12, MachineInstr *&Lo20,
353 MachineInstr *&Hi12, MachineInstr *&
Last, MachineInstr &TailAdd,
356 TailAdd.
getOpcode() == LoongArch::ADD_D) &&
357 "Expected ADD instruction!");
361 SmallVector<MachineInstr *, 4> Instrs;
366 for (
int i = 0; i < 4; i++) {
368 if (
Reg == LoongArch::R0)
375 MachineInstr *Curr =
MRI->getVRegDef(
Reg);
383 case LoongArch::ORI: {
392 case LoongArch::LU12I_W: {
401 case LoongArch::LU32I_D: {
406 Mask ^= 0x000FFFFF00000000ULL;
411 case LoongArch::LU52I_D: {
416 Mask ^= 0xFFF0000000000000ULL;
428 foldOffset(Hi20, Lo12, Lo20, Hi12,
Last, TailAdd,
Offset);
430 for (
auto I : Instrs) {
432 I->eraseFromParent();
438bool LoongArchMergeBaseOffsetOpt::detectAndFoldOffset(MachineInstr &Hi20,
442 MachineInstr *&
Last) {
450 if (!
MRI->hasOneUse(DestReg))
454 MachineInstr &
Tail = *
MRI->use_instr_begin(DestReg);
455 switch (
Tail.getOpcode()) {
457 LLVM_DEBUG(
dbgs() <<
"Don't know how to get offset from this instr:"
460 case LoongArch::ADDI_W:
464 case LoongArch::ADDI_D:
465 case LoongArch::ADDU16I_D: {
468 if (
Tail.getOpcode() == LoongArch::ADDU16I_D)
473 if (
MRI->hasOneUse(TailDestReg)) {
474 MachineInstr &TailTail = *
MRI->use_instr_begin(TailDestReg);
477 if (TailTail.
getOpcode() == LoongArch::ADDI_W ||
478 TailTail.
getOpcode() == LoongArch::ADDI_D) {
481 foldOffset(Hi20, Lo12, Lo20, Hi12,
Last, TailTail,
Offset);
482 Tail.eraseFromParent();
491 case LoongArch::ADD_W:
495 case LoongArch::ADD_D:
497 return foldLargeOffset(Hi20, Lo12, Lo20, Hi12,
Last,
Tail, DestReg);
507 case LoongArch::LD_B:
508 return isLarge ? LoongArch::LDX_B : LoongArch::LD_B;
509 case LoongArch::LD_H:
510 return isLarge ? LoongArch::LDX_H : LoongArch::LD_H;
511 case LoongArch::LD_W:
512 case LoongArch::LDPTR_W:
513 return isLarge ? LoongArch::LDX_W : LoongArch::LD_W;
514 case LoongArch::LD_D:
515 case LoongArch::LDPTR_D:
516 return isLarge ? LoongArch::LDX_D : LoongArch::LD_D;
517 case LoongArch::LD_BU:
518 return isLarge ? LoongArch::LDX_BU : LoongArch::LD_BU;
519 case LoongArch::LD_HU:
520 return isLarge ? LoongArch::LDX_HU : LoongArch::LD_HU;
521 case LoongArch::LD_WU:
522 return isLarge ? LoongArch::LDX_WU : LoongArch::LD_WU;
523 case LoongArch::FLD_S:
524 return isLarge ? LoongArch::FLDX_S : LoongArch::FLD_S;
525 case LoongArch::FLD_D:
526 return isLarge ? LoongArch::FLDX_D : LoongArch::FLD_D;
528 return isLarge ? LoongArch::VLDX : LoongArch::VLD;
529 case LoongArch::XVLD:
530 return isLarge ? LoongArch::XVLDX : LoongArch::XVLD;
531 case LoongArch::VLDREPL_B:
532 return LoongArch::VLDREPL_B;
533 case LoongArch::XVLDREPL_B:
534 return LoongArch::XVLDREPL_B;
535 case LoongArch::ST_B:
536 return isLarge ? LoongArch::STX_B : LoongArch::ST_B;
537 case LoongArch::ST_H:
538 return isLarge ? LoongArch::STX_H : LoongArch::ST_H;
539 case LoongArch::ST_W:
540 case LoongArch::STPTR_W:
541 return isLarge ? LoongArch::STX_W : LoongArch::ST_W;
542 case LoongArch::ST_D:
543 case LoongArch::STPTR_D:
544 return isLarge ? LoongArch::STX_D : LoongArch::ST_D;
545 case LoongArch::FST_S:
546 return isLarge ? LoongArch::FSTX_S : LoongArch::FST_S;
547 case LoongArch::FST_D:
548 return isLarge ? LoongArch::FSTX_D : LoongArch::FST_D;
550 return isLarge ? LoongArch::VSTX : LoongArch::VST;
551 case LoongArch::XVST:
552 return isLarge ? LoongArch::XVSTX : LoongArch::XVST;
558bool LoongArchMergeBaseOffsetOpt::foldIntoMemoryOps(MachineInstr &Hi20,
562 MachineInstr *&
Last) {
607 std::optional<int64_t> CommonOffset;
608 DenseMap<const MachineInstr *, SmallVector<unsigned>>
609 InlineAsmMemoryOpIndexesMap;
610 for (
const MachineInstr &
UseMI :
MRI->use_instructions(DestReg)) {
611 switch (
UseMI.getOpcode()) {
615 case LoongArch::VLDREPL_B:
616 case LoongArch::XVLDREPL_B:
621 case LoongArch::LD_B:
622 case LoongArch::LD_H:
623 case LoongArch::LD_W:
624 case LoongArch::LD_D:
625 case LoongArch::LD_BU:
626 case LoongArch::LD_HU:
627 case LoongArch::LD_WU:
628 case LoongArch::LDPTR_W:
629 case LoongArch::LDPTR_D:
630 case LoongArch::FLD_S:
631 case LoongArch::FLD_D:
633 case LoongArch::XVLD:
634 case LoongArch::ST_B:
635 case LoongArch::ST_H:
636 case LoongArch::ST_W:
637 case LoongArch::ST_D:
638 case LoongArch::STPTR_W:
639 case LoongArch::STPTR_D:
640 case LoongArch::FST_S:
641 case LoongArch::FST_D:
643 case LoongArch::XVST: {
644 if (
UseMI.getOperand(1).isFI())
650 "Expected base address use");
653 if (CommonOffset &&
Offset != CommonOffset)
658 case LoongArch::INLINEASM:
659 case LoongArch::INLINEASM_BR: {
663 SmallVector<unsigned> InlineAsmMemoryOpIndexes;
667 const MachineOperand &FlagsMO =
UseMI.getOperand(
I);
669 if (!FlagsMO.
isImm())
679 for (
unsigned J = 0; J <
NumOps; ++J) {
680 const MachineOperand &MO =
UseMI.getOperand(
I + 1 + J);
688 if (
Flags.getMemoryConstraintID() != InlineAsm::ConstraintCode::m)
691 const MachineOperand &AddrMO =
UseMI.getOperand(
I + 1);
695 const MachineOperand &OffsetMO =
UseMI.getOperand(
I + 2);
696 if (!OffsetMO.
isImm())
701 if (CommonOffset &&
Offset != CommonOffset)
706 InlineAsmMemoryOpIndexesMap.
insert(
707 std::make_pair(&
UseMI, InlineAsmMemoryOpIndexes));
750 if (Hi20.
getOpcode() == LoongArch::PCADDU12I ||
751 Hi20.
getOpcode() == LoongArch::PCALAU12I) {
755 }
else if (Hi20.
getOpcode() == LoongArch::LU12I_W) {
757 Add->getOperand(3).setOffset(NewOffset);
762 for (MachineInstr &
UseMI :
764 if (
UseMI.getOpcode() == LoongArch::INLINEASM ||
765 UseMI.getOpcode() == LoongArch::INLINEASM_BR) {
766 auto &InlineAsmMemoryOpIndexes = InlineAsmMemoryOpIndexesMap[&
UseMI];
767 for (
unsigned I : InlineAsmMemoryOpIndexes) {
768 MachineOperand &MO =
UseMI.getOperand(
I + 1);
795 UseMI.removeOperand(2);
796 UseMI.removeOperand(1);
799 UseMI.getOperand(1).setIsKill(
false);
800 UseMI.getOperand(2).setIsKill(
false);
802 UseMI.removeOperand(2);
803 UseMI.addOperand(ImmOp);
809 Last->eraseFromParent();
813 if (Hi20.
getOpcode() == LoongArch::PCADDU12I ||
814 Hi20.
getOpcode() == LoongArch::PCALAU12I) {
817 }
else if (Hi20.
getOpcode() == LoongArch::LU12I_W) {
820 Add->getOperand(0).getReg());
826bool LoongArchMergeBaseOffsetOpt::runOnMachineFunction(MachineFunction &Fn) {
832 bool MadeChange =
false;
834 for (MachineBasicBlock &
MBB : Fn) {
836 for (MachineInstr &Hi20 :
MBB) {
837 MachineInstr *Lo12 =
nullptr;
838 MachineInstr *Lo20 =
nullptr;
839 MachineInstr *Hi12 =
nullptr;
840 MachineInstr *
Last =
nullptr;
841 if (Hi20.
getOpcode() == LoongArch::PCADDU12I ||
842 Hi20.
getOpcode() == LoongArch::PCALAU12I) {
844 if (!detectFoldable(Hi20, Lo12, Lo20, Hi12,
Last))
846 }
else if (Hi20.
getOpcode() == LoongArch::LU12I_W) {
847 MachineInstr *
Add =
nullptr;
849 if (!detectFoldable(Hi20,
Add, Lo12))
857 MadeChange |= detectAndFoldOffset(Hi20, *Lo12, Lo20, Hi12,
Last);
858 MadeChange |= foldIntoMemoryOps(Hi20, *Lo12, Lo20, Hi12,
Last);
867 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
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.
bool isBlockAddress() const
isBlockAddress - Tests if this is a MO_BlockAddress operand.
Register getReg() const
getReg - Returns the register number.
void setTargetFlags(unsigned F)
LLVM_ABI void ChangeToCPI(unsigned Idx, int Offset, unsigned TargetFlags=0)
ChangeToCPI - Replace this operand with a new constant pool index operand.
MCSymbol * getMCSymbol() const
@ MO_ConstantPoolIndex
Address of indexed Constant in Constant Pool.
@ 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.