Jelajahi Sumber

* finally fix for fixing up conditional jumps that are too long

git-svn-id: trunk@1161 -
Jonas Maebe 20 tahun lalu
induk
melakukan
8b8d3de3bf
2 mengubah file dengan 93 tambahan dan 2 penghapusan
  1. 88 1
      compiler/powerpc/aasmcpu.pas
  2. 5 1
      compiler/psub.pas

+ 88 - 1
compiler/powerpc/aasmcpu.pas

@@ -98,9 +98,11 @@ uses
     function spilling_create_load(const ref:treference;r:tregister): tai;
     function spilling_create_store(r:tregister; const ref:treference): tai;
 
+    procedure fixup_jmps(list: taasmoutput);
+
 implementation
 
-uses cutils;
+uses cutils, cclasses;
 
 {*****************************************************************************
                                  taicpu Constructors
@@ -415,6 +417,91 @@ uses cutils;
       end;
 
 
+    procedure fixup_jmps(list: taasmoutput);
+      var
+        p: tai;
+        newjmp: taicpu;
+        labelpositions: tlist;
+        instrpos: ptrint;
+        l: tasmlabel;
+        inserted_something: boolean;
+      begin
+        // if certainly not enough instructions to cause an overflow, don't bother
+        if (list.count <= (high(smallint) div 4)) then
+          exit;
+        labelpositions := tlist.create;
+        p := tai(list.first);
+        instrpos := 1;
+        // record label positions
+        while assigned(p) do
+          begin
+            if p.typ = ait_label then
+              begin
+                if (tai_label(p).l.labelnr > labelpositions.count) then
+                  labelpositions.count := tai_label(p).l.labelnr * 2;
+                labelpositions[tai_label(p).l.labelnr] := pointer(instrpos);
+              end;
+            if p.typ = ait_instruction then
+              inc(instrpos);
+            p := tai(p.next);
+          end;
+
+        // check and fix distances
+        repeat
+          inserted_something := false;
+          p := tai(list.first);
+          instrpos := 1;
+          while assigned(p) do
+            begin
+              case p.typ of
+                ait_label:
+                  // update labelposition in case it changed due to insertion
+                  // of jumps
+                  begin
+                    // can happen because of newly inserted labels
+                    if (tai_label(p).l.labelnr > labelpositions.count) then
+                      labelpositions.count := tai_label(p).l.labelnr * 2;
+                    labelpositions[tai_label(p).l.labelnr] := pointer(instrpos);
+                  end;
+                ait_instruction:
+                  begin
+                    inc(instrpos);
+                    case taicpu(p).opcode of
+                      A_BC:
+                        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
+                           (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
+                          begin
+                            // add a new label after this jump
+                            objectlibrary.getjumplabel(l);
+                            list.insertafter(tai_label.create(l),p);
+                            // add a new unconditional jump between this jump and the label
+                            newjmp := taicpu.op_sym(A_B,taicpu(p).oper[0]^.ref^.symbol);
+                            newjmp.is_jmp := true;
+                            newjmp.fileinfo := taicpu(p).fileinfo;
+                            list.insertafter(newjmp,p);
+                            inc(instrpos);
+                            // change the conditional jump to point to the newly inserted label
+                            tasmlabel(taicpu(p).oper[0]^.ref^.symbol).decrefs;
+                            taicpu(p).oper[0]^.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;
+              p := tai(p.next);
+            end;
+         until not inserted_something;
+        labelpositions.free;
+      end;
+
+
 begin
   cai_align:=tai_align;
   cai_cpu:=taicpu;

+ 5 - 1
compiler/psub.pas

@@ -97,7 +97,7 @@ implementation
        { codegen }
        tgobj,cgobj,dbgbase,
        ncgutil,regvars
-{$ifdef arm}
+{$if defined(arm) or defined(powerpc)}
        ,aasmcpu
 {$endif arm}
        {$ifndef NOOPT}
@@ -849,6 +849,10 @@ implementation
             insertpcrelativedata(aktproccode,aktlocaldata);
 {$endif ARM}
 
+{$ifdef POWERPC}
+            fixup_jmps(aktproccode);
+{$endif POWERPC}
+
             { insert line debuginfo }
             if (cs_debuginfo in aktmoduleswitches) or
                (cs_gdb_lineinfo in aktglobalswitches) then