Browse Source

* x86: Revamped OptPass2Jcc CMOV code to shrink and reuse registers as much as possible

J. Gareth "Curious Kit" Moreton 2 years ago
parent
commit
6ffa258abb
1 changed files with 58 additions and 13 deletions
  1. 58 13
      compiler/x86/aoptx86.pas

+ 58 - 13
compiler/x86/aoptx86.pas

@@ -11696,6 +11696,9 @@ unit aoptx86;
 
 
     function TX86AsmOptimizer.OptPass2Jcc(var p : tai) : boolean;
+      const
+        subreg2opsize : array[tsubregister] of topsize =
+          (S_NO,S_B,S_B,S_W,S_L,S_Q,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO);
       var
         hp1,hp2: tai;
         carryadd_opcode : TAsmOp;
@@ -11714,6 +11717,10 @@ unit aoptx86;
 
         ConstRegs: array[0..MAX_CMOV_REGISTERS - 1] of TRegister;
         ConstVals: array[0..MAX_CMOV_REGISTERS - 1] of TCGInt;
+        ConstSizes: array[0..MAX_CMOV_REGISTERS - 1] of TSubRegister; { May not match ConstRegs if one is shared over multiple CMOVs. }
+        ConstMovs: array[0..MAX_CMOV_REGISTERS - 1] of tai; { Location of initialisation instruction }
+
+        ConstWriteSizes: array[0..first_int_imreg - 1] of TSubRegister; { Largest size of register written. }
 
         { Tries to convert a mov const,%reg instruction into a CMOV by reserving a
           new register to store the constant }
@@ -11750,10 +11757,10 @@ unit aoptx86;
             { See if the value has already been reserved for another CMOV instruction }
             CurrentVal := taicpu(p).oper[0]^.val;
             for X := 0 to StoredCount - 1 do
-              if (ConstVals[X] = CurrentVal) and
-                (getsubreg(taicpu(p).oper[1]^.reg) <= getsubreg(ConstRegs[X])) then
+              if ConstVals[X] = CurrentVal then
                 begin
-                  ConstRegs[StoredCount] := newreg(R_INTREGISTER, getsupreg(ConstRegs[X]), RegSize);
+                  ConstRegs[StoredCount] := ConstRegs[X];
+                  ConstSizes[StoredCount] := RegSize;
                   ConstVals[StoredCount] := CurrentVal;
                   Result := True;
 
@@ -11762,7 +11769,7 @@ unit aoptx86;
                   Exit;
                 end;
 
-            ANewReg := GetIntRegisterBetween(RegSize, TmpUsedRegs, search_start_p, stop_search_p, True);
+            ANewReg := GetIntRegisterBetween(R_SUBWHOLE, TmpUsedRegs, search_start_p, stop_search_p, True);
             if ANewReg = NR_NO then
               { No free registers }
               Exit;
@@ -11772,6 +11779,7 @@ unit aoptx86;
             IncludeRegInUsedRegs(ANewReg, TmpUsedRegs);
 
             ConstRegs[StoredCount] := ANewReg;
+            ConstSizes[StoredCount] := RegSize;
             ConstVals[StoredCount] := CurrentVal;
 
             Inc(StoredCount);
@@ -12242,10 +12250,13 @@ unit aoptx86;
                      l := 0;
                      c := 0;
 
-                     { Initialise RegWrites, ConstRegs and ConstVals }
+                     { Initialise RegWrites, ConstRegs, ConstVals, ConstSizes, ConstWriteSizes and ConstMovs }
                      FillChar(RegWrites[0], MAX_CMOV_INSTRUCTIONS * 2 * SizeOf(TRegister), 0);
                      FillChar(ConstRegs[0], MAX_CMOV_REGISTERS * SizeOf(TRegister), 0);
                      FillChar(ConstVals[0], MAX_CMOV_REGISTERS * SizeOf(TCGInt), 0);
+                     FillChar(ConstSizes[0], MAX_CMOV_REGISTERS * SizeOf(TSubRegister), 0);
+                     FillChar(ConstWriteSizes[0], first_int_imreg * SizeOf(TOpSize), 0);
+                     FillChar(ConstMovs[0], MAX_CMOV_REGISTERS * SizeOf(taicpu), 0);
 
                      RefModified := False;
                      while assigned(hp1) and
