@@ -58,6 +58,8 @@ enum Op {
58
58
LD_W = 0x28800000 ,
59
59
LD_D = 0x28c00000 ,
60
60
JIRL = 0x4c000000 ,
61
+ B = 0x50000000 ,
62
+ BL = 0x54000000 ,
61
63
};
62
64
63
65
enum Reg {
@@ -830,6 +832,37 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
830
832
remove = 4 ;
831
833
}
832
834
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
+
833
866
static bool relax (Ctx &ctx, InputSection &sec) {
834
867
const uint64_t secAddr = sec.getVA ();
835
868
const MutableArrayRef<Relocation> relocs = sec.relocs ();
@@ -874,6 +907,10 @@ static bool relax(Ctx &ctx, InputSection &sec) {
874
907
if (isPairRelaxable (relocs, i))
875
908
relaxPCHi20Lo12 (ctx, sec, i, loc, r, relocs[i + 2 ], remove);
876
909
break ;
910
+ case R_LARCH_CALL36:
911
+ if (relaxable (relocs, i))
912
+ relaxCall36 (ctx, sec, i, loc, r, remove);
913
+ break ;
877
914
}
878
915
879
916
// For all anchors whose offsets are <= r.offset, they are preceded by
@@ -977,6 +1014,10 @@ void LoongArch::finalizeRelax(int passes) const {
977
1014
// RelExpr is needed for relocating.
978
1015
r.expr = r.sym ->hasFlag (NEEDS_PLT) ? R_PLT_PC : R_PC;
979
1016
break ;
1017
+ case R_LARCH_B26:
1018
+ skip = 4 ;
1019
+ write32le (p, aux.writes [writesIdx++]);
1020
+ break ;
980
1021
default :
981
1022
llvm_unreachable (" unsupported type" );
982
1023
}
0 commit comments