Browse Source

+ avr assemblers do not convert automatically cond. branches with too large jump distances into an unconditional branch and a reverse condition branch, so fpc does this now

git-svn-id: trunk@18837 -
florian 14 years ago
parent
commit
cf0d808708
3 changed files with 185 additions and 2 deletions
  1. 5 0
      compiler/aasmbase.pas
  2. 173 1
      compiler/avr/aasmcpu.pas
  3. 7 1
      compiler/psub.pas

+ 5 - 0
compiler/aasmbase.pas

@@ -147,6 +147,11 @@ interface
            TAsmList with loadsym/loadref/const_symbol (PFV) }
            TAsmList with loadsym/loadref/const_symbol (PFV) }
          refs       : longint;
          refs       : longint;
        public
        public
+         { on avr the compiler needs to replace cond. jumps with too large offsets
+           so we have to store an offset somewhere to calculate jump distances }
+{$ifdef AVR}
+         offset     : longint;
+{$endif AVR}
          bind       : TAsmsymbind;
          bind       : TAsmsymbind;
          typ        : TAsmsymtype;
          typ        : TAsmsymtype;
          { Alternate symbol which can be used for 'renaming' needed for
          { Alternate symbol which can be used for 'renaming' needed for

+ 173 - 1
compiler/avr/aasmcpu.pas

@@ -29,7 +29,8 @@ uses
   cclasses,
   cclasses,
   globtype,globals,verbose,
   globtype,globals,verbose,
   aasmbase,aasmtai,aasmdata,aasmsym,
   aasmbase,aasmtai,aasmdata,aasmsym,
-  cgbase,cgutils,cpubase,cpuinfo;
+  cgbase,cgutils,cpubase,cpuinfo,
+  ogbase;
 
 
     const
     const
       { "mov reg,reg" source operand number }
       { "mov reg,reg" source operand number }
@@ -37,7 +38,19 @@ uses
       { "mov reg,reg" source operand number }
       { "mov reg,reg" source operand number }
       O_MOV_DEST = 0;
       O_MOV_DEST = 0;
 
 
+      maxinfolen = 5;
+
     type
     type
+      tinsentry = record
+        opcode  : tasmop;
+        ops     : byte;
+        optypes : array[0..3] of longint;
+        code    : array[0..maxinfolen] of char;
+        flags   : longint;
+      end;
+
+      pinsentry=^tinsentry;
+
       taicpu = class(tai_cpu_abstract_sym)
       taicpu = class(tai_cpu_abstract_sym)
          constructor op_none(op : tasmop);
          constructor op_none(op : tasmop);
 
 
@@ -61,6 +74,24 @@ uses
 
 
          { register spilling code }
          { register spilling code }
          function spilling_get_operation_type(opnr: longint): topertype;override;
          function spilling_get_operation_type(opnr: longint): topertype;override;
+
+         { assembler }
+      public
+         { the next will reset all instructions that can change in pass 2 }
+         procedure ResetPass1;override;
+         procedure ResetPass2;override;
+{         function  CheckIfValid:boolean;
+         function GetString:string; }
+         function  Pass1(objdata:TObjData):longint;override;
+//         procedure Pass2(objdata:TObjData);override;
+         function calcsize(p:PInsEntry):shortint;
+      private
+         { next fields are filled in pass1, so pass2 is faster }
+         inssize   : shortint;
+         insoffset : longint;
+         insentry  : PInsEntry;
+         LastInsOffset : longint; { need to be public to be reset }
+         function  FindInsentry(objdata:TObjData):boolean;
       end;
       end;
 
 
       tai_align = class(tai_align_abstract)
       tai_align = class(tai_align_abstract)
@@ -75,6 +106,10 @@ uses
 
 
     function setcondition(i : taicpu;c : tasmcond) : taicpu;
     function setcondition(i : taicpu;c : tasmcond) : taicpu;
 
 
+    { replaces cond. branches by rjmp/jmp and the inverse cond. branch if needed
+      and transforms special instructions to valid instruction encodings }
+    procedure finalizeavrcode(list : TAsmList);
+
 implementation
 implementation
 
 
 {*****************************************************************************
 {*****************************************************************************
@@ -222,6 +257,84 @@ implementation
       end;
       end;
 
 
 
 
+    function  taicpu.calcsize(p:PInsEntry):shortint;
+      begin
+        case opcode of
+          A_CALL,
+          A_JMP:
+            result:=4;
+          A_LDS:
+            if (getsupreg(oper[0]^.reg)>=RS_R16) and (getsupreg(oper[0]^.reg)<=RS_R31) and
+              (oper[1]^.val>=0) and (oper[1]^.val<=127) then
+              result:=2
+            else
+              result:=4;
+          A_STS:
+            if (getsupreg(oper[1]^.reg)>=RS_R16) and (getsupreg(oper[1]^.reg)<=RS_R31) and
+              (oper[0]^.val>=0) and (oper[0]^.val<=127) then
+              result:=2
+            else
+              result:=4;
+        else
+          result:=2;
+        end;
+      end;
+
+
+    procedure taicpu.ResetPass1;
+      begin
+        { we need to reset everything here, because the choosen insentry
+          can be invalid for a new situation where the previously optimized
+          insentry is not correct }
+        InsEntry:=nil;
+        InsSize:=0;
+        LastInsOffset:=-1;
+      end;
+
+
+    procedure taicpu.ResetPass2;
+      begin
+{        { we are here in a second pass, check if the instruction can be optimized }
+        if assigned(InsEntry) and
+           ((InsEntry^.flags and IF_PASS2)<>0) then
+         begin
+           InsEntry:=nil;
+           InsSize:=0;
+         end;
+}
+        LastInsOffset:=-1;
+      end;
+
+
+    function taicpu.FindInsentry(objdata:TObjData):boolean;
+      begin
+        result:=false;
+      end;
+
+
+    function taicpu.Pass1(objdata:TObjData):longint;
+      begin
+        Pass1:=0;
+        { Save the old offset and set the new offset }
+        InsOffset:=ObjData.CurrObjSec.Size;
+        InsSize:=calcsize(InsEntry);
+        { Error? }
+        if (Insentry=nil) and (InsSize=-1) then
+          exit;
+        { set the file postion }
+        current_filepos:=fileinfo;
+
+        { Get InsEntry }
+        if FindInsEntry(objdata) then
+         begin
+           LastInsOffset:=InsOffset;
+           Pass1:=InsSize;
+           exit;
+         end;
+        LastInsOffset:=-1;
+      end;
+
+
     function spilling_create_load(const ref:treference;r:tregister):Taicpu;
     function spilling_create_load(const ref:treference;r:tregister):Taicpu;
       begin
       begin
         case getregtype(r) of
         case getregtype(r) of
@@ -277,6 +390,65 @@ implementation
       end;
       end;
 
 
 
 
+    procedure finalizeavrcode(list : TAsmList);
+      var
+        CurrOffset : longint;
+        curtai : tai;
+        again : boolean;
+        l : tasmlabel;
+      begin
+        again:=true;
+        while again do
+          begin
+            again:=false;
+            CurrOffset:=0;
+            curtai:=tai(list.first);
+            while assigned(curtai) do
+              begin
+                { instruction? }
+                if not(curtai.typ in SkipInstr) then
+                  case curtai.typ of
+                    ait_instruction:
+                      begin
+                        taicpu(curtai).InsOffset:=CurrOffset;
+                        inc(CurrOffset,taicpu(curtai).calcsize(nil));
+                      end;
+                    ait_align:
+                      inc(CurrOffset,tai_align(curtai).aligntype);
+                    ait_marker:
+                      ;
+                    ait_label:
+                      begin
+                        tai_label(curtai).labsym.offset:=CurrOffset;
+                      end;
+                    else
+                      internalerror(2011082401);
+                  end;
+                curtai:=tai(curtai.next);
+              end;
+
+            curtai:=tai(list.first);
+            while assigned(curtai) do
+              begin
+                if (curtai.typ=ait_instruction) and
+                  (taicpu(curtai).opcode in [A_BRxx]) and
+                  ((taicpu(curtai).InsOffset-taicpu(curtai).oper[0]^.ref^.symbol.offset>64) or
+                   (taicpu(curtai).InsOffset-taicpu(curtai).oper[0]^.ref^.symbol.offset<-63)
+                  ) then
+                  begin
+                    current_asmdata.getjumplabel(l);
+                    list.insertafter(tai_label.create(l),curtai);
+                    list.insertafter(taicpu.op_sym(A_JMP,taicpu(curtai).oper[0]^.ref^.symbol),curtai);
+                    taicpu(curtai).oper[0]^.ref^.symbol:=l;
+                    taicpu(curtai).condition:=inverse_cond(taicpu(curtai).condition);
+                    again:=true;
+                  end;
+                curtai:=tai(curtai.next);
+              end;
+          end;
+      end;
+
+
 begin
 begin
   cai_cpu:=taicpu;
   cai_cpu:=taicpu;
   cai_align:=tai_align;
   cai_align:=tai_align;

+ 7 - 1
compiler/psub.pas

@@ -104,7 +104,7 @@ implementation
        opttail,
        opttail,
        optcse,optloop,
        optcse,optloop,
        optutils
        optutils
-{$if defined(arm) or defined(powerpc) or defined(powerpc64)}
+{$if defined(arm) or defined(powerpc) or defined(powerpc64) or defined(avr)}
        ,aasmcpu
        ,aasmcpu
 {$endif arm}
 {$endif arm}
        {$ifndef NOOPT}
        {$ifndef NOOPT}
@@ -1228,6 +1228,12 @@ implementation
             finalizearmcode(aktproccode,aktlocaldata);
             finalizearmcode(aktproccode,aktlocaldata);
 {$endif ARM}
 {$endif ARM}
 
 
+{$ifdef AVR}
+            { because of the limited branch distance of cond. branches, they must be replaced
+              somtimes by normal jmps and an inverse branch }
+            finalizeavrcode(aktproccode);
+{$endif AVR}
+
             { Add end symbol and debug info }
             { Add end symbol and debug info }
             { this must be done after the pcrelativedata is appended else the distance calculation of
             { this must be done after the pcrelativedata is appended else the distance calculation of
               insertpcrelativedata will be wrong, further the pc indirect data is part of the procedure
               insertpcrelativedata will be wrong, further the pc indirect data is part of the procedure