Skip to content

Commit f1f995b

Browse files
committed
Relax call36/tail36.
Instructions with relocation `R_LARCH_CALL36` may be relax as follows: ``` From: pcaddu18i $dest, %call36(foo) R_LARCH_CALL36, R_LARCH_RELAX jirl $r, $dest, 0 To: b/bl foo # bl if r=$ra, b if r=$zero R_LARCH_B26 ```
1 parent 30cb382 commit f1f995b

File tree

1 file changed

+41
-0
lines changed

1 file changed

+41
-0
lines changed

lld/ELF/Arch/LoongArch.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ enum Op {
5858
LD_W = 0x28800000,
5959
LD_D = 0x28c00000,
6060
JIRL = 0x4c000000,
61+
B = 0x50000000,
62+
BL = 0x54000000,
6163
};
6264

6365
enum Reg {
@@ -830,6 +832,37 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
830832
remove = 4;
831833
}
832834

835+
// Relax code sequence.
836+
// From:
837+
// pcaddu18i $ra, %call36(foo)
838+
// jirl $ra, $ra, 0
839+
// To:
840+
// b/bl foo
841+
static void relaxCall36(Ctx &ctx, const InputSection &sec, size_t i,
842+
uint64_t loc, Relocation &r, uint32_t &remove) {
843+
const uint64_t symLocal =
844+
(r.expr == R_PLT_PC ? r.sym->getPltVA(ctx) : r.sym->getVA(ctx)) +
845+
r.addend;
846+
847+
const int64_t distance = symLocal - loc;
848+
// Check if the distance aligns 4 bytes or exceeds the range of b[l].
849+
if ((distance & 0x3) != 0 || !isInt<28>(distance))
850+
return;
851+
852+
const uint32_t nextInsn = read32le(sec.content().data() + r.offset + 4);
853+
if (getD5(nextInsn) == R_RA) {
854+
// convert jirl to bl
855+
sec.relaxAux->relocTypes[i] = R_LARCH_B26;
856+
sec.relaxAux->writes.push_back(insn(BL, 0, 0, 0));
857+
remove = 4;
858+
} else if (getD5(nextInsn) == R_ZERO) {
859+
// convert jirl to b
860+
sec.relaxAux->relocTypes[i] = R_LARCH_B26;
861+
sec.relaxAux->writes.push_back(insn(B, 0, 0, 0));
862+
remove = 4;
863+
}
864+
}
865+
833866
static bool relax(Ctx &ctx, InputSection &sec) {
834867
const uint64_t secAddr = sec.getVA();
835868
const MutableArrayRef<Relocation> relocs = sec.relocs();
@@ -874,6 +907,10 @@ static bool relax(Ctx &ctx, InputSection &sec) {
874907
if (isPairRelaxable(relocs, i))
875908
relaxPCHi20Lo12(ctx, sec, i, loc, r, relocs[i + 2], remove);
876909
break;
910+
case R_LARCH_CALL36:
911+
if (relaxable(relocs, i))
912+
relaxCall36(ctx, sec, i, loc, r, remove);
913+
break;
877914
}
878915

879916
// For all anchors whose offsets are <= r.offset, they are preceded by
@@ -977,6 +1014,10 @@ void LoongArch::finalizeRelax(int passes) const {
9771014
// RelExpr is needed for relocating.
9781015
r.expr = r.sym->hasFlag(NEEDS_PLT) ? R_PLT_PC : R_PC;
9791016
break;
1017+
case R_LARCH_B26:
1018+
skip = 4;
1019+
write32le(p, aux.writes[writesIdx++]);
1020+
break;
9801021
default:
9811022
llvm_unreachable("unsupported type");
9821023
}

0 commit comments

Comments
 (0)