@@ -12341,7 +12352,7 @@ unit aoptx86;
                                           below) }
                                         if not TmpUsedRegs[R_INTREGISTER].IsUsed(ConstRegs[x]) then
                                           begin
-                                            hp_new := taicpu.op_const_reg(A_MOV, reg2opsize(ConstRegs[x]), taicpu(hp1).oper[0]^.val, ConstRegs[x]);
+                                            hp_new := taicpu.op_const_reg(A_MOV, subreg2opsize[R_SUBWHOLE], taicpu(hp1).oper[0]^.val, ConstRegs[X]);
                                             taicpu(hp_new).fileinfo := taicpu(hp_prev).fileinfo;
 
                                             asml.InsertBefore(hp_new, hp_flagalloc);
@@ -12349,14 +12360,20 @@ unit aoptx86;
                                               TrySwapMovOp(hp_prev2, hp_new);
 
                                             IncludeRegInUsedRegs(ConstRegs[x], TmpUsedRegs);
+
+                                            ConstMovs[X] := hp_new;
                                           end
                                         else
                                         { We just need an instruction between hp_prev and hp1
                                           where we know the register is marked as in use }
                                           hp_new := hpmov1;
 
+                                        { Keep track of largest write for this register so it can be optimised later }
+                                        if (getsubreg(taicpu(hp1).oper[1]^.reg) > ConstWriteSizes[getsupreg(ConstRegs[X])]) then
+                                          ConstWriteSizes[getsupreg(ConstRegs[X])] := getsubreg(taicpu(hp1).oper[1]^.reg);
+
                                         AllocRegBetween(ConstRegs[x], hp_new, hp1, UsedRegs);
-                                        taicpu(hp1).loadreg(0, newreg(R_INTREGISTER, getsupreg(ConstRegs[X]), getsubreg(taicpu(hp1).oper[1]^.reg)));
+                                        taicpu(hp1).loadreg(0, newreg(R_INTREGISTER, getsupreg(ConstRegs[X]), ConstSizes[X]));
                                         Inc(x);
                                       end;
 
@@ -12368,6 +12385,14 @@ unit aoptx86;
                                 GetNextInstruction(hp1, hp1);
                               until (hp1 = hp_lblxxx);
 
+                              { Update initialisation MOVs to the smallest possible size }
+                              for c := 0 to x - 1 do
+                                if Assigned(ConstMovs[c]) then
+                                  begin
+                                    taicpu(ConstMovs[c]).opsize := subreg2opsize[ConstWriteSizes[Word(ConstRegs[c])]];
+                                    setsubreg(taicpu(ConstMovs[c]).oper[1]^.reg, ConstWriteSizes[Word(ConstRegs[c])]);
+                                  end;
+
                               hp2 := hp_lblxxx;
                               repeat
                                 if not Assigned(hp2) then
@@ -12595,7 +12620,7 @@ unit aoptx86;
 
                                         for x := 0 to c - 1 do
                                           if (ConstVals[x] = taicpu(hp1).oper[0]^.val) and
-                                            (getsubreg(taicpu(hp1).oper[1]^.reg) <= getsubreg(ConstRegs[X])) then
+                                            (getsubreg(taicpu(hp1).oper[1]^.reg) = ConstSizes[X]) then
                                             begin
                                               RegMatch := True;
 
@@ -12606,20 +12631,26 @@ unit aoptx86;
                                                 below) }
                                               if not TmpUsedRegs[R_INTREGISTER].IsUsed(ConstRegs[x]) then
                                                 begin
-                                                  hp_new := taicpu.op_const_reg(A_MOV, reg2opsize(ConstRegs[X]), taicpu(hp1).oper[0]^.val, ConstRegs[X]);
+                                                  hp_new := taicpu.op_const_reg(A_MOV, subreg2opsize[R_SUBWHOLE], taicpu(hp1).oper[0]^.val, ConstRegs[X]);
                                                   asml.InsertBefore(hp_new, hp_flagalloc);
                                                   if Assigned(hp_prev2) then
                                                     TrySwapMovOp(hp_prev2, hp_new);
 
                                                   IncludeRegInUsedRegs(ConstRegs[x], TmpUsedRegs);
