Skip to content

Commit 20f900d

Browse files
committed
[RISCV] Track Linker Relaxable through Assembly Relaxation
Span-dependent instructions on RISC-V interact in a complex manner with linker relaxation. The Span-dependent assembler algorithm implemented in LLVM has to start with the smallest version of an instruction and then only make it larger, so we compress instructions before emitting them to the streamer. When the instruction is streamed, the information that the instruction (or rather, the fixup on the instruction) is linker relaxable must be accurate, even though the assembler relaxation process may transform a not-linker-relaxable instruction/fixup into one that that is linker relaxable, for instance `c.jal` becoming `qc.e.jal`, or `bne` getting turned into `beq; jal` (the `jal` is linker relaxable). I do not fully understand why the linker relaxation information has to be accurate at streaming-time if the assembler knows it may be relaxing the instruction (i.e., potentially making it longer), but I have been told this is the case. In order for this to work, the following things have to happen: - Any instruction/fixup which might be relaxed to a linker-relaxable instruction/fixup, gets marked as `RelaxCandidate = true` in RISCVMCCodeEmitter. - In RISCVAsmBackend, when emitting the `R_RISCV_RELAX` relocation, we have to check that the relocation/fixup kind is one that may need a relax relocation, as well as that it is marked as linker relaxable (the latter will not be set if relaxation is disabled). - Linker Relaxable instructions streamed to a Relaxable fragment need to mark the fragment and its section as linker relaxable. I also added more debug output for Sections/Fixups which are marked Linker Relaxable. This results in more `R_RISCV_BRANCH` relocations, but I do not think there is anything we can do about that. Fixes: #150071
1 parent 01472d8 commit 20f900d

File tree

9 files changed

+120
-24
lines changed

9 files changed

+120
-24
lines changed

llvm/lib/MC/MCFragment.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ LLVM_DUMP_METHOD void MCFragment::dump() const {
6868
OS << "\n Fixup @" << F.getOffset() << " Value:";
6969
F.getValue()->print(OS, nullptr);
7070
OS << " Kind:" << F.getKind();
71+
if (F.isLinkerRelaxable())
72+
OS << " LinkerRelaxable";
7173
}
7274
};
7375

llvm/lib/MC/MCObjectStreamer.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -461,11 +461,21 @@ void MCObjectStreamer::emitInstToFragment(const MCInst &Inst,
461461
getAssembler().getEmitter().encodeInstruction(Inst, Data, Fixups, STI);
462462

463463
F->Kind = MCFragment::FT_Relaxable;
464-
F->STI = &STI;
465-
F->HasInstructions = true;
464+
F->setHasInstructions(STI);
465+
466466
F->setVarContents(Data);
467-
F->setVarFixups(Fixups);
468467
F->setInst(Inst);
468+
469+
for (auto &Fixup : Fixups) {
470+
if (!Fixup.isLinkerRelaxable())
471+
continue;
472+
auto *Sec = F->getParent();
473+
if (!Sec->isLinkerRelaxable())
474+
Sec->setLinkerRelaxable();
475+
F->setLinkerRelaxable();
476+
}
477+
F->setVarFixups(Fixups);
478+
469479
newFragment();
470480
}
471481

