Skip to content

Commit 0288d06

Browse files
authored
[LoongArch] Avoid scheduling relaxable code sequence and attach relax relocs (#121330)
If linker relaxation enabled, relaxable code sequence expanded from pseudos should avoid being separated by instruction scheduling. This commit tags scheduling boundary for them to avoid being scheduled. (Except for `tls_le/tls_ie` and `call36/tail36`. Because `tls_le/tls_ie` can be scheduled and have no influence to relax, `call36/tail36` are expanded later in `LoongArchExpandPseudo` pass.) A new mask target-flag is added to attach relax relocs to the relaxable code sequence. (No need to add it for `tls_le` and `call36/tail36` because we can simply add relax relocs for them according to their relocs. But for other code sequence, such as `PCALA_{HI20/LO12}`, we must use the mask flag, mainly because relax should not be added when code model is large.) Because of the new mask target-flag, get "direct" flags is necessary when using their target-flags. In addition, code sequence after being optimized by `MergeBaseOffset` pass may not relaxable any more, so the relax "bitmask" flag should be removed.
1 parent 814b34f commit 0288d06

11 files changed

+360
-21
lines changed

llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -187,18 +187,21 @@ bool LoongArchPreRAExpandPseudo::expandPcalau12iInstPair(
187187
MachineInstr &MI = *MBBI;
188188
DebugLoc DL = MI.getDebugLoc();
189189

190+
const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
191+
bool EnableRelax = STI.hasFeature(LoongArch::FeatureRelax);
192+
190193
Register DestReg = MI.getOperand(0).getReg();
191194
Register ScratchReg =
192195
MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
193196
MachineOperand &Symbol = MI.getOperand(1);
194197

195198
BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), ScratchReg)
196-
.addDisp(Symbol, 0, FlagsHi);
199+
.addDisp(Symbol, 0, LoongArchII::encodeFlags(FlagsHi, EnableRelax));
197200

198201
MachineInstr *SecondMI =
199202
BuildMI(MBB, MBBI, DL, TII->get(SecondOpcode), DestReg)
200203
.addReg(ScratchReg)
201-
.addDisp(Symbol, 0, FlagsLo);
204+
.addDisp(Symbol, 0, LoongArchII::encodeFlags(FlagsLo, EnableRelax));
202205

203206
if (MI.hasOneMemOperand())
204207
SecondMI->addMemOperand(*MF, *MI.memoperands_begin());
@@ -481,14 +484,17 @@ bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSDesc(
481484
unsigned ADD = STI.is64Bit() ? LoongArch::ADD_D : LoongArch::ADD_W;
482485
unsigned ADDI = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
483486
unsigned LD = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
487+
bool EnableRelax = STI.hasFeature(LoongArch::FeatureRelax);
484488

485489
Register DestReg = MI.getOperand(0).getReg();
486490
Register Tmp1Reg =
487491
MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
488492
MachineOperand &Symbol = MI.getOperand(Large ? 2 : 1);
489493

490494
BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), Tmp1Reg)
491-
.addDisp(Symbol, 0, LoongArchII::MO_DESC_PC_HI);
495+
.addDisp(Symbol, 0,
496+
LoongArchII::encodeFlags(LoongArchII::MO_DESC_PC_HI,
497+
EnableRelax && !Large));
492498

