@@ -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
6365enum 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+
833866static 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