llvm/lib/MC/MCSection.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ LLVM_DUMP_METHOD void MCSection::dump(
3939
raw_ostream &OS = errs();
4040

4141
OS << "MCSection Name:" << getName();
42+
if (LinkerRelaxable)
43+
OS << " LinkerRelaxable";
4244
for (auto &F : *this) {
4345
OS << '\n';
4446
F.dump();

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

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,40 @@ void RISCVAsmBackend::maybeAddVendorReloc(const MCFragment &F,
803803
Asm->getWriter().recordRelocation(F, VendorFixup, VendorTarget, VendorValue);
804804
}
805805

806+
static bool fixupGetsRelaxRelocation(const MCFixupKind Kind) {
807+
switch (Kind) {
808+
default:
809+
break;
810+
case RISCV::fixup_riscv_lo12_i:
811+
case RISCV::fixup_riscv_lo12_s:
812+
case RISCV::fixup_riscv_hi20:
813+
case RISCV::fixup_riscv_pcrel_lo12_i:
814+
case RISCV::fixup_riscv_pcrel_lo12_s:
815+
case RISCV::fixup_riscv_pcrel_hi20:
816+
case RISCV::fixup_riscv_call_plt:
817+
case RISCV::fixup_riscv_qc_abs20_u:
818+
case RISCV::fixup_riscv_qc_e_32:
819+
case RISCV::fixup_riscv_qc_e_call_plt:
820+
case ELF::R_RISCV_TPREL_LO12_I:
821+
case ELF::R_RISCV_TPREL_LO12_S:
822+
case ELF::R_RISCV_TPREL_HI20:
823+
return true;
824+
}
825+
return false;
826+
}
827+
828+
void RISCVAsmBackend::maybeAddRelaxReloc(const MCFragment &F,
829+
const MCFixup &Fixup) {
830+
if (!Fixup.isLinkerRelaxable() || !fixupGetsRelaxRelocation(Fixup.getKind()))
831+
return;
832+
833+
MCFixup RelaxFixup =
834+
MCFixup::create(Fixup.getOffset(), nullptr, ELF::R_RISCV_RELAX);
835+
MCValue RelaxTarget = MCValue::get(nullptr);
836+
uint64_t RelaxValue;
837+
Asm->getWriter().recordRelocation(F, RelaxFixup, RelaxTarget, RelaxValue);
838+
}
839+
806840
bool RISCVAsmBackend::addReloc(const MCFragment &F, const MCFixup &Fixup,
807841
const MCValue &Target, uint64_t &FixedValue,
808842
bool IsResolved) {
@@ -845,25 +879,24 @@ bool RISCVAsmBackend::addReloc(const MCFragment &F, const MCFixup &Fixup,
845879
return false;
846880
}
847881

848-
// If linker relaxation is enabled and supported by the current relocation,
849-
// generate a relocation and then append a RELAX.
850-
if (Fixup.isLinkerRelaxable())
882+
// If linker relaxation is enabled and supported by the current fixup, then we
883+
// always want to generate a relocation.
884+
if (Fixup.isLinkerRelaxable() && fixupGetsRelaxRelocation(Fixup.getKind()))
851885
IsResolved = false;
886+
852887
if (IsResolved && Fixup.isPCRel())
853888
IsResolved = isPCRelFixupResolved(Target.getAddSym(), F);
854889

855890
if (!IsResolved) {
856-
// Some Fixups require a vendor relocation, record it (directly) before we
891+
// Some Fixups require a VENDOR relocation, record it (directly) before we
857892
// add the relocation.
858893
maybeAddVendorReloc(F, Fixup);
859894

860895
Asm->getWriter().recordRelocation(F, Fixup, Target, FixedValue);
861-
}
862896

863-
if (Fixup.isLinkerRelaxable()) {
864-
auto FA = MCFixup::create(Fixup.getOffset(), nullptr, ELF::R_RISCV_RELAX);
865-
Asm->getWriter().recordRelocation(F, FA, MCValue::get(nullptr),
866-
FixedValueA);
897+
// Some Fixups may get a RELAX relocation, record it (directly) after we
898+
// add the relocation.
899+
maybeAddRelaxReloc(F, Fixup);
867900
}
868901

869902
return false;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class RISCVAsmBackend : public MCAsmBackend {
4444
uint64_t &FixedValue, bool IsResolved);
4545

4646
void maybeAddVendorReloc(const MCFragment &, const MCFixup &);
47+
void maybeAddRelaxReloc(const MCFragment &, const MCFixup &);
4748

4849
void applyFixup(const MCFragment &, const MCFixup &, const MCValue &Target,
4950
uint8_t *Data, uint64_t Value, bool IsResolved) override;

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

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -576,8 +576,25 @@ uint64_t RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo,
576576
"getImmOpValue expects only expressions or immediates");
577577
const MCExpr *Expr = MO.getExpr();
578578
MCExpr::ExprKind Kind = Expr->getKind();
579-
unsigned FixupKind = RISCV::fixup_riscv_invalid;
579+
580+
// `RelaxCandidate` must be set to `true` in two cases:
581+
// - The fixup's relocation gets a R_RISCV_RELAX relocation
582+
// - The underlying instruction may be relaxed to an instruction that gets a
583+
// `R_RISCV_RELAX` relocation.
584+
//
585+
// The actual emission of `R_RISCV_RELAX` will be handled in
586+
// `RISCVAsmBackend`.
580587
bool RelaxCandidate = false;
588+
auto AsmRelaxToLinkerRelaxable = [&]() -> void {
589+
if (!STI.hasFeature(RISCV::FeatureExactAssembly))
590+
RelaxCandidate = true;
591+
};
592+
auto AsmRelaxToLinkerRelaxableWithFeature = [&](unsigned Feature) -> void {
593+
if (!STI.hasFeature(RISCV::FeatureExactAssembly) && STI.hasFeature(Feature))
594+
RelaxCandidate = true;
595+
};
596+
597+
unsigned FixupKind = RISCV::fixup_riscv_invalid;
581598
if (Kind == MCExpr::Specifier) {
582599
const auto *RVExpr = cast<MCSpecifierExpr>(Expr);
583600
FixupKind = RVExpr->getSpecifier();
@@ -644,18 +661,23 @@ uint64_t RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo,
644661
// FIXME: Sub kind binary exprs have chance of underflow.
645662
if (MIFrm == RISCVII::InstFormatJ) {
646663
FixupKind = RISCV::fixup_riscv_jal;
664+
AsmRelaxToLinkerRelaxableWithFeature(RISCV::FeatureVendorXqcilb);
647665
} else if (MIFrm == RISCVII::InstFormatB) {
648666
FixupKind = RISCV::fixup_riscv_branch;
667+
AsmRelaxToLinkerRelaxable();
649668
} else if (MIFrm == RISCVII::InstFormatCJ) {
650669
FixupKind = RISCV::fixup_riscv_rvc_jump;
670+
AsmRelaxToLinkerRelaxableWithFeature(RISCV::FeatureVendorXqcilb);
651671
} else if (MIFrm == RISCVII::InstFormatCB) {
652672
FixupKind = RISCV::fixup_riscv_rvc_branch;
673+
AsmRelaxToLinkerRelaxable();
653674
} else if (MIFrm == RISCVII::InstFormatCI) {
654675
FixupKind = RISCV::fixup_riscv_rvc_imm;
655676
} else if (MIFrm == RISCVII::InstFormatI) {
656677
FixupKind = RISCV::fixup_riscv_12_i;
657678
} else if (MIFrm == RISCVII::InstFormatQC_EB) {
658679
FixupKind = RISCV::fixup_riscv_qc_e_branch;
680+
AsmRelaxToLinkerRelaxable();
659681
} else if (MIFrm == RISCVII::InstFormatQC_EAI) {
660682
FixupKind = RISCV::fixup_riscv_qc_e_32;
661683
RelaxCandidate = true;
@@ -670,9 +692,9 @@ uint64_t RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo,
670692
assert(FixupKind != RISCV::fixup_riscv_invalid && "Unhandled expression!");
671693

672694
addFixup(Fixups, 0, Expr, FixupKind);
673-
// If linker relaxation is enabled and supported by this relocation, set
674-
// a bit so that if fixup is unresolved, a R_RISCV_RELAX relocation will be
675-
// appended.
695+
// If linker relaxation is enabled and supported by this relocation, set a bit
696+
// so that the assembler knows the size of the instruction is not fixed/known,
697+
// and the relocation will need a R_RISCV_RELAX relocation.
676698
if (EnableRelax && RelaxCandidate)
677699
Fixups.back().setLinkerRelaxable();
678700
++MCNumFixups;

llvm/test/MC/RISCV/Relocations/mc-dump.s

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
# RUN: llvm-mc -filetype=obj --triple=riscv64 --mattr=+relax %s -debug-only=mc-dump -o /dev/null 2>&1 | FileCheck %s
33

44
# CHECK:Sections:[
5-
# CHECK-NEXT:MCSection Name:.text
5+
# CHECK-NEXT:MCSection Name:.text LinkerRelaxable
66
# CHECK-NEXT:0 Align Size:0+0 []
77
# CHECK-NEXT: Align:4 Fill:0 FillLen:1 MaxBytesToEmit:4 Nops
88
# CHECK-NEXT: Symbol @0 .text
99
# CHECK-NEXT:0 Data LinkerRelaxable Size:8 [97,00,00,00,e7,80,00,00]
10-
# CHECK-NEXT: Fixup @0 Value:specifier(19,ext) Kind:4023
10+
# CHECK-NEXT: Fixup @0 Value:specifier(19,ext) Kind:4023 LinkerRelaxable
1111
# CHECK-NEXT: Symbol @0 $x
1212
# CHECK-NEXT:8 Align LinkerRelaxable Size:0+4 []
1313
# CHECK-NEXT: Align:8 Fill:0 FillLen:1 MaxBytesToEmit:8 Nops

llvm/test/MC/RISCV/align.s

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,14 +137,18 @@ data2:
137137

138138
## Branches crossing the linker-relaxable R_RISCV_ALIGN need relocations.
139139
# RELAX-RELOC: .rela.text3 {
140-
# RELAX-RELOC-NEXT: 0x4 R_RISCV_BRANCH .Ltmp[[#]] 0x0
141-
# RELAX-RELOC-NEXT: 0x8 R_RISCV_ALIGN - 0x4
142-
# RELAX-RELOC-NEXT: 0xC R_RISCV_BRANCH .Ltmp[[#]] 0x0
140+
# RELAX-RELOC-NEXT: 0x0 R_RISCV_BRANCH .Ltmp[[#]] 0x0
141+
# RELAX-RELOC-NEXT: 0x4 R_RISCV_BRANCH .Ltmp[[#]] 0x0
142+
# RELAX-RELOC-NEXT: 0x8 R_RISCV_ALIGN - 0x4
143+
# RELAX-RELOC-NEXT: 0xC R_RISCV_BRANCH .Ltmp[[#]] 0x0
144+
# RELAX-RELOC-NEXT: 0x10 R_RISCV_BRANCH .Ltmp[[#]] 0x0
143145
# RELAX-RELOC-NEXT: }
144146
# C-OR-ZCA-EXT-RELAX-RELOC: .rela.text3 {
145-
# C-OR-ZCA-EXT-RELAX-RELOC-NEXT: 0x4 R_RISCV_BRANCH .Ltmp[[#]] 0x0
146-
# C-OR-ZCA-EXT-RELAX-RELOC-NEXT: 0x8 R_RISCV_ALIGN - 0x4
147-
# C-OR-ZCA-EXT-RELAX-RELOC-NEXT: 0xC R_RISCV_BRANCH .Ltmp[[#]] 0x0
147+
# C-OR-ZCA-EXT-RELAX-RELOC-NEXT: 0x0 R_RISCV_BRANCH .Ltmp[[#]] 0x0
148+
# C-OR-ZCA-EXT-RELAX-RELOC-NEXT: 0x4 R_RISCV_BRANCH .Ltmp[[#]] 0x0
149+
# C-OR-ZCA-EXT-RELAX-RELOC-NEXT: 0x8 R_RISCV_ALIGN - 0x4
150+
# C-OR-ZCA-EXT-RELAX-RELOC-NEXT: 0xC R_RISCV_BRANCH .Ltmp[[#]] 0x0
151+
# C-OR-ZCA-EXT-RELAX-RELOC-NEXT: 0x10 R_RISCV_BRANCH .Ltmp[[#]] 0x0
148152
# C-OR-ZCA-EXT-RELAX-RELOC-NEXT: }
149153
.section .text3, "ax"
150154
bnez t1, 1f
@@ -161,9 +165,11 @@ data2:
161165
# RELAX-RELOC: .rela.text3a {
162166
# RELAX-RELOC-NEXT: 0x0 R_RISCV_CALL_PLT foo 0x0
163167
# RELAX-RELOC-NEXT: 0x0 R_RISCV_RELAX - 0x0
168+
# RELAX-RELOC-NEXT: 0x8 R_RISCV_BRANCH .Ltmp[[#]] 0x0
164169
# RELAX-RELOC-NEXT: 0xC R_RISCV_BRANCH .Ltmp[[#]] 0x0
165170
# RELAX-RELOC-NEXT: 0x10 R_RISCV_ALIGN - 0x4
166171
# RELAX-RELOC-NEXT: 0x14 R_RISCV_BRANCH .Ltmp[[#]] 0x0
172+
# RELAX-RELOC-NEXT: 0x18 R_RISCV_BRANCH .Ltmp[[#]] 0x0
167173
# RELAX-RELOC-NEXT: }
168174
.section .text3a, "ax"
169175
call foo
@@ -177,9 +183,11 @@ bnez t1, 2b
177183

178184
## .text3 with a call at the end
179185
# RELAX-RELOC: .rela.text3b {
186+
# RELAX-RELOC-NEXT: 0x0 R_RISCV_BRANCH .Ltmp[[#]] 0x0
180187
# RELAX-RELOC-NEXT: 0x4 R_RISCV_BRANCH .Ltmp[[#]] 0x0
181188
# RELAX-RELOC-NEXT: 0x8 R_RISCV_ALIGN - 0x4
182189
# RELAX-RELOC-NEXT: 0xC R_RISCV_BRANCH .Ltmp[[#]] 0x0
190+
# RELAX-RELOC-NEXT: 0x10 R_RISCV_BRANCH .Ltmp[[#]] 0x0
183191
# RELAX-RELOC-NEXT: 0x14 R_RISCV_CALL_PLT foo 0x0
184192
# RELAX-RELOC-NEXT: 0x14 R_RISCV_RELAX - 0x0
185193
# RELAX-RELOC-NEXT: }
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# RUN: llvm-mc --triple=riscv32 -mattr=+relax,+experimental-xqcilb \
2+
# RUN: %s -filetype=obj -o - -riscv-add-build-attributes \
3+
# RUN: | llvm-objdump -dr - \
4+
# RUN: | FileCheck %s
5+
6+
.global foo
7+
8+
bar:
9+
jal x1, foo
10+
# CHECK: qc.e.jal 0x0 <bar>
11+
# CHECK-NEXT: R_RISCV_VENDOR QUALCOMM
12+
# CHECK-NEXT: R_RISCV_CUSTOM195 foo
13+
# CHECK-NEXT: R_RISCV_RELAX *ABS*
14+
bne a0, a1, bar
15+
# CHECK-NEXT: bne a0, a1, 0x6 <bar+0x6>
16+
# CHECK-NEXT: R_RISCV_BRANCH bar
17+
ret
18+
# CHECK-NEXT: ret

0 commit comments

Comments
 (0)