Skip to content

Commit fbd619f

Browse files
committed
RISCV: Remove unneeded relocations when mixing relax/norelax code
RISCVAsmBackend::ForceRelocs is introduced to create required relocations in mixed relax/norelax code. However, it also leads to redundant relocations. Consider the example adapted from llvm#77436 ``` .option norelax j label // For assembly input, RISCVAsmParser::ParseInstruction sets ForceRelocs (https://reviews.llvm.org/D46423). // For direct object emission, RISCVELFStreamer sets ForceRelocs (llvm#77436) .option relax call foo // linker-relaxable .option norelax j label // redundant relocation due to ForceRelocs .option relax label: ``` Follow-up to llvm#140494
1 parent 95202ab commit fbd619f

File tree

9 files changed

+47
-42
lines changed

9 files changed

+47
-42
lines changed

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/lib/MC/MCAssembler.cpp

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

900+
this->HasFinalLayout = true;
901+
900902
// Evaluate and apply the fixups, generating relocation entries as necessary.
901903
for (MCSection &Sec : *this) {
902904
for (MCFragment &Frag : Sec) {

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+
// A relaxable fragment has indeterminate size before finishLayout.
396+
// Afterwards (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/Target/RISCV/AsmParser/RISCVAsmParser.cpp

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2820,21 +2820,6 @@ bool RISCVAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
28202820
bool RISCVAsmParser::parseInstruction(ParseInstructionInfo &Info,
28212821
StringRef Name, SMLoc NameLoc,
28222822
OperandVector &Operands) {
2823-
// Ensure that if the instruction occurs when relaxation is enabled,
2824-
// relocations are forced for the file. Ideally this would be done when there
2825-
// is enough information to reliably determine if the instruction itself may
2826-
// cause relaxations. Unfortunately instruction processing stage occurs in the
2827-
// same pass as relocation emission, so it's too late to set a 'sticky bit'
2828-
// for the entire file.
2829-
if (getSTI().hasFeature(RISCV::FeatureRelax)) {
2830-
auto *Assembler = getTargetStreamer().getStreamer().getAssemblerPtr();
2831-
if (Assembler != nullptr) {
2832-
RISCVAsmBackend &MAB =
2833-
static_cast<RISCVAsmBackend &>(Assembler->getBackend());
2834-
MAB.setForceRelocs();
2835-
}
2836-
}
2837-
28382823
// Apply mnemonic aliases because the destination mnemonic may have require
28392824
// custom operand parsing. The generic tblgen'erated code does this later, at
28402825
// the start of MatchInstructionImpl(), but that's too late for custom

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

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,9 @@ MCFixupKindInfo RISCVAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
104104
return Infos[Kind - FirstTargetFixupKind];
105105
}
106106

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.
107+
// If linker relaxation is enabled, always emit relocations even if the fixup
108+
// can be resolved. This is necessary for correctness as offsets may change
109+
// during relaxation.
110110
bool RISCVAsmBackend::shouldForceRelocation(const MCAssembler &Asm,
111111
const MCFixup &Fixup,
112112
const MCValue &Target,
@@ -124,7 +124,7 @@ bool RISCVAsmBackend::shouldForceRelocation(const MCAssembler &Asm,
124124
break;
125125
}
126126

127-
return STI->hasFeature(RISCV::FeatureRelax) || ForceRelocs;
127+
return STI->hasFeature(RISCV::FeatureRelax);
128128
}
129129

130130
bool RISCVAsmBackend::fixupNeedsRelaxationAdvanced(const MCAssembler &,
@@ -570,6 +570,18 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
570570
}
571571
}
572572

573+
bool RISCVAsmBackend::isPCRelFixupResolved(const MCAssembler &Asm,
574+
const MCSymbol *SymA,
575+
const MCFragment &F) {
576+
if (!PCRelTemp)
577+
PCRelTemp = Asm.getContext().createTempSymbol();
578+
PCRelTemp->setFragment(const_cast<MCFragment *>(&F));
579+
MCValue Res;
580+
MCExpr::evaluateSymbolicAdd(&Asm, false, MCValue::get(SymA),
581+
MCValue::get(nullptr, PCRelTemp), Res);
582+
return !Res.getSubSym();
583+
}
584+
573585
bool RISCVAsmBackend::evaluateTargetFixup(
574586
const MCAssembler &Asm, const MCFixup &Fixup, const MCFragment *DF,
575587
const MCValue &Target, const MCSubtargetInfo *STI, uint64_t &Value) {
@@ -613,7 +625,9 @@ bool RISCVAsmBackend::evaluateTargetFixup(
613625
Value = Asm.getSymbolOffset(SA) + AUIPCTarget.getConstant();
614626
Value -= Asm.getFragmentOffset(*AUIPCDF) + AUIPCFixup->getOffset();
615627

616-
return AUIPCFixup->getTargetKind() == RISCV::fixup_riscv_pcrel_hi20;
628+
if (AUIPCFixup->getTargetKind() != RISCV::fixup_riscv_pcrel_hi20)
629+
return false;
630+
return isPCRelFixupResolved(Asm, AUIPCTarget.getAddSym(), *AUIPCDF);
617631
}
618632

619633
bool RISCVAsmBackend::addReloc(MCAssembler &Asm, const MCFragment &F,
@@ -659,11 +673,14 @@ bool RISCVAsmBackend::addReloc(MCAssembler &Asm, const MCFragment &F,
659673
return false;
660674
}
661675

676+
if (IsResolved &&
677+
(getFixupKindInfo(Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel))
678+
IsResolved = isPCRelFixupResolved(Asm, Target.getAddSym(), F);
662679
IsResolved = MCAsmBackend::addReloc(Asm, F, Fixup, Target, FixedValue,
663680
IsResolved, STI);
664681
// If linker relaxation is enabled and supported by the current relocation,
665682
// append a RELAX relocation.
666-
if (Fixup.needsRelax()) {
683+
if (!IsResolved && Fixup.needsRelax()) {
667684
auto FA = MCFixup::create(Fixup.getOffset(), nullptr, ELF::R_RISCV_RELAX);
668685
Asm.getWriter().recordRelocation(Asm, &F, FA, MCValue::get(nullptr),
669686
FixedValueA);

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

Lines changed: 5 additions & 3 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;

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/test/CodeGen/RISCV/option-relax-relocation.ll

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
;; after linker relaxation. See https://github.com/ClangBuiltLinux/linux/issues/1965
33

44
; RUN: llc -mtriple=riscv64 -mattr=-relax -filetype=obj < %s \
5-
; RUN: | llvm-objdump -d -r - | FileCheck %s
5+
; RUN: | llvm-objdump -d -r - | FileCheck %s --check-prefixes=CHECK,NORELAX
66
; RUN: llc -mtriple=riscv64 -mattr=+relax -filetype=obj < %s \
77
; RUN: | llvm-objdump -d -r - | FileCheck %s --check-prefixes=CHECK,RELAX
88

@@ -12,14 +12,20 @@
1212
; CHECK-NEXT: R_RISCV_CALL_PLT f
1313
; RELAX-NEXT: R_RISCV_RELAX *ABS*
1414
; CHECK-NEXT: jalr ra
15+
; CHECK-NEXT: j {{.*}}
16+
; CHECK-NEXT: j {{.*}}
17+
; NORELAX-NEXT: li a0, 0x0
18+
; RELAX-NEXT: R_RISCV_JAL .L0
1519

1620
define dso_local noundef signext i32 @main() local_unnamed_addr #0 {
1721
entry:
18-
callbr void asm sideeffect ".option push\0A.option norvc\0A.option norelax\0Aj $0\0A.option pop\0A", "!i"() #2
22+
callbr void asm sideeffect ".option push\0A.option norvc\0A.option norelax\0Aj $0\0A.option pop\0A", "!i"()
1923
to label %asm.fallthrough [label %label]
2024

2125
asm.fallthrough: ; preds = %entry
2226
tail call void @f()
27+
callbr void asm sideeffect ".option push\0A.option norvc\0A.option norelax\0Aj $0\0A.option pop\0A", "!i"()
28+
to label %asm.fallthrough [label %label]
2329
br label %label
2430

2531
label: ; preds = %asm.fallthrough, %entry

llvm/test/MC/RISCV/option-relax.s

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,11 @@
2121

2222
# CHECK-INST: call foo
2323
# CHECK-RELOC: R_RISCV_CALL_PLT foo 0x0
24-
# CHECK-RELOC-NOT: R_RISCV_RELAX - 0x0
24+
# CHECK-RELOC-NOT: R_RISCV
2525
call foo
2626

27-
# CHECK-RELOC-NEXT: R_RISCV_ADD64
28-
# CHECK-RELOC-NEXT: R_RISCV_SUB64
2927
.dword .L2-.L1
30-
# CHECK-RELOC-NEXT: R_RISCV_JAL
3128
jal zero, .L1
32-
# CHECK-RELOC-NEXT: R_RISCV_BRANCH
3329
beq s1, s1, .L1
3430

3531
.L2:
@@ -41,8 +37,6 @@ beq s1, s1, .L1
4137
# CHECK-RELOC-NEXT: R_RISCV_RELAX - 0x0
4238
call bar
4339

44-
# CHECK-RELOC-NEXT: R_RISCV_ADD64
45-
# CHECK-RELOC-NEXT: R_RISCV_SUB64
4640
.dword .L2-.L1
4741
# CHECK-RELOC-NEXT: R_RISCV_JAL
4842
jal zero, .L1
@@ -57,8 +51,6 @@ beq s1, s1, .L1
5751
# CHECK-RELOC-NOT: R_RISCV_RELAX - 0x0
5852
call baz
5953

60-
# CHECK-RELOC-NEXT: R_RISCV_ADD64
61-
# CHECK-RELOC-NEXT: R_RISCV_SUB64
6254
.dword .L2-.L1
6355
# CHECK-RELOC-NEXT: R_RISCV_JAL
6456
jal zero, .L1

0 commit comments

Comments
 (0)