Procházet zdrojové kódy

* make use of lea if possible

git-svn-id: trunk@25898 -
florian před 11 roky
rodič
revize
3c58cad96b
2 změnil soubory, kde provedl 78 přidání a 1 odebrání
  1. 64 0
      compiler/x86/cgx86.pas
  2. 14 1
      compiler/x86/nx86add.pas

+ 64 - 0
compiler/x86/cgx86.pas

@@ -70,6 +70,9 @@ unit cgx86;
         procedure a_op_ref_reg(list : TAsmList; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister); override;
         procedure a_op_reg_ref(list : TAsmList; Op: TOpCG; size: TCGSize;reg: TRegister; const ref: TReference); override;
 
+        procedure a_op_const_reg_reg(list : TAsmList; op : Topcg; size : Tcgsize; a : tcgint; src,dst : Tregister); override;
+        procedure a_op_reg_reg_reg(list : TAsmList; op : TOpCg; size : tcgsize; src1,src2,dst : tregister); override;
+
         { move instructions }
         procedure a_load_const_reg(list : TAsmList; tosize: tcgsize; a : tcgint;reg : tregister);override;
         procedure a_load_const_ref(list : TAsmList; tosize: tcgsize; a : tcgint;const ref : treference);override;
@@ -1547,11 +1550,71 @@ unit cgx86;
       end;
 
 
+    procedure tcgx86.a_op_const_reg_reg(list:TAsmList;op:Topcg;size:Tcgsize;
+                                        a:tcgint;src,dst:Tregister);
+      var
+        power  : longint;
+        href : treference;
+      begin
+      {  if (op in [OP_MUL,OP_IMUL]) and (size in [OS_32,OS_S32,OS_64,OS_S64]) and
+          not(cs_check_overflow in current_settings.localswitches) and
+          (a>1) and ispowerof2(int64(a-1),power) and (power in [1..3]) then
+          begin
+            reference_reset_base(href,src,0,0);
+            href.index:=src;
+            href.scalefactor:=a-1;
+            list.concat(taicpu.op_ref_reg(A_LEA,TCgSize2OpSize[size],href,dst));
+          end
+        else } if (op=OP_ADD) and
+          ((size in [OS_32,OS_S32]) or
+           { lea supports only 32 bit signed displacments }
+           ((size=OS_64) and (a>=0) and (a<=maxLongint)) or
+           ((size=OS_S64) and (a>=-maxLongint) and (a<=maxLongint))
+          ) and
+          not(cs_check_overflow in current_settings.localswitches) then
+          begin
+            reference_reset_base(href,src,a,0);
+            list.concat(taicpu.op_ref_reg(A_LEA,TCgSize2OpSize[size],href,dst));
+          end
+        else if (op=OP_SUB) and
+          ((size in [OS_32,OS_S32]) or
+           { lea supports only 32 bit signed displacments }
+           ((size=OS_64) and (a>=0) and (a<=maxLongint)) or
+           ((size=OS_S64) and (a>=-maxLongint) and (a<=maxLongint))
+          ) and
+          not(cs_check_overflow in current_settings.localswitches) then
+          begin
+            reference_reset_base(href,src,-a,0);
+            list.concat(taicpu.op_ref_reg(A_LEA,TCgSize2OpSize[size],href,dst));
+          end
+        else
+          inherited a_op_const_reg_reg(list,op,size,a,src,dst);
+      end;
+
+
+    procedure tcgx86.a_op_reg_reg_reg(list: TAsmList; op: TOpCg;
+      size: tcgsize; src1, src2, dst: tregister);
+      var
+        href : treference;
+      begin
+        if (op=OP_ADD) and (size in [OS_32,OS_S32,OS_64,OS_S64]) and
+          not(cs_check_overflow in current_settings.localswitches) then
+          begin
+            reference_reset_base(href,src1,0,0);
+            href.index:=src2;
+            list.concat(taicpu.op_ref_reg(A_LEA,TCgSize2OpSize[size],href,dst));
+          end
+        else
+          inherited a_op_reg_reg_reg(list,op,size,src1,src2,dst);
+      end;
+
+
     procedure tcgx86.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister);
 
       var
         opcode : tasmop;
         power  : longint;
+        href : treference;
 {$ifdef x86_64}
         tmpreg : tregister;
 {$endif x86_64}
@@ -1605,6 +1668,7 @@ unit cgx86;
                   list.concat(taicpu.op_const_reg(A_SHL,TCgSize2OpSize[size],power,reg));
                   exit;
                 end;
+
               if op = OP_IMUL then
                 list.concat(taicpu.op_const_reg(A_IMUL,TCgSize2OpSize[size],a,reg))
               else

+ 14 - 1
compiler/x86/nx86add.pas

@@ -85,6 +85,7 @@ unit nx86add;
         power : longint;
         hl4   : tasmlabel;
         r     : Tregister;
+        href  : treference;
       begin
         { at this point, left.location.loc should be LOC_REGISTER }
         if right.location.loc=LOC_REGISTER then
@@ -156,6 +157,18 @@ unit nx86add;
                   begin
                     emit_const_reg(A_SHL,TCGSize2Opsize[opsize],power,left.location.register);
                   end
+                else if (op=A_IMUL) and
+                    (right.location.loc=LOC_CONSTANT) and
+                    (right.location.value>1) and (ispowerof2(int64(right.location.value)-1,power)) and
+                    (power in [1..3]) and
+                    not(cs_check_overflow in current_settings.localswitches) then
+                  begin
+                    reference_reset_base(href,left.location.register,0,0);
+                    href.index:=left.location.register;
+                    href.scalefactor:=int64(right.location.value)-1;
+                    left.location.register:=cg.getintregister(current_asmdata.CurrAsmList,opsize);
+                    current_asmdata.CurrAsmList.concat(taicpu.op_ref_reg(A_LEA,TCgSize2OpSize[opsize],href,left.location.register));
+                  end
                else
                  begin
                    if extra_not then
@@ -210,7 +223,7 @@ unit nx86add;
               { maybe we can reuse a constant register when the
                 operation is a comparison that doesn't change the
                 value of the register }
-              hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,opdef,(nodetype in [ltn,lten,gtn,gten,equaln,unequaln]));
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,opdef,(nodetype in [ltn,lten,gtn,gten,equaln,unequaln]));
             end;
           end;
         if (right.location.loc<>LOC_CONSTANT) and