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) }
          refs       : longint;
        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;
          typ        : TAsmsymtype;
          { Alternate symbol which can be used for 'renaming' needed for

+ 173 - 1
compiler/avr/aasmcpu.pas

@@ -29,7 +29,8 @@ uses
   cclasses,
   globtype,globals,verbose,
   aasmbase,aasmtai,aasmdata,aasmsym,
-  cgbase,cgutils,cpubase,cpuinfo;
+  cgbase,cgutils,cpubase,cpuinfo,
+  ogbase;
 
     const
       { "mov reg,reg" source operand number }
@@ -37,7 +38,19 @@ uses
       { "mov reg,reg" source operand number }
       O_MOV_DEST = 0;
 
+      maxinfolen = 5;
+
     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)
          constructor op_none(op : tasmop);
 
@@ -61,6 +74,24 @@ uses
 
          { register spilling code }
          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;
 
       tai_align = class(tai_align_abstract)
@@ -75,6 +106,10 @@ uses
 
     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
 
 {*****************************************************************************
@@ -222,6 +257,84 @@ implementation
       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;
       begin
         case getregtype(r) of
@@ -277,6 +390,65 @@ implementation
       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
   cai_cpu:=taicpu;
   cai_align:=tai_align;

+ 7 - 1
compiler/psub.pas

@@ -104,7 +104,7 @@ implementation
        opttail,
        optcse,optloop,
        optutils
-{$if defined(arm) or defined(powerpc) or defined(powerpc64)}
+{$if defined(arm) or defined(powerpc) or defined(powerpc64) or defined(avr)}
        ,aasmcpu
 {$endif arm}
        {$ifndef NOOPT}
@@ -1228,6 +1228,12 @@ implementation
             finalizearmcode(aktproccode,aktlocaldata);
 {$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 }
             { 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