浏览代码

* 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 -

sergei 9 年之前
父节点
当前提交
e23ed15634
共有 1 个文件被更改,包括 90 次插入109 次删除
  1. 90 109
      compiler/mips/aasmcpu.pas

+ 90 - 109
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<high(smallint)) then
       exit;
     labelpositions := TFPList.create;
     p := tai(list.first);
@@ -538,11 +563,11 @@ procedure fixup_jmps(list: TAsmList);
       end;
 
     { 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;
     // check and fix distances
     repeat
-      inserted_something := false;
+      again := false;
       p := tai(list.first);
       instrpos := 1;
       while assigned(p) do
@@ -561,120 +586,76 @@ procedure fixup_jmps(list: TAsmList);
               begin
                 inc(instrpos,2);
                 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}
 {$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
+                            { 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
-                                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
-                                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;
-                            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;