From 9cc211e88eb8ae3c23f023eca398e3d5809da7ca Mon Sep 17 00:00:00 2001 From: Jonas Maebe Date: Fri, 8 Jan 2010 15:36:22 +0000 Subject: [PATCH] * 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 - --- .gitattributes | 2 + compiler/pdecvar.pas | 2 + compiler/scandir.pas | 6 +- compiler/symconst.pas | 7 +- compiler/symtable.pas | 166 ++++++++++++++++++++++----------------- tests/webtbs/tw15061.pp | 37 +++++++++ tests/webtbs/tw15061a.pp | 37 +++++++++ 7 files changed, 182 insertions(+), 75 deletions(-) create mode 100644 tests/webtbs/tw15061.pp create mode 100644 tests/webtbs/tw15061a.pp diff --git a/.gitattributes b/.gitattributes index 53f06486c0..cfe24ebeb8 100644 --- a/.gitattributes +++ b/.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 diff --git a/compiler/pdecvar.pas b/compiler/pdecvar.pas index e29096b390..ce1416aa4d 100644 --- a/compiler/pdecvar.pas +++ b/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 diff --git a/compiler/scandir.pas b/compiler/scandir.pas index d52073feef..3ba695b2a0 100644 --- a/compiler/scandir.pas +++ b/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 diff --git a/compiler/symconst.pas b/compiler/symconst.pas index 11cc62a925..267731c5f8 100644 --- a/compiler/symconst.pas +++ b/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} diff --git a/compiler/symtable.pas b/compiler/symtable.pas index 6806a6744f..62d30dd6a2 100644 --- a/compiler/symtable.pas +++ b/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 (fieldalignment16) 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 (fieldalignment16) 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 diff --git a/tests/webtbs/tw15061.pp b/tests/webtbs/tw15061.pp new file mode 100644 index 0000000000..fb178c73b6 --- /dev/null +++ b/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. + diff --git a/tests/webtbs/tw15061a.pp b/tests/webtbs/tw15061a.pp new file mode 100644 index 0000000000..b7505be43f --- /dev/null +++ b/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. +