Răsfoiți Sursa

Fixed reference handling mostly for Coldfire CPUs. While they are conceptually based on
M68000 CPUs they are nevertheless more restricted in some cases, so these need to be
handled explicitely (especially if symbols are involved).

git-svn-id: trunk@22738 -

svenbarth 12 ani în urmă
părinte
comite
dea2a205c9
1 a modificat fișierele cu 176 adăugiri și 29 ștergeri
  1. 176 29
      compiler/m68k/cgcpu.pas

+ 176 - 29
compiler/m68k/cgcpu.pas

@@ -317,6 +317,7 @@ unit cgcpu;
           { Push the data starting at ofs }
           href:=r;
           inc(href.offset,ofs);
+          fixref(list,href);
           if tcgsize2size[paraloc^.size]>cgpara.alignment then
             pushsize:=paraloc^.size
           else
@@ -414,41 +415,114 @@ unit cgcpu;
 
 
     function tcg68k.fixref(list: TAsmList; var ref: treference): boolean;
-
+       var
+         hreg,idxreg : tregister;
+         href : treference;
        begin
          result:=false;
-         { The Coldfire and MC68020+ have extended
+         { The MC68020+ has extended
            addressing capabilities with a 32-bit
            displacement.
          }
-         if (current_settings.cputype<>cpu_MC68000) then
+         if (current_settings.cputype=cpu_MC68020) then
            exit;
-         if (ref.base<>NR_NO) then
-           begin
-             if (ref.index <> NR_NO) and assigned(ref.symbol) then
-                internalerror(20020814);
-             { base + reg }
-             if ref.index <> NR_NO then
-                begin
-                   { base + reg + offset }
-                   if (ref.offset < low(shortint)) or (ref.offset > high(shortint)) then
+         { ToDo: check which constraints of Coldfire also apply to MC68000 }
+         case current_settings.cputype of
+           cpu_MC68000:
+             begin
+               if (ref.base<>NR_NO) then
+                 begin
+                   if (ref.index <> NR_NO) and assigned(ref.symbol) then
+                      internalerror(2002081402);
+                   { base + reg }
+                   if ref.index <> NR_NO then
+                      begin
+                         { base + reg + offset }
+                         if (ref.offset < low(shortint)) or (ref.offset > high(shortint)) then
+                           begin
+                              list.concat(taicpu.op_const_reg(A_ADD,S_L,ref.offset,ref.base));
+                              fixref := true;
+                              ref.offset := 0;
+                              exit;
+                           end;
+                      end
+                   else
+                   { base + offset }
+                   if (ref.offset < low(smallint)) or (ref.offset > high(smallint)) then
                      begin
-                        list.concat(taicpu.op_const_reg(A_ADD,S_L,ref.offset,ref.base));
-                        fixref := true;
-                        ref.offset := 0;
-                        exit;
+                       list.concat(taicpu.op_const_reg(A_ADD,S_L,ref.offset,ref.base));
+                       fixref := true;
+                       ref.offset := 0;
+                       exit;
                      end;
-                end
-             else
-             { base + offset }
-             if (ref.offset < low(smallint)) or (ref.offset > high(smallint)) then
-               begin
-                 list.concat(taicpu.op_const_reg(A_ADD,S_L,ref.offset,ref.base));
-                 fixref := true;
-                 ref.offset := 0;
-                 exit;
-               end;
-           end;
+                 end;
+             end;
+           cpu_Coldfire:
+             begin
+               if (ref.base<>NR_NO) then
+                 begin
+                   if assigned(ref.symbol) and (ref.index=NR_NO) then
+                     begin
+                       hreg:=cg.getaddressregister(list);
+                       reference_reset_symbol(href,ref.symbol,0,ref.alignment);
+                       list.concat(taicpu.op_ref_reg(A_LEA,S_L,href,hreg));
+                       ref.index:=ref.base;
+                       ref.base:=hreg;
+                       ref.symbol:=nil;
+                     end;
+                   if (ref.index<>NR_NO) and assigned(ref.symbol) then
+                     begin
+                       list.concat(taicpu.op_reg_reg(A_ADD,S_L,ref.base,ref.index));
+                       ref.index:=NR_NO;
+                     end;
+                   {if (ref.index <> NR_NO) and assigned(ref.symbol) then
+                      internalerror(2002081403);}
+                   { first ensure that base is an address register }
+                   if not isaddressregister(ref.base) then
+                     begin
+                       hreg:=getaddressregister(list);
+                       list.concat(taicpu.op_reg_reg(A_MOVE,S_L,ref.base,hreg));
+                       fixref:=true;
+                       ref.base:=hreg;
+                     end;
+                   { base + reg }
+                   if ref.index <> NR_NO then
+                      begin
+                         { base + reg + offset }
+                         if (ref.offset < low(shortint)) or (ref.offset > high(shortint)) then
+                           begin
+                              list.concat(taicpu.op_const_reg(A_ADD,S_L,ref.offset,ref.base));
+                              fixref := true;
+                              ref.offset := 0;
+                              exit;
+                           end;
+                      end
+                   else
+                   { base + offset }
+                   if (ref.offset < low(smallint)) or (ref.offset > high(smallint)) then
+                     begin
+                       list.concat(taicpu.op_const_reg(A_ADD,S_L,ref.offset,ref.base));
+                       fixref:=true;
+                       ref.offset:=0;
+                       exit;
+                     end;
+                 end
+               else
+                 { Note: symbol -> ref would be supported as long as ref does not
+                         contain a offset or index... (maybe something for the
+                         optimizer) }
+                 if Assigned(ref.symbol) {and (ref.index<>NR_NO)} then
+                   begin
+                     hreg:=cg.getaddressregister(list);
+                     idxreg:=ref.index;
+                     ref.index:=NR_NO;
+                     list.concat(taicpu.op_ref_reg(A_LEA,S_L,ref,hreg));
+                     reference_reset_base(ref,hreg,0,ref.alignment);
+                     ref.index:=idxreg;
+                     fixref:=true;
+                   end;
+             end;
+         end;
        end;
 
 
@@ -514,12 +588,32 @@ unit cgcpu;
       end;
 
     procedure tcg68k.a_load_const_ref(list : TAsmList; tosize: tcgsize; a : tcgint;const ref : treference);
+      var
+        hreg : tregister;
+        href : treference;
       begin
 {$ifdef DEBUG_CHARLIE}
         list.concat(tai_comment.create(strpnew('a_load_const_ref')));
 {$endif DEBUG_CHARLIE}
 
-        list.concat(taicpu.op_const_ref(A_MOVE,S_L,longint(a),ref));
+        href:=ref;
+        fixref(list,href);
+        { for coldfire we need to go through a temporary register if we have a
+          offset, index or symbol given }
+        if (current_settings.cputype=cpu_coldfire) and
+            (
+              (href.offset<>0) or
+              { TODO : check whether we really need this second condition }
+              (href.index<>NR_NO) or
+              assigned(href.symbol)
+            ) then
+          begin
+            hreg:=getintregister(list,tosize);
+            list.concat(taicpu.op_const_reg(A_MOVE,S_L,longint(a),hreg));
+            list.concat(taicpu.op_reg_ref(A_MOVE,S_L,hreg,href));
+          end
+        else
+          list.concat(taicpu.op_const_ref(A_MOVE,S_L,longint(a),href));
       end;
 
 
@@ -541,6 +635,8 @@ unit cgcpu;
       var
         aref: treference;
         bref: treference;
+        dofix : boolean;
+        hreg: TRegister;
       begin
         aref := sref;
         bref := dref;
@@ -549,6 +645,57 @@ unit cgcpu;
 {$ifdef DEBUG_CHARLIE}
 //        writeln('a_load_ref_ref');
 {$endif DEBUG_CHARLIE}
+        { Coldfire dislikes certain move combinations }
+        if current_settings.cputype=cpu_coldfire then
+          begin
+            { TODO : move.b/w only allowed in newer coldfires... (ISA_B+) }
+
+            dofix:=false;
+            if { (d16,Ax) and (d8,Ax,Xi) }
+                (
+                  (aref.base<>NR_NO) and
+                  (
+                    (aref.index<>NR_NO) or
+                    (aref.offset<>0)
+                  )
+                ) or
+                { (xxx) }
+                assigned(aref.symbol) then
+              begin
+                if aref.index<>NR_NO then
+                  begin
+                    dofix:={ (d16,Ax) and (d8,Ax,Xi) }
+                           (
+                             (bref.base<>NR_NO) and
+                             (
+                               (bref.index<>NR_NO) or
+                               (bref.offset<>0)
+                             )
+                           ) or
+                           { (xxx) }
+                           assigned(bref.symbol);
+                  end
+                else
+                  { offset <> 0, but no index }
+                  begin
+                    dofix:={ (d8,Ax,Xi) }
+                           (
+                             (bref.base<>NR_NO) and
+                             (bref.index<>NR_NO)
+                           ) or
+                           { (xxx) }
+                           assigned(bref.symbol);
+                  end;
+              end;
+
+            if dofix then
+              begin
+                hreg:=getaddressregister(list);
+                list.concat(taicpu.op_ref_reg(A_LEA,S_L,bref,hreg));
+                list.concat(taicpu.op_reg_ref(A_MOVE,S_L{TCGSize2OpSize[fromsize]},hreg,bref));
+                exit;
+              end;
+          end;
         list.concat(taicpu.op_ref_ref(A_MOVE,TCGSize2OpSize[fromsize],aref,bref));
       end;
 
@@ -566,7 +713,7 @@ unit cgcpu;
       var
        href : treference;
       begin
-         href := ref;
+         href:=ref;
          fixref(list,href);
          list.concat(taicpu.op_ref_reg(A_MOVE,TCGSize2OpSize[fromsize],href,register));
          { extend the value in the register }