Skip to content

Commit 5771499

Browse files
lenaryquic-seaswara
authored andcommitted
[RISCV] Implement Relaxations for QC.E.J/QC.E.JAL
These relaxations are like call relaxations, so they are done in the same phase as call relaxations. The Relaxations are: - QC.E.J to C.J or JAL X0 - QC.E.JAL to C.JAL or JAL X1 This change also adds a command-line switch for turning off all the xqci relaxations, which defaults to Off. Signed-off-by: Sam Elliott <[email protected]>
1 parent a843223 commit 5771499

File tree

9 files changed

+268
-0
lines changed

9 files changed

+268
-0
lines changed

include/eld/Config/GeneralOptions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,10 @@ class GeneralOptions {
870870

871871
bool getRISCVRelaxToC() const { return BRiscvRelaxToC; }
872872

873+
void setRISCVRelaxXqci(bool Value) { BRiscvRelaxXqci = Value; }
874+
875+
bool getRISCVRelaxXqci() const { return BRiscvRelaxXqci; }
876+
873877
bool warnCommon() const { return BWarnCommon; }
874878

875879
void setWarnCommon() { BWarnCommon = true; }
@@ -1225,6 +1229,7 @@ class GeneralOptions {
12251229
bool RiscvZeroRelax = true; // Zero-page relaxation
12261230
bool RiscvGPRelax = true; // GP relaxation
12271231
bool BRiscvRelaxToC = true; // enable riscv relax to compressed code
1232+
bool BRiscvRelaxXqci = false; // enable riscv relaxations for xqci
12281233
bool AllowIncompatibleSectionsMix = false; // Allow incompatibleSections;
12291234
bool ProgressBar = false; // Show progressbar.
12301235
bool RecordInputFiles = false; // --reproduce

include/eld/Driver/RISCVLinkerOptions.td

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ def no_riscv_relax_compressed
4141
HelpText<"Disable relaxation to compressed instructions">,
4242
Group<grp_riscv_linker>;
4343

44+
def riscv_relax_xqci
45+
: Flag<["--"], "relax-xqci">,
46+
HelpText<"Enable relaxing to/from Xqci instructions">,
47+
Group<grp_riscv_linker>;
48+
def no_riscv_relax_xqci
49+
: Flag<["--"], "no-relax-xqci">,
50+
HelpText<"Disable relaxing to/from Xqci instructions (default behavior)">,
51+
Group<grp_riscv_linker>;
52+
4453
def riscv_relax : Flag<["--"], "relax">,
4554
HelpText<"Enable relaxation (default behavior)">,
4655
Group<grp_riscv_linker>;

lib/LinkerWrapper/RISCVLinkDriver.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@ opt::OptTable *RISCVLinkDriver::parseOptions(ArrayRef<const char *> Args,
121121
if (ArgList.hasArg(OPT_RISCVLinkOptTable::no_riscv_relax_compressed))
122122
Config.options().setRISCVRelaxToC(false);
123123

124+
// --relax-xqci, --no-relax-xqci (default)
125+
Config.options().setRISCVRelaxXqci(
126+
ArgList.hasFlag(OPT_RISCVLinkOptTable::riscv_relax_xqci,
127+
OPT_RISCVLinkOptTable::no_riscv_relax_xqci, false));
128+
124129
// --enable-bss-mixing
125130
if (ArgList.hasArg(OPT_RISCVLinkOptTable::enable_bss_mixing))
126131
Config.options().setAllowBSSMixing(true);

lib/Target/RISCV/RISCVLDBackend.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,75 @@ bool RISCVLDBackend::doRelaxationCall(Relocation *reloc, bool DoCompressed) {
299299
return true;
300300
}
301301

302+
bool RISCVLDBackend::doRelaxationQCCall(Relocation *reloc, bool DoCompressed) {
303+
// This function performs the relaxation to replace: QC.E.JAL or QC.E.J with
304+
// one of JAL, C.J, or C.JAL.
305+
306+
Fragment *frag = reloc->targetRef()->frag();
307+
RegionFragmentEx *region = llvm::dyn_cast<RegionFragmentEx>(frag);
308+
if (!region)
309+
return true;
310+
uint64_t offset = reloc->targetRef()->offset();
311+
312+
// extract instruction
313+
uint64_t qc_e_jump = reloc->target() & 0xffffffffffff;
314+
bool isTailCall = (qc_e_jump & 0xf1f07f) == 0x00401f;
315+
316+
Relocator::DWord S = getSymbolValuePLT(*reloc);
317+
Relocator::DWord A = reloc->addend();
318+
Relocator::DWord P = reloc->place(m_Module);
319+
Relocator::DWord X = S + A - P;
320+
321+
bool canRelaxXqci =
322+
config().targets().is32Bits() && config().options().getRISCVRelaxXqci();
323+
bool canRelax =
324+
config().options().getRISCVRelax() && canRelaxXqci && llvm::isInt<21>(X);
325+
bool canCompress = DoCompressed && llvm::isInt<12>(X);
326+
327+
if (!canRelax) {
328+
reportMissedRelaxation("RISCV_QC_E_CALL", *region, offset,
329+
canCompress ? 4 : 2, reloc->symInfo()->name());
330+
return false;
331+
}
332+
333+
if (canCompress) {
334+
uint32_t compressed = isTailCall ? 0xa001 : 0x2001;
335+
const char *msg = isTailCall ? "RISCV_QC_E_J_C" : "RISCV_QC_E_JAL_C";
336+
337+
if (m_Module.getPrinter()->isVerbose())
338+
config().raise(Diag::relax_to_compress)
339+
<< msg << llvm::utohexstr(qc_e_jump, true, 12)
340+
<< llvm::utohexstr(compressed, true, 4) << reloc->symInfo()->name()
341+
<< region->getOwningSection()->name() << llvm::utohexstr(offset)
342+
<< region->getOwningSection()
343+
->getInputFile()
344+
->getInput()
345+
->decoratedPath();
346+
347+
region->replaceInstruction(offset, reloc, compressed, 2);
348+
// Replace the reloc to R_RISCV_RVC_JUMP
349+
reloc->setType(llvm::ELF::R_RISCV_RVC_JUMP);
350+
reloc->setTargetData(compressed);
351+
relaxDeleteBytes(msg, *region, offset + 2, 4,
352+
reloc->symInfo()->name());
353+
return true;
354+
}
355+
356+
// Replace the instruction to JAL
357+
unsigned rd = isTailCall ? /*x0*/ 0 : /*ra*/ 1;
358+
uint32_t jal_instr = 0x6fu | rd << 7;
359+
region->replaceInstruction(offset, reloc, jal_instr, 4);
360+
// Replace the reloc to R_RISCV_JAL
361+
reloc->setType(llvm::ELF::R_RISCV_JAL);
362+
reloc->setTargetData(jal_instr);
363+
// Delete the next instruction
364+
const char *msg = isTailCall ? "RISCV_QC_E_J" : "RISCV_QC_E_JAL";
365+
relaxDeleteBytes(msg, *region, offset + 4, 2,
366+
reloc->symInfo()->name());
367+
368+
return true;
369+
}
370+
302371
bool RISCVLDBackend::doRelaxationLui(Relocation *reloc, Relocator::DWord G) {
303372

304373
/* Three types of relaxation can be applied here, in order of preference:
@@ -759,6 +828,11 @@ void RISCVLDBackend::mayBeRelax(int relaxation_pass, bool &pFinished) {
759828
pFinished = false;
760829
break;
761830
}
831+
case ELF::riscv::internal::R_RISCV_QC_E_CALL_PLT: {
832+
if (nextRelax && relaxation_pass == RELAXATION_CALL)
833+
doRelaxationQCCall(relocation, DoCompressed);
834+
break;
835+
}
762836
}
763837
if (!config().getDiagEngine()->diagnose()) {
764838
m_Module.setFailure(true);

lib/Target/RISCV/RISCVLDBackend.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ class RISCVLDBackend : public GNULDBackend {
198198
bool isGOTReloc(Relocation *reloc) const;
199199

200200
bool doRelaxationCall(Relocation *R, bool DoCompressed);
201+
bool doRelaxationQCCall(Relocation *R, bool DoCompressed);
201202

202203
bool doRelaxationLui(Relocation *R, Relocation::DWord G);
203204

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.text
2+
.global f
3+
f:
4+
/* exact+relax needed while llvm/llvm-project#142702 is not yet fixed/landed */
5+
.option exact
6+
.option relax
7+
8+
qc.e.jal f
9+
qc.e.j f
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/* exact+relax needed while llvm/llvm-project#142702 is not yet fixed/landed */
2+
.option exact
3+
.option relax
4+
5+
.text
6+
.align 1
7+
.type f, @function
8+
f:
9+
ret
10+
.size f, .-f
11+
12+
.align 1
13+
.globl main
14+
.type main, @function
15+
main:
16+
qc.e.jal f
17+
qc.e.j f
18+
19+
.org 0x780
20+
qc.e.jal f
21+
qc.e.j f
22+
23+
.org 0x880
24+
qc.e.jal f
25+
qc.e.j f
26+
27+
.org 0xfff00
28+
qc.e.jal f
29+
qc.e.j f
30+
31+
.org 0x100100
32+
qc.e.jal f
33+
qc.e.j f
34+
35+
.size main, .-main
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#----------QC_E_CALL_TO_JAL.test----------------- Executable------------------#
2+
#BEGIN_COMMENT
3+
# Do relaxation from QC.E.J and QC.E.JAL to JAL or C.J/C.JAL
4+
#END_COMMENT
5+
#--------------------------------------------------------------------
6+
REQUIRES: riscv32
7+
RUN: %clang %clangopts -c %p/Inputs/x.s -o %t.o -menable-experimental-extensions -march=rv32gc_xqcilb0p2
8+
9+
# Relaxations are enabled, including compressed ones.
10+
RUN: %link %linkopts --relax-xqci %t.o -o %t.1.out -MapStyle txt -Map %t.1.map --verbose 2>&1 | %filecheck %s --check-prefix=VERBOSE_RELAX_C
11+
RUN: %link %linkopts --relax-xqci %t.o -o %t.1.so -shared -MapStyle txt -Map %t.1.so.map --verbose 2>&1 | %filecheck %s --check-prefix=VERBOSE_RELAX_C
12+
VERBOSE_RELAX_C: RISCV_QC_E_JAL_C : relaxing instruction 0x00000000c01f to compressed instruction 0x2001 for symbol f in section .text+0x4 file {{.*}}.o
13+
VERBOSE_RELAX_C: RISCV_QC_E_JAL_C : Deleting 4 bytes for symbol 'f' in section .text+0x6 file {{.*}}.o
14+
VERBOSE_RELAX_C: RISCV_QC_E_J_C : relaxing instruction 0x00000000401f to compressed instruction 0xa001 for symbol f in section .text+0x6 file {{.*}}.o
15+
VERBOSE_RELAX_C: RISCV_QC_E_J_C : Deleting 4 bytes for symbol 'f' in section .text+0x8 file {{.*}}.o
16+
VERBOSE_RELAX_C: RISCV_QC_E_JAL_C : relaxing instruction 0x00000000c01f to compressed instruction 0x2001 for symbol f in section .text+0x778 file {{.*}}.o
17+
VERBOSE_RELAX_C: RISCV_QC_E_JAL_C : Deleting 4 bytes for symbol 'f' in section .text+0x77a file {{.*}}.o
18+
VERBOSE_RELAX_C: RISCV_QC_E_J_C : relaxing instruction 0x00000000401f to compressed instruction 0xa001 for symbol f in section .text+0x77A file {{.*}}.o
19+
VERBOSE_RELAX_C: RISCV_QC_E_J_C : Deleting 4 bytes for symbol 'f' in section .text+0x77c file {{.*}}.o
20+
VERBOSE_RELAX_C: RISCV_QC_E_JAL : Deleting 2 bytes for symbol 'f' in section .text+0x874 file {{.*}}.o
21+
VERBOSE_RELAX_C: RISCV_QC_E_J : Deleting 2 bytes for symbol 'f' in section .text+0x878 file {{.*}}.o
22+
VERBOSE_RELAX_C: RISCV_QC_E_JAL : Deleting 2 bytes for symbol 'f' in section .text+0xffef0 file {{.*}}.o
23+
VERBOSE_RELAX_C: RISCV_QC_E_J : Deleting 2 bytes for symbol 'f' in section .text+0xffef4 file {{.*}}.o
24+
VERBOSE_RELAX_C: RISCV_QC_E_CALL : Cannot relax 2 bytes for symbol 'f' in section .text+0x1000e8 file {{.*}}.o
25+
VERBOSE_RELAX_C: RISCV_QC_E_CALL : Cannot relax 2 bytes for symbol 'f' in section .text+0x1000ee file {{.*}}.o
26+
27+
RUN: %objdump -d %t.1.out 2>&1 | %filecheck %s --check-prefix=DUMP_RELAX_C
28+
RUN: %objdump -d %t.1.so 2>&1 | %filecheck %s --check-prefix=DUMP_RELAX_C
29+
DUMP_RELAX_C: 3ff5 jal 0x{{[[:xdigit:]]+}} <f>
30+
DUMP_RELAX_C: bfed j 0x{{[[:xdigit:]]+}} <f>
31+
DUMP_RELAX_C: 3061 jal 0x{{[[:xdigit:]]+}} <f>
32+
DUMP_RELAX_C: b059 j 0x{{[[:xdigit:]]+}} <f>
33+
DUMP_RELAX_C: f90ff0ef jal 0x{{[[:xdigit:]]+}} <f>
34+
DUMP_RELAX_C: f8cff06f j 0x{{[[:xdigit:]]+}} <f>
35+
DUMP_RELAX_C: 914000ef jal 0x{{[[:xdigit:]]+}} <f>
36+
DUMP_RELAX_C: 9100006f j 0x{{[[:xdigit:]]+}} <f>
37+
DUMP_RELAX_C: cc9f f00e ffef qc.e.jal 0x{{[[:xdigit:]]+}} <f>
38+
DUMP_RELAX_C: 499f f00e ffef qc.e.j 0x{{[[:xdigit:]]+}} <f>
39+
40+
RUN: %filecheck %s --input-file=%t.1.map --check-prefix=MAP_RELAX_C
41+
RUN: %filecheck %s --input-file=%t.1.so.map --check-prefix=MAP_RELAX_C
42+
MAP_RELAX_C: # LinkStats Begin
43+
MAP_RELAX_C: # RelaxationBytesDeleted : 24
44+
MAP_RELAX_C: # RelaxationBytesMissed : 4
45+
MAP_RELAX_C: # LinkStats End
46+
47+
MAP_RELAX_C: .text {{.+}}, Alignment: 0x2, Flags: SHF_ALLOC|SHF_EXECINSTR, Type: SHT_PROGBITS
48+
MAP_RELAX_C: # RelaxationBytesDeleted : 24
49+
MAP_RELAX_C: # RelaxationBytesMissed : 4
50+
MAP_RELAX_C: .text {{.+}}.o #SHT_PROGBITS,SHF_ALLOC|SHF_EXECINSTR,2
51+
52+
# Only non-compressed relaxations are enabled.
53+
RUN: %link %linkopts --relax-xqci --no-relax-c %t.o -o %t.2.out -MapStyle txt -Map %t.2.map --verbose 2>&1 | %filecheck %s --check-prefix=VERBOSE_RELAX
54+
RUN: %link %linkopts --relax-xqci --no-relax-c %t.o -o %t.2.so -shared -MapStyle txt -Map %t.2.so.map --verbose 2>&1 | %filecheck %s --check-prefix=VERBOSE_RELAX
55+
VERBOSE_RELAX: RISCV_QC_E_JAL : Deleting 2 bytes for symbol 'f' in section .text+0x8 file {{.*}}.o
56+
VERBOSE_RELAX: RISCV_QC_E_J : Deleting 2 bytes for symbol 'f' in section .text+0xc file {{.*}}.o
57+
VERBOSE_RELAX: RISCV_QC_E_JAL : Deleting 2 bytes for symbol 'f' in section .text+0x780 file {{.*}}.o
58+
VERBOSE_RELAX: RISCV_QC_E_J : Deleting 2 bytes for symbol 'f' in section .text+0x784 file {{.*}}.o
59+
VERBOSE_RELAX: RISCV_QC_E_JAL : Deleting 2 bytes for symbol 'f' in section .text+0x87c file {{.*}}.o
60+
VERBOSE_RELAX: RISCV_QC_E_J : Deleting 2 bytes for symbol 'f' in section .text+0x880 file {{.*}}.o
61+
VERBOSE_RELAX: RISCV_QC_E_JAL : Deleting 2 bytes for symbol 'f' in section .text+0xffef8 file {{.*}}.o
62+
VERBOSE_RELAX: RISCV_QC_E_J : Deleting 2 bytes for symbol 'f' in section .text+0xffefc file {{.*}}.o
63+
VERBOSE_RELAX: RISCV_QC_E_CALL : Cannot relax 2 bytes for symbol 'f' in section .text+0x1000f0 file {{.*}}.o
64+
VERBOSE_RELAX: RISCV_QC_E_CALL : Cannot relax 2 bytes for symbol 'f' in section .text+0x1000f6 file {{.*}}.o
65+
66+
RUN: %objdump -d %t.2.out 2>&1 | %filecheck %s --check-prefix=DUMP_RELAX
67+
RUN: %objdump -d %t.2.so 2>&1 | %filecheck %s --check-prefix=DUMP_RELAX
68+
DUMP_RELAX: ffdff0ef jal 0x{{[[:xdigit:]]+}} <f>
69+
DUMP_RELAX: ff9ff06f j 0x{{[[:xdigit:]]+}} <f>
70+
DUMP_RELAX: 885ff0ef jal 0x{{[[:xdigit:]]+}} <f>
71+
DUMP_RELAX: 881ff06f j 0x{{[[:xdigit:]]+}} <f>
72+
DUMP_RELAX: f88ff0ef jal 0x{{[[:xdigit:]]+}} <f>
73+
DUMP_RELAX: f84ff06f j 0x{{[[:xdigit:]]+}} <f>
74+
DUMP_RELAX: 90c000ef jal 0x{{[[:xdigit:]]+}} <f>
75+
DUMP_RELAX: 9080006f j 0x{{[[:xdigit:]]+}} <f>
76+
DUMP_RELAX: c89f f00e ffef qc.e.jal 0x{{[[:xdigit:]]+}} <f>
77+
DUMP_RELAX: 459f f00e ffef qc.e.j 0x{{[[:xdigit:]]+}} <f>
78+
79+
RUN: %filecheck %s --input-file=%t.2.map --check-prefix=MAP_RELAX
80+
RUN: %filecheck %s --input-file=%t.2.so.map --check-prefix=MAP_RELAX
81+
MAP_RELAX: # LinkStats Begin
82+
MAP_RELAX: # RelaxationBytesDeleted : 16
83+
MAP_RELAX: # LinkStats End
84+
85+
MAP_RELAX: .text {{.+}}, Alignment: 0x2, Flags: SHF_ALLOC|SHF_EXECINSTR, Type: SHT_PROGBITS
86+
MAP_RELAX: # RelaxationBytesDeleted : 16
87+
MAP_RELAX: .text {{.+}}.o #SHT_PROGBITS,SHF_ALLOC|SHF_EXECINSTR,2
88+
89+
### Relaxations are disabled.
90+
RUN: %link %linkopts --no-relax-xqci --no-relax %t.o -o %t.3.out -MapStyle txt -Map %t.3.map --verbose 2>&1 | %filecheck %s --check-prefix=VERBOSE_NORELAX
91+
RUN: %link %linkopts --no-relax-xqci --no-relax %t.o -o %t.3.so -shared -MapStyle txt -Map %t.3.so.map --verbose 2>&1 | %filecheck %s --check-prefix=VERBOSE_NORELAX
92+
VERBOSE_NORELAX-COUNT-10: RISCV_QC_E_CALL : Cannot relax
93+
VERBOSE_NORELAX-NOT: Deleting
94+
95+
RUN: %objdump -d %t.3.out 2>&1 | %filecheck %s --check-prefix=DUMP_NORELAX
96+
RUN: %objdump -d %t.3.so 2>&1 | %filecheck %s --check-prefix=DUMP_NORELAX
97+
DUMP_NORELAX: qc.e.jal
98+
DUMP_NORELAX: qc.e.j
99+
DUMP_NORELAX: qc.e.jal
100+
DUMP_NORELAX: qc.e.j
101+
DUMP_NORELAX: qc.e.jal
102+
DUMP_NORELAX: qc.e.j
103+
DUMP_NORELAX: qc.e.jal
104+
DUMP_NORELAX: qc.e.j
105+
DUMP_NORELAX: qc.e.jal
106+
DUMP_NORELAX: qc.e.j
107+
108+
RUN: %filecheck %s --input-file=%t.3.map --check-prefix=MAP_NORELAX
109+
RUN: %filecheck %s --input-file=%t.3.so.map --check-prefix=MAP_NORELAX
110+
MAP_NORELAX: # LinkStats Begin
111+
MAP_NORELAX-NOT: # RelaxationBytesDeleted
112+
MAP_NORELAX: # LinkStats End
113+
114+
MAP_NORELAX: .text {{.+}}, Alignment: 0x2, Flags: SHF_ALLOC|SHF_EXECINSTR, Type: SHT_PROGBITS
115+
MAP_NORELAX-NOT: # RelaxationBytesDeleted
116+
MAP_NORELAX: .text {{.+}}.o #SHT_PROGBITS,SHF_ALLOC|SHF_EXECINSTR,2
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#----------QC_E_CALL_TO_JAL_PLT.test-------------------------------#
2+
#BEGIN_COMMENT
3+
# Check that offset to PLT is used when relaxing.
4+
#END_COMMENT
5+
#--------------------------------------------------------------------
6+
REQUIRES: riscv32
7+
RUN: %clang %clangopts -c %p/Inputs/shared.s -o %t.shared.o -menable-experimental-extensions -march=rv32gc_xqcilb0p2
8+
RUN: %link %linkopts --relax-xqci -shared %t.shared.o -o %t.so --section-start=.text=0x1000 --section-start=.plt=0x20000
9+
RUN: %objdump -d %t.so 2>&1 | %filecheck %s
10+
11+
CHECK: {{0+}}20000 <.plt>:
12+
CHECK: {{0+}}01000 <f>:
13+
1000: 0201f0ef jal 0x20020 <.plt+0x20>
14+
1004: 01c1f06f j 0x20020 <.plt+0x20>

0 commit comments

Comments
 (0)