25#define DEBUG_TYPE "loongarch-merge-base-offset"
26#define LoongArch_MERGE_BASE_OFFSET_NAME "LoongArch Merge Base Offset"
60 MachineFunctionProperties::Property::IsSSA);
74char LoongArchMergeBaseOffsetOpt::ID = 0;
104 if (Hi20.getOpcode() != LoongArch::PCALAU12I)
112 return Op.isGlobal() ||
Op.isCPI() ||
Op.isBlockAddress();
115 if (!isGlobalOrCPIOrBlockAddress(Hi20Op1) || Hi20Op1.
getOffset() != 0)
118 Register HiDestReg = Hi20.getOperand(0).getReg();
119 if (!
MRI->hasOneUse(HiDestReg))
123 if (UseInst->
getOpcode() != LoongArch::ADD_D) {
125 if ((ST->is64Bit() && Lo12->getOpcode() != LoongArch::ADDI_D) ||
126 (!ST->is64Bit() && Lo12->getOpcode() != LoongArch::ADDI_W))
135 Hi12 =
MRI->getVRegDef(LastOp1Reg);
139 if (!isGlobalOrCPIOrBlockAddress(Hi12Op2) || Hi12Op2.
getOffset() != 0)
141 if (!
MRI->hasOneUse(Hi12->getOperand(0).getReg()))
144 Lo20 =
MRI->getVRegDef(Hi12->getOperand(1).getReg());
148 if (!isGlobalOrCPIOrBlockAddress(Lo20Op2) || Lo20Op2.
getOffset() != 0)
150 if (!
MRI->hasOneUse(Lo20->getOperand(0).getReg()))
153 Lo12 =
MRI->getVRegDef(Lo20->getOperand(1).getReg());
154 if (!
MRI->hasOneUse(Lo12->getOperand(0).getReg()))
159 assert(Hi20.getOpcode() == LoongArch::PCALAU12I);
161 !(isGlobalOrCPIOrBlockAddress(Lo12Op2) || Lo12Op2.
isMCSymbol()) ||
171 }
else if (Hi20Op1.
isCPI()) {
182void LoongArchMergeBaseOffsetOpt::foldOffset(
195 MRI->constrainRegClass(
Def->getOperand(0).getReg(),
196 MRI->getRegClass(
Tail.getOperand(0).getReg()));
197 MRI->replaceRegWith(
Tail.getOperand(0).getReg(),
Def->getOperand(0).getReg());
198 Tail.eraseFromParent();
200 <<
" " << Hi20 <<
" " << Lo12;);
240bool LoongArchMergeBaseOffsetOpt::foldLargeOffset(
245 TailAdd.
getOpcode() == LoongArch::ADD_D) &&
246 "Expected ADD instruction!");
255 for (
int i = 0; i < 4; i++) {
257 if (Reg == LoongArch::R0)
261 if (!
Reg.isVirtual() || !
MRI->hasOneUse(Reg))
272 case LoongArch::ORI: {
281 case LoongArch::LU12I_W: {
290 case LoongArch::LU32I_D: {
295 Mask ^= 0x000FFFFF00000000ULL;
300 case LoongArch::LU52I_D: {
305 Mask ^= 0xFFF0000000000000ULL;
317 foldOffset(Hi20, Lo12, Lo20, Hi12,
Last, TailAdd,
Offset);
319 for (
auto I : Instrs) {
321 I->eraseFromParent();
327bool LoongArchMergeBaseOffsetOpt::detectAndFoldOffset(
MachineInstr &Hi20,
338 if (!
MRI->hasOneUse(DestReg))
343 switch (
Tail.getOpcode()) {
345 LLVM_DEBUG(
dbgs() <<
"Don't know how to get offset from this instr:"
348 case LoongArch::ADDI_W:
352 case LoongArch::ADDI_D:
353 case LoongArch::ADDU16I_D: {
356 if (
Tail.getOpcode() == LoongArch::ADDU16I_D)
361 if (
MRI->hasOneUse(TailDestReg)) {
363 if (
ST->is64Bit() && TailTail.
getOpcode() == LoongArch::ADDI_W)
365 if (TailTail.
getOpcode() == LoongArch::ADDI_W ||
366 TailTail.
getOpcode() == LoongArch::ADDI_D) {
369 foldOffset(Hi20, Lo12, Lo20, Hi12,
Last, TailTail,
Offset);
370 Tail.eraseFromParent();
379 case LoongArch::ADD_W:
383 case LoongArch::ADD_D:
385 return foldLargeOffset(Hi20, Lo12, Lo20, Hi12,
Last,
Tail, DestReg);
395 case LoongArch::LD_B:
396 return isLarge ? LoongArch::LDX_B : LoongArch::LD_B;
397 case LoongArch::LD_H:
398 return isLarge ? LoongArch::LDX_H : LoongArch::LD_H;
399 case LoongArch::LD_W:
400 case LoongArch::LDPTR_W:
401 return isLarge ? LoongArch::LDX_W : LoongArch::LD_W;
402 case LoongArch::LD_D:
403 case LoongArch::LDPTR_D:
404 return isLarge ? LoongArch::LDX_D : LoongArch::LD_D;
405 case LoongArch::LD_BU:
406 return isLarge ? LoongArch::LDX_BU : LoongArch::LD_BU;
407 case LoongArch::LD_HU:
408 return isLarge ? LoongArch::LDX_HU : LoongArch::LD_HU;
409 case LoongArch::LD_WU:
410 return isLarge ? LoongArch::LDX_WU : LoongArch::LD_WU;
411 case LoongArch::FLD_S:
412 return isLarge ? LoongArch::FLDX_S : LoongArch::FLD_S;
413 case LoongArch::FLD_D:
414 return isLarge ? LoongArch::FLDX_D : LoongArch::FLD_D;
416 return isLarge ? LoongArch::VLDX : LoongArch::VLD;
417 case LoongArch::XVLD:
418 return isLarge ? LoongArch::XVLDX : LoongArch::XVLD;
419 case LoongArch::VLDREPL_B:
420 return LoongArch::VLDREPL_B;
421 case LoongArch::XVLDREPL_B:
422 return LoongArch::XVLDREPL_B;
423 case LoongArch::ST_B:
424 return isLarge ? LoongArch::STX_B : LoongArch::ST_B;
425 case LoongArch::ST_H:
426 return isLarge ? LoongArch::STX_H : LoongArch::ST_H;
427 case LoongArch::ST_W:
428 case LoongArch::STPTR_W:
429 return isLarge ? LoongArch::STX_W : LoongArch::ST_W;
430 case LoongArch::ST_D:
431 case LoongArch::STPTR_D:
432 return isLarge ? LoongArch::STX_D : LoongArch::ST_D;
433 case LoongArch::FST_S:
434 return isLarge ? LoongArch::FSTX_S : LoongArch::FST_S;
435 case LoongArch::FST_D:
436 return isLarge ? LoongArch::FSTX_D : LoongArch::FST_D;
438 return isLarge ? LoongArch::VSTX : LoongArch::VST;
439 case LoongArch::XVST:
440 return isLarge ? LoongArch::XVSTX : LoongArch::XVST;
446bool LoongArchMergeBaseOffsetOpt::foldIntoMemoryOps(
MachineInstr &Hi20,
482 std::optional<int64_t> CommonOffset;
484 InlineAsmMemoryOpIndexesMap;
486 switch (
UseMI.getOpcode()) {
490 case LoongArch::VLDREPL_B:
491 case LoongArch::XVLDREPL_B:
496 case LoongArch::LD_B:
497 case LoongArch::LD_H:
498 case LoongArch::LD_W:
499 case LoongArch::LD_D:
500 case LoongArch::LD_BU:
501 case LoongArch::LD_HU:
502 case LoongArch::LD_WU:
503 case LoongArch::LDPTR_W:
504 case LoongArch::LDPTR_D:
505 case LoongArch::FLD_S:
506 case LoongArch::FLD_D:
508 case LoongArch::XVLD:
509 case LoongArch::ST_B:
510 case LoongArch::ST_H:
511 case LoongArch::ST_W:
512 case LoongArch::ST_D:
513 case LoongArch::STPTR_W:
514 case LoongArch::STPTR_D:
515 case LoongArch::FST_S:
516 case LoongArch::FST_D:
518 case LoongArch::XVST: {
519 if (
UseMI.getOperand(1).isFI())
525 "Expected base address use");
528 if (CommonOffset &&
Offset != CommonOffset)
533 case LoongArch::INLINEASM:
534 case LoongArch::INLINEASM_BR: {
541 I <
UseMI.getNumOperands();
I += 1 + NumOps) {
544 if (!FlagsMO.
isImm())
548 NumOps =
Flags.getNumOperandRegisters();
551 if (NumOps != 2 || !
Flags.isMemKind()) {
554 for (
unsigned J = 0; J < NumOps; ++J) {
563 if (
Flags.getMemoryConstraintID() != InlineAsm::ConstraintCode::m)
571 if (!OffsetMO.
isImm())
576 if (CommonOffset &&
Offset != CommonOffset)
581 InlineAsmMemoryOpIndexesMap.
insert(
582 std::make_pair(&
UseMI, InlineAsmMemoryOpIndexes));
595 NewOffset = SignExtend64<32>(NewOffset);
597 if (!isInt<32>(NewOffset))
612 if (
UseMI.getOpcode() == LoongArch::INLINEASM ||
613 UseMI.getOpcode() == LoongArch::INLINEASM_BR) {
614 auto &InlineAsmMemoryOpIndexes = InlineAsmMemoryOpIndexesMap[&
UseMI];
615 for (
unsigned I : InlineAsmMemoryOpIndexes) {
638 UseMI.removeOperand(2);
639 UseMI.removeOperand(1);
642 UseMI.getOperand(1).setIsKill(
false);
643 UseMI.getOperand(2).setIsKill(
false);
645 UseMI.removeOperand(2);
646 UseMI.addOperand(ImmOp);
652 Last->eraseFromParent();
661bool LoongArchMergeBaseOffsetOpt::runOnMachineFunction(
MachineFunction &Fn) {
667 bool MadeChange =
false;
676 if (!detectFoldable(Hi20, Lo12, Lo20, Hi12,
Last))
678 MadeChange |= detectAndFoldOffset(Hi20, *Lo12, Lo20, Hi12,
Last);
679 MadeChange |= foldIntoMemoryOps(Hi20, *Lo12, Lo20, Hi12,
Last);
688 return new LoongArchMergeBaseOffsetOpt();
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
const HexagonInstrInfo * TII
static unsigned getNewOpc(unsigned Op, bool isLarge)
#define LoongArch_MERGE_BASE_OFFSET_NAME
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Represent the analysis usage information of a pass.
void setPreservesCFG()
This function should be called by the pass, iff they do not:
This class represents an Operation in the Expression.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
FunctionPass class - This class is used to implement most global optimizations.
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.
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
virtual MachineFunctionProperties getRequiredProperties() const
Properties which a MachineFunction may have at a given point in time.
MachineFunctionProperties & set(Property P)
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.
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.
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.
void ChangeToGA(const GlobalValue *GV, int64_t Offset, unsigned TargetFlags=0)
ChangeToGA - Replace this operand with a new global address operand.
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.
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,...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
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)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
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.
@ Tail
Attemps to make calls as fast as possible while guaranteeing that tail call optimization can always b...
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Reg
All possible values of the reg field in the ModR/M byte.
NodeAddr< DefNode * > Def
This is an optimization pass for GlobalISel generic memory operations.
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...
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
DWARFExpression::Operation Op
FunctionPass * createLoongArchMergeBaseOffsetOptPass()
Returns an instance of the Merge Base Offset Optimization pass.