493499
if (Large) {
494500
// Code Sequence:
@@ -526,19 +532,25 @@ bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSDesc(
526532
// pcalau12i $a0, %desc_pc_hi20(sym)
527533
// addi.w/d $a0, $a0, %desc_pc_lo12(sym)
528534
// ld.w/d $ra, $a0, %desc_ld(sym)
529-
// jirl $ra, $ra, %desc_ld(sym)
530-
// add.d $dst, $a0, $tp
535+
// jirl $ra, $ra, %desc_call(sym)
536+
// add.w/d $dst, $a0, $tp
531537
BuildMI(MBB, MBBI, DL, TII->get(ADDI), LoongArch::R4)
532538
.addReg(Tmp1Reg)
533-
.addDisp(Symbol, 0, LoongArchII::MO_DESC_PC_LO);
539+
.addDisp(
540+
Symbol, 0,
541+
LoongArchII::encodeFlags(LoongArchII::MO_DESC_PC_LO, EnableRelax));
534542
}
535543

536544
BuildMI(MBB, MBBI, DL, TII->get(LD), LoongArch::R1)
537545
.addReg(LoongArch::R4)
538-
.addDisp(Symbol, 0, LoongArchII::MO_DESC_LD);
546+
.addDisp(Symbol, 0,
547+
LoongArchII::encodeFlags(LoongArchII::MO_DESC_LD,
548+
EnableRelax && !Large));
539549
BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PseudoDESC_CALL), LoongArch::R1)
540550
.addReg(LoongArch::R1)
541-
.addDisp(Symbol, 0, LoongArchII::MO_DESC_CALL);
551+
.addDisp(Symbol, 0,
552+
LoongArchII::encodeFlags(LoongArchII::MO_DESC_CALL,
553+
EnableRelax && !Large));
542554
BuildMI(MBB, MBBI, DL, TII->get(ADD), DestReg)
543555
.addReg(LoongArch::R4)
544556
.addReg(LoongArch::R2);

llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp

Lines changed: 90 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,83 @@ bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
455455
break;
456456
}
457457

458+
const auto &STI = MF.getSubtarget<LoongArchSubtarget>();
459+
if (STI.hasFeature(LoongArch::FeatureRelax)) {
460+
// When linker relaxation enabled, the following instruction patterns are
461+
// prohibited from being reordered:
462+
//
463+
// * pcalau12i $a0, %pc_hi20(s)
464+
// addi.w/d $a0, $a0, %pc_lo12(s)
465+
//
466+
// * pcalau12i $a0, %got_pc_hi20(s)
467+
// ld.w/d $a0, $a0, %got_pc_lo12(s)
468+
//
469+
// * pcalau12i $a0, %ld_pc_hi20(s) | %gd_pc_hi20(s)
470+
// addi.w/d $a0, $a0, %got_pc_lo12(s)
471+
//
472+
// * pcalau12i $a0, %desc_pc_hi20(s)
473+
// addi.w/d $a0, $a0, %desc_pc_lo12(s)
474+
// ld.w/d $ra, $a0, %desc_ld(s)
475+
// jirl $ra, $ra, %desc_call(s)
476+
unsigned AddiOp = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
477+
unsigned LdOp = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
478+
switch (MI.getOpcode()) {
479+
case LoongArch::PCALAU12I: {
480+
auto MO0 = LoongArchII::getDirectFlags(MI.getOperand(1));
481+
auto SecondOp = std::next(MII);
482+
if (MO0 == LoongArchII::MO_DESC_PC_HI) {
483+
if (SecondOp == MIE || SecondOp->getOpcode() != AddiOp)
484+
break;
485+
auto Ld = std::next(SecondOp);
486+
if (Ld == MIE || Ld->getOpcode() != LdOp)
487+
break;
488+
auto MO1 = LoongArchII::getDirectFlags(SecondOp->getOperand(2));
489+
auto MO2 = LoongArchII::getDirectFlags(Ld->getOperand(2));
490+
if (MO1 == LoongArchII::MO_DESC_PC_LO && MO2 == LoongArchII::MO_DESC_LD)
491+
return true;
492+
break;
493+
}
494+
if (SecondOp == MIE ||
495+
(SecondOp->getOpcode() != AddiOp && SecondOp->getOpcode() != LdOp))
496+
break;
497+
auto MO1 = LoongArchII::getDirectFlags(SecondOp->getOperand(2));
498+
if (MO0 == LoongArchII::MO_PCREL_HI && SecondOp->getOpcode() == AddiOp &&
499+
MO1 == LoongArchII::MO_PCREL_LO)
500+
return true;
501+
if (MO0 == LoongArchII::MO_GOT_PC_HI && SecondOp->getOpcode() == LdOp &&
502+
MO1 == LoongArchII::MO_GOT_PC_LO)
503+
return true;
504+
if ((MO0 == LoongArchII::MO_LD_PC_HI ||
505+
MO0 == LoongArchII::MO_GD_PC_HI) &&
506+
SecondOp->getOpcode() == AddiOp && MO1 == LoongArchII::MO_GOT_PC_LO)
507+
return true;
508+
break;
509+
}
510+
case LoongArch::ADDI_W:
511+
case LoongArch::ADDI_D: {
512+
auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));
513+
if (MO == LoongArchII::MO_PCREL_LO || MO == LoongArchII::MO_GOT_PC_LO)
514+
return true;
515+
break;
516+
}
517+
case LoongArch::LD_W:
518+
case LoongArch::LD_D: {
519+
auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));
520+
if (MO == LoongArchII::MO_GOT_PC_LO)
521+
return true;
522+
break;
523+
}
524+
case LoongArch::PseudoDESC_CALL: {
525+
auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));
526+
if (MO == LoongArchII::MO_DESC_CALL)
527+
return true;
528+
break;
529+
}
530+
default:
531+
break;
532+
}
533+
}
534+
458535
return false;
459536
}
460537

