Browse Source

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 years ago
parent
commit
f505822ab5
2 changed files with 53 additions and 13 deletions
  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 }
         { Output debug message to console - null function if EXTDEBUG is not defined }
         class procedure DebugWrite(Message: string); static; inline;
         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 }
         { Removes all instructions between an unconditional jump and the next label }
         procedure RemoveDeadCodeAfterJump(p: taicpu);
         procedure RemoveDeadCodeAfterJump(p: taicpu);
 
 
@@ -1564,6 +1568,25 @@ Unit AoptObj;
 {$endif DEBUG_JUMP}
 {$endif DEBUG_JUMP}
       end;
       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 }
     { Removes all instructions between an unconditional jump and the next label }
     procedure TAOptObj.RemoveDeadCodeAfterJump(p: taicpu);
     procedure TAOptObj.RemoveDeadCodeAfterJump(p: taicpu);
       var
       var
@@ -2014,29 +2037,20 @@ Unit AoptObj;
                             Result := True;
                             Result := True;
                             Exit;
                             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
                           end
                         else
                         else
                           { NOTE: There is currently no watertight, cross-platform way to create
                           { NOTE: There is currently no watertight, cross-platform way to create
                             an unconditional jump without access to the cg object.  If anyone can
                             an unconditional jump without access to the cg object.  If anyone can
                             improve this particular optimisation to work on AVR and RISC-V,
                             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
                           begin
                             { Since cond1 is a subset of inv(cond2), jmp<cond2> will always branch if
                             { 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. }
                               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');
                             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
                             { NOTE: Changing the jump to unconditional won't open up new opportunities
                               for GetFinalDestination on earlier jumps because there's no live label
                               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}
 {$i fpcdefs.inc}
 
 
-{$define DEBUG_AOPTCPU}
+{ $define DEBUG_AOPTCPU}
 
 
   Interface
   Interface
 
 
@@ -36,6 +36,10 @@ unit aoptcpu;
       TAsmOpSet = set of TAsmOp;
       TAsmOpSet = set of TAsmOp;
 
 
       TCpuAsmOptimizer = class(TAsmOptimizer)
       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 RegModifiedByInstruction(Reg: TRegister; p1: tai): boolean; override;
         function GetNextInstructionUsingReg(Current: tai;
         function GetNextInstructionUsingReg(Current: tai;
           var Next: tai; reg: TRegister): Boolean;
           var Next: tai; reg: TRegister): Boolean;
@@ -147,6 +151,28 @@ unit aoptcpu;
 {$endif DEBUG_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;
  function TCpuAsmOptimizer.InstructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;
     var
     var
       p: taicpu;
       p: taicpu;