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)
139 if (UseInst->
getOpcode() != LoongArch::ADD_D) {
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)
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)
240 !(isGlobalOrCPI(AddOp3) || AddOp3.
isMCSymbol()) ||
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)
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)
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) {
435 I->eraseFromParent();
441bool LoongArchMergeBaseOffsetOpt::detectAndFoldOffset(MachineInstr &Hi20,
445 MachineInstr *&
Last) {
458 switch (
Tail.getOpcode()) {
460 LLVM_DEBUG(
dbgs() <<
"Don't know how to get offset from this instr:"
463 case LoongArch::ADDI_W:
467 case LoongArch::ADDI_D:
468 case LoongArch::ADDU16I_D: {
471 if (
Tail.getOpcode() == LoongArch::ADDU16I_D)
480 if (TailTail.
getOpcode() == LoongArch::ADDI_W ||
481 TailTail.
getOpcode() == LoongArch::ADDI_D) {
484 foldOffset(Hi20, Lo12, Lo20, Hi12,
Last, TailTail,
Offset);
485 Tail.eraseFromParent();
491 foldOffset(Hi20, Lo12, Lo20, Hi12,
Last, Tail,
Offset);
494 case LoongArch::ADD_W:
498 case LoongArch::ADD_D:
500 return foldLargeOffset(Hi20, Lo12, Lo20, Hi12,
Last, Tail, DestReg);
510 case LoongArch::LD_B:
511 return isLarge ? LoongArch::LDX_B : LoongArch::LD_B;
512 case LoongArch::LD_H:
513 return isLarge ? LoongArch::LDX_H : LoongArch::LD_H;
514 case LoongArch::LD_W:
515 case LoongArch::LDPTR_W:
516 return isLarge ? LoongArch::LDX_W : LoongArch::LD_W;
517 case LoongArch::LD_D:
518 case LoongArch::LDPTR_D:
519 return isLarge ? LoongArch::LDX_D : LoongArch::LD_D;
520 case LoongArch::LD_BU:
521 return isLarge ? LoongArch::LDX_BU : LoongArch::LD_BU;
522 case LoongArch::LD_HU:
523 return isLarge ? LoongArch::LDX_HU : LoongArch::LD_HU;
524 case LoongArch::LD_WU:
525 return isLarge ? LoongArch::LDX_WU : LoongArch::LD_WU;
526 case LoongArch::FLD_S:
527 return isLarge ? LoongArch::FLDX_S : LoongArch::FLD_S;
528 case LoongArch::FLD_D:
529 return isLarge ? LoongArch::FLDX_D : LoongArch::FLD_D;
531 return isLarge ? LoongArch::VLDX : LoongArch::VLD;
532 case LoongArch::XVLD:
533 return isLarge ? LoongArch::XVLDX : LoongArch::XVLD;
534 case LoongArch::VLDREPL_B:
535 return LoongArch::VLDREPL_B;
536 case LoongArch::XVLDREPL_B:
537 return LoongArch::XVLDREPL_B;
538 case LoongArch::ST_B:
539 return isLarge ? LoongArch::STX_B : LoongArch::ST_B;
540 case LoongArch::ST_H:
541 return isLarge ? LoongArch::STX_H : LoongArch::ST_H;
542 case LoongArch::ST_W:
543 case LoongArch::STPTR_W:
544 return isLarge ? LoongArch::STX_W : LoongArch::ST_W;
545 case LoongArch::ST_D:
546 case LoongArch::STPTR_D:
547 return isLarge ? LoongArch::STX_D : LoongArch::ST_D;
548 case LoongArch::FST_S:
549 return isLarge ? LoongArch::FSTX_S : LoongArch::FST_S;
550 case LoongArch::FST_D:
551 return isLarge ? LoongArch::FSTX_D : LoongArch::FST_D;
553 return isLarge ? LoongArch::VSTX : LoongArch::VST;
554 case LoongArch::XVST:
555 return isLarge ? LoongArch::XVSTX : LoongArch::XVST;
561bool LoongArchMergeBaseOffsetOpt::foldIntoMemoryOps(MachineInstr &Hi20,
565 MachineInstr *&
Last) {
610 std::optional<int64_t> CommonOffset;
611 DenseMap<const MachineInstr *, SmallVector<unsigned>>
612 InlineAsmMemoryOpIndexesMap;
614 switch (
UseMI.getOpcode()) {
618 case LoongArch::VLDREPL_B:
619 case LoongArch::XVLDREPL_B:
624 case LoongArch::LD_B:
625 case LoongArch::LD_H:
626 case LoongArch::LD_W:
627 case LoongArch::LD_D:
628 case LoongArch::LD_BU:
629 case LoongArch::LD_HU:
630 case LoongArch::LD_WU:
631 case LoongArch::LDPTR_W:
632 case LoongArch::LDPTR_D:
633 case LoongArch::FLD_S:
634 case LoongArch::FLD_D:
636 case LoongArch::XVLD:
637 case LoongArch::ST_B:
638 case LoongArch::ST_H:
639 case LoongArch::ST_W:
640 case LoongArch::ST_D:
641 case LoongArch::STPTR_W:
642 case LoongArch::STPTR_D:
643 case LoongArch::FST_S:
644 case LoongArch::FST_D:
646 case LoongArch::XVST: {
647 if (
UseMI.getOperand(1).isFI())
653 "Expected base address use");
656 if (CommonOffset &&
Offset != CommonOffset)
661 case LoongArch::INLINEASM:
662 case LoongArch::INLINEASM_BR: {
666 SmallVector<unsigned> InlineAsmMemoryOpIndexes;
670 const MachineOperand &FlagsMO =
UseMI.getOperand(
I);
672 if (!FlagsMO.
isImm())
682 for (
unsigned J = 0; J <
NumOps; ++J) {
683 const MachineOperand &MO =
UseMI.getOperand(
I + 1 + J);
691 if (
Flags.getMemoryConstraintID() != InlineAsm::ConstraintCode::m)
694 const MachineOperand &AddrMO =
UseMI.getOperand(
I + 1);
698 const MachineOperand &OffsetMO =
UseMI.getOperand(
I + 2);
699 if (!OffsetMO.
isImm())
704 if (CommonOffset &&
Offset != CommonOffset)
709 InlineAsmMemoryOpIndexesMap.
insert(
710 std::make_pair(&
UseMI, InlineAsmMemoryOpIndexes));
760 if (Hi20.
getOpcode() == LoongArch::PCADDU12I ||
761 Hi20.
getOpcode() == LoongArch::PCALAU12I) {
765 }
else if (Hi20.
getOpcode() == LoongArch::LU12I_W) {
772 for (MachineInstr &
UseMI :
774 if (
UseMI.getOpcode() == LoongArch::INLINEASM ||
775 UseMI.getOpcode() == LoongArch::INLINEASM_BR) {
776 auto &InlineAsmMemoryOpIndexes = InlineAsmMemoryOpIndexesMap[&
UseMI];
777 for (
unsigned I : InlineAsmMemoryOpIndexes) {
778 MachineOperand &MO =
UseMI.getOperand(
I + 1);
805 UseMI.removeOperand(2);
806 UseMI.removeOperand(1);
809 UseMI.getOperand(1).setIsKill(
false);
810 UseMI.getOperand(2).setIsKill(
false);
812 UseMI.removeOperand(2);
813 UseMI.addOperand(ImmOp);
819 Last->eraseFromParent();
823 if (Hi20.
getOpcode() == LoongArch::PCADDU12I ||
824 Hi20.
getOpcode() == LoongArch::PCALAU12I) {
827 }
else if (Hi20.
getOpcode() == LoongArch::LU12I_W) {
830 Add->getOperand(0).getReg());
836bool LoongArchMergeBaseOffsetOpt::runOnMachineFunction(
MachineFunction &Fn) {
842 bool MadeChange =
false;
844 for (MachineBasicBlock &
MBB : Fn) {
846 for (MachineInstr &Hi20 :
MBB) {
847 MachineInstr *Lo12 =
nullptr;
848 MachineInstr *Lo20 =
nullptr;
849 MachineInstr *Hi12 =
nullptr;
850 MachineInstr *
Last =
nullptr;
851 if (Hi20.
getOpcode() == LoongArch::PCADDU12I ||
852 Hi20.
getOpcode() == LoongArch::PCALAU12I) {
854 if (!detectFoldable(Hi20, Lo12, Lo20, Hi12,
Last))
856 }
else if (Hi20.
getOpcode() == LoongArch::LU12I_W) {
857 MachineInstr *
Add =
nullptr;
859 if (!detectFoldable(Hi20,
Add, Lo12))
867 MadeChange |= detectAndFoldOffset(Hi20, *Lo12, Lo20, Hi12,
Last);
868 MadeChange |= foldIntoMemoryOps(Hi20, *Lo12, Lo20, Hi12,
Last);
877 return new LoongArchMergeBaseOffsetOpt();
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.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
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,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
LLVM_ABI void markUsesInDebugValueAsUndef(Register Reg) const
markUsesInDebugValueAsUndef - Mark every DBG_VALUE referencing the specified register as undefined wh...
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
use_instr_iterator use_instr_begin(Register RegNo) const
bool hasOneUse(Register RegNo) const
hasOneUse - Return true if there is exactly one instruction using the specified register.
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
LLVM_ABI const TargetRegisterClass * constrainRegClass(Register Reg, const TargetRegisterClass *RC, unsigned MinNumRegs=0)
constrainRegClass - Constrain the register class of the specified virtual register to be a common sub...
LLVM_ABI void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
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)
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.
@ 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.