瀏覽代碼

o patch by J. Gareth Moreton:
* fix jump optimizer for MIPS(EL).
+ New method called "MakeUnconditional" introduced that can do platform-specific changes

git-svn-id: trunk@43518 -

florian 5 年之前
父節點
當前提交
f505822ab5
共有 2 個文件被更改,包括 53 次插入13 次删除
  1. 26 12
      compiler/aoptobj.pas
  2. 27 1
      compiler/mips/aoptcpu.pas

+ 26 - 12
compiler/aoptobj.pas

@@ -375,6 +375,10 @@ Unit AoptObj;
         { Output debug message to console - null function if EXTDEBUG is not defined }
         class procedure DebugWrite(Message: string); static; inline;
 
+        { Converts a conditional jump into an unconditional jump.  Only call this
+          procedure on an instruction that you already know is a conditional jump }
+        procedure MakeUnconditional(p: taicpu); virtual;
+
         { Removes all instructions between an unconditional jump and the next label }
         procedure RemoveDeadCodeAfterJump(p: taicpu);
 
@@ -1564,6 +1568,25 @@ Unit AoptObj;
 {$endif DEBUG_JUMP}
       end;
 
+
+    { Converts a conditional jump into an unconditional jump.  Only call this
+      procedure on an instruction that you already know is a conditional jump }
+    procedure TAOptObj.MakeUnconditional(p: taicpu);
+      begin
+        { TODO: If anyone can improve this particular optimisation to work on
+          AVR and RISC-V, please do (it's currently not called at all). [Kit] }
+{$if not defined(avr) and not defined(riscv32) and not defined(riscv64)}
+{$if defined(powerpc) or defined(powerpc64)}
+        p.condition.cond := C_None;
+        p.condition.simple := True;
+{$else powerpc}
+        p.condition := C_None;
+{$endif powerpc}
+        p.opcode := aopt_uncondjmp;
+{$endif not avr and not riscv}
+      end;
+
+
     { Removes all instructions between an unconditional jump and the next label }
     procedure TAOptObj.RemoveDeadCodeAfterJump(p: taicpu);
       var
@@ -2014,29 +2037,20 @@ Unit AoptObj;
                             Result := True;
                             Exit;
 
-{$if not defined(avr) and not defined(riscv32) and not defined(riscv64) and not defined(mips)}
+{$if not defined(avr) and not defined(riscv32) and not defined(riscv64)}
                           end
                         else
                           { NOTE: There is currently no watertight, cross-platform way to create
                             an unconditional jump without access to the cg object.  If anyone can
                             improve this particular optimisation to work on AVR and RISC-V,
-                            please do. [Kit]
-
-                            On MIPS, it causes an endless loop, so I disabled it for now
-                          }
+                            please do. [Kit] }
                           begin
                             { Since cond1 is a subset of inv(cond2), jmp<cond2> will always branch if
                               jmp<cond1> does not, so change jmp<cond2> to an unconditional jump. }
 
                             DebugWrite('JUMP DEBUG: jmp<cond> before jmp<inv_cond> - made second jump unconditional');
 
-{$if defined(powerpc) or defined(powerpc64)}
-                            taicpu(hp2).condition.cond := C_None;
-                            taicpu(hp2).condition.simple := True;
-{$else powerpc}
-                            taicpu(hp2).condition := C_None;
-{$endif powerpc}
-                            taicpu(hp2).opcode := aopt_uncondjmp;
+                            MakeUnconditional(taicpu(hp1));
 
                             { NOTE: Changing the jump to unconditional won't open up new opportunities
                               for GetFinalDestination on earlier jumps because there's no live label

+ 27 - 1
compiler/mips/aoptcpu.pas

@@ -25,7 +25,7 @@ unit aoptcpu;
 
 {$i fpcdefs.inc}
 
-{$define DEBUG_AOPTCPU}
+{ $define DEBUG_AOPTCPU}
 
   Interface
 
@@ -36,6 +36,10 @@ unit aoptcpu;
       TAsmOpSet = set of TAsmOp;
 
       TCpuAsmOptimizer = class(TAsmOptimizer)
+        { Converts a conditional jump into an unconditional jump.  Only call this
+          procedure on an instruction that you already know is a conditional jump }
+        procedure MakeUnconditional(p: taicpu); override;
+
         function RegModifiedByInstruction(Reg: TRegister; p1: tai): boolean; override;
         function GetNextInstructionUsingReg(Current: tai;
           var Next: tai; reg: TRegister): Boolean;
@@ -147,6 +151,28 @@ unit aoptcpu;
 {$endif DEBUG_AOPTCPU}
 
 
+  { Converts a conditional jump into an unconditional jump.  Only call this
+    procedure on an instruction that you already know is a conditional jump }
+  procedure TCpuAsmOptimizer.MakeUnconditional(p: taicpu);
+    var
+      idx, topidx: Byte;
+    begin
+      inherited MakeUnconditional(p);
+
+      topidx := p.ops-1;
+      if topidx = 0 then
+        Exit;
+
+      { Move destination address into first register, then delete the rest }
+      p.loadoper(0, p.oper[topidx]^);
+      for idx := topidx downto 1 do
+        p.freeop(idx);
+      p.ops := 1;
+      p.opercnt := 1;
+
+    end;
+
+
  function TCpuAsmOptimizer.InstructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;
     var
       p: taicpu;