Jelajahi Sumber

+ MIPS: implemented peephole optimization which changes appropriate patterns into conditional moves, which are available on MIPS4 and higher.

git-svn-id: trunk@28008 -
sergei 11 tahun lalu
induk
melakukan
c2a29a0dbb
1 mengubah file dengan 203 tambahan dan 0 penghapusan
  1. 203 0
      compiler/mips/aoptcpu.pas

+ 203 - 0
compiler/mips/aoptcpu.pas

@@ -38,6 +38,7 @@ unit aoptcpu;
           var AllUsedRegs: TAllUsedRegs): Boolean;
         function TryRemoveMov(var p: tai; opcode: TAsmOp): boolean;
         function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
+        procedure PeepHoleOptPass2; override;
       End;
 
   Implementation
@@ -92,6 +93,56 @@ unit aoptcpu;
     end;
 
 
+  function CanBeCMOV(p: tai): boolean;
+    begin
+      result:=assigned(p) and (p.typ=ait_instruction) and
+        (taicpu(p).opcode in [A_MOV_D,A_MOV_S,A_MOVE]);
+    end;
+
+
+  procedure ChangeToCMOV(p: taicpu; cond: tasmcond; reg: tregister);
+    begin
+      case cond of
+        C_COP1TRUE:
+          case p.opcode of
+            A_MOV_D: p.opcode:=A_MOVT_D;
+            A_MOV_S: p.opcode:=A_MOVT_S;
+            A_MOVE:  p.opcode:=A_MOVT;
+          else
+            InternalError(2014061701);
+          end;
+        C_COP1FALSE:
+          case p.opcode of
+            A_MOV_D: p.opcode:=A_MOVF_D;
+            A_MOV_S: p.opcode:=A_MOVF_S;
+            A_MOVE:  p.opcode:=A_MOVF;
+          else
+            InternalError(2014061702);
+          end;
+        C_EQ:
+          case p.opcode of
+            A_MOV_D: p.opcode:=A_MOVZ_D;
+            A_MOV_S: p.opcode:=A_MOVZ_S;
+            A_MOVE:  p.opcode:=A_MOVZ;
+          else
+            InternalError(2014061703);
+          end;
+        C_NE:
+          case p.opcode of
+            A_MOV_D: p.opcode:=A_MOVN_D;
+            A_MOV_S: p.opcode:=A_MOVN_S;
+            A_MOVE:  p.opcode:=A_MOVN;
+          else
+            InternalError(2014061704);
+          end;
+      else
+        InternalError(2014061705);
+      end;
+      p.ops:=3;
+      p.loadreg(2,reg);
+    end;
+
+
   function instructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;
     var
       p: taicpu;
@@ -357,6 +408,158 @@ unit aoptcpu;
       end;
     end;
 
