* MIPS: emit PIC-friendly instruction sequences instead of "J" when fixing up branches outside of 128K range. Resolves #25399.

git-svn-id: trunk@26215 -
This commit is contained in:
sergei 2013-12-11 10:56:07 +00:00
parent a68b9fd01f
commit ffba5aee60

View File

@ -469,11 +469,12 @@ procedure fixup_jmps(list: TAsmList);
var
p,pdelayslot: tai;
newcomment: tai_comment;
newjmp,newnoop: taicpu;
newins,newjmp,newnoop: taicpu;
labelpositions: TFPList;
instrpos: ptrint;
l: tasmlabel;
inserted_something: boolean;
href: treference;
begin
// if certainly not enough instructions to cause an overflow, dont bother
if (list.count <= (high(smallint) div 4)) then
@ -541,11 +542,36 @@ procedure fixup_jmps(list: TAsmList);
(ptruint(abs(ptrint(labelpositions[tasmlabel(taicpu(p).oper[0]^.ref^.symbol).labelnr]-instrpos)) - (low(smallint) div 4)) > ptruint((high(smallint) - low(smallint)) div 4)) then
{$pop}
begin
{ This is not PIC safe }
taicpu(p).opcode:=A_J;
newcomment:=tai_comment.create(strpnew('fixup_jmps, A_BA changed into A_J'));
list.insertbefore(newcomment,p);
end;
if (cs_create_pic in current_settings.moduleswitches) then
begin
newcomment:=tai_comment.create(strpnew('fixup_jmps, A_BA changed into PIC sequence'));
list.insertbefore(newcomment,p);
href:=taicpu(p).oper[0]^.ref^;
href.refaddr:=addr_pic;
href.base:=NR_GP;
newins:=taicpu.op_reg_ref(A_LW,NR_PIC_FUNC,href);
newins.fileinfo:=taicpu(p).fileinfo;
list.insertbefore(newins,p);
inc(instrpos,2);
if (href.symbol.bind=AB_LOCAL) then
begin
href.refaddr:=addr_low;
href.base:=NR_NO;
newins:=taicpu.op_reg_reg_ref(A_ADDIU,NR_PIC_FUNC,NR_PIC_FUNC,href);
newins.fileinfo:=taicpu(p).fileinfo;
list.insertbefore(newins,p);
inc(instrpos,2);
end;
taicpu(p).opcode:=A_JR;
taicpu(p).loadreg(0,NR_PIC_FUNC);
end
else
begin
taicpu(p).opcode:=A_J;
newcomment:=tai_comment.create(strpnew('fixup_jmps, A_BA changed into A_J'));
list.insertbefore(newcomment,p);
end;
end;
A_BC:
if (taicpu(p).ops=3) and (taicpu(p).oper[2]^.typ = top_ref) and
assigned(taicpu(p).oper[2]^.ref^.symbol) and
@ -574,11 +600,39 @@ procedure fixup_jmps(list: TAsmList);
// add a new unconditional jump between this jump and the label
newcomment:=tai_comment.create(strpnew('fixup_jmps, A_BXX changed into A_BNOTXX label;A_J;label:'));
list.insertbefore(newcomment,p);
newjmp := taicpu.op_sym(A_J,taicpu(p).oper[2]^.ref^.symbol);
newjmp.is_jmp := true;
newjmp.fileinfo := taicpu(p).fileinfo;
list.insertafter(newjmp,pdelayslot);
inc(instrpos,2);
if (cs_create_pic in current_settings.moduleswitches) then
begin
reference_reset_symbol(href,taicpu(p).oper[2]^.ref^.symbol,0,sizeof(pint));
href.refaddr:=addr_pic;
href.base:=NR_GP;
newins:=taicpu.op_reg_ref(A_LW,NR_PIC_FUNC,href);
newins.fileinfo:=taicpu(p).fileinfo;
list.insertafter(newins,pdelayslot);
pdelayslot:=newins;
inc(instrpos,2);
if (href.symbol.bind=AB_LOCAL) then
begin
href.base:=NR_NO;
href.refaddr:=addr_low;
newins:=taicpu.op_reg_reg_ref(A_ADDIU,NR_PIC_FUNC,NR_PIC_FUNC,href);
newins.fileinfo:=taicpu(p).fileinfo;
list.insertafter(newins,pdelayslot);
pdelayslot:=newins;
inc(instrpos,2);
end;
newjmp:=taicpu.op_reg(A_JR,NR_PIC_FUNC);
newjmp.fileinfo:=taicpu(p).fileinfo;
list.insertafter(newjmp,pdelayslot);
inc(instrpos,2);
end
else
begin
newjmp := taicpu.op_sym(A_J,taicpu(p).oper[2]^.ref^.symbol);
newjmp.is_jmp := true;
newjmp.fileinfo := taicpu(p).fileinfo;
list.insertafter(newjmp,pdelayslot);
inc(instrpos,2);
end;
{ Add a delay slot for new A_J instruction }
newnoop:=taicpu.op_none(A_NOP);
newnoop.fileinfo := taicpu(p).fileinfo;