+
+                                                  ConstMovs[X] := hp_new;
                                                 end
                                               else
                                                 { We just need an instruction between hp_prev and hp1
                                                   where we know the register is marked as in use }
                                                 hp_new := hpmov2;
 
+                                              { Keep track of largest write for this register so it can be optimised later }
+                                              if (getsubreg(taicpu(hp1).oper[1]^.reg) > ConstWriteSizes[getsupreg(ConstRegs[X])]) then
+                                                ConstWriteSizes[getsupreg(ConstRegs[X])] := getsubreg(taicpu(hp1).oper[1]^.reg);
+
                                               AllocRegBetween(ConstRegs[x], hp_new, hp1, UsedRegs);
-                                              taicpu(hp1).loadreg(0, newreg(R_INTREGISTER, getsupreg(ConstRegs[X]), getsubreg(taicpu(hp1).oper[1]^.reg)));
+                                              taicpu(hp1).loadreg(0, newreg(R_INTREGISTER, getsupreg(ConstRegs[X]), ConstSizes[X]));
                                               Break;
                                             end;
 
@@ -12678,7 +12709,7 @@ unit aoptx86;
 
                                         for x := 0 to c - 1 do
                                           if (ConstVals[x] = taicpu(hp1).oper[0]^.val) and
-                                            (getsubreg(taicpu(hp1).oper[1]^.reg) <= getsubreg(ConstRegs[X])) then
+                                            (getsubreg(taicpu(hp1).oper[1]^.reg) = ConstSizes[X]) then
                                             begin
                                               RegMatch := True;
 
@@ -12689,20 +12720,26 @@ unit aoptx86;
                                                 below) }
                                               if not TmpUsedRegs[R_INTREGISTER].IsUsed(ConstRegs[x]) then
                                                 begin
-                                                  hp_new := taicpu.op_const_reg(A_MOV, reg2opsize(ConstRegs[X]), taicpu(hp1).oper[0]^.val, ConstRegs[X]);
+                                                  hp_new := taicpu.op_const_reg(A_MOV, subreg2opsize[R_SUBWHOLE], taicpu(hp1).oper[0]^.val, ConstRegs[X]);
                                                   asml.InsertBefore(hp_new, hp_flagalloc);
                                                   if Assigned(hp_prev2) then
                                                     TrySwapMovOp(hp_prev2, hp_new);
 
                                                   IncludeRegInUsedRegs(ConstRegs[x], TmpUsedRegs);
+
+                                                  ConstMovs[X] := hp_new;
                                                 end
                                               else
                                                 { We just need an instruction between hp_prev and hp1
                                                   where we know the register is marked as in use }
                                                 hp_new := hpmov1;
 
+                                              { Keep track of largest write for this register so it can be optimised later }
+                                              if (getsubreg(taicpu(hp1).oper[1]^.reg) > ConstWriteSizes[getsupreg(ConstRegs[X])]) then
+                                                ConstWriteSizes[getsupreg(ConstRegs[X])] := getsubreg(taicpu(hp1).oper[1]^.reg);
+
                                               AllocRegBetween(ConstRegs[x], hp_new, hp1, UsedRegs);
-                                              taicpu(hp1).loadreg(0, newreg(R_INTREGISTER, getsupreg(ConstRegs[X]), getsubreg(taicpu(hp1).oper[1]^.reg)));
+                                              taicpu(hp1).loadreg(0, newreg(R_INTREGISTER, getsupreg(ConstRegs[X]), ConstSizes[X]));
                                               Break;
                                             end;
 
@@ -12717,6 +12754,14 @@ unit aoptx86;
                                 GetNextInstruction(hp1, hp1);
                               until (hp1 = hp_jump); { Stop at the jump, not lbl xxx }
 
+                              { Update initialisation MOVs to the smallest possible size }
+                              for x := 0 to c - 1 do
+                                if Assigned(ConstMovs[x]) then
+                                  begin
+                                    taicpu(ConstMovs[x]).opsize := subreg2opsize[ConstWriteSizes[Word(ConstRegs[x])]];
+                                    setsubreg(taicpu(ConstMovs[x]).oper[1]^.reg, ConstWriteSizes[Word(ConstRegs[x])]);
+                                  end;
+
                               UpdateUsedRegs(tai(hp_jump.next));
                               UpdateUsedRegs(tai(hp_lblyyy.next));