Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 42 additions & 27 deletions lib/Target/RISCV/RISCVLDBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,9 +299,13 @@ bool RISCVLDBackend::doRelaxationCall(Relocation *reloc, bool DoCompressed) {
return true;
}

bool RISCVLDBackend::doRelaxationQCCall(Relocation *reloc, bool DoCompressed) {
// This function performs the relaxation to replace: QC.E.JAL or QC.E.J with
// one of JAL, C.J, or C.JAL.
bool RISCVLDBackend::doRelaxationQCCall(Relocation *reloc) {
/* Four similar relaxations can be applied here, in order of preference:
* -- qc.e.j -> c.j (saves 4 bytes)
* -- qc.e.jal -> c.jal (saves 4 bytes)
* -- qc.e.j -> jal (saves 2 bytes)
* -- qc.e.jal -> jal (saves 2 bytes)
*/

Fragment *frag = reloc->targetRef()->frag();
RegionFragmentEx *region = llvm::dyn_cast<RegionFragmentEx>(frag);
Expand All @@ -318,19 +322,20 @@ bool RISCVLDBackend::doRelaxationQCCall(Relocation *reloc, bool DoCompressed) {
Relocator::DWord P = reloc->place(m_Module);
Relocator::DWord X = S + A - P;

bool canRelaxXqci =
config().targets().is32Bits() && config().options().getRISCVRelaxXqci();
bool canRelax =
config().options().getRISCVRelax() && canRelaxXqci && llvm::isInt<21>(X);
bool canCompress = DoCompressed && llvm::isInt<12>(X);
bool canRelaxXqci = config().options().getRISCVRelax() &&
config().targets().is32Bits() &&
config().options().getRISCVRelaxXqci();

if (!canRelax) {
reportMissedRelaxation("RISCV_QC_E_CALL", *region, offset,
canCompress ? 4 : 2, reloc->symInfo()->name());
return false;
}
// For JAL, the destination must be within 21 bits.
bool canRelaxJAL = canRelaxXqci && llvm::isInt<21>(X);

if (canCompress) {
// For C.J/C.JAL, the destination must be within 12 bits. `QC.E.J` and
// `QC.E.JAL` only have destinations of `x0` and `ra` respectively, which are
// compatible with the compressed forms.
bool canRelaxC_J = canRelaxXqci && config().options().getRISCVRelaxToC() &&
llvm::isInt<12>(X);

if (canRelaxC_J) {
uint32_t compressed = isTailCall ? 0xa001 : 0x2001;
const char *msg = isTailCall ? "RISCV_QC_E_J_C" : "RISCV_QC_E_JAL_C";

Expand All @@ -353,19 +358,29 @@ bool RISCVLDBackend::doRelaxationQCCall(Relocation *reloc, bool DoCompressed) {
return true;
}

// Replace the instruction to JAL
unsigned rd = isTailCall ? /*x0*/ 0 : /*ra*/ 1;
uint32_t jal_instr = 0x6fu | rd << 7;
region->replaceInstruction(offset, reloc, jal_instr, 4);
// Replace the reloc to R_RISCV_JAL
reloc->setType(llvm::ELF::R_RISCV_JAL);
reloc->setTargetData(jal_instr);
// Delete the next instruction
const char *msg = isTailCall ? "RISCV_QC_E_J" : "RISCV_QC_E_JAL";
relaxDeleteBytes(msg, *region, offset + 4, 2,
reloc->symInfo()->name());
if (canRelaxJAL) {
// Replace the instruction to JAL
unsigned rd = isTailCall ? /*x0*/ 0 : /*ra*/ 1;
uint32_t jal_instr = 0x6fu | rd << 7;

return true;
region->replaceInstruction(offset, reloc, jal_instr, 4);
reloc->setTargetData(jal_instr);
reloc->setType(llvm::ELF::R_RISCV_JAL);
const char *msg = isTailCall ? "RISCV_QC_E_J" : "RISCV_QC_E_JAL";
// Delete the next instruction
relaxDeleteBytes(msg, *region, offset + 4, 2, reloc->symInfo()->name());

// Report missed relaxation as `C.J`/`C.JAL` would have been smaller
reportMissedRelaxation("RISCV_QC_E_CALL", *region, offset, 2,
reloc->symInfo()->name());

return true;
}

reportMissedRelaxation("RISCV_QC_E_CALL", *region, offset, 4,
reloc->symInfo()->name());

return false;
}

bool RISCVLDBackend::doRelaxationLui(Relocation *reloc, Relocator::DWord G) {
Expand Down Expand Up @@ -830,7 +845,7 @@ void RISCVLDBackend::mayBeRelax(int relaxation_pass, bool &pFinished) {
}
case ELF::riscv::internal::R_RISCV_QC_E_CALL_PLT: {
if (nextRelax && relaxation_pass == RELAXATION_CALL)
doRelaxationQCCall(relocation, DoCompressed);
doRelaxationQCCall(relocation);
break;
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Target/RISCV/RISCVLDBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ class RISCVLDBackend : public GNULDBackend {
bool isGOTReloc(Relocation *reloc) const;

bool doRelaxationCall(Relocation *R, bool DoCompressed);
bool doRelaxationQCCall(Relocation *R, bool DoCompressed);
bool doRelaxationQCCall(Relocation *R);

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,15 @@ VERBOSE_RELAX_C: RISCV_QC_E_JAL_C : Deleting 4 bytes for symbol 'f' in section .
VERBOSE_RELAX_C: RISCV_QC_E_J_C : relaxing instruction 0x00000000401f to compressed instruction 0xa001 for symbol f in section .text+0x77A file {{.*}}.o
VERBOSE_RELAX_C: RISCV_QC_E_J_C : Deleting 4 bytes for symbol 'f' in section .text+0x77c file {{.*}}.o
VERBOSE_RELAX_C: RISCV_QC_E_JAL : Deleting 2 bytes for symbol 'f' in section .text+0x874 file {{.*}}.o
VERBOSE_RELAX_C: RISCV_QC_E_CALL : Cannot relax 2 bytes for symbol 'f' in section .text+0x870 file {{.*}}.o
VERBOSE_RELAX_C: RISCV_QC_E_J : Deleting 2 bytes for symbol 'f' in section .text+0x878 file {{.*}}.o
VERBOSE_RELAX_C: RISCV_QC_E_CALL : Cannot relax 2 bytes for symbol 'f' in section .text+0x874 file {{.*}}.o
VERBOSE_RELAX_C: RISCV_QC_E_JAL : Deleting 2 bytes for symbol 'f' in section .text+0xffef0 file {{.*}}.o
VERBOSE_RELAX_C: RISCV_QC_E_CALL : Cannot relax 2 bytes for symbol 'f' in section .text+0xffeec file {{.*}}.o
VERBOSE_RELAX_C: RISCV_QC_E_J : Deleting 2 bytes for symbol 'f' in section .text+0xffef4 file {{.*}}.o
VERBOSE_RELAX_C: RISCV_QC_E_CALL : Cannot relax 2 bytes for symbol 'f' in section .text+0x1000e8 file {{.*}}.o
VERBOSE_RELAX_C: RISCV_QC_E_CALL : Cannot relax 2 bytes for symbol 'f' in section .text+0x1000ee file {{.*}}.o
VERBOSE_RELAX_C: RISCV_QC_E_CALL : Cannot relax 2 bytes for symbol 'f' in section .text+0xffef0 file {{.*}}.o
VERBOSE_RELAX_C: RISCV_QC_E_CALL : Cannot relax 4 bytes for symbol 'f' in section .text+0x1000e8 file {{.*}}.o
VERBOSE_RELAX_C: RISCV_QC_E_CALL : Cannot relax 4 bytes for symbol 'f' in section .text+0x1000ee file {{.*}}.o

RUN: %objdump -d %t.1.out 2>&1 | %filecheck %s --check-prefix=DUMP_RELAX_C
RUN: %objdump -d %t.1.so 2>&1 | %filecheck %s --check-prefix=DUMP_RELAX_C
Expand All @@ -41,27 +45,35 @@ RUN: %filecheck %s --input-file=%t.1.map --check-prefix=MAP_RELAX_C
RUN: %filecheck %s --input-file=%t.1.so.map --check-prefix=MAP_RELAX_C
MAP_RELAX_C: # LinkStats Begin
MAP_RELAX_C: # RelaxationBytesDeleted : 24
MAP_RELAX_C: # RelaxationBytesMissed : 4
MAP_RELAX_C: # RelaxationBytesMissed : 16
MAP_RELAX_C: # LinkStats End

MAP_RELAX_C: .text {{.+}}, Alignment: 0x2, Flags: SHF_ALLOC|SHF_EXECINSTR, Type: SHT_PROGBITS
MAP_RELAX_C: # RelaxationBytesDeleted : 24
MAP_RELAX_C: # RelaxationBytesMissed : 4
MAP_RELAX_C: # RelaxationBytesMissed : 16
MAP_RELAX_C: .text {{.+}}.o #SHT_PROGBITS,SHF_ALLOC|SHF_EXECINSTR,2

# Only non-compressed relaxations are enabled.
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
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
VERBOSE_RELAX: RISCV_QC_E_JAL : Deleting 2 bytes for symbol 'f' in section .text+0x8 file {{.*}}.o
VERBOSE_RELAX: RISCV_QC_E_CALL : Cannot relax 2 bytes for symbol 'f' in section .text+0x4 file {{.*}}.o
VERBOSE_RELAX: RISCV_QC_E_J : Deleting 2 bytes for symbol 'f' in section .text+0xc file {{.*}}.o
VERBOSE_RELAX: RISCV_QC_E_CALL : Cannot relax 2 bytes for symbol 'f' in section .text+0x8 file {{.*}}.o
VERBOSE_RELAX: RISCV_QC_E_JAL : Deleting 2 bytes for symbol 'f' in section .text+0x780 file {{.*}}.o
VERBOSE_RELAX: RISCV_QC_E_CALL : Cannot relax 2 bytes for symbol 'f' in section .text+0x77c file {{.*}}.o
VERBOSE_RELAX: RISCV_QC_E_J : Deleting 2 bytes for symbol 'f' in section .text+0x784 file {{.*}}.o
VERBOSE_RELAX: RISCV_QC_E_CALL : Cannot relax 2 bytes for symbol 'f' in section .text+0x780 file {{.*}}.o
VERBOSE_RELAX: RISCV_QC_E_JAL : Deleting 2 bytes for symbol 'f' in section .text+0x87c file {{.*}}.o
VERBOSE_RELAX: RISCV_QC_E_CALL : Cannot relax 2 bytes for symbol 'f' in section .text+0x878 file {{.*}}.o
VERBOSE_RELAX: RISCV_QC_E_J : Deleting 2 bytes for symbol 'f' in section .text+0x880 file {{.*}}.o
VERBOSE_RELAX: RISCV_QC_E_CALL : Cannot relax 2 bytes for symbol 'f' in section .text+0x87c file {{.*}}.o
VERBOSE_RELAX: RISCV_QC_E_JAL : Deleting 2 bytes for symbol 'f' in section .text+0xffef8 file {{.*}}.o
VERBOSE_RELAX: RISCV_QC_E_CALL : Cannot relax 2 bytes for symbol 'f' in section .text+0xffef4 file {{.*}}.o
VERBOSE_RELAX: RISCV_QC_E_J : Deleting 2 bytes for symbol 'f' in section .text+0xffefc file {{.*}}.o
VERBOSE_RELAX: RISCV_QC_E_CALL : Cannot relax 2 bytes for symbol 'f' in section .text+0x1000f0 file {{.*}}.o
VERBOSE_RELAX: RISCV_QC_E_CALL : Cannot relax 2 bytes for symbol 'f' in section .text+0x1000f6 file {{.*}}.o
VERBOSE_RELAX: RISCV_QC_E_CALL : Cannot relax 2 bytes for symbol 'f' in section .text+0xffef8 file {{.*}}.o
VERBOSE_RELAX: RISCV_QC_E_CALL : Cannot relax 4 bytes for symbol 'f' in section .text+0x1000f0 file {{.*}}.o
VERBOSE_RELAX: RISCV_QC_E_CALL : Cannot relax 4 bytes for symbol 'f' in section .text+0x1000f6 file {{.*}}.o

RUN: %objdump -d %t.2.out 2>&1 | %filecheck %s --check-prefix=DUMP_RELAX
RUN: %objdump -d %t.2.so 2>&1 | %filecheck %s --check-prefix=DUMP_RELAX
Expand All @@ -80,10 +92,12 @@ RUN: %filecheck %s --input-file=%t.2.map --check-prefix=MAP_RELAX
RUN: %filecheck %s --input-file=%t.2.so.map --check-prefix=MAP_RELAX
MAP_RELAX: # LinkStats Begin
MAP_RELAX: # RelaxationBytesDeleted : 16
MAP_RELAX: # RelaxationBytesMissed : 24
MAP_RELAX: # LinkStats End

MAP_RELAX: .text {{.+}}, Alignment: 0x2, Flags: SHF_ALLOC|SHF_EXECINSTR, Type: SHT_PROGBITS
MAP_RELAX: # RelaxationBytesDeleted : 16
MAP_RELAX: # RelaxationBytesMissed : 24
MAP_RELAX: .text {{.+}}.o #SHT_PROGBITS,SHF_ALLOC|SHF_EXECINSTR,2

### Relaxations are disabled.
Expand All @@ -108,9 +122,11 @@ DUMP_NORELAX: qc.e.j
RUN: %filecheck %s --input-file=%t.3.map --check-prefix=MAP_NORELAX
RUN: %filecheck %s --input-file=%t.3.so.map --check-prefix=MAP_NORELAX
MAP_NORELAX: # LinkStats Begin
MAP_NORELAX: # RelaxationBytesMissed : 40
MAP_NORELAX-NOT: # RelaxationBytesDeleted
MAP_NORELAX: # LinkStats End

MAP_NORELAX: .text {{.+}}, Alignment: 0x2, Flags: SHF_ALLOC|SHF_EXECINSTR, Type: SHT_PROGBITS
MAP_NORELAX: # RelaxationBytesMissed : 40
MAP_NORELAX-NOT: # RelaxationBytesDeleted
MAP_NORELAX: .text {{.+}}.o #SHT_PROGBITS,SHF_ALLOC|SHF_EXECINSTR,2
Loading