@@ -630,7 +707,8 @@ bool LoongArchInstrInfo::reverseBranchCondition(
630707

631708
std::pair<unsigned, unsigned>
632709
LoongArchInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const {
633-
return std::make_pair(TF, 0u);
710+
const unsigned Mask = LoongArchII::MO_DIRECT_FLAG_MASK;
711+
return std::make_pair(TF & Mask, TF & ~Mask);
634712
}
635713

636714
ArrayRef<std::pair<unsigned, const char *>>
@@ -656,20 +734,29 @@ LoongArchInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
656734
{MO_IE_PC_LO, "loongarch-ie-pc-lo"},
657735
{MO_IE_PC64_LO, "loongarch-ie-pc64-lo"},
658736
{MO_IE_PC64_HI, "loongarch-ie-pc64-hi"},
737+
{MO_LD_PC_HI, "loongarch-ld-pc-hi"},
738+
{MO_GD_PC_HI, "loongarch-gd-pc-hi"},
739+
{MO_CALL36, "loongarch-call36"},
659740
{MO_DESC_PC_HI, "loongarch-desc-pc-hi"},
660741
{MO_DESC_PC_LO, "loongarch-desc-pc-lo"},
661742
{MO_DESC64_PC_LO, "loongarch-desc64-pc-lo"},
662743
{MO_DESC64_PC_HI, "loongarch-desc64-pc-hi"},
663744
{MO_DESC_LD, "loongarch-desc-ld"},
664745
{MO_DESC_CALL, "loongarch-desc-call"},
665-
{MO_LD_PC_HI, "loongarch-ld-pc-hi"},
666-
{MO_GD_PC_HI, "loongarch-gd-pc-hi"},
667746
{MO_LE_HI_R, "loongarch-le-hi-r"},
668747
{MO_LE_ADD_R, "loongarch-le-add-r"},
669748
{MO_LE_LO_R, "loongarch-le-lo-r"}};
670749
return ArrayRef(TargetFlags);
671750
}
672751

