diff --git a/compiler/mips/aasmcpu.pas b/compiler/mips/aasmcpu.pas index 11da6f329d..cc7c13efc3 100644 --- a/compiler/mips/aasmcpu.pas +++ b/compiler/mips/aasmcpu.pas @@ -497,16 +497,41 @@ procedure DoneAsm; procedure fixup_jmps(list: TAsmList); var p,pdelayslot: tai; - newcomment: tai_comment; - newins,newjmp,newnoop: taicpu; + newjmp,newnoop: taicpu; labelpositions: TFPList; instrpos: ptrint; 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 + // MIPS relative branch range is +-32K instructions, i.e +-128 kBytes // if certainly not enough instructions to cause an overflow, dont bother - if (list.count <= (high(smallint) div 4)) then + if (list.count 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} {$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} begin - if (cs_create_pic in current_settings.moduleswitches) then + if (taicpu(p).opcode=A_BC) 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 - (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); + { 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); - 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 + 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 - 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); + create_pic_load(taicpu(p),insai); + newjmp:=taicpu.op_reg(A_JR,NR_PIC_FUNC); + end + else + begin + newjmp:=taicpu.op_sym(A_J,taicpu(p).oper[2]^.ref^.symbol); + newjmp.is_jmp := true; end; - newjmp:=taicpu.op_reg(A_JR,NR_PIC_FUNC); newjmp.fileinfo:=taicpu(p).fileinfo; - list.insertafter(newjmp,pdelayslot); + list.insertbefore(newjmp,insai); 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 - else + else // opcode=A_BA 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; - { 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; @@ -683,7 +664,7 @@ procedure fixup_jmps(list: TAsmList); end; p := tai(p.next); end; - until not inserted_something; + until not again; labelpositions.free; end;