瀏覽代碼

o better code generation for avr:
* omit entry/exit code, if no frame pointer is used, partly fixes issue #27842
* take advantage of adiw/sbiw
* make more often use of ldd/std

git-svn-id: trunk@30732 -

florian 10 年之前
父節點
當前提交
5c8d0d87cd
共有 1 個文件被更改,包括 113 次插入57 次删除
  1. 113 57
      compiler/avr/cgcpu.pas

+ 113 - 57
compiler/avr/cgcpu.pas

@@ -109,6 +109,7 @@ unit cgcpu;
       protected
         procedure a_op_reg_reg_internal(list: TAsmList; Op: TOpCG; size: TCGSize; src, srchi, dst, dsthi: TRegister);
         procedure a_op_const_reg_internal(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg, reghi: TRegister);
+        procedure maybegetcpuregister(list : tasmlist; reg : tregister);
       end;
 
       tcg64favr = class(tcg64f32)
@@ -879,14 +880,15 @@ unit cgcpu;
        end;
 
 
-    function tcgavr.normalize_ref(list:TAsmList;ref: treference;tmpreg : tregister) : treference;
+    procedure tcgavr.maybegetcpuregister(list:tasmlist;reg : tregister);
+      begin
+        { allocate the register only, if a cpu register is passed }
+        if getsupreg(reg)<first_int_imreg then
+          getcpuregister(list,reg);
+      end;
 
-      procedure maybegetcpuregister(list:tasmlist;reg : tregister);
-        begin
-          { allocate the register only, if a cpu register is passed }
-          if getsupreg(reg)<first_int_imreg then
-            getcpuregister(list,reg);
-        end;
+
+    function tcgavr.normalize_ref(list:TAsmList;ref: treference;tmpreg : tregister) : treference;
 
       var
         tmpref : treference;
@@ -906,7 +908,29 @@ unit cgcpu;
             ref.base:=ref.index;
             ref.index:=NR_NO;
           end;
-        if assigned(ref.symbol) or (ref.offset<>0) then
+
+        { can we take advantage of adiw/sbiw? }
+        if (current_settings.cputype>=cpu_avr2) and not(assigned(ref.symbol)) and (ref.offset<>0) and (ref.offset>=-63) and (ref.offset<=63) and
+          ((tmpreg=NR_R24) or (tmpreg=NR_R26) or (tmpreg=NR_R28) or (tmpreg=NR_R30)) and (ref.base<>NR_NO) then
+          begin
+            maybegetcpuregister(list,tmpreg);
+            emit_mov(list,tmpreg,ref.base);
+            maybegetcpuregister(list,GetNextReg(tmpreg));
+            emit_mov(list,GetNextReg(tmpreg),GetNextReg(ref.base));
+            if ref.index<>NR_NO then
+              begin
+                list.concat(taicpu.op_reg_reg(A_ADD,tmpreg,ref.index));
+                list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(tmpreg),GetNextReg(ref.index)));
+              end;
+            if ref.offset>0 then
+              list.concat(taicpu.op_reg_const(A_ADIW,tmpreg,ref.offset))
+            else
+              list.concat(taicpu.op_reg_const(A_SBIW,tmpreg,-ref.offset));
+            ref.offset:=0;
+            ref.base:=tmpreg;
+            ref.index:=NR_NO;
+          end
+        else if assigned(ref.symbol) or (ref.offset<>0) then
           begin
             reference_reset(tmpref,0);
             tmpref.symbol:=ref.symbol;
@@ -982,20 +1006,39 @@ unit cgcpu;
          QuickRef : Boolean;
        begin
          QuickRef:=false;
-         if not((Ref.addressmode=AM_UNCHANGED) and
-                (Ref.symbol=nil) and
-                ((Ref.base=NR_R28) or
-                 (Ref.base=NR_R29)) and
-                 (Ref.Index=NR_No) and
-                 (Ref.Offset in [0..64-tcgsize2size[tosize]])) and
-           not((Ref.Base=NR_NO) and (Ref.Index=NR_NO)) then
-           href:=normalize_ref(list,Ref,NR_R30)
-         else
+
+         href:=Ref;
+         { ensure, href.base contains a valid register if there is any register used }
+         if href.base=NR_NO then
            begin
-             QuickRef:=true;
-             href:=Ref;
+             href.base:=href.index;
+             href.index:=NR_NO;
            end;
 
+         { try to use std/sts }
+         if not((href.Base=NR_NO) and (href.Index=NR_NO)) then
+           begin
+             if not((href.addressmode=AM_UNCHANGED) and
+                    (href.symbol=nil) and
+                     (href.Index=NR_NO) and
+                     (href.Offset in [0..64-tcgsize2size[fromsize]])) then
+               href:=normalize_ref(list,href,NR_R30)
+             else
+               begin
+                 if (href.base<>NR_R28) and (href.base<>NR_R30) then
+                   begin
+                     maybegetcpuregister(list,NR_R30);
+                     emit_mov(list,NR_R30,href.base);
+                     maybegetcpuregister(list,NR_R31);
+                     emit_mov(list,NR_R31,GetNextReg(href.base));
+                     href.base:=NR_R30;
+                   end;
+                 QuickRef:=true;
+               end;
+           end
+         else
+           QuickRef:=true;
+
          if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
            internalerror(2011021307);
 
@@ -1154,20 +1197,39 @@ unit cgcpu;
          QuickRef : boolean;
        begin
          QuickRef:=false;