752+
ArrayRef<std::pair<unsigned, const char *>>
753+
LoongArchInstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const {
754+
using namespace LoongArchII;
755+
static const std::pair<unsigned, const char *> TargetFlags[] = {
756+
{MO_RELAX, "loongarch-relax"}};
757+
return ArrayRef(TargetFlags);
758+
}
759+
673760
// Returns true if this is the sext.w pattern, addi.w rd, rs, 0.
674761
bool LoongArch::isSEXT_W(const MachineInstr &MI) {
675762
return MI.getOpcode() == LoongArch::ADDI_W && MI.getOperand(1).isReg() &&

llvm/lib/Target/LoongArch/LoongArchInstrInfo.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ class LoongArchInstrInfo : public LoongArchGenInstrInfo {
9191
ArrayRef<std::pair<unsigned, const char *>>
9292
getSerializableDirectMachineOperandTargetFlags() const override;
9393

94+
ArrayRef<std::pair<unsigned, const char *>>
95+
getSerializableBitmaskMachineOperandTargetFlags() const override;
96+
9497
protected:
9598
const LoongArchSubtarget &STI;
9699
};

llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym,
2727
MCContext &Ctx = AP.OutContext;
2828
LoongArchMCExpr::VariantKind Kind;
2929

30-
switch (MO.getTargetFlags()) {
30+
switch (LoongArchII::getDirectFlags(MO)) {
3131
default:
3232
llvm_unreachable("Unknown target flag on GV operand");
3333
case LoongArchII::MO_None:
@@ -134,7 +134,7 @@ static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym,
134134
ME, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
135135

136136
if (Kind != LoongArchMCExpr::VK_LoongArch_None)
137-
ME = LoongArchMCExpr::create(ME, Kind, Ctx);
137+
ME = LoongArchMCExpr::create(ME, Kind, Ctx, LoongArchII::hasRelaxFlag(MO));
138138
return MCOperand::createExpr(ME);
139139
}
140140

llvm/lib/Target/LoongArch/LoongArchMergeBaseOffset.cpp

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ bool LoongArchMergeBaseOffsetOpt::detectFoldable(MachineInstr &Hi20,
105105
return false;
106106

107107
const MachineOperand &Hi20Op1 = Hi20.getOperand(1);
108-
if (Hi20Op1.getTargetFlags() != LoongArchII::MO_PCREL_HI)
108+
if (LoongArchII::getDirectFlags(Hi20Op1) != LoongArchII::MO_PCREL_HI)
109109
return false;
110110

111111
auto isGlobalOrCPIOrBlockAddress = [](const MachineOperand &Op) {
@@ -157,7 +157,7 @@ bool LoongArchMergeBaseOffsetOpt::detectFoldable(MachineInstr &Hi20,
157157

158158
const MachineOperand &Lo12Op2 = Lo12->getOperand(2);
159159
assert(Hi20.getOpcode() == LoongArch::PCALAU12I);
160-
if (Lo12Op2.getTargetFlags() != LoongArchII::MO_PCREL_LO ||
160+
if (LoongArchII::getDirectFlags(Lo12Op2) != LoongArchII::MO_PCREL_LO ||
161161
!(isGlobalOrCPIOrBlockAddress(Lo12Op2) || Lo12Op2.isMCSymbol()) ||
162162
Lo12Op2.getOffset() != 0)
163163
return false;
@@ -597,9 +597,28 @@ bool LoongArchMergeBaseOffsetOpt::foldIntoMemoryOps(MachineInstr &Hi20,
597597
if (!isInt<32>(NewOffset))
598598
return false;
599599

600+
// If optimized by this pass successfully, MO_RELAX bitmask target-flag should
601+
// be removed from the code sequence.
602+
//
603+
// For example:
604+
// pcalau12i $a0, %pc_hi20(symbol)
605+
// addi.d $a0, $a0, %pc_lo12(symbol)
606+
// ld.w $a0, $a0, 0
607+
//
608+
// =>
609+
//
610+
// pcalau12i $a0, %pc_hi20(symbol)
611+
// ld.w $a0, $a0, %pc_lo12(symbol)
612+
//
613+
// Code sequence optimized before can be relax by linker. But after being
614+
// optimized, it cannot be relaxed any more. So MO_RELAX flag should not be
615+
// carried by them.
600616
Hi20.getOperand(1).setOffset(NewOffset);
617+
Hi20.getOperand(1).setTargetFlags(
618+
LoongArchII::getDirectFlags(Hi20.getOperand(1)));
601619
MachineOperand &ImmOp = Lo12.getOperand(2);
602620
ImmOp.setOffset(NewOffset);
621+
ImmOp.setTargetFlags(LoongArchII::getDirectFlags(ImmOp));
603622
if (Lo20 && Hi12) {
604623
Lo20->getOperand(2).setOffset(NewOffset);
605624
Hi12->getOperand(2).setOffset(NewOffset);
@@ -617,15 +636,16 @@ bool LoongArchMergeBaseOffsetOpt::foldIntoMemoryOps(MachineInstr &Hi20,
617636
switch (ImmOp.getType()) {
618637
case MachineOperand::MO_GlobalAddress:
619638
MO.ChangeToGA(ImmOp.getGlobal(), ImmOp.getOffset(),
620-
ImmOp.getTargetFlags());
639+
LoongArchII::getDirectFlags(ImmOp));
621640
break;
622641
case MachineOperand::MO_MCSymbol:
623-
MO.ChangeToMCSymbol(ImmOp.getMCSymbol(), ImmOp.getTargetFlags());
642+
MO.ChangeToMCSymbol(ImmOp.getMCSymbol(),
643+
LoongArchII::getDirectFlags(ImmOp));
624644
MO.setOffset(ImmOp.getOffset());
625645
break;
626646
case MachineOperand::MO_BlockAddress:
627647
MO.ChangeToBA(ImmOp.getBlockAddress(), ImmOp.getOffset(),
628-
ImmOp.getTargetFlags());
648+
LoongArchII::getDirectFlags(ImmOp));
629649
break;
630650
default:
631651
report_fatal_error("unsupported machine operand type");

llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchTarget() {
3838
initializeLoongArchMergeBaseOffsetOptPass(*PR);
3939
initializeLoongArchOptWInstrsPass(*PR);
4040
initializeLoongArchPreRAExpandPseudoPass(*PR);
41+
initializeLoongArchExpandPseudoPass(*PR);
4142
initializeLoongArchDAGToDAGISelLegacyPass(*PR);
4243
}
4344

llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "MCTargetDesc/LoongArchMCTargetDesc.h"
1818
#include "llvm/ADT/StringRef.h"
1919
#include "llvm/ADT/StringSwitch.h"
20+
#include "llvm/CodeGen/MachineOperand.h"
2021
#include "llvm/MC/MCInstrDesc.h"
2122
#include "llvm/TargetParser/SubtargetFeature.h"
2223

@@ -58,8 +59,31 @@ enum {
5859
MO_LE_ADD_R,
5960
MO_LE_LO_R,
6061
// TODO: Add more flags.
62+
63+
// Used to differentiate between target-specific "direct" flags and "bitmask"
64+
// flags. A machine operand can only have one "direct" flag, but can have
65+
// multiple "bitmask" flags.
66+
MO_DIRECT_FLAG_MASK = 0x3f,
67+
68+
MO_RELAX = 0x40
6169
};
6270

71+
// Given a MachineOperand that may carry out "bitmask" flags, such as MO_RELAX,
72+
// return LoongArch target-specific "direct" flags.
73+
static inline unsigned getDirectFlags(const MachineOperand &MO) {
74+
return MO.getTargetFlags() & MO_DIRECT_FLAG_MASK;
75+
}
76+
77+
// Add MO_RELAX "bitmask" flag when FeatureRelax is enabled.
78+
static inline unsigned encodeFlags(unsigned Flags, bool Relax) {
79+
return Flags | (Relax ? MO_RELAX : 0);
80+
}
81+
82+
// \returns true if the given MachineOperand has MO_RELAX "bitmask" flag.
83+
static inline bool hasRelaxFlag(const MachineOperand &MO) {
84+
return MO.getTargetFlags() & MO_RELAX;
85+
}
86+
6387
// Target-specific flags of LAInst.
6488
// All definitions must match LoongArchInstrFormats.td.
6589
enum {

llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ LoongArchMCCodeEmitter::getExprOpValue(const MCInst &MI, const MCOperand &MO,
249249
break;
250250
case LoongArchMCExpr::VK_LoongArch_CALL36:
251251
FixupKind = LoongArch::fixup_loongarch_call36;
252+
RelaxCandidate = true;
252253
break;
253254
case LoongArchMCExpr::VK_LoongArch_TLS_DESC_PC_HI20:
254255
FixupKind = LoongArch::fixup_loongarch_tls_desc_pc_hi20;

0 commit comments

Comments
 (0)