|
@@ -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;
|
|
|
|
- newins,newjmp,newnoop: taicpu;
|
|
|
|
|
|
+ newjmp,newnoop: taicpu;
|
|
labelpositions: TFPList;
|
|
labelpositions: TFPList;
|
|
instrpos: ptrint;
|
|
instrpos: ptrint;
|
|
l: tasmlabel;
|
|
l: tasmlabel;
|
|
- inserted_something: boolean;
|
|
|
|
- href: treference;
|
|
|
|
|
|
+ again: boolean;
|
|
|
|
+ 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:
|
|
|
|
- if (taicpu(p).oper[0]^.typ = top_ref) and
|
|
|
|
- assigned(taicpu(p).oper[0]^.ref^.symbol) and
|
|
|
|
- (taicpu(p).oper[0]^.ref^.symbol is tasmlabel) and
|
|
|
|
- (labelpositions[tasmlabel(taicpu(p).oper[0]^.ref^.symbol).labelnr] <> NIL) and
|
|
|
|
|
|
+ A_BA,A_BC:
|
|
|
|
+ if (taicpu(p).ops>0) and (taicpu(p).oper[taicpu(p).ops-1]^.typ=top_ref) and
|
|
|
|
+ assigned(taicpu(p).oper[taicpu(p).ops-1]^.ref^.symbol) and
|
|
|
|
+ (taicpu(p).oper[taicpu(p).ops-1]^.ref^.symbol is tasmlabel) 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'));
|
|
|
|
- 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
|
|
|
|
|
|
+ { we're adding a new label together with the only branch to it;
|
|
|
|
+ providing exact label position is not necessary }
|
|
|
|
+ current_asmdata.getjumplabel(l);
|
|
|
|
+ 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);
|
|
|
|
+
|
|
|
|
+ insai:=tai_label.create(l);
|
|
|
|
+ list.insertafter(insai,pdelayslot);
|
|
|
|
+ // add a new unconditional jump between this jump and the label
|
|
|
|
+ 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
|
|
begin
|
|
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);
|
|
|
|
- // 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);
|
|
|
|
- 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
|
|
|
|
|
|
+ create_pic_load(taicpu(p),insai);
|
|
|
|
+ newjmp:=taicpu.op_reg(A_JR,NR_PIC_FUNC);
|
|
|
|
+ end
|
|
|
|
+ else
|
|
begin
|
|
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);
|
|
|
|
|
|
+ newjmp:=taicpu.op_sym(A_J,taicpu(p).oper[2]^.ref^.symbol);
|
|
|
|
+ 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);
|
|
|
|
- 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
|
|
|
|
+ list.insertbefore(tai_comment.create(strpnew('fixup_jmps, A_BA changed into PIC sequence')),p);
|
|
|
|
+ create_pic_load(taicpu(p),p);
|
|
|
|
+ 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;
|
|
|
|
|