-         if not((Ref.addressmode=AM_UNCHANGED) and
-                (Ref.symbol=nil) and
-                ((Ref.base=NR_R28) or
-                 (Ref.base=NR_R29)) and
-                 (Ref.Index=NR_No) and
-                 (Ref.Offset in [0..64-tcgsize2size[fromsize]])) and
-           not((Ref.Base=NR_NO) and (Ref.Index=NR_NO)) then
-           href:=normalize_ref(list,Ref,NR_R30)
-         else
+
+         href:=Ref;
+         { ensure, href.base contains a valid register if there is any register used }
+         if href.base=NR_NO then
            begin
-             QuickRef:=true;
-             href:=Ref;
+             href.base:=href.index;
+             href.index:=NR_NO;
            end;
 
+         { try to use ldd/lds }
+         if not((href.Base=NR_NO) and (href.Index=NR_NO)) then
+           begin
+             if not((href.addressmode=AM_UNCHANGED) and
+                    (href.symbol=nil) and
+                     (href.Index=NR_NO) and
+                     (href.Offset in [0..64-tcgsize2size[fromsize]])) then
+               href:=normalize_ref(list,href,NR_R30)
+             else
+               begin
+                 if (href.base<>NR_R28) and (href.base<>NR_R30) then
+                   begin
+                     maybegetcpuregister(list,NR_R30);
+                     emit_mov(list,NR_R30,href.base);
+                     maybegetcpuregister(list,NR_R31);
+                     emit_mov(list,NR_R31,GetNextReg(href.base));
+                     href.base:=NR_R30;
+                   end;
+                 QuickRef:=true;
+               end;
+           end
+         else
+           QuickRef:=true;
+
          if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
            internalerror(2011021307);
 
@@ -1631,6 +1693,14 @@ unit cgcpu;
       begin
         if not(nostackframe) then
           begin
+            { check if the framepointer is actually used, this is done here because
+              we have to know the size of the locals (must be 0), avr does not know
+              an sp based stack }
+
+            if not(current_procinfo.procdef.stack_tainting_parameter(calleeside)) and
+              (localsize=0) then
+              current_procinfo.framepointer:=NR_NO;
+
             { save int registers,
               but only if the procedure returns }
             if not(po_noreturn in current_procinfo.procdef.procoptions) then
@@ -1640,25 +1710,19 @@ unit cgcpu;
             { if the framepointer is potentially used, save it always because we need a proper stack frame,
               even if the procedure never returns, the procedure could be e.g. a nested one accessing
               an outer stackframe }
-            if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+            if current_procinfo.framepointer<>NR_NO then
               regs:=regs+[RS_R28,RS_R29];
 
             for reg:=RS_R31 downto RS_R0 do
               if reg in regs then
                 list.concat(taicpu.op_reg(A_PUSH,newreg(R_INTREGISTER,reg,R_SUBWHOLE)));
 
-            if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+            if current_procinfo.framepointer<>NR_NO then
               begin
                 list.concat(taicpu.op_reg_const(A_IN,NR_R28,NIO_SP_LO));
                 list.concat(taicpu.op_reg_const(A_IN,NR_R29,NIO_SP_HI));
-              end
-            else
-              { the framepointer cannot be omitted on avr because sp
-                is not a register but part of the i/o map
-              }
-              internalerror(2011021901);
-
-            a_adjust_sp(list,-localsize);
+                a_adjust_sp(list,-localsize);
+              end;
           end;
       end;
 
@@ -1676,24 +1740,16 @@ unit cgcpu;
           exit;
         if not(nostackframe) then
           begin
-            if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+            regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
+            if current_procinfo.framepointer<>NR_NO then
               begin
+                regs:=regs+[RS_R28,RS_R29];
                 LocalSize:=current_procinfo.calc_stackframe_size;
                 a_adjust_sp(list,LocalSize);
-                regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
-                if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
-                  regs:=regs+[RS_R28,RS_R29];
-
-                for reg:=RS_R0 to RS_R31 do
-                  if reg in regs then
-                    list.concat(taicpu.op_reg(A_POP,newreg(R_INTREGISTER,reg,R_SUBWHOLE)));
-
-              end
-            else
-              { the framepointer cannot be omitted on avr because sp
-                is not a register but part of the i/o map
-              }
-              internalerror(2011021902);
+              end;
+            for reg:=RS_R0 to RS_R31 do
+              if reg in regs then
+                list.concat(taicpu.op_reg(A_POP,newreg(R_INTREGISTER,reg,R_SUBWHOLE)));
           end;
         list.concat(taicpu.op_none(A_RET));
       end;
@@ -1842,7 +1898,7 @@ unit cgcpu;
             if not((source.addressmode=AM_UNCHANGED) and
                    (source.symbol=nil) and
                    ((source.base=NR_R28) or
-                    (source.base=NR_R29)) and
+                    (source.base=NR_R30)) and
                     (source.Index=NR_NO) and
                     (source.Offset in [0..64-len])) and
               not((source.Base=NR_NO) and (source.Index=NR_NO)) then
@@ -1856,7 +1912,7 @@ unit cgcpu;
             if not((dest.addressmode=AM_UNCHANGED) and
                    (dest.symbol=nil) and
                    ((dest.base=NR_R28) or
-                    (dest.base=NR_R29)) and
+                    (dest.base=NR_R30)) and
                     (dest.Index=NR_No) and
                     (dest.Offset in [0..64-len])) and
               not((dest.Base=NR_NO) and (dest.Index=NR_NO)) then