mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-12 07:26:24 +02:00
* MIPS: reworked and fixed procedure fixup_jmps:
* support conditional branches with 2 parameters * factored out common parts * adjusted range limits, they were copy-pasted from PowerPC target which uses 14-bit offsets. MIPS however uses 16-bit offsets, i.e. can branch 4 times farther. git-svn-id: trunk@33088 -
This commit is contained in:
parent
6ca424900b
commit
e23ed15634
@ -497,16 +497,41 @@ procedure DoneAsm;
|
|||||||
procedure fixup_jmps(list: TAsmList);
|
procedure fixup_jmps(list: TAsmList);
|
||||||
var
|
var
|
||||||
p,pdelayslot: tai;
|
p,pdelayslot: tai;
|
||||||
newcomment: tai_comment;
|
newjmp,newnoop: taicpu;
|
||||||
newins,newjmp,newnoop: taicpu;
|
|
||||||
labelpositions: TFPList;
|
labelpositions: TFPList;
|
||||||
instrpos: ptrint;
|
instrpos: ptrint;
|
||||||
l: tasmlabel;
|
l: tasmlabel;
|
||||||
inserted_something: boolean;
|
again: boolean;
|
||||||
href: treference;
|
insai: tai;
|
||||||
|
|
||||||
|
procedure create_pic_load(ai: taicpu; insloc: tai);
|
||||||
|
var
|
||||||
|
href: treference;
|
||||||
|
newins: taicpu;
|
||||||
|
begin
|
||||||
|
{ validity of operand has been checked by caller }
|
||||||
|
href:=ai.oper[ai.ops-1]^.ref^;
|
||||||
|
href.refaddr:=addr_pic;
|
||||||
|
href.base:=NR_GP;
|
||||||
|
newins:=taicpu.op_reg_ref(A_LW,NR_PIC_FUNC,href);
|
||||||
|
newins.fileinfo:=ai.fileinfo;
|
||||||
|
list.insertbefore(newins,insloc);
|
||||||
|
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:=ai.fileinfo;
|
||||||
|
list.insertbefore(newins,insloc);
|
||||||
|
inc(instrpos,2);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
// MIPS relative branch range is +-32K instructions, i.e +-128 kBytes
|
||||||
// if certainly not enough instructions to cause an overflow, dont bother
|
// if certainly not enough instructions to cause an overflow, dont bother
|
||||||
if (list.count <= (high(smallint) div 4)) then
|
if (list.count<high(smallint)) then
|
||||||
exit;
|
exit;
|
||||||
labelpositions := TFPList.create;
|
labelpositions := TFPList.create;
|
||||||
p := tai(list.first);
|
p := tai(list.first);
|
||||||
@ -538,11 +563,11 @@ procedure fixup_jmps(list: TAsmList);
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
{ If the number of instructions is below limit, we can't overflow either }
|
{ If the number of instructions is below limit, we can't overflow either }
|
||||||
if (instrpos <= (high(smallint) div 4)) then
|
if (instrpos<high(smallint)) then
|
||||||
exit;
|
exit;
|
||||||
// check and fix distances
|
// check and fix distances
|
||||||
repeat
|
repeat
|
||||||
inserted_something := false;
|
again := false;
|
||||||
p := tai(list.first);
|
p := tai(list.first);
|
||||||
instrpos := 1;
|
instrpos := 1;
|
||||||
while assigned(p) do
|
while assigned(p) do
|
||||||
@ -561,120 +586,76 @@ procedure fixup_jmps(list: TAsmList);
|
|||||||
begin
|
begin
|
||||||
inc(instrpos,2);
|
inc(instrpos,2);
|
||||||
case taicpu(p).opcode of
|
case taicpu(p).opcode of
|
||||||
A_BA:
|
A_BA,A_BC:
|
||||||
if (taicpu(p).oper[0]^.typ = top_ref) and
|
if (taicpu(p).ops>0) and (taicpu(p).oper[taicpu(p).ops-1]^.typ=top_ref) and
|
||||||
assigned(taicpu(p).oper[0]^.ref^.symbol) and
|
assigned(taicpu(p).oper[taicpu(p).ops-1]^.ref^.symbol) and
|
||||||
(taicpu(p).oper[0]^.ref^.symbol is tasmlabel) and
|
(taicpu(p).oper[taicpu(p).ops-1]^.ref^.symbol is tasmlabel) and
|
||||||
(labelpositions[tasmlabel(taicpu(p).oper[0]^.ref^.symbol).labelnr] <> NIL) and
|
(labelpositions[tasmlabel(taicpu(p).oper[taicpu(p).ops-1]^.ref^.symbol).labelnr] <> NIL) and
|
||||||
{$push}
|
{$push}
|
||||||
{$q-}
|
{$q-}
|
||||||
(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
|
(ptruint(abs(ptrint(labelpositions[tasmlabel(taicpu(p).oper[taicpu(p).ops-1]^.ref^.symbol).labelnr]-instrpos)) - low(smallint)) > ptruint((high(smallint) - low(smallint)))) then
|
||||||
{$pop}
|
{$pop}
|
||||||
begin
|
begin
|
||||||
if (cs_create_pic in current_settings.moduleswitches) then
|
if (taicpu(p).opcode=A_BC) then
|
||||||
begin
|
begin
|
||||||
newcomment:=tai_comment.create(strpnew('fixup_jmps, A_BA changed into PIC sequence'));
|
{ we're adding a new label together with the only branch to it;
|
||||||
list.insertbefore(newcomment,p);
|
providing exact label position is not necessary }
|
||||||
href:=taicpu(p).oper[0]^.ref^;
|
current_asmdata.getjumplabel(l);
|
||||||
href.refaddr:=addr_pic;
|
pdelayslot:=tai(p.next);
|
||||||
href.base:=NR_GP;
|
{ We need to insert the new instruction after the delay slot instruction ! }
|
||||||
newins:=taicpu.op_reg_ref(A_LW,NR_PIC_FUNC,href);
|
while assigned(pdelayslot) and (pdelayslot.typ<>ait_instruction) do
|
||||||
newins.fileinfo:=taicpu(p).fileinfo;
|
pdelayslot:=tai(pdelayslot.next);
|
||||||
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
|
|
||||||
(taicpu(p).oper[2]^.ref^.symbol is tasmlabel) and
|
|
||||||
(labelpositions[tasmlabel(taicpu(p).oper[2]^.ref^.symbol).labelnr] <> NIL) and
|
|
||||||
{$push}
|
|
||||||
{$q-}
|
|
||||||
(ptruint(abs(ptrint(labelpositions[tasmlabel(taicpu(p).oper[2]^.ref^.symbol).labelnr]-instrpos)) - (low(smallint) div 4)) > ptruint((high(smallint) - low(smallint)) div 4)) then
|
|
||||||
{$pop}
|
|
||||||
begin
|
|
||||||
// add a new label after this jump
|
|
||||||
current_asmdata.getjumplabel(l);
|
|
||||||
{ new label -> may have to increase array size }
|
|
||||||
if (l.labelnr >= labelpositions.count) then
|
|
||||||
labelpositions.count := l.labelnr + 10;
|
|
||||||
{ newjmp will be inserted before the label, and it's inserted after }
|
|
||||||
{ plus delay slot }
|
|
||||||
{ the current jump -> instrpos+3 }
|
|
||||||
labelpositions[l.labelnr] := pointer(instrpos+2*3);
|
|
||||||
pdelayslot:=tai(p.next);
|
|
||||||
{ We need to insert the new instruction after the delay slot instruction ! }
|
|
||||||
while assigned(pdelayslot) and (pdelayslot.typ<>ait_instruction) do
|
|
||||||
pdelayslot:=tai(pdelayslot.next);
|
|
||||||
|
|
||||||
list.insertafter(tai_label.create(l),pdelayslot);
|
insai:=tai_label.create(l);
|
||||||
// add a new unconditional jump between this jump and the label
|
list.insertafter(insai,pdelayslot);
|
||||||
newcomment:=tai_comment.create(strpnew('fixup_jmps, A_BXX changed into A_BNOTXX label;A_J;label:'));
|
// add a new unconditional jump between this jump and the label
|
||||||
list.insertbefore(newcomment,p);
|
list.insertbefore(tai_comment.create(strpnew('fixup_jmps, A_BXX changed into A_BNOTXX label;A_J;label:')),p);
|
||||||
if (cs_create_pic in current_settings.moduleswitches) then
|
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
|
begin
|
||||||
href.base:=NR_NO;
|
create_pic_load(taicpu(p),insai);
|
||||||
href.refaddr:=addr_low;
|
newjmp:=taicpu.op_reg(A_JR,NR_PIC_FUNC);
|
||||||
newins:=taicpu.op_reg_reg_ref(A_ADDIU,NR_PIC_FUNC,NR_PIC_FUNC,href);
|
end
|
||||||
newins.fileinfo:=taicpu(p).fileinfo;
|
else
|
||||||
list.insertafter(newins,pdelayslot);
|
begin
|
||||||
pdelayslot:=newins;
|
newjmp:=taicpu.op_sym(A_J,taicpu(p).oper[2]^.ref^.symbol);
|
||||||
inc(instrpos,2);
|
newjmp.is_jmp := true;
|
||||||
end;
|
end;
|
||||||
newjmp:=taicpu.op_reg(A_JR,NR_PIC_FUNC);
|
|
||||||
newjmp.fileinfo:=taicpu(p).fileinfo;
|
newjmp.fileinfo:=taicpu(p).fileinfo;
|
||||||
list.insertafter(newjmp,pdelayslot);
|
list.insertbefore(newjmp,insai);
|
||||||
inc(instrpos,2);
|
inc(instrpos,2);
|
||||||
|
|
||||||
|
{ Add a delay slot for new A_J instruction }
|
||||||
|
newnoop:=taicpu.op_none(A_NOP);
|
||||||
|
newnoop.fileinfo := taicpu(p).fileinfo;
|
||||||
|
list.insertbefore(newnoop,insai);
|
||||||
|
inc(instrpos,2);
|
||||||
|
// change the conditional jump to point to the newly inserted label
|
||||||
|
tasmlabel(taicpu(p).oper[taicpu(p).ops-1]^.ref^.symbol).decrefs;
|
||||||
|
taicpu(p).oper[taicpu(p).ops-1]^.ref^.symbol := l;
|
||||||
|
l.increfs;
|
||||||
|
// and invert its condition code
|
||||||
|
taicpu(p).condition := inverse_cond(taicpu(p).condition);
|
||||||
|
{ skip inserted stuff and continue processing from 'pdelayslot' }
|
||||||
|
p:=pdelayslot;
|
||||||
|
again:=true;
|
||||||
end
|
end
|
||||||
else
|
else // opcode=A_BA
|
||||||
begin
|
begin
|
||||||
newjmp := taicpu.op_sym(A_J,taicpu(p).oper[2]^.ref^.symbol);
|
if (cs_create_pic in current_settings.moduleswitches) then
|
||||||
newjmp.is_jmp := true;
|
begin
|
||||||
newjmp.fileinfo := taicpu(p).fileinfo;
|
list.insertbefore(tai_comment.create(strpnew('fixup_jmps, A_BA changed into PIC sequence')),p);
|
||||||
list.insertafter(newjmp,pdelayslot);
|
create_pic_load(taicpu(p),p);
|
||||||
inc(instrpos,2);
|
taicpu(p).opcode:=A_JR;
|
||||||
|
taicpu(p).loadreg(0,NR_PIC_FUNC);
|
||||||
|
again:=true;
|
||||||
|
{ inserted stuff before 'p', continue processing from 'p' on }
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
list.insertbefore(tai_comment.create(strpnew('fixup_jmps, A_BA changed into A_J')),p);
|
||||||
|
taicpu(p).opcode:=A_J;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
{ Add a delay slot for new A_J instruction }
|
|
||||||
newnoop:=taicpu.op_none(A_NOP);
|
|
||||||
newnoop.fileinfo := taicpu(p).fileinfo;
|
|
||||||
list.insertafter(newnoop,newjmp);
|
|
||||||
inc(instrpos,2);
|
|
||||||
// change the conditional jump to point to the newly inserted label
|
|
||||||
tasmlabel(taicpu(p).oper[2]^.ref^.symbol).decrefs;
|
|
||||||
taicpu(p).oper[2]^.ref^.symbol := l;
|
|
||||||
l.increfs;
|
|
||||||
// and invert its condition code
|
|
||||||
taicpu(p).condition := inverse_cond(taicpu(p).condition);
|
|
||||||
// we inserted an instruction, so will have to check everything again
|
|
||||||
inserted_something := true;
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -683,7 +664,7 @@ procedure fixup_jmps(list: TAsmList);
|
|||||||
end;
|
end;
|
||||||
p := tai(p.next);
|
p := tai(p.next);
|
||||||
end;
|
end;
|
||||||
until not inserted_something;
|
until not again;
|
||||||
labelpositions.free;
|
labelpositions.free;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user