+
+  procedure TCpuAsmOptimizer.PeepHoleOptPass2;
+    var
+      p: tai;
+      l: longint;
+      hp1,hp2,hp3: tai;
+      condition: tasmcond;
+      condreg: tregister;
+    begin
+      { Currently, everything below is mips4+ }
+      if (current_settings.cputype<cpu_mips4) then
+        exit;
+      p:=BlockStart;
+      ClearUsedRegs;
+      while (p<>BlockEnd) Do
+        begin
+          UpdateUsedRegs(tai(p.next));
+          case p.typ of
+            ait_instruction:
+              begin
+                case taicpu(p).opcode of
+                  A_BC:
+                    begin
+                      condreg:=NR_NO;
+                      if (taicpu(p).condition in [C_COP1TRUE,C_COP1FALSE]) then
+                        { TODO: must be taken from "p" if/when codegen makes use of multiple %fcc }
+                        condreg:=NR_FCC0
+                      else if (taicpu(p).condition in [C_EQ,C_NE]) then
+                        begin
+                          if (taicpu(p).oper[0]^.reg=NR_R0) then
+                            condreg:=taicpu(p).oper[1]^.reg
+                          else if (taicpu(p).oper[1]^.reg=NR_R0) then
+                            condreg:=taicpu(p).oper[0]^.reg
+                        end;
+
+                      if (condreg<>NR_NO) then
+                        begin
+                          { check for
+                              bCC   xxx
+                              <several movs>
+                          xxx:
+                          }
+                          l:=0;
+                          GetNextInstruction(p, hp1);
+                          while CanBeCMOV(hp1) do       // CanBeCMOV returns False for nil or labels
+                            begin
+                              inc(l);
+                              GetNextInstruction(hp1,hp1);
+                            end;
+                          if assigned(hp1) then
+                            begin
+                              if FindLabel(tasmlabel(taicpu(p).oper[taicpu(p).ops-1]^.ref^.symbol),hp1) then
+                                begin
+                                  if (l<=4) and (l>0) then
+                                    begin
+                                      condition:=inverse_cond(taicpu(p).condition);
+                                      hp2:=p;
+                                      GetNextInstruction(p,hp1);
+                                      p:=hp1;
+                                      repeat
+                                        ChangeToCMOV(taicpu(hp1),condition,condreg);
+                                        GetNextInstruction(hp1,hp1);
+                                      until not CanBeCMOV(hp1);
+                                      { wait with removing else GetNextInstruction could
+                                        ignore the label if it was the only usage in the
+                                        jump moved away }
+                                      tasmlabel(taicpu(hp2).oper[taicpu(hp2).ops-1]^.ref^.symbol).decrefs;
+                                      RemoveDelaySlot(hp2);
+                                      asml.remove(hp2);
+                                      hp2.free;
+                                      continue;
+                                    end;
+                                end
+                              else
+                                begin
+                                  { check further for
+                                        bCC   xxx
+                                        <several movs 1>
+                                        b     yyy
+                                    xxx:
+                                        <several movs 2>
+                                    yyy:
+                                  }
+                                  { hp2 points to jmp yyy }
+                                  hp2:=hp1;
+                                  { skip hp1 to xxx }
+                                  GetNextInstruction(hp1, hp1);
+                                  if assigned(hp2) and
+                                    assigned(hp1) and
+                                    (l<=3) and
+                                    (hp2.typ=ait_instruction) and
+                                    (taicpu(hp2).opcode=A_BA) and
+                                    { real label and jump, no further references to the
+                                      label are allowed }
+                                    (tasmlabel(taicpu(p).oper[taicpu(p).ops-1]^.ref^.symbol).getrefs<=2) and
+                                    FindLabel(tasmlabel(taicpu(p).oper[taicpu(p).ops-1]^.ref^.symbol),hp1) then
+                                    begin
+                                      l:=0;
+                                      { skip hp1 to <several moves 2> }
+                                      GetNextInstruction(hp1, hp1);
+                                      while CanBeCMOV(hp1) do
+                                        begin
+                                          inc(l);
+                                          GetNextInstruction(hp1, hp1);
+                                        end;
+                                      { hp1 points to yyy: }
+                                      if assigned(hp1) and
+                                        FindLabel(tasmlabel(taicpu(hp2).oper[taicpu(hp2).ops-1]^.ref^.symbol),hp1) then
+                                        begin
+                                          condition:=inverse_cond(taicpu(p).condition);
+                                          GetNextInstruction(p,hp1);
+                                          hp3:=p;
+                                          p:=hp1;
+                                          repeat
+                                            ChangeToCMOV(taicpu(hp1),condition,condreg);
+                                            GetNextInstruction(hp1,hp1);
+                                          until not CanBeCMOV(hp1);
+                                          { hp2 is still at b yyy }
+                                          GetNextInstruction(hp2,hp1);
+                                          { hp2 is now at xxx: }
+                                          condition:=inverse_cond(condition);
+                                          GetNextInstruction(hp1,hp1);
+                                          { hp1 is now at <several movs 2> }
+                                          repeat
+                                            ChangeToCMOV(taicpu(hp1),condition,condreg);
+                                            GetNextInstruction(hp1,hp1);
+                                          until not CanBeCMOV(hp1);
+                                          { remove bCC }
+                                          tasmlabel(taicpu(hp3).oper[taicpu(hp3).ops-1]^.ref^.symbol).decrefs;
+                                          RemoveDelaySlot(hp3);
+                                          asml.remove(hp3);
+                                          hp3.free;
+                                          { remove jmp }
+                                          tasmlabel(taicpu(hp2).oper[taicpu(hp2).ops-1]^.ref^.symbol).decrefs;
+                                          RemoveDelaySlot(hp2);
+                                          asml.remove(hp2);
+                                          hp2.free;
+                                          continue;
+                                        end;
+                                    end;
+                                end;
+                            end;
+                        end;
+                    end;
+                end;
+              end;
+          end;
+          UpdateUsedRegs(p);
+          p:=tai(p.next);
+        end;
+    end;
+
 begin
   casmoptimizer:=TCpuAsmOptimizer;
 end.