From 76e0ee7a41aef98e026d76b8847002e796e80736 Mon Sep 17 00:00:00 2001 From: Jonas Maebe Date: Mon, 6 Oct 2014 20:53:51 +0000 Subject: [PATCH] * fixed adding padding bytes before anonymous records: the alignment of such records is only known once we have completely parsed all of their data (the alignment of a record depends on the alignment requirements of its field with the largest alignment) -> only insert the padding bytes after completely parsing them git-svn-id: branches/hlcgllvm@28765 - --- compiler/aasmcnst.pas | 319 ++++++++++++++++++++++++------------ compiler/llvm/nllvmtcon.pas | 49 +++++- 2 files changed, 258 insertions(+), 110 deletions(-) diff --git a/compiler/aasmcnst.pas b/compiler/aasmcnst.pas index d8c39f33f0..b08570ed2f 100644 --- a/compiler/aasmcnst.pas +++ b/compiler/aasmcnst.pas @@ -88,6 +88,8 @@ type constructor create(_adetyp: ttypedconstkind; _fdef: tdef); function getenumerator: tadeenumerator; procedure addvalue(val: tai_abstracttypedconst); + function valuecount: longint; + procedure insertvaluebeforepos(val: tai_abstracttypedconst; pos: longint); procedure finish; destructor destroy; override; end; @@ -141,7 +143,11 @@ type property curindex: longint read fcurindex write fcurindex; property nextindex: longint read fnextindex write fnextindex; public - constructor create(_def: tdef; _typ: ttypedconstkind); + constructor create(_def: tdef; _typ: ttypedconstkind); virtual; + { calculated padding bytes for alignment if needed, and add the def of the + next field in case we are constructing an anonymous record } + function prepare_next_field(nextfielddef: tdef): asizeint; + property def: tdef read fdef; property typ: ttypedconstkind read ftyp; property curfield: tfieldvarsym read fcurfield write fcurfield; @@ -158,15 +164,8 @@ type { class type to use when creating new aggregate information instances } protected class var caggregateinformation: taggregateinformationclass; - public - { set the default value for caggregateinformation (= taggregateinformation) } - class constructor classcreate; - private function getcurragginfo: taggregateinformation; - { add padding bytes for alignment if needed, and add the def of the next - field in case we are constructing an anonymous record } - procedure prepare_next_field(nextfielddef: tdef); procedure set_next_field(AValue: tfieldvarsym); protected { temporary list in which all data is collected } @@ -192,6 +191,10 @@ type bytes etc (by calling this one) } procedure do_emit_tai(p: tai; def: tdef); virtual; + { calls prepare_next_field() and adds the padding bytes in the current + location } + procedure pad_next_field(nextfielddef: tdef); + { easy access to the top level aggregate information instance } property curagginfo: taggregateinformation read getcurragginfo; public @@ -208,6 +211,14 @@ type protected function emit_string_const_common(list: TAsmList; stringtype: tstringtype; len: asizeint; encoding: tstringencoding; out startlab: tasmlabel):tasmlabofs; + procedure begin_aggregate_internal(def: tdef; anonymous: boolean); virtual; + procedure end_aggregate_internal(def: tdef; anonymous: boolean); virtual; + { when building an anonymous record, we cannot immediately insert the + alignment before it in case it's nested, since we only know the required + alignment once all fields have been inserted -> mark the location before + the anonymous record, and insert the alignment once it's finished } + procedure mark_anon_aggregate_alignment; virtual; abstract; + procedure insert_marked_aggregate_alignment(def: tdef); virtual; abstract; public class function get_dynstring_rec_name(typ: tstringtype; winlike: boolean; len: asizeint): string; { class functions and an extra list parameter, because emitting the data @@ -220,10 +231,10 @@ type that consists of multiple tai constant data entries, or that represents an aggregate at the Pascal level (a record, a non-dynamic array, ... } - procedure maybe_begin_aggregate(def: tdef); virtual; + procedure maybe_begin_aggregate(def: tdef); { end a potential aggregate type. Must be paired with every maybe_begin_aggregate } - procedure maybe_end_aggregate(def: tdef); virtual; + procedure maybe_end_aggregate(def: tdef); { similar as above, but in case a) it's definitely a record b) the def of the record should be automatically constructed based on @@ -284,6 +295,22 @@ type end; ttai_typedconstbuilderclass = class of ttai_typedconstbuilder; + tlowlevelaggregateinformation = class(taggregateinformation) + protected + fanonrecmarker: tai; + public + property anonrecmarker: tai read fanonrecmarker write fanonrecmarker; + end; + + ttai_lowleveltypedconstbuilder = class(ttai_typedconstbuilder) + protected + procedure mark_anon_aggregate_alignment; override; + procedure insert_marked_aggregate_alignment(def: tdef); override; + public + { set the default value for caggregateinformation (= tlowlevelaggregateinformation) } + class constructor classcreate; + end; + var ctai_typedconstbuilder: ttai_typedconstbuilderclass; @@ -331,6 +358,45 @@ implementation end; + function taggregateinformation.prepare_next_field(nextfielddef: tdef): asizeint; + var + currentoffset,nextoffset: asizeint; + i: longint; + begin + { get the next field and its offset, and make that next field the current + one } + if assigned(nextfield) then + begin + nextoffset:=nextfield.fieldoffset; + currentoffset:=curoffset; + curfield:=nextfield; + end + else + begin + { must set nextfield for unions and objects, as we cannot + automatically detect the "next" field in that case } + if ((def.typ=recorddef) and + trecorddef(def).isunion) or + is_object(def) then + internalerror(2014091202); + { if we are constructing this record as data gets emitted, add a field + for this data } + if anonrecord then + trecorddef(def).add_field_by_def(nextfielddef); + { find next field } + i:=curindex; + repeat + inc(i); + until tsym(tabstractrecorddef(def).symtable.symlist[i]).typ=fieldvarsym; + nextoffset:=fieldoffset[i]; + currentoffset:=curoffset; + curindex:=i; + end; + { need padding? } + result:=nextoffset-currentoffset; + end; + + {**************************************************************************** tai_abstracttypedconst ****************************************************************************} @@ -490,6 +556,18 @@ implementation end; + function tai_aggregatetypedconst.valuecount: longint; + begin + result:=fvalues.count; + end; + + + procedure tai_aggregatetypedconst.insertvaluebeforepos(val: tai_abstracttypedconst; pos: longint); + begin + fvalues.insert(pos,val); + end; + + procedure tai_aggregatetypedconst.finish; begin if fisstring then @@ -537,60 +615,19 @@ implementation end; - procedure ttai_typedconstbuilder.prepare_next_field(nextfielddef: tdef); + procedure ttai_typedconstbuilder.pad_next_field(nextfielddef: tdef); var - nextoffset: asizeint; - curoffset: asizeint; - info: taggregateinformation; - i: longint; + fillbytes: asizeint; begin - info:=curagginfo; - if not assigned(info) then - internalerror(2014091002); - { current offset in the data } - curoffset:=info.curoffset; - { get the next field and its offset, and make that next field the current - one } - if assigned(info.nextfield) then - begin - nextoffset:=info.nextfield.fieldoffset; - info.curfield:=info.nextfield; - end - else - begin - { must set nextfield for unions and objects, as we cannot - automatically detect the "next" field in that case } - if ((info.def.typ=recorddef) and - trecorddef(info.def).isunion) or - is_object(info.def) then - internalerror(2014091202); - { if we are constructing this record as data gets emitted, add a field - for this data } - if info.anonrecord then - trecorddef(info.def).add_field_by_def(nextfielddef); - { find next field } - i:=info.curindex; - repeat - inc(i); - until tsym(tabstractrecorddef(info.def).symtable.symlist[i]).typ=fieldvarsym; - nextoffset:=info.fieldoffset[i]; - info.curindex:=i; - end; - { need padding? } - while curoffset0 do begin do_emit_tai(tai_const.create_8bit(0),u8inttype); - inc(curoffset); + dec(fillbytes); end; end; - class constructor ttai_typedconstbuilder.classcreate; - begin - caggregateinformation:=taggregateinformation; - end; - - function ttai_typedconstbuilder.aggregate_kind(def: tdef): ttypedconstkind; begin if (def.typ in [recorddef,filedef,variantdef]) or @@ -741,7 +778,7 @@ implementation is_object(info.def)) and { may add support for these later } not is_packed_record_or_object(info.def) then - prepare_next_field(def); + pad_next_field(def); end; { emit the data } do_emit_tai(p,def); @@ -808,6 +845,70 @@ implementation end; + procedure ttai_typedconstbuilder.begin_aggregate_internal(def: tdef; anonymous: boolean); + var + info: taggregateinformation; + tck: ttypedconstkind; + begin + tck:=aggregate_kind(def); + if tck=tck_simple then + exit; + if not assigned(faggregateinformation) then + faggregateinformation:=tfpobjectlist.create + { if we're starting an anonymous record, we can't align it yet because + the alignment depends on the fields that will be added -> we'll do + it at the end } + else if not anonymous then + begin + { add padding if necessary, and update the current field/offset } + info:=curagginfo; + if is_record(curagginfo.def) or + is_object(curagginfo.def) then + pad_next_field(def); + end + { if this is the outer record, no padding is required; the alignment + has to be specified explicitly in that case via get_final_asmlist() } + else if assigned(curagginfo) and + (curagginfo.def.typ=recorddef) then + { mark where we'll have to insert the padding bytes at the end } + mark_anon_aggregate_alignment; + info:=caggregateinformation.create(def,aggregate_kind(def)); + faggregateinformation.add(info); + end; + + + procedure ttai_typedconstbuilder.end_aggregate_internal(def: tdef; anonymous: boolean); + var + info: taggregateinformation; + fillbytes: asizeint; + tck: ttypedconstkind; + begin + tck:=aggregate_kind(def); + if tck=tck_simple then + exit; + info:=curagginfo; + if not assigned(info) then + internalerror(2014091002); + if def<>info.def then + internalerror(2014091205); + { add tail padding if necessary } + if (is_record(def) or + is_object(def)) and + not is_packed_record_or_object(def) then + begin + fillbytes:=def.size-info.curoffset; + while fillbytes>0 do + begin + do_emit_tai(Tai_const.Create_8bit(0),u8inttype); + dec(fillbytes) + end; + end; + { pop and free the information } + faggregateinformation.count:=faggregateinformation.count-1; + info.free; + end; + + class function ttai_typedconstbuilder.get_dynstring_rec_name(typ: tstringtype; winlike: boolean; len: asizeint): string; begin case typ of @@ -908,57 +1009,14 @@ implementation procedure ttai_typedconstbuilder.maybe_begin_aggregate(def: tdef); - var - info: taggregateinformation; - tck: ttypedconstkind; begin - tck:=aggregate_kind(def); - if tck=tck_simple then - exit; - if not assigned(faggregateinformation) then - faggregateinformation:=tfpobjectlist.create - else - begin - { add padding if necessary, and update the current field/offset } - info:=curagginfo; - if is_record(curagginfo.def) or - is_object(curagginfo.def) then - prepare_next_field(def); - end; - info:=caggregateinformation.create(def,aggregate_kind(def)); - faggregateinformation.add(info); + begin_aggregate_internal(def,false); end; procedure ttai_typedconstbuilder.maybe_end_aggregate(def: tdef); - var - info: taggregateinformation; - fillbytes: asizeint; - tck: ttypedconstkind; begin - tck:=aggregate_kind(def); - if tck=tck_simple then - exit; - info:=curagginfo; - if not assigned(info) then - internalerror(2014091002); - if def<>info.def then - internalerror(2014091205); - { add tail padding if necessary } - if (is_record(def) or - is_object(def)) and - not is_packed_record_or_object(def) then - begin - fillbytes:=def.size-info.curoffset; - while fillbytes>0 do - begin - do_emit_tai(Tai_const.Create_8bit(0),u8inttype); - dec(fillbytes) - end; - end; - { pop and free the information } - faggregateinformation.count:=faggregateinformation.count-1; - info.free; + end_aggregate_internal(def,false); end; @@ -990,7 +1048,7 @@ implementation { create skeleton def } anonrecorddef:=crecorddef.create_global_internal(optionalname,packrecords); { generic aggregate housekeeping } - maybe_begin_aggregate(anonrecorddef); + begin_aggregate_internal(anonrecorddef,true); { mark as anonymous record } curagginfo.anonrecord:=true; { in case a descendent wants to do something with the anonrecorddef too } @@ -1001,18 +1059,26 @@ implementation function ttai_typedconstbuilder.end_anonymous_record: trecorddef; var info: taggregateinformation; + anonrecord: boolean; begin info:=curagginfo; if not assigned(info) or (info.def.typ<>recorddef) then internalerror(2014080201); result:=trecorddef(info.def); + { make a copy, as we need it after info has been freed by + maybe_end_aggregate(result) } + anonrecord:=info.anonrecord; { finalise the record skeleton (all fields have been added already by emit_tai()) -- anonrecord may not be set in case we reused an earlier constructed def } - if info.anonrecord then + if anonrecord then trecordsymtable(result.symtable).addalignmentpadding; - maybe_end_aggregate(result); + end_aggregate_internal(result,true); + if anonrecord and + assigned(curagginfo) and + (curagginfo.def.typ=recorddef) then + insert_marked_aggregate_alignment(result); end; @@ -1122,7 +1188,48 @@ implementation end; +{**************************************************************************** + tai_abstracttypedconst + ****************************************************************************} + + class constructor ttai_lowleveltypedconstbuilder.classcreate; + begin + caggregateinformation:=tlowlevelaggregateinformation; + end; + + + procedure ttai_lowleveltypedconstbuilder.mark_anon_aggregate_alignment; + var + marker: tai_marker; + begin + marker:=tai_marker.Create(mark_position); + fasmlist.concat(marker); + tlowlevelaggregateinformation(curagginfo).anonrecmarker:=marker; + end; + + + procedure ttai_lowleveltypedconstbuilder.insert_marked_aggregate_alignment(def: tdef); + var + info: tlowlevelaggregateinformation; + fillbytes: asizeint; + begin + info:=tlowlevelaggregateinformation(curagginfo); + if not assigned(info.anonrecmarker) then + internalerror(2014091401); + fillbytes:=info.prepare_next_field(def); + while fillbytes>0 do + begin + fasmlist.insertafter(tai_const.create_8bit(0),info.anonrecmarker); + dec(fillbytes); + end; + fasmlist.remove(info.anonrecmarker); + info.anonrecmarker.free; + info.anonrecmarker:=nil; + end; + + + begin - ctai_typedconstbuilder:=ttai_typedconstbuilder; + ctai_typedconstbuilder:=ttai_lowleveltypedconstbuilder; end. diff --git a/compiler/llvm/nllvmtcon.pas b/compiler/llvm/nllvmtcon.pas index 8db7a62552..8c140a53fe 100644 --- a/compiler/llvm/nllvmtcon.pas +++ b/compiler/llvm/nllvmtcon.pas @@ -35,8 +35,12 @@ interface tllvmaggregateinformation = class(taggregateinformation) private faggai: tai_aggregatetypedconst; + fanonrecalignpos: longint; public + constructor create(_def: tdef; _typ: ttypedconstkind); override; + property aggai: tai_aggregatetypedconst read faggai write faggai; + property anonrecalignpos: longint read fanonrecalignpos write fanonrecalignpos; end; tllvmtai_typedconstbuilder = class(ttai_typedconstbuilder) @@ -60,12 +64,14 @@ interface procedure update_queued_tai(resdef: tdef; outerai, innerai: tai; newindex: longint); function wrap_with_type(p: tai; def: tdef): tai; procedure do_emit_tai(p: tai; def: tdef); override; + procedure mark_anon_aggregate_alignment; override; + procedure insert_marked_aggregate_alignment(def: tdef); override; + procedure begin_aggregate_internal(def: tdef; anonymous: boolean); override; + procedure end_aggregate_internal(def: tdef; anonymous: boolean); override; public constructor create; override; destructor destroy; override; procedure emit_tai_procvar2procdef(p: tai; pvdef: tprocvardef); override; - procedure maybe_begin_aggregate(def: tdef); override; - procedure maybe_end_aggregate(def: tdef); override; procedure queue_init(todef: tdef); override; procedure queue_vecn(def: tdef; const index: tconstexprint); override; procedure queue_subscriptn(def: tabstractrecorddef; vs: tfieldvarsym); override; @@ -90,6 +96,15 @@ implementation cpubase,llvmbase, symbase,symtable,llvmdef,defutil; + { tllvmaggregateinformation } + + constructor tllvmaggregateinformation.create(_def: tdef; _typ: ttypedconstkind); + begin + inherited; + fanonrecalignpos:=-1; + end; + + class constructor tllvmtai_typedconstbuilder.classcreate; begin caggregateinformation:=tllvmaggregateinformation; @@ -199,6 +214,32 @@ implementation end; + procedure tllvmtai_typedconstbuilder.mark_anon_aggregate_alignment; + var + info: tllvmaggregateinformation; + begin + info:=tllvmaggregateinformation(curagginfo); + info.anonrecalignpos:=info.aggai.valuecount; + end; + + + procedure tllvmtai_typedconstbuilder.insert_marked_aggregate_alignment(def: tdef); + var + info: tllvmaggregateinformation; + fillbytes: asizeint; + begin + info:=tllvmaggregateinformation(curagginfo); + if info.anonrecalignpos=-1 then + internalerror(2014091501); + fillbytes:=info.prepare_next_field(def); + while fillbytes>0 do + begin + info.aggai.insertvaluebeforepos(tai_simpletypedconst.create(tck_simple,u8inttype,tai_const.create_8bit(0)),info.anonrecalignpos); + dec(fillbytes); + end; + end; + + procedure tllvmtai_typedconstbuilder.emit_tai_procvar2procdef(p: tai; pvdef: tprocvardef); begin if not pvdef.is_addressonly then @@ -207,7 +248,7 @@ implementation end; - procedure tllvmtai_typedconstbuilder.maybe_begin_aggregate(def: tdef); + procedure tllvmtai_typedconstbuilder.begin_aggregate_internal(def: tdef; anonymous: boolean); var agg: tai_aggregatetypedconst; tck: ttypedconstkind; @@ -235,7 +276,7 @@ implementation end; - procedure tllvmtai_typedconstbuilder.maybe_end_aggregate(def: tdef); + procedure tllvmtai_typedconstbuilder.end_aggregate_internal(def: tdef; anonymous: boolean); var info: tllvmaggregateinformation; begin