summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorjonas <jonas@3ad0048d-3df7-0310-abae-a5850022a9f2>2012-07-22 16:47:19 +0000
committerjonas <jonas@3ad0048d-3df7-0310-abae-a5850022a9f2>2012-07-22 16:47:19 +0000
commit77fcf8aa859167aee3f7587018772da789189a38 (patch)
tree31f881f7507e7b6f759f8c8b5cdba6b3f31d98ba /compiler
parentf46ac3464864baf117555e500eced691d52b8735 (diff)
downloadfpc-77fcf8aa859167aee3f7587018772da789189a38.tar.gz
+ optimization that (re)orders instance fields of Delphi-style classes in
order to minimise memory losses due to alignment padding. Not yet enabled by default at any optimization level, but can be (de)activated separately via -Oo(no)orderfields o added separate tdef.structalignment method that returns the alignment of a type when it appears in a record/object/class (factors out AIX-specific double alignment in structs) o changed the handling of the offset of a delegate interface implemented via a field, by taking the field offset on demand rather than at declaration time (because the ordering optimization causes the offsets of fields to be unknown until the entire declaration has been parsed) git-svn-id: http://svn.freepascal.org/svn/fpc/trunk@21947 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'compiler')
-rw-r--r--compiler/arm/cpuinfo.pas2
-rw-r--r--compiler/avr/cpuinfo.pas2
-rw-r--r--compiler/cclasses.pas8
-rw-r--r--compiler/globtype.pas8
-rw-r--r--compiler/i386/cpuinfo.pas3
-rw-r--r--compiler/m68k/cpuinfo.pas3
-rw-r--r--compiler/mips/cpuinfo.pas3
-rw-r--r--compiler/pdecobj.pas10
-rw-r--r--compiler/pdecvar.pas37
-rw-r--r--compiler/powerpc/cpuinfo.pas3
-rw-r--r--compiler/powerpc64/cpuinfo.pas3
-rw-r--r--compiler/ptype.pas4
-rw-r--r--compiler/sparc/cpuinfo.pas3
-rw-r--r--compiler/symdef.pas31
-rw-r--r--compiler/symtable.pas272
-rw-r--r--compiler/symtype.pas8
-rw-r--r--compiler/x86_64/cpuinfo.pas2
17 files changed, 311 insertions, 91 deletions
diff --git a/compiler/arm/cpuinfo.pas b/compiler/arm/cpuinfo.pas
index b3f389861b..bdad818974 100644
--- a/compiler/arm/cpuinfo.pas
+++ b/compiler/arm/cpuinfo.pas
@@ -1026,7 +1026,7 @@ Const
{ no need to write info about those }
[cs_opt_level1,cs_opt_level2,cs_opt_level3]+
[cs_opt_regvar,cs_opt_loopunroll,cs_opt_tailrecursion,
- cs_opt_stackframe,cs_opt_nodecse];
+ cs_opt_stackframe,cs_opt_nodecse,cs_opt_reorder_fields];
level1optimizerswitches = genericlevel1optimizerswitches;
level2optimizerswitches = genericlevel2optimizerswitches + level1optimizerswitches +
diff --git a/compiler/avr/cpuinfo.pas b/compiler/avr/cpuinfo.pas
index 70c4e70886..0f174de79e 100644
--- a/compiler/avr/cpuinfo.pas
+++ b/compiler/avr/cpuinfo.pas
@@ -188,7 +188,7 @@ Const
{ no need to write info about those }
[cs_opt_level1,cs_opt_level2,cs_opt_level3]+
[cs_opt_regvar,cs_opt_loopunroll,cs_opt_tailrecursion,
- cs_opt_stackframe,cs_opt_nodecse];
+ cs_opt_stackframe,cs_opt_nodecse,cs_opt_reorder_fields];
cpuflagsstr : array[tcpuflags] of string[20] =
('AVR_HAS_JMP_CALL',
'AVR_HAS_MOVW',
diff --git a/compiler/cclasses.pas b/compiler/cclasses.pas
index bb9558e1e0..c90bfef0e6 100644
--- a/compiler/cclasses.pas
+++ b/compiler/cclasses.pas
@@ -151,6 +151,7 @@ type
function Last: TObject; {$ifdef CCLASSESINLINE}inline;{$endif}
procedure Move(CurIndex, NewIndex: Integer); {$ifdef CCLASSESINLINE}inline;{$endif}
procedure Assign(Obj:TFPObjectList);
+ procedure ConcatListCopy(Obj:TFPObjectList);
procedure Pack; {$ifdef CCLASSESINLINE}inline;{$endif}
procedure Sort(Compare: TListSortCompare); {$ifdef CCLASSESINLINE}inline;{$endif}
procedure ForEachCall(proc2call:TObjectListCallback;arg:pointer); {$ifdef CCLASSESINLINE}inline;{$endif}
@@ -1088,10 +1089,15 @@ begin
end;
procedure TFPObjectList.Assign(Obj: TFPObjectList);
+begin
+ Clear;
+ ConcatListCopy(Obj);
+end;
+
+procedure TFPObjectList.ConcatListCopy(Obj: TFPObjectList);
var
i: Integer;
begin
- Clear;
for I := 0 to Obj.Count - 1 do
Add(Obj[i]);
end;
diff --git a/compiler/globtype.pas b/compiler/globtype.pas
index cffcd1de97..7709a03bfe 100644
--- a/compiler/globtype.pas
+++ b/compiler/globtype.pas
@@ -243,7 +243,8 @@ interface
cs_opt_level1,cs_opt_level2,cs_opt_level3,
cs_opt_regvar,cs_opt_uncertain,cs_opt_size,cs_opt_stackframe,
cs_opt_peephole,cs_opt_asmcse,cs_opt_loopunroll,cs_opt_tailrecursion,cs_opt_nodecse,
- cs_opt_nodedfa,cs_opt_loopstrength,cs_opt_scheduler,cs_opt_autoinline,cs_useebp
+ cs_opt_nodedfa,cs_opt_loopstrength,cs_opt_scheduler,cs_opt_autoinline,cs_useebp,
+ cs_opt_reorder_fields
);
toptimizerswitches = set of toptimizerswitch;
@@ -263,11 +264,12 @@ interface
end;
const
- OptimizerSwitchStr : array[toptimizerswitch] of string[10] = ('',
+ OptimizerSwitchStr : array[toptimizerswitch] of string[11] = ('',
'LEVEL1','LEVEL2','LEVEL3',
'REGVAR','UNCERTAIN','SIZE','STACKFRAME',
'PEEPHOLE','ASMCSE','LOOPUNROLL','TAILREC','CSE',
- 'DFA','STRENGTH','SCHEDULE','AUTOINLINE','USEEBP'
+ 'DFA','STRENGTH','SCHEDULE','AUTOINLINE','USEEBP',
+ 'ORDERFIELDS'
);
WPOptimizerSwitchStr : array [twpoptimizerswitch] of string[14] = (
'DEVIRTCALLS','OPTVMTS','SYMBOLLIVENESS'
diff --git a/compiler/i386/cpuinfo.pas b/compiler/i386/cpuinfo.pas
index 3d301e4155..c5174e0098 100644
--- a/compiler/i386/cpuinfo.pas
+++ b/compiler/i386/cpuinfo.pas
@@ -102,7 +102,8 @@ Const
[cs_opt_level1,cs_opt_level2,cs_opt_level3]+
[cs_opt_peephole,cs_opt_regvar,cs_opt_stackframe,
cs_opt_asmcse,cs_opt_loopunroll,cs_opt_uncertain,
- cs_opt_tailrecursion,cs_opt_nodecse,cs_useebp];
+ cs_opt_tailrecursion,cs_opt_nodecse,cs_useebp,
+ cs_opt_reorder_fields];
level1optimizerswitches = genericlevel1optimizerswitches + [cs_opt_peephole];
level2optimizerswitches = genericlevel2optimizerswitches + level1optimizerswitches +
diff --git a/compiler/m68k/cpuinfo.pas b/compiler/m68k/cpuinfo.pas
index 0006c73243..432110c1e8 100644
--- a/compiler/m68k/cpuinfo.pas
+++ b/compiler/m68k/cpuinfo.pas
@@ -75,7 +75,8 @@ Const
genericlevel3optimizerswitches-
{ no need to write info about those }
[cs_opt_level1,cs_opt_level2,cs_opt_level3]+
- [cs_opt_regvar,cs_opt_loopunroll,cs_opt_nodecse];
+ [cs_opt_regvar,cs_opt_loopunroll,cs_opt_nodecse,
+ cs_opt_reorder_fields];
level1optimizerswitches = genericlevel1optimizerswitches;
level2optimizerswitches = genericlevel2optimizerswitches + level1optimizerswitches +
diff --git a/compiler/mips/cpuinfo.pas b/compiler/mips/cpuinfo.pas
index ddf0494b9c..8a6271cce2 100644
--- a/compiler/mips/cpuinfo.pas
+++ b/compiler/mips/cpuinfo.pas
@@ -68,7 +68,8 @@ Const
);
{ Supported optimizations, only used for information }
- supported_optimizerswitches = [cs_opt_regvar,cs_opt_loopunroll,cs_opt_nodecse];
+ supported_optimizerswitches = [cs_opt_regvar,cs_opt_loopunroll,cs_opt_nodecse,
+ cs_opt_reorder_fields];
level1optimizerswitches = [];
level2optimizerswitches = level1optimizerswitches + [cs_opt_regvar,cs_opt_stackframe,cs_opt_nodecse];
diff --git a/compiler/pdecobj.pas b/compiler/pdecobj.pas
index f284fda740..bac768be68 100644
--- a/compiler/pdecobj.pas
+++ b/compiler/pdecobj.pas
@@ -966,6 +966,7 @@ implementation
object_member_blocktype : tblock_type;
fields_allowed, is_classdef, class_fields, is_final, final_fields: boolean;
vdoptions: tvar_dec_options;
+ fieldlist: tfpobjectlist;
procedure parse_const;
@@ -1059,6 +1060,7 @@ implementation
is_final:=false;
final_fields:=false;
object_member_blocktype:=bt_general;
+ fieldlist:=tfpobjectlist.create(false);
repeat
case token of
_TYPE :
@@ -1173,9 +1175,11 @@ implementation
vdoptions:=[vd_object];
if class_fields then
include(vdoptions,vd_class);
+ if is_class(current_structdef) then
+ include(vdoptions,vd_canreorder);
if final_fields then
include(vdoptions,vd_final);
- read_record_fields(vdoptions);
+ read_record_fields(vdoptions,fieldlist);
end
else if object_member_blocktype=bt_type then
types_dec(true)
@@ -1226,6 +1230,10 @@ implementation
consume(_ID); { Give a ident expected message, like tp7 }
end;
until false;
+
+ if is_class(current_structdef) then
+ tabstractrecordsymtable(current_structdef.symtable).addfieldlist(fieldlist,true);
+ fieldlist.free;
end;
diff --git a/compiler/pdecvar.pas b/compiler/pdecvar.pas
index 5aeb1b7fa3..ab1f4614c5 100644
--- a/compiler/pdecvar.pas
+++ b/compiler/pdecvar.pas
@@ -27,17 +27,18 @@ unit pdecvar;
interface
uses
+ cclasses,
symtable,symsym,symdef;
type
- tvar_dec_option=(vd_record,vd_object,vd_threadvar,vd_class,vd_final);
+ tvar_dec_option=(vd_record,vd_object,vd_threadvar,vd_class,vd_final,vd_canreorder);
tvar_dec_options=set of tvar_dec_option;
function read_property_dec(is_classproperty:boolean;astruct:tabstractrecorddef):tpropertysym;
procedure read_var_decls(options:Tvar_dec_options);
- procedure read_record_fields(options:Tvar_dec_options);
+ procedure read_record_fields(options:Tvar_dec_options; reorderlist: TFPObjectList);
procedure read_public_and_external(vs: tabstractvarsym);
@@ -48,7 +49,7 @@ implementation
uses
SysUtils,
{ common }
- cutils,cclasses,
+ cutils,
{ global }
globtype,globals,tokens,verbose,constexp,
systems,
@@ -938,8 +939,10 @@ implementation
fieldvarsym :
begin
ImplIntf.IType:=etFieldValue;
- { this must be done more sophisticated, here is also probably the wrong place }
- ImplIntf.IOffset:=tfieldvarsym(p.propaccesslist[palt_read].firstsym^.sym).fieldoffset;
+ { this must be done in a more robust way. Can't read the
+ fieldvarsym's fieldoffset yet, because it may not yet
+ be set }
+ ImplIntf.ImplementsField:=p.propaccesslist[palt_read].firstsym^.sym;
end
else
internalerror(200802161);
@@ -1577,7 +1580,7 @@ implementation
end;
- procedure read_record_fields(options:Tvar_dec_options);
+ procedure read_record_fields(options:Tvar_dec_options; reorderlist: TFPObjectList);
var
sc : TFPObjectList;
i : longint;
@@ -1637,6 +1640,11 @@ implementation
if token=_ID then
begin
vs:=tfieldvarsym.create(sorg,vs_value,generrordef,[]);
+ { normally the visibility is set via addfield, but sometimes
+ we collect symbols so we can add them in a batch of
+ potentially mixed visibility, and then the individual
+ symbols need to have their visibility already set }
+ vs.visibility:=visibility;
sc.add(vs);
recst.insert(vs);
end;
@@ -1796,14 +1804,13 @@ implementation
end;
end;
- { Generate field in the recordsymtable }
- for i:=0 to sc.count-1 do
- begin
- fieldvs:=tfieldvarsym(sc[i]);
- { static data fields are already inserted in the globalsymtable }
- if not(sp_static in fieldvs.symoptions) then
- recst.addfield(fieldvs,visibility);
- end;
+ if not(vd_canreorder in options) then
+ { add field(s) to the recordsymtable }
+ recst.addfieldlist(sc,false)
+ else
+ { we may reorder the fields before adding them to the symbol
+ table }
+ reorderlist.concatlistcopy(sc)
end;
if m_delphi in current_settings.modeswitches then
@@ -1875,7 +1882,7 @@ implementation
consume(_LKLAMMER);
inc(variantrecordlevel);
if token<>_RKLAMMER then
- read_record_fields([vd_record]);
+ read_record_fields([vd_record],nil);
dec(variantrecordlevel);
consume(_RKLAMMER);
{ calculates maximal variant size }
diff --git a/compiler/powerpc/cpuinfo.pas b/compiler/powerpc/cpuinfo.pas
index 1d91423462..5b4ebe6676 100644
--- a/compiler/powerpc/cpuinfo.pas
+++ b/compiler/powerpc/cpuinfo.pas
@@ -77,7 +77,8 @@ Const
genericlevel3optimizerswitches-
{ no need to write info about those }
[cs_opt_level1,cs_opt_level2,cs_opt_level3]+
- [cs_opt_regvar,cs_opt_loopunroll,cs_opt_nodecse,cs_opt_tailrecursion];
+ [cs_opt_regvar,cs_opt_loopunroll,cs_opt_nodecse,
+ cs_opt_tailrecursion,cs_opt_reorder_fields];
level1optimizerswitches = genericlevel1optimizerswitches;
level2optimizerswitches = genericlevel2optimizerswitches + level1optimizerswitches + [cs_opt_regvar,cs_opt_nodecse,cs_opt_tailrecursion];
diff --git a/compiler/powerpc64/cpuinfo.pas b/compiler/powerpc64/cpuinfo.pas
index 7b845cc45d..1449a7c8fb 100644
--- a/compiler/powerpc64/cpuinfo.pas
+++ b/compiler/powerpc64/cpuinfo.pas
@@ -69,7 +69,8 @@ const
genericlevel3optimizerswitches-
{ no need to write info about those }
[cs_opt_level1,cs_opt_level2,cs_opt_level3]+
- [cs_opt_regvar,cs_opt_loopunroll,cs_opt_nodecse,cs_opt_tailrecursion];
+ [cs_opt_regvar,cs_opt_loopunroll,cs_opt_nodecse,
+ cs_opt_tailrecursion,cs_opt_reorder_fields];
level1optimizerswitches = genericlevel1optimizerswitches;
level2optimizerswitches = genericlevel2optimizerswitches + level1optimizerswitches +
diff --git a/compiler/ptype.pas b/compiler/ptype.pas
index cd747b1405..4f0eedf784 100644
--- a/compiler/ptype.pas
+++ b/compiler/ptype.pas
@@ -648,7 +648,7 @@ implementation
vdoptions:=[vd_record];
if classfields then
include(vdoptions,vd_class);
- read_record_fields(vdoptions);
+ read_record_fields(vdoptions,nil);
end
else if member_blocktype=bt_type then
types_dec(true)
@@ -813,7 +813,7 @@ implementation
end
else
begin
- read_record_fields([vd_record]);
+ read_record_fields([vd_record],nil);
{$ifdef jvm}
{ we need a constructor to create temps, a deep copy helper, ... }
add_java_default_record_methods_intf(trecorddef(current_structdef));
diff --git a/compiler/sparc/cpuinfo.pas b/compiler/sparc/cpuinfo.pas
index 41fb3d8608..8dcfb9e549 100644
--- a/compiler/sparc/cpuinfo.pas
+++ b/compiler/sparc/cpuinfo.pas
@@ -77,7 +77,8 @@ const
{ no need to write info about those }
[cs_opt_level1,cs_opt_level2,cs_opt_level3]+
[cs_opt_regvar,cs_opt_loopunroll,
- cs_opt_tailrecursion,cs_opt_nodecse];
+ cs_opt_tailrecursion,cs_opt_nodecse,
+ cs_opt_reorder_fields];
level1optimizerswitches = genericlevel1optimizerswitches;
level2optimizerswitches = genericlevel2optimizerswitches + level1optimizerswitches +
diff --git a/compiler/symdef.pas b/compiler/symdef.pas
index 3d24125e04..748860ee8a 100644
--- a/compiler/symdef.pas
+++ b/compiler/symdef.pas
@@ -231,14 +231,18 @@ interface
{ TImplementedInterface }
TImplementedInterface = class
+ private
+ fIOffset : longint;
+ function GetIOffset: longint;
+ public
IntfDef : tobjectdef;
IntfDefDeref : tderef;
IType : tinterfaceentrytype;
- IOffset : longint;
VtblImplIntf : TImplementedInterface;
NameMappings : TFPHashList;
ProcDefs : TFPObjectList;
ImplementsGetter : tsym;
+ ImplementsField : tsym;
constructor create(aintf: tobjectdef);
constructor create_deref(d:tderef);
destructor destroy; override;
@@ -249,6 +253,7 @@ interface
function GetMapping(const origname: string):string;
procedure AddImplProc(pd:tprocdef);
function IsImplMergePossible(MergingIntf:TImplementedInterface;out weight: longint): boolean;
+ property IOffset: longint read GetIOffset write fIOffset;
end;
{ tvmtentry }
@@ -422,6 +427,7 @@ interface
function GetTypeName:string;override;
function is_publishable : boolean;override;
function alignment:shortint;override;
+ function structalignment: shortint;override;
procedure setsize;
function getvardef:longint;override;
end;
@@ -2286,6 +2292,19 @@ implementation
end;
+ function tfloatdef.structalignment: shortint;
+ begin
+ { aix is really annoying: the recommended scalar alignment for both
+ int64 and double is 64 bits, but in structs int64 has to be aligned
+ to 8 bytes and double to 4 bytes }
+ if (target_info.system in systems_aix) and
+ (floattype=s64real) then
+ result:=4
+ else
+ result:=alignment;
+ end;
+
+
procedure tfloatdef.setsize;
begin
case floattype of
@@ -6235,6 +6254,16 @@ implementation
TImplementedInterface
****************************************************************************}
+ function TImplementedInterface.GetIOffset: longint;
+ begin
+ if (fIOffset=-1) and
+ (IType in [etFieldValue,etFieldValueClass]) then
+ result:=tfieldvarsym(ImplementsField).fieldoffset
+ else
+ result:=fIOffset;
+ end;
+
+
constructor TImplementedInterface.create(aintf: tobjectdef);
begin
inherited create;
diff --git a/compiler/symtable.pas b/compiler/symtable.pas
index 627c01ddc8..273a9454fb 100644
--- a/compiler/symtable.pas
+++ b/compiler/symtable.pas
@@ -86,6 +86,7 @@ interface
procedure ppuwrite(ppufile:tcompilerppufile);override;
procedure alignrecord(fieldoffset:asizeint;varalign:shortint);
procedure addfield(sym:tfieldvarsym;vis:tvisibility);
+ procedure addfieldlist(list: tfpobjectlist; maybereorder: boolean);
procedure addalignmentpadding;
procedure insertdef(def:TDefEntry);override;
function is_packed: boolean;
@@ -100,6 +101,7 @@ interface
{ size in bytes of padding }
_paddingsize : word;
procedure setdatasize(val: asizeint);
+ function getfieldoffset(sym: tfieldvarsym; base: asizeint; var globalfieldalignment: shortint): asizeint;
public
function iscurrentunit: boolean; override;
property datasize : asizeint read _datasize write setdatasize;
@@ -934,7 +936,6 @@ implementation
procedure tabstractrecordsymtable.addfield(sym:tfieldvarsym;vis:tvisibility);
var
l : asizeint;
- varalignfield,
varalign : shortint;
vardef : tdef;
begin
@@ -949,16 +950,7 @@ implementation
{ Calculate field offset }
l:=sym.getsize;
vardef:=sym.vardef;
- varalign:=vardef.alignment;
-{$if defined(powerpc) or defined(powerpc64)}
- { aix is really annoying: the recommended scalar alignment for both
- int64 and double is 64 bits, but in structs int64 has to be aligned
- to 8 bytes and double to 4 bytes }
- if (target_info.system in systems_aix) and
- is_double(vardef) then
- varalign:=4;
-{$endif powerpc or powerpc64}
-
+ varalign:=vardef.structalignment;
case usefieldalignment of
bit_alignment:
begin
@@ -997,61 +989,160 @@ implementation
{ rest is not applicable }
exit;
end;
- { Calc the alignment size for C style records }
- C_alignment:
+ else
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
+ sym.fieldoffset:=getfieldoffset(sym,_datasize,fieldalignment);
+ if l>high(asizeint)-sym.fieldoffset 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
+ Message(sym_e_segment_too_large);
+ _datasize:=high(asizeint);
+ end
else
- fieldalignment:=1;
- varalign:=2;
+ _datasize:=sym.fieldoffset+l;
+ { Calc alignment needed for this record }
+ alignrecord(sym.fieldoffset,varalign);
end;
end;
- if varalign=0 then
- varalign:=size_2_align(l);
- varalignfield:=used_align(varalign,current_settings.alignment.recordalignmin,fieldalignment);
+ end;
+
+
+ function field_alignment_compare(item1, item2: pointer): integer;
+ var
+ field1: tfieldvarsym absolute item1;
+ field2: tfieldvarsym absolute item2;
+ begin
+ { we don't care about static fields, those become global variables }
+ if (sp_static in field1.symoptions) or
+ (sp_static in field2.symoptions) then
+ exit(0);
+ { sort from large to small alignment, and in case of the same alignment
+ in declaration order (items declared close together are possibly
+ also related and hence possibly used together -> putting them next
+ to each other can improve cache behaviour) }
+ result:=field2.vardef.alignment-field1.vardef.alignment;
+ if result=0 then
+ result:=field1.symid-field2.symid;
+ end;
+
- sym.fieldoffset:=align(_datasize,varalignfield);
- if l>high(asizeint)-sym.fieldoffset then
+ procedure tabstractrecordsymtable.addfieldlist(list: tfpobjectlist; maybereorder: boolean);
+ var
+ fieldvs, insertfieldvs, bestfieldvs: tfieldvarsym;
+ base, fieldoffset, space, insertfieldsize, insertfieldoffset, bestinsertfieldoffset, bestspaceleft: asizeint;
+ i, j, bestfieldindex: longint;
+ globalfieldalignment,
+ prevglobalfieldalignment,
+ newfieldalignment: shortint;
+ changed: boolean;
+ begin
+ if maybereorder and
+ (cs_opt_reorder_fields in current_settings.optimizerswitches) then
begin
- Message(sym_e_segment_too_large);
- _datasize:=high(asizeint);
- end
- else
- _datasize:=sym.fieldoffset+l;
- { Calc alignment needed for this record }
- alignrecord(sym.fieldoffset,varalign);
+ { sort the non-class fields to minimise losses due to alignment }
+ list.sort(@field_alignment_compare);
+ { now fill up gaps caused by alignment skips with smaller fields
+ where possible }
+ repeat
+ i:=0;
+ base:=_datasize;
+ globalfieldalignment:=fieldalignment;
+ changed:=false;
+ while i<list.count do
+ begin
+ fieldvs:=tfieldvarsym(list[i]);
+ if sp_static in fieldvs.symoptions then
+ begin
+ inc(i);
+ continue;
+ end;
+ prevglobalfieldalignment:=globalfieldalignment;
+ fieldoffset:=getfieldoffset(fieldvs,base,globalfieldalignment);
+ newfieldalignment:=globalfieldalignment;
+
+ { size of the gap between the end of the previous field and
+ the start of the current one }
+ space:=fieldoffset-base;
+ bestspaceleft:=space;
+ while space>0 do
+ begin
+ bestfieldindex:=-1;
+ for j:=i+1 to list.count-1 do
+ begin
+ insertfieldvs:=tfieldvarsym(list[j]);
+ if sp_static in insertfieldvs.symoptions then
+ continue;
+ insertfieldsize:=insertfieldvs.getsize;
+ { can the new field fit possibly in the gap? }
+ if insertfieldsize<=space then
+ begin
+ { restore globalfieldalignment to situation before
+ the original field was inserted }
+ globalfieldalignment:=prevglobalfieldalignment;
+ { at what offset would it be inserted? (this new
+ field has its own alignment requirements, which
+ may make it impossible to fit after all) }
+ insertfieldoffset:=getfieldoffset(insertfieldvs,base,globalfieldalignment);
+ globalfieldalignment:=prevglobalfieldalignment;
+ { taking into account the alignment, does it still
+ fit and if so, does it fit better than the
+ previously found best fit? }
+ if (insertfieldoffset+insertfieldsize<=fieldoffset) and
+ (fieldoffset-insertfieldoffset-insertfieldsize<bestspaceleft) then
+ begin
+ { new best fit }
+ bestfieldindex:=j;
+ bestinsertfieldoffset:=insertfieldoffset;
+ bestspaceleft:=fieldoffset-insertfieldoffset-insertfieldsize;
+ if bestspaceleft=0 then
+ break;
+ end;
+ end;
+ end;
+ { if we didn't find any field to fit, stop trying for this
+ gap }
+ if bestfieldindex=-1 then
+ break;
+ changed:=true;
+ { we found a field to insert -> adjust the new base
+ address }
+ base:=bestinsertfieldoffset+tfieldvarsym(list[bestfieldindex]).getsize;
+ { update globalfieldalignment for this newly inserted
+ field }
+ getfieldoffset(tfieldvarsym(list[bestfieldindex]),base,globalfieldalignment);
+ { move the new field before the current one }
+ list.move(bestfieldindex,i);
+ { and skip the new field (which is now at position i) }
+ inc(i);
+ { there may be more space left -> continue }
+ space:=bestspaceleft;
+ end;
+ if base>fieldoffset then
+ internalerror(2012071302);
+ { check the next field }
+ base:=fieldoffset+fieldvs.getsize;
+ { since the original field had the same or greater alignment
+ than anything we inserted before it, the global field
+ alignment is still the same now as it was originally after
+ inserting that field }
+ globalfieldalignment:=newfieldalignment;
+ inc(i);
+ end;
+ { there may be small gaps left *before* inserted fields }
+ until not changed;
+ end;
+ { finally, set the actual field offsets }
+ for i:=0 to list.count-1 do
+ begin
+ fieldvs:=tfieldvarsym(list[i]);
+ { static data fields are already inserted in the globalsymtable }
+ if not(sp_static in fieldvs.symoptions) then
+ begin
+ { read_record_fields already set the visibility of the fields,
+ because a single list can contain symbols with different
+ visibility }
+ addfield(fieldvs,fieldvs.visibility);
+ end;
+ end;
end;
@@ -1145,6 +1236,69 @@ implementation
databitsize:=val*8;
end;
+ function tabstractrecordsymtable.getfieldoffset(sym: tfieldvarsym; base: asizeint; var globalfieldalignment: shortint): asizeint;
+ var
+ l : asizeint;
+ varalignfield,
+ varalign : shortint;
+ vardef : tdef;
+ begin
+ { Calculate field offset }
+ l:=sym.getsize;
+ vardef:=sym.vardef;
+ varalign:=vardef.structalignment;
+ case usefieldalignment of
+ bit_alignment:
+ { has to be handled separately }
+ internalerror(2012071301);
+ C_alignment:
+ begin
+ { Calc the alignment size for C style records }
+ 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 (globalfieldalignment<current_settings.alignment.maxCrecordalign) then
+ begin
+ if (varalign>16) and (globalfieldalignment<32) then
+ globalfieldalignment:=32
+ else if (varalign>12) and (globalfieldalignment<16) then
+ globalfieldalignment:=16
+ { 12 is needed for long double }
+ else if (varalign>8) and (globalfieldalignment<12) then
+ globalfieldalignment:=12
+ else if (varalign>4) and (globalfieldalignment<8) then
+ globalfieldalignment:=8
+ else if (varalign>2) and (globalfieldalignment<4) then
+ globalfieldalignment:=4
+ else if (varalign>1) and (globalfieldalignment<2) then
+ globalfieldalignment:=2;
+ end;
+ globalfieldalignment:=min(globalfieldalignment,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
+ globalfieldalignment:=2
+ else
+ globalfieldalignment:=1;
+ varalign:=2;
+ end;
+ end;
+ if varalign=0 then
+ varalign:=size_2_align(l);
+ varalignfield:=used_align(varalign,current_settings.alignment.recordalignmin,globalfieldalignment);
+
+ result:=align(base,varalignfield);
+ end;
+
function tabstractrecordsymtable.iscurrentunit: boolean;
begin
Result := Assigned(current_module) and (current_module.moduleid=moduleid);
diff --git a/compiler/symtype.pas b/compiler/symtype.pas
index 6bf2399d43..ae2d381ffa 100644
--- a/compiler/symtype.pas
+++ b/compiler/symtype.pas
@@ -77,6 +77,8 @@ interface
function size:asizeint;virtual;abstract;
function packedbitsize:asizeint;virtual;
function alignment:shortint;virtual;abstract;
+ { alignment when this type appears in a record/class/... }
+ function structalignment:shortint;virtual;
function getvardef:longint;virtual;abstract;
function getparentdef:tdef;virtual;
function geTSymtable(t:tgeTSymtable):TSymtable;virtual;
@@ -328,6 +330,12 @@ implementation
end;
+ function tdef.structalignment: shortint;
+ begin
+ result:=alignment;
+ end;
+
+
procedure tdef.ChangeOwner(st:TSymtable);
begin
// if assigned(Owner) then
diff --git a/compiler/x86_64/cpuinfo.pas b/compiler/x86_64/cpuinfo.pas
index 3b44c3c906..0d23567d08 100644
--- a/compiler/x86_64/cpuinfo.pas
+++ b/compiler/x86_64/cpuinfo.pas
@@ -91,7 +91,7 @@ Const
{ no need to write info about those }
[cs_opt_level1,cs_opt_level2,cs_opt_level3]+
[cs_opt_regvar,cs_opt_loopunroll,cs_opt_stackframe,
- cs_opt_tailrecursion,cs_opt_nodecse];
+ cs_opt_tailrecursion,cs_opt_nodecse,cs_opt_reorder_fields];
level1optimizerswitches = genericlevel1optimizerswitches;
level2optimizerswitches = genericlevel2optimizerswitches + level1optimizerswitches +