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(
196 MRI->constrainRegClass(
Def->getOperand(0).getReg(),
197 MRI->getRegClass(
Tail.getOperand(0).getReg()));
198 MRI->replaceRegWith(
Tail.getOperand(0).getReg(),
Def->getOperand(0).getReg());
199 Tail.eraseFromParent();
201 <<
" " << Hi20 <<
" " << Lo12;);
228bool LoongArchMergeBaseOffsetOpt::foldLargeOffset(
233 TailAdd.
getOpcode() == LoongArch::ADD_D) &&
234 "Expected ADD instruction!");
240 if (!
Reg.isVirtual() || !
MRI->hasOneUse(Reg))
244 if (OffsetTail.
getOpcode() == LoongArch::ORI) {
251 int64_t OffLo = OriImmOp.
getImm();
254 if (OriReg == LoongArch::R0) {
256 foldOffset(Hi20, Lo12, Lo20, Hi12,
Last, TailAdd, OffLo);
263 if (OffsetLu12i.
getOpcode() != LoongArch::LU12I_W ||
267 int64_t
Offset = SignExtend64<32>(Lu12iImmOp.
getImm() << 12);
272 <<
" " << OffsetLu12i);
273 foldOffset(Hi20, Lo12, Lo20, Hi12,
Last, TailAdd,
Offset);
277 }
else if (OffsetTail.
getOpcode() == LoongArch::LU12I_W) {
282 foldOffset(Hi20, Lo12, Lo20, Hi12,
Last, TailAdd,
Offset);
289bool LoongArchMergeBaseOffsetOpt::detectAndFoldOffset(
MachineInstr &Hi20,
300 if (!
MRI->hasOneUse(DestReg))
305 switch (
Tail.getOpcode()) {
307 LLVM_DEBUG(
dbgs() <<
"Don't know how to get offset from this instr:"
310 case LoongArch::ADDI_W:
314 case LoongArch::ADDI_D:
315 case LoongArch::ADDU16I_D: {
318 if (
Tail.getOpcode() == LoongArch::ADDU16I_D)
323 if (
MRI->hasOneUse(TailDestReg)) {
325 if (
ST->is64Bit() && TailTail.
getOpcode() == LoongArch::ADDI_W)
327 if (TailTail.
getOpcode() == LoongArch::ADDI_W ||
328 TailTail.
getOpcode() == LoongArch::ADDI_D) {
331 foldOffset(Hi20, Lo12, Lo20, Hi12,
Last, TailTail,
Offset);
332 Tail.eraseFromParent();
341 case LoongArch::ADD_W:
345 case LoongArch::ADD_D:
354 return foldLargeOffset(Hi20, Lo12, Lo20, Hi12,
Last,
Tail, DestReg);
364 case LoongArch::LD_B:
365 return isLarge ? LoongArch::LDX_B : LoongArch::LD_B;
366 case LoongArch::LD_H:
367 return isLarge ? LoongArch::LDX_H : LoongArch::LD_H;
368 case LoongArch::LD_W:
369 case LoongArch::LDPTR_W:
370 return isLarge ? LoongArch::LDX_W : LoongArch::LD_W;
371 case LoongArch::LD_D:
372 case LoongArch::LDPTR_D:
373 return isLarge ? LoongArch::LDX_D : LoongArch::LD_D;
374 case LoongArch::LD_BU:
375 return isLarge ? LoongArch::LDX_BU : LoongArch::LD_BU;
376 case LoongArch::LD_HU:
377 return isLarge ? LoongArch::LDX_HU : LoongArch::LD_HU;
378 case LoongArch::LD_WU:
379 return isLarge ? LoongArch::LDX_WU : LoongArch::LD_WU;
380 case LoongArch::FLD_S:
381 return isLarge ? LoongArch::FLDX_S : LoongArch::FLD_S;
382 case LoongArch::FLD_D:
383 return isLarge ? LoongArch::FLDX_D : LoongArch::FLD_D;
385 return isLarge ? LoongArch::VLDX : LoongArch::VLD;
386 case LoongArch::XVLD:
387 return isLarge ? LoongArch::XVLDX : LoongArch::XVLD;
388 case LoongArch::VLDREPL_B:
389 return LoongArch::VLDREPL_B;
390 case LoongArch::XVLDREPL_B:
391 return LoongArch::XVLDREPL_B;
392 case LoongArch::ST_B:
393 return isLarge ? LoongArch::STX_B : LoongArch::ST_B;
394 case LoongArch::ST_H:
395 return isLarge ? LoongArch::STX_H : LoongArch::ST_H;
396 case LoongArch::ST_W:
397 case LoongArch::STPTR_W:
398 return isLarge ? LoongArch::STX_W : LoongArch::ST_W;
399 case LoongArch::ST_D:
400 case LoongArch::STPTR_D:
401 return isLarge ? LoongArch::STX_D : LoongArch::ST_D;
402 case LoongArch::FST_S:
403 return isLarge ? LoongArch::FSTX_S : LoongArch::FST_S;
404 case LoongArch::FST_D:
405 return isLarge ? LoongArch::FSTX_D : LoongArch::FST_D;
407 return isLarge ? LoongArch::VSTX : LoongArch::VST;
408 case LoongArch::XVST:
409 return isLarge ? LoongArch::XVSTX : LoongArch::XVST;
415bool LoongArchMergeBaseOffsetOpt::foldIntoMemoryOps(
MachineInstr &Hi20,
451 std::optional<int64_t> CommonOffset;
453 InlineAsmMemoryOpIndexesMap;
455 switch (
UseMI.getOpcode()) {
459 case LoongArch::VLDREPL_B:
460 case LoongArch::XVLDREPL_B:
465 case LoongArch::LD_B:
466 case LoongArch::LD_H:
467 case LoongArch::LD_W:
468 case LoongArch::LD_D:
469 case LoongArch::LD_BU:
470 case LoongArch::LD_HU:
471 case LoongArch::LD_WU:
472 case LoongArch::LDPTR_W:
473 case LoongArch::LDPTR_D:
474 case LoongArch::FLD_S:
475 case LoongArch::FLD_D:
477 case LoongArch::XVLD:
478 case LoongArch::ST_B:
479 case LoongArch::ST_H:
480 case LoongArch::ST_W:
481 case LoongArch::ST_D:
482 case LoongArch::STPTR_W:
483 case LoongArch::STPTR_D:
484 case LoongArch::FST_S:
485 case LoongArch::FST_D:
487 case LoongArch::XVST: {
488 if (
UseMI.getOperand(1).isFI())
494 "Expected base address use");
497 if (CommonOffset &&
Offset != CommonOffset)
502 case LoongArch::INLINEASM:
503 case LoongArch::INLINEASM_BR: {
510 I <
UseMI.getNumOperands();
I += 1 + NumOps) {
513 if (!FlagsMO.
isImm())
517 NumOps =
Flags.getNumOperandRegisters();
520 if (NumOps != 2 || !
Flags.isMemKind()) {
523 for (
unsigned J = 0; J < NumOps; ++J) {
532 if (
Flags.getMemoryConstraintID() != InlineAsm::ConstraintCode::m)
540 if (!OffsetMO.
isImm())
545 if (CommonOffset &&
Offset != CommonOffset)
550 InlineAsmMemoryOpIndexesMap.
insert(
551 std::make_pair(&
UseMI, InlineAsmMemoryOpIndexes));
564 NewOffset = SignExtend64<32>(NewOffset);
566 if (!isInt<32>(NewOffset))
581 if (
UseMI.getOpcode() == LoongArch::INLINEASM ||
582 UseMI.getOpcode() == LoongArch::INLINEASM_BR) {
583 auto &InlineAsmMemoryOpIndexes = InlineAsmMemoryOpIndexesMap[&
UseMI];
584 for (
unsigned I : InlineAsmMemoryOpIndexes) {
607 UseMI.removeOperand(2);
608 UseMI.removeOperand(1);
611 UseMI.getOperand(1).setIsKill(
false);
612 UseMI.getOperand(2).setIsKill(
false);
614 UseMI.removeOperand(2);
615 UseMI.addOperand(ImmOp);
621 Last->eraseFromParent();
630bool LoongArchMergeBaseOffsetOpt::runOnMachineFunction(
MachineFunction &Fn) {
636 bool MadeChange =
false;
645 if (!detectFoldable(Hi20, Lo12, Lo20, Hi12,
Last))
647 MadeChange |= detectAndFoldOffset(Hi20, *Lo12, Lo20, Hi12,
Last);
648 MadeChange |= foldIntoMemoryOps(Hi20, *Lo12, Lo20, Hi12,
Last);
657 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.
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...
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.