[ELF] Optimize basic block section bytesDropped/jumpInstrMods

and make them more space efficient. This decreases sizeof(InputSection) from 176
to 160, and decreases peak memory usage by 0.3% when linking Chrome.
This commit is contained in:
Fangrui Song 2021-12-26 22:17:30 -08:00
parent ec501f15a8
commit e90c8c0422
4 changed files with 14 additions and 13 deletions

View File

@ -304,7 +304,8 @@ bool X86_64::deleteFallThruJmpInsn(InputSection &is, InputFile *file,
JmpInsnOpcode jInvert = invertJmpOpcode(jmpOpcodeB); JmpInsnOpcode jInvert = invertJmpOpcode(jmpOpcodeB);
if (jInvert == J_UNKNOWN) if (jInvert == J_UNKNOWN)
return false; return false;
is.jumpInstrMods.push_back({jInvert, (rB.offset - 1), 4}); is.jumpInstrMod = make<JumpInstrMod>();
*is.jumpInstrMod = {rB.offset - 1, jInvert, 4};
// Move R's values to rB except the offset. // Move R's values to rB except the offset.
rB = {r.expr, r.type, rB.offset, r.addend, r.sym}; rB = {r.expr, r.type, rB.offset, r.addend, r.sym};
// Cancel R // Cancel R

View File

@ -1106,12 +1106,9 @@ void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd) {
// a jmp insn must be modified to shrink the jmp insn or to flip the jmp // a jmp insn must be modified to shrink the jmp insn or to flip the jmp
// insn. This is primarily used to relax and optimize jumps created with // insn. This is primarily used to relax and optimize jumps created with
// basic block sections. // basic block sections.
if (isa<InputSection>(this)) { if (jumpInstrMod) {
for (const JumpInstrMod &jumpMod : jumpInstrMods) { target.applyJumpInstrMod(buf + jumpInstrMod->offset, jumpInstrMod->original,
uint64_t offset = jumpMod.offset; jumpInstrMod->size);
uint8_t *bufLoc = buf + offset;
target.applyJumpInstrMod(bufLoc, jumpMod.original, jumpMod.size);
}
} }
} }

View File

@ -130,13 +130,16 @@ public:
// one or two jump instructions at the end that could be relaxed to a smaller // one or two jump instructions at the end that could be relaxed to a smaller
// instruction. The members below help trimming the trailing jump instruction // instruction. The members below help trimming the trailing jump instruction
// and shrinking a section. // and shrinking a section.
unsigned bytesDropped = 0; uint8_t bytesDropped = 0;
// Whether the section needs to be padded with a NOP filler due to // Whether the section needs to be padded with a NOP filler due to
// deleteFallThruJmpInsn. // deleteFallThruJmpInsn.
bool nopFiller = false; bool nopFiller = false;
void drop_back(uint64_t num) { bytesDropped += num; } void drop_back(unsigned num) {
assert(bytesDropped + num < 256);
bytesDropped += num;
}
void push_back(uint64_t num) { void push_back(uint64_t num) {
assert(bytesDropped >= num); assert(bytesDropped >= num);
@ -203,7 +206,7 @@ public:
// block sections are enabled. Basic block sections creates opportunities to // block sections are enabled. Basic block sections creates opportunities to
// relax jump instructions at basic block boundaries after reordering the // relax jump instructions at basic block boundaries after reordering the
// basic blocks. // basic blocks.
SmallVector<JumpInstrMod, 0> jumpInstrMods; JumpInstrMod *jumpInstrMod = nullptr;
// A function compiled with -fsplit-stack calling a function // A function compiled with -fsplit-stack calling a function
// compiled without -fsplit-stack needs its prologue adjusted. Find // compiled without -fsplit-stack needs its prologue adjusted. Find
@ -377,9 +380,9 @@ private:
}; };
#ifdef _WIN32 #ifdef _WIN32
static_assert(sizeof(InputSection) <= 184, "InputSection is too big"); static_assert(sizeof(InputSection) <= 168, "InputSection is too big");
#else #else
static_assert(sizeof(InputSection) <= 176, "InputSection is too big"); static_assert(sizeof(InputSection) <= 160, "InputSection is too big");
#endif #endif
inline bool isDebugSection(const InputSectionBase &sec) { inline bool isDebugSection(const InputSectionBase &sec) {

View File

@ -117,8 +117,8 @@ struct Relocation {
// jump instruction opcodes at basic block boundaries and are particularly // jump instruction opcodes at basic block boundaries and are particularly
// useful when basic block sections are enabled. // useful when basic block sections are enabled.
struct JumpInstrMod { struct JumpInstrMod {
JumpModType original;
uint64_t offset; uint64_t offset;
JumpModType original;
unsigned size; unsigned size;
}; };