[BOLT][AArch64] Add support for LDR relaxation on LDRSWl (#196051)

BOLT currently supports LDR relaxation for LDRXl and LDRWl. Add support
for LDR relaxation on LDRSWl.
This commit is contained in:
Shanzhi Chen 2026-05-08 20:07:09 +08:00 committed by GitHub
parent 27c5421df2
commit 51e82b849c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 58 additions and 24 deletions

View file

@ -861,12 +861,7 @@ public:
return false;
}
virtual bool isLDRWl(const MCInst &Inst) const {
llvm_unreachable("not implemented");
return false;
}
virtual bool isLDRXl(const MCInst &Inst) const {
virtual bool isLoadLiteralGPR(const MCInst &Inst) const {
llvm_unreachable("not implemented");
return false;
}

View file

@ -46,7 +46,7 @@ void AArch64RelaxationPass::runOnFunction(BinaryFunction &BF) {
bool IsADR = BC.MIB->isADR(Inst);
// TODO: Handle other types of LDR (literal, PC-relative) instructions.
if (!IsADR && !BC.MIB->isLDRXl(Inst) && !BC.MIB->isLDRWl(Inst))
if (!IsADR && !BC.MIB->isLoadLiteralGPR(Inst))
continue;
const MCSymbol *Symbol = BC.MIB->getTargetSymbol(Inst, IsADR ? 0 : 1);

View file

@ -715,12 +715,10 @@ public:
return Inst.getOpcode() == AArch64::ADDXri;
}
bool isLDRWl(const MCInst &Inst) const override {
return Inst.getOpcode() == AArch64::LDRWl;
}
bool isLDRXl(const MCInst &Inst) const override {
return Inst.getOpcode() == AArch64::LDRXl;
bool isLoadLiteralGPR(const MCInst &Inst) const override {
unsigned OpCode = Inst.getOpcode();
return OpCode == AArch64::LDRWl || OpCode == AArch64::LDRXl ||
OpCode == AArch64::LDRSWl;
}
MCPhysReg getADRReg(const MCInst &Inst) const {
@ -744,16 +742,36 @@ public:
InstructionListType createAdrpLdr(const MCInst &LDRInst,
MCContext *Ctx) const override {
assert((isLDRXl(LDRInst) || isLDRWl(LDRInst)) &&
"LDR (literal, 32 or 64-bit integer load) instruction expected");
assert(isLoadLiteralGPR(LDRInst) &&
"LDR (literal) or LDRSW (literal) expected");
assert(LDRInst.getOperand(0).isReg() &&
"unexpected operand in LDR instruction");
const MCPhysReg DataReg = LDRInst.getOperand(0).getReg();
const MCPhysReg AddrReg =
isLDRXl(LDRInst) ? DataReg
: (MCPhysReg)RegInfo->getMatchingSuperReg(
DataReg, AArch64::sub_32,
&RegInfo->getRegClass(AArch64::GPR64RegClassID));
MCPhysReg AddrReg;
unsigned OpCode;
uint32_t RelType;
switch (LDRInst.getOpcode()) {
case AArch64::LDRWl:
AddrReg = (MCPhysReg)RegInfo->getMatchingSuperReg(
DataReg, AArch64::sub_32,
&RegInfo->getRegClass(AArch64::GPR64RegClassID));
OpCode = AArch64::LDRWui;
RelType = ELF::R_AARCH64_LDST32_ABS_LO12_NC;
break;
case AArch64::LDRXl:
AddrReg = DataReg;
OpCode = AArch64::LDRXui;
RelType = ELF::R_AARCH64_LDST64_ABS_LO12_NC;
break;
case AArch64::LDRSWl:
AddrReg = DataReg;
OpCode = AArch64::LDRSWui;
RelType = ELF::R_AARCH64_LDST64_ABS_LO12_NC;
break;
default:
llvm_unreachable("LDR (literal) or LDRSW (literal) expected");
}
const MCSymbol *Target = getTargetSymbol(LDRInst, 1);
assert(Target && "missing target symbol in LDR instruction");
@ -764,15 +782,13 @@ public:
Insts[0].addOperand(MCOperand::createImm(0));
setOperandToSymbolRef(Insts[0], /* OpNum */ 1, Target, 0, Ctx,
ELF::R_AARCH64_NONE);
Insts[1].setOpcode(isLDRXl(LDRInst) ? AArch64::LDRXui : AArch64::LDRWui);
Insts[1].setOpcode(OpCode);
Insts[1].clear();
Insts[1].addOperand(MCOperand::createReg(DataReg));
Insts[1].addOperand(MCOperand::createReg(AddrReg));
Insts[1].addOperand(MCOperand::createImm(0));
Insts[1].addOperand(MCOperand::createImm(0));
setOperandToSymbolRef(Insts[1], /* OpNum */ 2, Target, 0, Ctx,
isLDRXl(LDRInst) ? ELF::R_AARCH64_LDST64_ABS_LO12_NC
: ELF::R_AARCH64_LDST32_ABS_LO12_NC);
setOperandToSymbolRef(Insts[1], /* OpNum */ 2, Target, 0, Ctx, RelType);
return Insts;
}

View file

@ -112,6 +112,29 @@ _start:
ret
.cfi_endproc
.size _start, .-_start
.endif
## Check LDR relaxation works on LDRSW (literal)
# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \
# RUN: --defsym RELAX_SIMPLE_LDRSW=1 %s -o %t.o
# RUN: %clang %cflags %t.o -o %t.so -Wl,-q
# RUN: llvm-bolt %t.so -o %t.bolt
# RUN: llvm-objdump -d %t.bolt | FileCheck %s --check-prefix=RELAX_LDRSW
# RELAX_LDRSW: adrp
# RELAX_LDRSW-NEXT: ldrsw
.ifdef RELAX_SIMPLE_LDRSW
.text
.global _start
.type _start, %function
_start:
.cfi_startproc
ldrsw x0, _foo
ret
.cfi_endproc
.size _start, .-_start
.endif
.section .text_cold