Skip to content

Commit bb03cdc

Browse files
authored
RISCV: Remove shouldForceRelocation and unneeded relocations
Follow-up to #140494 `shouldForceRelocation` is conservative and produces redundant relocations. For example, RISCVAsmBackend::ForceRelocs (introduced to support mixed relax/norelax code) leads to redundant relocations in the following example adapted from #77436 ``` .option norelax j label // For assembly input, RISCVAsmParser::ParseInstruction sets ForceRelocs (https://reviews.llvm.org/D46423). // For direct object emission, RISCVELFStreamer sets ForceRelocs (#77436) .option relax call foo // linker-relaxable .option norelax j label // redundant relocation due to ForceRelocs .option relax label: ``` Root problem: The `isSymbolRefDifferenceFullyResolvedImpl` condition in MCAssembler::evaluateFixup does not check whether two locations are separated by a fragment whose size can be indeterminate due to linker instruction (e.g. MCDataFragment with relaxation, or MCAlignFragment due to indeterminate start offst). This patch * Updates the fragment walk code in `attemptToFoldSymbolOffsetDifference` to treat MCRelaxableFragment (for --riscv-asm-relax-branches) as fixed size after finishLayout. * Adds a condition in `addReloc` to complement `isSymbolRefDifferenceFullyResolvedImpl`. * Removes the no longer needed `shouldForceRelocation`. This fragment walk code path handles nicely handles mixed relax/norelax case from https://discourse.llvm.org/t/possible-problem-related-to-subtarget-usage/75283 and allows us to remove `MCSubtargetInfo` argument (#73721) as a follow-up. This fragment walk code should be avoided in the absence of linker-relaxable fragments within the current section. Adjust two bolt/test/RISCV tests (#141310) Pull Request: #140692
1 parent d5802c3 commit bb03cdc

22 files changed

+86
-112
lines changed

bolt/test/RISCV/reloc-label-diff.s

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,6 @@ _test_end:
2020
.data
2121
// CHECK: Hex dump of section '.data':
2222
// CHECK: 0x{{.*}} 04000000
23+
.reloc ., R_RISCV_ADD32, _test_end
24+
.reloc ., R_RISCV_SUB32, _start
2325
.word _test_end - _start

bolt/test/RISCV/reorder-blocks-reverse.s

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
.p2align 1
88
_start:
99
nop
10+
.reloc ., R_RISCV_BRANCH, 1f
1011
beq t0, t1, 1f
1112
nop
1213
beq t0, t2, 2f

