Procházet zdrojové kódy

* changed {$align mac68k} from an alias for {$packrecords 2} to a proper
implementation for mac68k alignment (mantis #15061)
* changed {$align power} from an alias for {$packrecords 4} to an alias for
{$packrecords c}, as Power alignment is the default C alignment for
PowerPC under Mac OS X (it's close to {$packrecords 4}, but not identical)

git-svn-id: trunk@14577 -

Jonas Maebe před 15 roky
rodič
revize
9cc211e88e

+ 2 - 0
.gitattributes

@@ -10178,6 +10178,8 @@ tests/webtbs/tw14992b.pp svneol=native#text/pascal
 tests/webtbs/tw14992c.pp svneol=native#text/pascal
 tests/webtbs/tw1501.pp svneol=native#text/plain
 tests/webtbs/tw15015.pp svneol=native#text/plain
+tests/webtbs/tw15061.pp svneol=native#text/plain
+tests/webtbs/tw15061a.pp svneol=native#text/plain
 tests/webtbs/tw15088.pp svneol=native#text/plain
 tests/webtbs/tw15169.pp svneol=native#text/plain
 tests/webtbs/tw15203.pp svneol=native#text/pascal

+ 2 - 0
compiler/pdecvar.pas

@@ -1613,6 +1613,8 @@ implementation
                 { 1 byte alignment if we are bitpacked }
                 bit_alignment:
                   usedalign:=1;
+                mac68k_alignment:
+                  usedalign:=2;
                 { otherwise alignment at the packrecords alignment of the }
                 { current record                                          }
                 else

+ 4 - 2
compiler/scandir.pas

@@ -144,9 +144,11 @@ unit scandir;
              begin
                { Support switches used in Apples Universal Interfaces}
                if (hs='MAC68K') then
-                 current_settings.packrecords:=2
+                 current_settings.packrecords:=mac68k_alignment
+               { "power" alignment is the default C packrecords setting on
+                 Mac OS X }
                else if (hs='POWER') then
-                 current_settings.packrecords:=4
+                 current_settings.packrecords:=C_alignment
                else if (hs='RESET') then
                  current_settings.packrecords:=0
                else

+ 4 - 3
compiler/symconst.pas

@@ -28,10 +28,11 @@ uses
   globtype;
 
 const
-  def_alignment = 4;
+  def_alignment     = 4;
 
-  C_alignment   = -1;
-  bit_alignment = -2;
+  C_alignment       = -1;
+  bit_alignment     = -2;
+  mac68k_alignment  = -3;
 
   { if you change one of the following contants, }
   { you have also to change the typinfo unit}

+ 96 - 70
compiler/symtable.pas

@@ -757,7 +757,9 @@ implementation
         case usealign of
           C_alignment,
           bit_alignment:
-            fieldalignment:=1
+            fieldalignment:=1;
+          mac68k_alignment:
+            fieldalignment:=2;
           else
             fieldalignment:=usealign;
         end;
@@ -813,10 +815,14 @@ implementation
       var
         varalignrecord: shortint;
       begin
-        if (usefieldalignment=C_alignment) then
-          varalignrecord:=used_align(varalign,current_settings.alignment.recordalignmin,current_settings.alignment.maxCrecordalign)
-        else
-          varalignrecord:=field2recordalignment(fieldoffset,varalign);
+        case usefieldalignment of
+          C_alignment:
+            varalignrecord:=used_align(varalign,current_settings.alignment.recordalignmin,current_settings.alignment.maxCrecordalign);
+          mac68k_alignment:
+            varalignrecord:=2;
+          else
+            varalignrecord:=field2recordalignment(fieldoffset,varalign);
+        end;
         recordalignment:=max(recordalignment,varalignrecord);
       end;
 
@@ -840,70 +846,85 @@ implementation
         vardef:=sym.vardef;
         varalign:=vardef.alignment;
 
-        if (usefieldalignment=bit_alignment) then
-          begin
-            { bitpacking only happens for ordinals, the rest is aligned at }
-            { 1 byte (compatible with GPC/GCC)                             }
-            if is_ordinal(vardef) then
-              begin
-                sym.fieldoffset:=databitsize;
-                l:=sym.getpackedbitsize;
-              end
-            else
-              begin
-                databitsize:=_datasize*8;
-                sym.fieldoffset:=databitsize;
-                if (l>high(aint) div 8) then
+        case usefieldalignment of
+          bit_alignment:
+            begin
+              { bitpacking only happens for ordinals, the rest is aligned at }
+              { 1 byte (compatible with GPC/GCC)                             }
+              if is_ordinal(vardef) then
+                begin
+                  sym.fieldoffset:=databitsize;
+                  l:=sym.getpackedbitsize;
+                end
+              else
+                begin
+                  databitsize:=_datasize*8;
+                  sym.fieldoffset:=databitsize;
+                  if (l>high(aint) div 8) then
+                    Message(sym_e_segment_too_large);
+                  l:=l*8;
+                end;
+              if varalign=0 then
+                varalign:=size_2_align(l);
+              recordalignment:=max(recordalignment,field2recordalignment(databitsize mod 8,varalign));
+              { bit packed records are limited to high(aint) bits }
+              { instead of bytes to avoid double precision        }
+              { arithmetic in offset calculations                 }
+              if int64(l)>high(aint)-sym.fieldoffset then
+                begin
                   Message(sym_e_segment_too_large);
-                l:=l*8;
-              end;
-            if varalign=0 then
-              varalign:=size_2_align(l);
-            recordalignment:=max(recordalignment,field2recordalignment(databitsize mod 8,varalign));
-            { bit packed records are limited to high(aint) bits }
-            { instead of bytes to avoid double precision        }
-            { arithmetic in offset calculations                 }
-            if int64(l)>high(aint)-sym.fieldoffset then
-              begin
-                Message(sym_e_segment_too_large);
-                _datasize:=high(aint);
-                databitsize:=high(aint);
-              end
-            else
-              begin
-                databitsize:=sym.fieldoffset+l;
-                _datasize:=(databitsize+7) div 8;
-              end;
-            { rest is not applicable }
-            exit;
-          end;
-        { Calc the alignment size for C style records }
-        if (usefieldalignment=C_alignment) then
-          begin
-            if (varalign>4) and
-              ((varalign mod 4)<>0) and
-              (vardef.typ=arraydef) then
-              Message1(sym_w_wrong_C_pack,vardef.typename);
-            if varalign=0 then
-              varalign:=l;
-            if (fieldalignment<current_settings.alignment.maxCrecordalign) then
-              begin
-                if (varalign>16) and (fieldalignment<32) then
-                  fieldalignment:=32
-                else if (varalign>12) and (fieldalignment<16) then
-                  fieldalignment:=16
-                { 12 is needed for long double }
-                else if (varalign>8) and (fieldalignment<12) then
-                  fieldalignment:=12
-                else if (varalign>4) and (fieldalignment<8) then
-                  fieldalignment:=8
-                else if (varalign>2) and (fieldalignment<4) then
-                  fieldalignment:=4
-                else if (varalign>1) and (fieldalignment<2) then
-                  fieldalignment:=2;
-              end;
-            fieldalignment:=min(fieldalignment,current_settings.alignment.maxCrecordalign);
-          end;
+                  _datasize:=high(aint);
+                  databitsize:=high(aint);
+                end
+              else
+                begin
+                  databitsize:=sym.fieldoffset+l;
+                  _datasize:=(databitsize+7) div 8;
+                end;
+              { rest is not applicable }
+              exit;
+            end;
+          { Calc the alignment size for C style records }
+          C_alignment:
+            begin
+              if (varalign>4) and
+                ((varalign mod 4)<>0) and
+                (vardef.typ=arraydef) then
+                Message1(sym_w_wrong_C_pack,vardef.typename);
+              if varalign=0 then
+                varalign:=l;
+              if (fieldalignment<current_settings.alignment.maxCrecordalign) then
+                begin
+                  if (varalign>16) and (fieldalignment<32) then
+                    fieldalignment:=32
+                  else if (varalign>12) and (fieldalignment<16) then
+                    fieldalignment:=16
+                  { 12 is needed for long double }
+                  else if (varalign>8) and (fieldalignment<12) then
+                    fieldalignment:=12
+                  else if (varalign>4) and (fieldalignment<8) then
+                    fieldalignment:=8
+                  else if (varalign>2) and (fieldalignment<4) then
+                    fieldalignment:=4
+                  else if (varalign>1) and (fieldalignment<2) then
+                    fieldalignment:=2;
+                end;
+              fieldalignment:=min(fieldalignment,current_settings.alignment.maxCrecordalign);
+            end;
+          mac68k_alignment:
+            begin
+              { mac68k alignment (C description):
+                 * char is aligned to 1 byte
+                 * everything else (except vector) is aligned to 2 bytes
+                 * vector is aligned to 16 bytes
+              }
+              if l>1 then
+                fieldalignment:=2
+              else
+                fieldalignment:=1;
+              varalign:=2;
+            end;
+        end;
         if varalign=0 then
           varalign:=size_2_align(l);
         varalignfield:=used_align(varalign,current_settings.alignment.recordalignmin,fieldalignment);
@@ -934,6 +955,9 @@ implementation
             { bitpacked }
             bit_alignment:
               padalignment:=1;
+            { mac68k: always round to multiple of 2 }
+            mac68k_alignment:
+              padalignment:=2;
             { default/no packrecords specified }
             0:
               padalignment:=recordalignment
@@ -1062,11 +1086,13 @@ implementation
                 varalignrecord:=field2recordalignment(tfieldvarsym(sym).fieldoffset,varalign);
               end;
             { update alignment of this record }
-            if (usefieldalignment<>C_alignment) then
+            if (usefieldalignment<>C_alignment) and
+               (usefieldalignment<>mac68k_alignment) then
               recordalignment:=max(recordalignment,varalignrecord);
           end;
         { update alignment for C records }
-        if (usefieldalignment=C_alignment) then
+        if (usefieldalignment=C_alignment) and
+           (usefieldalignment<>mac68k_alignment) then
           recordalignment:=max(recordalignment,unionst.recordalignment);
         { Register defs in the new record symtable }
         for i:=0 to unionst.DefList.Count-1 do

+ 37 - 0
tests/webtbs/tw15061.pp

@@ -0,0 +1,37 @@
+{$ifdef FPC}
+{$mode macpas}
+{$align mac68k}
+{$endif}
+
+{$ifdef __GPC__}
+{ maximum-field-alignment=16}
+{$endif}
+
+program patbug;
+type
+{$ifdef FPC}
+    PtrWord = PtrUInt;
+{$endif}
+  pattern = record pat: array[0..7] of byte end;
+  patrec = record b: boolean; p: pattern end;
+  doublerec = record b: boolean; d: double end;
+var
+    gPatRec: patrec;
+    gDoubleRec: doublerec;
+begin
+    writeln( 'SizeOf( patrec) = ', SizeOf( patrec));
+    if (sizeof(patrec)<>10) then
+      halt(1);
+    writeln( 'Offset of p: pattern = ', PtrWord( @gPatRec.p) - PtrWord( @gPatRec));
+    if ((PtrWord( @gPatRec.p) - PtrWord( @gPatRec)) <> 2) then
+      halt(2);
+    writeln;
+    writeln( 'SizeOf( doublerec) = ', SizeOf( doublerec));
+    if (sizeof(doublerec)<>10) then
+      halt(3);
+    writeln( 'Offset of d: double = ', PtrWord( @gDoubleRec.d) - PtrWord( @gDoubleRec));
+    if ((PtrWord( @gDoubleRec.d) - PtrWord( @gDoubleRec))<>2) then
+      halt(4);
+    writeln;
+end.
+

+ 37 - 0
tests/webtbs/tw15061a.pp

@@ -0,0 +1,37 @@
+{$ifdef FPC}
+{$mode macpas}
+{$align power}
+{$endif}
+
+{$ifdef __GPC__}
+{ maximum-field-alignment=16}
+{$endif}
+
+program patbug;
+type
+{$ifdef FPC}
+    PtrWord = PtrUInt;
+{$endif}
+  pattern = record pat: array[0..7] of byte end;
+  patrec = record b: boolean; p: pattern end;
+  doublerec = record b: boolean; d: double end;
+var
+    gPatRec: patrec;
+    gDoubleRec: doublerec;
+begin
+    writeln( 'SizeOf( patrec) = ', SizeOf( patrec));
+    if (sizeof(patrec)<>9) then
+      halt(1);
+    writeln( 'Offset of p: pattern = ', PtrWord( @gPatRec.p) - PtrWord( @gPatRec));
+    if ((PtrWord( @gPatRec.p) - PtrWord( @gPatRec)) <> 1) then
+      halt(2);
+    writeln;
+    writeln( 'SizeOf( doublerec) = ', SizeOf( doublerec));
+    if (sizeof(doublerec)<>12) then
+      halt(3);
+    writeln( 'Offset of d: double = ', PtrWord( @gDoubleRec.d) - PtrWord( @gDoubleRec));
+    if ((PtrWord( @gDoubleRec.d) - PtrWord( @gDoubleRec))<>4) then
+      halt(4);
+    writeln;
+end.
+