* 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:
sergei 2016-02-12 13:53:04 +00:00
parent 6ca424900b
commit e23ed15634

View File

@ -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;