llvm/include/llvm/MC/MCAssembler.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class MCAssembler {
6464
std::unique_ptr<MCObjectWriter> Writer;
6565

6666
bool HasLayout = false;
67+
bool HasFinalLayout = false;
6768
bool RelaxAll = false;
6869

6970
SectionListType Sections;
@@ -197,6 +198,7 @@ class MCAssembler {
197198
void layout();
198199

199200
bool hasLayout() const { return HasLayout; }
201+
bool hasFinalLayout() const { return HasFinalLayout; }
200202
bool getRelaxAll() const { return RelaxAll; }
201203
void setRelaxAll(bool Value) { RelaxAll = Value; }
202204

llvm/include/llvm/MC/MCFixup.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@ class MCFixup {
7373
/// determine how the operand value should be encoded into the instruction.
7474
MCFixupKind Kind = FK_NONE;
7575

76-
/// Used by RISC-V style linker relaxation. If the fixup is unresolved,
77-
/// whether a RELAX relocation should follow.
78-
bool NeedsRelax = false;
76+
/// Used by RISC-V style linker relaxation. Whether the fixup is
77+
/// linker-relaxable.
78+
bool LinkerRelaxable = false;
7979

8080
/// Consider bit fields if we need more flags.
8181

@@ -105,8 +105,8 @@ class MCFixup {
105105

106106
const MCExpr *getValue() const { return Value; }
107107

108-
bool needsRelax() const { return NeedsRelax; }
109-
void setNeedsRelax() { NeedsRelax = true; }
108+
bool isLinkerRelaxable() const { return LinkerRelaxable; }
109+
void setLinkerRelaxable() { LinkerRelaxable = true; }
110110

111111
/// Return the generic fixup kind for a value with the given size. It
112112
/// is an error to pass an unsupported size.

llvm/include/llvm/MC/MCSection.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ class MCSection {
107107

108108
bool IsVirtual : 1;
109109

110+
/// Whether the section contains linker-relaxable fragments. If true, the
111+
/// offset between two locations may not be fully resolved.
112+
bool LinkerRelaxable : 1;
113+
110114
MCDummyFragment DummyFragment;
111115

112116
// Mapping from subsection number to fragment list. At layout time, the
@@ -175,6 +179,9 @@ class MCSection {
175179
bool isRegistered() const { return IsRegistered; }
176180
void setIsRegistered(bool Value) { IsRegistered = Value; }
177181

182+
bool isLinkerRelaxable() const { return LinkerRelaxable; }
183+
void setLinkerRelaxable() { LinkerRelaxable = true; }
184+
178185
const MCDummyFragment &getDummyFragment() const { return DummyFragment; }
179186
MCDummyFragment &getDummyFragment() { return DummyFragment; }
180187

llvm/lib/MC/MCAssembler.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,10 @@ void MCAssembler::layout() {
897897
// example, to set the index fields in the symbol data).
898898
getWriter().executePostLayoutBinding(*this);
899899

900+
// Fragment sizes are finalized. For RISC-V linker relaxation, this flag
901+
// helps check whether a PC-relative fixup is fully resolved.
902+
this->HasFinalLayout = true;
903+
900904
// Evaluate and apply the fixups, generating relocation entries as necessary.
901905
for (MCSection &Sec : *this) {
902906
for (MCFragment &Frag : Sec) {

llvm/lib/MC/MCELFStreamer.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,8 +450,10 @@ void MCELFStreamer::emitInstToData(const MCInst &Inst,
450450
auto Fixups = MutableArrayRef(DF->getFixups()).slice(FixupStartIndex);
451451
for (auto &Fixup : Fixups) {
452452
Fixup.setOffset(Fixup.getOffset() + CodeOffset);
453-
if (Fixup.needsRelax())
453+
if (Fixup.isLinkerRelaxable()) {
454454
DF->setLinkerRelaxable();
455+
getCurrentSectionOnly()->setLinkerRelaxable();
456+
}
455457
}
456458

457459
DF->setHasInstructions(STI);

llvm/lib/MC/MCExpr.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,12 @@ static void attemptToFoldSymbolOffsetDifference(const MCAssembler *Asm,
390390
unsigned Count;
391391
if (DF) {
392392
Displacement += DF->getContents().size();
393+
} else if (auto *RF = dyn_cast<MCRelaxableFragment>(FI);
394+
RF && Asm->hasFinalLayout()) {
395+
// Before finishLayout, a relaxable fragment's size is indeterminate.
396+
// After layout, during relocation generation, it can be treated as a
397+
// data fragment.
398+
Displacement += RF->getContents().size();
393399
} else if (auto *AF = dyn_cast<MCAlignFragment>(FI);
394400
AF && Layout && AF->hasEmitNops() &&
395401
!Asm->getBackend().shouldInsertExtraNopBytesForCodeAlign(

llvm/lib/MC/MCSection.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ MCSection::MCSection(SectionVariant V, StringRef Name, bool IsText,
2323
bool IsVirtual, MCSymbol *Begin)
2424
: Begin(Begin), BundleGroupBeforeFirstInst(false), HasInstructions(false),
2525
HasLayout(false), IsRegistered(false), IsText(IsText),
26-
IsVirtual(IsVirtual), Name(Name), Variant(V) {
26+
IsVirtual(IsVirtual), LinkerRelaxable(false), Name(Name), Variant(V) {
2727
DummyFragment.setParent(this);
2828
// The initial subsection number is 0. Create a fragment list.
2929
CurFragList = &Subsections.emplace_back(0u, FragList{}).second;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ bool LoongArchAsmBackend::addReloc(MCAssembler &Asm, const MCFragment &F,
504504
IsResolved = Fallback();
505505
// If linker relaxation is enabled and supported by the current relocation,
506506
// append a RELAX relocation.
507-
if (Fixup.needsRelax()) {
507+
if (Fixup.isLinkerRelaxable()) {
508508
auto FA = MCFixup::create(Fixup.getOffset(), nullptr, ELF::R_LARCH_RELAX);
509509
Asm.getWriter().recordRelocation(Asm, &F, FA, MCValue::get(nullptr),
510510
FixedValueA);

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ LoongArchMCCodeEmitter::getExprOpValue(const MCInst &MI, const MCOperand &MO,
203203
// a bit so that if fixup is unresolved, a R_LARCH_RELAX relocation will be
204204
// appended.
205205
if (EnableRelax && RelaxCandidate)
206-
Fixups.back().setNeedsRelax();
206+
Fixups.back().setLinkerRelaxable();
207207

208208
return 0;
209209
}
@@ -254,7 +254,7 @@ void LoongArchMCCodeEmitter::expandAddTPRel(const MCInst &MI,
254254
Fixups.push_back(
255255
MCFixup::create(0, Expr, ELF::R_LARCH_TLS_LE_ADD_R, MI.getLoc()));
256256
if (STI.hasFeature(LoongArch::FeatureRelax))
257-
Fixups.back().setNeedsRelax();
257+
Fixups.back().setLinkerRelaxable();
258258

259259
// Emit a normal ADD instruction with the given operands.
260260
unsigned ADD = MI.getOpcode() == LoongArch::PseudoAddTPRel_D

llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2885,21 +2885,6 @@ bool RISCVAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
28852885
bool RISCVAsmParser::parseInstruction(ParseInstructionInfo &Info,
28862886
StringRef Name, SMLoc NameLoc,
28872887
OperandVector &Operands) {
2888-
// Ensure that if the instruction occurs when relaxation is enabled,
2889-
// relocations are forced for the file. Ideally this would be done when there
2890-
// is enough information to reliably determine if the instruction itself may
2891-
// cause relaxations. Unfortunately instruction processing stage occurs in the
2892-
// same pass as relocation emission, so it's too late to set a 'sticky bit'
2893-
// for the entire file.
2894-
if (getSTI().hasFeature(RISCV::FeatureRelax)) {
2895-
auto *Assembler = getTargetStreamer().getStreamer().getAssemblerPtr();
2896-
if (Assembler != nullptr) {
2897-
RISCVAsmBackend &MAB =
2898-
static_cast<RISCVAsmBackend &>(Assembler->getBackend());
2899-
MAB.setForceRelocs();
2900-
}
2901-
}
2902-
29032888
// Apply mnemonic aliases because the destination mnemonic may have require
29042889
// custom operand parsing. The generic tblgen'erated code does this later, at
29052890
// the start of MatchInstructionImpl(), but that's too late for custom

llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "llvm/MC/MCContext.h"
1515
#include "llvm/MC/MCELFObjectWriter.h"
1616
#include "llvm/MC/MCExpr.h"
17+
#include "llvm/MC/MCFragment.h"
1718
#include "llvm/MC/MCObjectWriter.h"
1819
#include "llvm/MC/MCSymbol.h"
1920
#include "llvm/MC/MCValue.h"
@@ -104,29 +105,6 @@ MCFixupKindInfo RISCVAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
104105
return Infos[Kind - FirstTargetFixupKind];
105106
}
106107

107-
// If linker relaxation is enabled, or the relax option had previously been
108-
// enabled, always emit relocations even if the fixup can be resolved. This is
109-
// necessary for correctness as offsets may change during relaxation.
110-
bool RISCVAsmBackend::shouldForceRelocation(const MCAssembler &Asm,
111-
const MCFixup &Fixup,
112-
const MCValue &Target,
113-
const MCSubtargetInfo *STI) {
114-
switch (Fixup.getTargetKind()) {
115-
default:
116-
break;
117-
case FK_Data_1:
118-
case FK_Data_2:
119-
case FK_Data_4:
120-
case FK_Data_8:
121-
case FK_Data_leb128:
122-
if (Target.isAbsolute())
123-
return false;
124-
break;
125-
}
126-
127-
return STI->hasFeature(RISCV::FeatureRelax) || ForceRelocs;
128-
}
129-
130108
bool RISCVAsmBackend::fixupNeedsRelaxationAdvanced(const MCAssembler &,
131109
const MCFixup &Fixup,
132110
const MCValue &,
@@ -570,6 +548,27 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
570548
}
571549
}
572550

551+
bool RISCVAsmBackend::isPCRelFixupResolved(const MCAssembler &Asm,
552+
const MCSymbol *SymA,
553+
const MCFragment &F) {
554+
// If the section does not contain linker-relaxable instructions, PC-relative
555+
// fixups can be resolved.
556+
if (!F.getParent()->isLinkerRelaxable())
557+
return true;
558+
559+
// Otherwise, check if the offset between the symbol and fragment is fully
560+
// resolved, unaffected by linker-relaxable fragments (e.g. instructions or
561+
// offset-affected MCAlignFragment). Complements the generic
562+
// isSymbolRefDifferenceFullyResolvedImpl.
563+
if (!PCRelTemp)
564+
PCRelTemp = Asm.getContext().createTempSymbol();
565+
PCRelTemp->setFragment(const_cast<MCFragment *>(&F));
566+
MCValue Res;
567+
MCExpr::evaluateSymbolicAdd(&Asm, false, MCValue::get(SymA),
568+
MCValue::get(nullptr, PCRelTemp), Res);
569+
return !Res.getSubSym();
570+
}
571+
573572
bool RISCVAsmBackend::evaluateTargetFixup(
574573
const MCAssembler &Asm, const MCFixup &Fixup, const MCFragment *DF,
575574
const MCValue &Target, const MCSubtargetInfo *STI, uint64_t &Value) {
@@ -613,7 +612,8 @@ bool RISCVAsmBackend::evaluateTargetFixup(
613612
Value = Asm.getSymbolOffset(SA) + AUIPCTarget.getConstant();
614613
Value -= Asm.getFragmentOffset(*AUIPCDF) + AUIPCFixup->getOffset();
615614

616-
return AUIPCFixup->getTargetKind() == RISCV::fixup_riscv_pcrel_hi20;
615+
return AUIPCFixup->getTargetKind() == RISCV::fixup_riscv_pcrel_hi20 &&
616+
isPCRelFixupResolved(Asm, AUIPCTarget.getAddSym(), *AUIPCDF);
617617
}
618618

619619
bool RISCVAsmBackend::addReloc(MCAssembler &Asm, const MCFragment &F,
@@ -659,11 +659,17 @@ bool RISCVAsmBackend::addReloc(MCAssembler &Asm, const MCFragment &F,
659659
return false;
660660
}
661661

662+
// If linker relaxation is enabled and supported by the current relocation,
663+
// generate a relocation and then append a RELAX.
664+
if (Fixup.isLinkerRelaxable())
665+
IsResolved = false;
666+
if (IsResolved &&
667+
(getFixupKindInfo(Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel))
668+
IsResolved = isPCRelFixupResolved(Asm, Target.getAddSym(), F);
662669
IsResolved = MCAsmBackend::addReloc(Asm, F, Fixup, Target, FixedValue,
663670
IsResolved, STI);
664-
// If linker relaxation is enabled and supported by the current relocation,
665-
// append a RELAX relocation.
666-
if (Fixup.needsRelax()) {
671+
672+
if (Fixup.isLinkerRelaxable()) {
667673
auto FA = MCFixup::create(Fixup.getOffset(), nullptr, ELF::R_RISCV_RELAX);
668674
Asm.getWriter().recordRelocation(Asm, &F, FA, MCValue::get(nullptr),
669675
FixedValueA);

llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,18 @@ class RISCVAsmBackend : public MCAsmBackend {
2525
const MCSubtargetInfo &STI;
2626
uint8_t OSABI;
2727
bool Is64Bit;
28-
bool ForceRelocs = false;
2928
const MCTargetOptions &TargetOptions;
29+
// Temporary symbol used to check whether a PC-relative fixup is resolved.
30+
MCSymbol *PCRelTemp = nullptr;
31+
32+
bool isPCRelFixupResolved(const MCAssembler &Asm, const MCSymbol *SymA,
33+
const MCFragment &F);
3034

3135
public:
3236
RISCVAsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI, bool Is64Bit,
3337
const MCTargetOptions &Options);
3438
~RISCVAsmBackend() override = default;
3539

36-
void setForceRelocs() { ForceRelocs = true; }
37-
3840
// Return Size with extra Nop Bytes for alignment directive in code section.
3941
bool shouldInsertExtraNopBytesForCodeAlign(const MCAlignFragment &AF,
4042
unsigned &Size) override;
@@ -60,10 +62,6 @@ class RISCVAsmBackend : public MCAsmBackend {
6062
std::unique_ptr<MCObjectTargetWriter>
6163
createObjectTargetWriter() const override;
6264

63-
bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup,
64-
const MCValue &Target,
65-
const MCSubtargetInfo *STI) override;
66-
6765
bool fixupNeedsRelaxationAdvanced(const MCAssembler &,
6866
const MCFixup &, const MCValue &, uint64_t,
6967
bool) const override;

llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,6 @@ RISCVTargetELFStreamer::RISCVTargetELFStreamer(MCStreamer &S,
3434
setTargetABI(RISCVABI::computeTargetABI(STI.getTargetTriple(), Features,
3535
MAB.getTargetOptions().getABIName()));
3636
setFlagsFromFeatures(STI);
37-
// `j label` in `.option norelax; j label; .option relax; ...; label:` needs a
38-
// relocation to ensure the jump target is correct after linking. This is due
39-
// to a limitation that shouldForceRelocation has to make the decision upfront
40-
// without knowing a possibly future .option relax. When RISCVAsmParser is used,
41-
// its ParseInstruction may call setForceRelocs as well.
42-
if (STI.hasFeature(RISCV::FeatureRelax))
43-
static_cast<RISCVAsmBackend &>(MAB).setForceRelocs();
4437
}
4538

4639
RISCVELFStreamer &RISCVTargetELFStreamer::getStreamer() {

llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ void RISCVMCCodeEmitter::expandAddTPRel(const MCInst &MI,
212212
Fixups.push_back(
213213
MCFixup::create(0, Expr, ELF::R_RISCV_TPREL_ADD, MI.getLoc()));
214214
if (STI.hasFeature(RISCV::FeatureRelax))
215-
Fixups.back().setNeedsRelax();
215+
Fixups.back().setLinkerRelaxable();
216216

217217
// Emit a normal ADD instruction with the given operands.
218218
MCInst TmpInst = MCInstBuilder(RISCV::ADD)
@@ -654,7 +654,7 @@ uint64_t RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo,
654654
// a bit so that if fixup is unresolved, a R_RISCV_RELAX relocation will be
655655
// appended.
656656
if (EnableRelax && RelaxCandidate)
657-
Fixups.back().setNeedsRelax();
657+
Fixups.back().setLinkerRelaxable();
658658
++MCNumFixups;
659659

660660
return 0;

llvm/test/CodeGen/RISCV/option-relax-relocation.ll

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
; RELAX-NEXT: R_RISCV_RELAX *ABS*
1414
; CHECK-NEXT: jalr ra
1515
; CHECK-NEXT: j {{.*}}
16-
; RELAX-NEXT: R_RISCV_JAL .LBB0_{{.*}}
1716
; CHECK-NEXT: j {{.*}}
1817
; RELAX-NEXT: R_RISCV_JAL .L0
1918
; NORELAX-NEXT: li a0, 0x0

llvm/test/MC/RISCV/fixups-binary-expression.s

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,14 @@ beq a0, a1, .LBB1+32
2121

2222
c.j .+32
2323
# CHECK-INSTR: c.j 0x30
24-
# CHECK-RELOC-NEXT: R_RISCV_RVC_JUMP
2524

2625
c.j .LBB2+4
2726
# CHECK-INSTR: c.j 0x22
2827
# CHECK-RELOC-NEXT: R_RISCV_RVC_JUMP
2928

3029
c.beqz a0, .-2
3130
# CHECK-INSTR: c.beqz a0, 0x12
32-
# CHECK-RELOC-NEXT: R_RISCV_RVC_BRANCH
3331

3432
call relax
33+
# CHECK-RELOC-NEXT: R_RISCV_CALL_PLT
3534
.LBB2:

llvm/test/MC/RISCV/linker-relaxation.s

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,17 @@ bar:
5858

5959
beq s1, s1, bar
6060
# NORELAX-RELOC-NOT: R_RISCV_BRANCH
61-
# RELAX-RELOC: R_RISCV_BRANCH bar 0x0
6261

6362
call bar
6463
# NORELAX-RELOC-NOT: R_RISCV_CALL
6564
# NORELAX-RELOC-NOT: R_RISCV_RELAX
66-
# RELAX-RELOC: R_RISCV_CALL_PLT bar 0x0
65+
# RELAX-RELOC-NEXT: R_RISCV_CALL_PLT bar 0x0
6766
# RELAX-RELOC: R_RISCV_RELAX - 0x0
6867

68+
beq s1, s1, bar
69+
# NORELAX-RELOC-NOT: R_RISCV_BRANCH
70+
# RELAX-RELOC-NEXT: R_RISCV_BRANCH bar 0x0
71+
6972
lui t1, %hi(bar)
7073
# NORELAX-RELOC: R_RISCV_HI20 bar 0x0
7174
# NORELAX-RELOC-NOT: R_RISCV_RELAX

0 commit comments

Comments
 (0)