|
@@ -49,6 +49,126 @@ implementation
|
|
|
|
|
|
{$maxfpuregisters 0}
|
|
{$maxfpuregisters 0}
|
|
|
|
|
|
|
|
+{*****************************************************************************
|
|
|
|
+ Bitpacked value helpers
|
|
|
|
+*****************************************************************************}
|
|
|
|
+
|
|
|
|
+ type
|
|
|
|
+ tbitpackedval = record
|
|
|
|
+ curval, nextval: aword;
|
|
|
|
+ curbitoffset: smallint;
|
|
|
|
+ loadbitsize,packedbitsize: byte;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ procedure initbitpackval(out bp: tbitpackedval; packedbitsize: byte);
|
|
|
|
+ begin
|
|
|
|
+ bp.curval:=0;
|
|
|
|
+ bp.nextval:=0;
|
|
|
|
+ bp.curbitoffset:=0;
|
|
|
|
+ bp.packedbitsize:=packedbitsize;
|
|
|
|
+ bp.loadbitsize:=packedbitsloadsize(bp.packedbitsize)*8;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+{$ifopt r+}
|
|
|
|
+{$defined rangeon}
|
|
|
|
+{$r-}
|
|
|
|
+{$endif}
|
|
|
|
+
|
|
|
|
+{$ifopt q+}
|
|
|
|
+{$define overflowon}
|
|
|
|
+{$q-}
|
|
|
|
+{$endif}
|
|
|
|
+ { (values between quotes below refer to fields of bp; fields not }
|
|
|
|
+ { mentioned are unused by this routine) }
|
|
|
|
+ { bitpacks "value" as bitpacked value of bitsize "packedbitsize" into }
|
|
|
|
+ { "curval", which has already been filled up to "curbitoffset", and }
|
|
|
|
+ { stores the spillover if any into "nextval". It also updates }
|
|
|
|
+ { curbitoffset to reflect how many bits of currval are now used (can be }
|
|
|
|
+ { > AIntBits in case of spillover) }
|
|
|
|
+ procedure bitpackval(value: aword; var bp: tbitpackedval);
|
|
|
|
+ var
|
|
|
|
+ shiftcount: longint;
|
|
|
|
+ begin
|
|
|
|
+ if (target_info.endian=endian_big) then
|
|
|
|
+ begin
|
|
|
|
+ { bitpacked format: left-aligned (i.e., "big endian bitness") }
|
|
|
|
+ bp.curval:=bp.curval or ((value shl (AIntBits-bp.packedbitsize)) shr bp.curbitoffset);
|
|
|
|
+ shiftcount:=((AIntBits-bp.packedbitsize)-bp.curbitoffset);
|
|
|
|
+ { carry-over to the next element? }
|
|
|
|
+ if (shiftcount<0) then
|
|
|
|
+ bp.nextval:=(value and ((aword(1) shl (-shiftcount))-1)) shl
|
|
|
|
+ (AIntBits+shiftcount)
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ { bitpacked format: right aligned (i.e., "little endian bitness") }
|
|
|
|
+ bp.curval:=bp.curval or (value shl bp.curbitoffset);
|
|
|
|
+ { carry-over to the next element? }
|
|
|
|
+ if (bp.curbitoffset+bp.packedbitsize>AIntBits) then
|
|
|
|
+ bp.nextval:=value shr (AIntBits-bp.curbitoffset)
|
|
|
|
+ end;
|
|
|
|
+ inc(bp.curbitoffset,bp.packedbitsize);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+{$ifdef rangeon}
|
|
|
|
+{$r+}
|
|
|
|
+{$undef rangeon}
|
|
|
|
+{$endif}
|
|
|
|
+
|
|
|
|
+{$ifdef overflowon}
|
|
|
|
+{$q+}
|
|
|
|
+{$undef overflowon}
|
|
|
|
+{$endif}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ procedure flush_packed_value(list: tasmlist; var bp: tbitpackedval);
|
|
|
|
+ var
|
|
|
|
+ bitstowrite: longint;
|
|
|
|
+ writeval : byte;
|
|
|
|
+ begin
|
|
|
|
+ { these values have to be byte swapped when cross-compiling }
|
|
|
|
+ { from one endianess to another, but this will be done }
|
|
|
|
+ { automatically by the assembler writer }
|
|
|
|
+ if (bp.curbitoffset < AIntBits) then
|
|
|
|
+ begin
|
|
|
|
+ { forced flush -> write multiple of loadsize }
|
|
|
|
+ bitstowrite:=align(bp.curbitoffset,bp.loadbitsize);
|
|
|
|
+ bp.curbitoffset:=0;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ bitstowrite:=AIntBits;
|
|
|
|
+ dec(bp.curbitoffset,AIntBits);
|
|
|
|
+ end;
|
|
|
|
+ while (bitstowrite>=8) do
|
|
|
|
+ begin
|
|
|
|
+ if (target_info.endian=endian_little) then
|
|
|
|
+ begin
|
|
|
|
+ { write lowest byte }
|
|
|
|
+ writeval:=byte(bp.curval);
|
|
|
|
+ bp.curval:=bp.curval shr 8;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ { write highest byte }
|
|
|
|
+ writeval:=bp.curval shr (AIntBits-8);
|
|
|
|
+ bp.curval:=(bp.curval and (not($ff shl (AIntBits-8)))) shl 8;
|
|
|
|
+ end;
|
|
|
|
+ list.concat(tai_const.create_8bit(writeval));
|
|
|
|
+ dec(bitstowrite,8);
|
|
|
|
+ end;
|
|
|
|
+ bp.curval:=bp.nextval;
|
|
|
|
+ bp.nextval:=0;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+{*****************************************************************************
|
|
|
|
+ read typed const
|
|
|
|
+*****************************************************************************}
|
|
|
|
+
|
|
|
|
+
|
|
{ this procedure reads typed constants }
|
|
{ this procedure reads typed constants }
|
|
procedure read_typed_const_data(list:tasmlist;def:tdef);
|
|
procedure read_typed_const_data(list:tasmlist;def:tdef);
|
|
|
|
|
|
@@ -605,6 +725,65 @@ implementation
|
|
n.free;
|
|
n.free;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+
|
|
|
|
+ { parse a single constant and add it to the packed const info }
|
|
|
|
+ { represented by curval etc (see explanation of bitpackval for }
|
|
|
|
+ { what the different parameters mean) }
|
|
|
|
+ function parse_single_packed_const(list: tasmlist; def: tdef; var bp: tbitpackedval): boolean;
|
|
|
|
+ var
|
|
|
|
+ n : tnode;
|
|
|
|
+ begin
|
|
|
|
+ result:=true;
|
|
|
|
+ n:=comp_expr(true);
|
|
|
|
+ if (n.nodetype <> ordconstn) or
|
|
|
|
+ not equal_defs(n.resultdef,def) and
|
|
|
|
+ not is_subequal(n.resultdef,def) then
|
|
|
|
+ begin
|
|
|
|
+ n.free;
|
|
|
|
+ incompatibletypes(n.resultdef,def);
|
|
|
|
+ consume_all_until(_SEMICOLON);
|
|
|
|
+ result:=false;
|
|
|
|
+ exit;
|
|
|
|
+ end;
|
|
|
|
+ bitpackval(tordconstnode(n).value,bp);
|
|
|
|
+ if (bp.curbitoffset>=AIntBits) then
|
|
|
|
+ flush_packed_value(list,bp);
|
|
|
|
+ n.free;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ { parses a packed array constant }
|
|
|
|
+ procedure parse_packed_array_def(list: tasmlist; def: tarraydef);
|
|
|
|
+ var
|
|
|
|
+ i : aint;
|
|
|
|
+ bp : tbitpackedval;
|
|
|
|
+ begin
|
|
|
|
+ if not(def.elementdef.typ in [orddef,enumdef]) then
|
|
|
|
+ internalerror(2007022010);
|
|
|
|
+ { begin of the array }
|
|
|
|
+ consume(_LKLAMMER);
|
|
|
|
+ initbitpackval(bp,def.elepackedbitsize);
|
|
|
|
+ i:=def.lowrange;
|
|
|
|
+ { can't use for-loop, fails when cross-compiling from }
|
|
|
|
+ { 32 to 64 bit because i is then 64 bit }
|
|
|
|
+ while (i<def.highrange) do
|
|
|
|
+ begin
|
|
|
|
+ { get next item of the packed array }
|
|
|
|
+ if not parse_single_packed_const(list,def.elementdef,bp) then
|
|
|
|
+ exit;
|
|
|
|
+ consume(_COMMA);
|
|
|
|
+ inc(i);
|
|
|
|
+ end;
|
|
|
|
+ { final item }
|
|
|
|
+ if not parse_single_packed_const(list,def.elementdef,bp) then
|
|
|
|
+ exit;
|
|
|
|
+ { flush final incomplete value if necessary }
|
|
|
|
+ if (bp.curbitoffset <> 0) then
|
|
|
|
+ flush_packed_value(list,bp);
|
|
|
|
+ consume(_RKLAMMER);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+
|
|
procedure parse_arraydef(list:tasmlist;def:tarraydef);
|
|
procedure parse_arraydef(list:tasmlist;def:tarraydef);
|
|
var
|
|
var
|
|
n : tnode;
|
|
n : tnode;
|
|
@@ -620,11 +799,11 @@ implementation
|
|
consume(_NIL);
|
|
consume(_NIL);
|
|
list.concat(Tai_const.Create_sym(nil));
|
|
list.concat(Tai_const.Create_sym(nil));
|
|
end
|
|
end
|
|
- { no packed array constants supported }
|
|
|
|
- else if is_packed_array(def) then
|
|
|
|
|
|
+ { packed array constant }
|
|
|
|
+ else if is_packed_array(def) and
|
|
|
|
+ (def.elepackedbitsize mod 8 <> 0) then
|
|
begin
|
|
begin
|
|
- Message(type_e_no_const_packed_array);
|
|
|
|
- consume_all_until(_RKLAMMER);
|
|
|
|
|
|
+ parse_packed_array_def(list,def);
|
|
end
|
|
end
|
|
{ normal array const between brackets }
|
|
{ normal array const between brackets }
|
|
else if try_to_consume(_LKLAMMER) then
|
|
else if try_to_consume(_LKLAMMER) then
|
|
@@ -759,15 +938,12 @@ implementation
|
|
hs : string;
|
|
hs : string;
|
|
sorg,s : TIDString;
|
|
sorg,s : TIDString;
|
|
tmpguid : tguid;
|
|
tmpguid : tguid;
|
|
- curroffset : aint;
|
|
|
|
- error : boolean;
|
|
|
|
|
|
+ curroffset,
|
|
|
|
+ fillbytes : aint;
|
|
|
|
+ bp : tbitpackedval;
|
|
|
|
+ error,
|
|
|
|
+ is_packed: boolean;
|
|
begin
|
|
begin
|
|
- { no packed record support }
|
|
|
|
- if is_packed_record_or_object(def) then
|
|
|
|
- begin
|
|
|
|
- Message(type_e_no_const_packed_record);
|
|
|
|
- exit;
|
|
|
|
- end;
|
|
|
|
{ GUID }
|
|
{ GUID }
|
|
if (def=rec_tguid) and
|
|
if (def=rec_tguid) and
|
|
((token=_CSTRING) or (token=_CCHAR) or (token=_ID)) then
|
|
((token=_CSTRING) or (token=_CCHAR) or (token=_ID)) then
|
|
@@ -793,6 +969,16 @@ implementation
|
|
n.free;
|
|
n.free;
|
|
exit;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
+ { bitpacked record? }
|
|
|
|
+ is_packed:=is_packed_record_or_object(def);
|
|
|
|
+ if (is_packed) then
|
|
|
|
+ begin
|
|
|
|
+ { loadbitsize = 8, bitpacked records are always padded to }
|
|
|
|
+ { a multiple of a byte. packedbitsize will be set separately }
|
|
|
|
+ { for each field }
|
|
|
|
+ initbitpackval(bp,0);
|
|
|
|
+ bp.loadbitsize:=8;
|
|
|
|
+ end;
|
|
{ normal record }
|
|
{ normal record }
|
|
consume(_LKLAMMER);
|
|
consume(_LKLAMMER);
|
|
curroffset:=0;
|
|
curroffset:=0;
|
|
@@ -855,31 +1041,62 @@ implementation
|
|
consume_all_until(_SEMICOLON)
|
|
consume_all_until(_SEMICOLON)
|
|
else
|
|
else
|
|
begin
|
|
begin
|
|
-
|
|
|
|
{ if needed fill (alignment) }
|
|
{ if needed fill (alignment) }
|
|
if tfieldvarsym(srsym).fieldoffset>curroffset then
|
|
if tfieldvarsym(srsym).fieldoffset>curroffset then
|
|
- for i:=1 to tfieldvarsym(srsym).fieldoffset-curroffset do
|
|
|
|
- list.concat(Tai_const.Create_8bit(0));
|
|
|
|
-
|
|
|
|
- { new position }
|
|
|
|
- curroffset:=tfieldvarsym(srsym).fieldoffset+tfieldvarsym(srsym).vardef.size;
|
|
|
|
-
|
|
|
|
- { read the data }
|
|
|
|
- read_typed_const_data(list,tfieldvarsym(srsym).vardef);
|
|
|
|
-
|
|
|
|
- { keep previous field for checking whether whole }
|
|
|
|
- { record was initialized (JM) }
|
|
|
|
- recsym := srsym;
|
|
|
|
- { goto next field }
|
|
|
|
- inc(symidx);
|
|
|
|
- if symidx<def.symtable.SymList.Count then
|
|
|
|
- srsym:=tsym(def.symtable.SymList[symidx])
|
|
|
|
|
|
+ begin
|
|
|
|
+ if not(is_packed) then
|
|
|
|
+ fillbytes:=tfieldvarsym(srsym).fieldoffset-curroffset
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ flush_packed_value(list,bp);
|
|
|
|
+ { curoffset is now aligned to the next byte }
|
|
|
|
+ curroffset:=align(curroffset,8);
|
|
|
|
+ { offsets are in bits in this case }
|
|
|
|
+ fillbytes:=(tfieldvarsym(srsym).fieldoffset-curroffset) div 8;
|
|
|
|
+ end;
|
|
|
|
+ for i:=1 to fillbytes do
|
|
|
|
+ list.concat(Tai_const.Create_8bit(0))
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ { new position }
|
|
|
|
+ curroffset:=tfieldvarsym(srsym).fieldoffset;
|
|
|
|
+ if not(is_packed) then
|
|
|
|
+ inc(curroffset,tfieldvarsym(srsym).vardef.size)
|
|
else
|
|
else
|
|
- srsym:=nil;
|
|
|
|
|
|
+ inc(curroffset,tfieldvarsym(srsym).vardef.packedbitsize);
|
|
|
|
+
|
|
|
|
+ { read the data }
|
|
|
|
+ if not(is_packed) or
|
|
|
|
+ { only orddefs and enumdefs are bitpacked, as in gcc/gpc }
|
|
|
|
+ not(tfieldvarsym(srsym).vardef.typ in [orddef,enumdef]) then
|
|
|
|
+ begin
|
|
|
|
+ if is_packed then
|
|
|
|
+ begin
|
|
|
|
+ flush_packed_value(list,bp);
|
|
|
|
+ curroffset:=align(curroffset,8);
|
|
|
|
+ end;
|
|
|
|
+ read_typed_const_data(list,tfieldvarsym(srsym).vardef);
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ bp.packedbitsize:=tfieldvarsym(srsym).vardef.packedbitsize;
|
|
|
|
+ parse_single_packed_const(list,tfieldvarsym(srsym).vardef,bp);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ { keep previous field for checking whether whole }
|
|
|
|
+ { record was initialized (JM) }
|
|
|
|
+ recsym := srsym;
|
|
|
|
+ { goto next field }
|
|
|
|
+ inc(symidx);
|
|
|
|
+ if symidx<def.symtable.SymList.Count then
|
|
|
|
+ srsym:=tsym(def.symtable.SymList[symidx])
|
|
|
|
+ else
|
|
|
|
+ srsym:=nil;
|
|
|
|
|
|
- if token=_SEMICOLON then
|
|
|
|
- consume(_SEMICOLON)
|
|
|
|
- else break;
|
|
|
|
|
|
+ if token=_SEMICOLON then
|
|
|
|
+ consume(_SEMICOLON)
|
|
|
|
+ else
|
|
|
|
+ break;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
@@ -892,7 +1109,15 @@ implementation
|
|
) then
|
|
) then
|
|
Message1(parser_w_skipped_fields_after,sorg);
|
|
Message1(parser_w_skipped_fields_after,sorg);
|
|
|
|
|
|
- for i:=1 to def.size-curroffset do
|
|
|
|
|
|
+ if not(is_packed) then
|
|
|
|
+ fillbytes:=def.size-curroffset
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ flush_packed_value(list,bp);
|
|
|
|
+ curroffset:=align(curroffset,8);
|
|
|
|
+ fillbytes:=def.size-(curroffset div 8);
|
|
|
|
+ end;
|
|
|
|
+ for i:=1 to fillbytes do
|
|
list.concat(Tai_const.Create_8bit(0));
|
|
list.concat(Tai_const.Create_8bit(0));
|
|
|
|
|
|
consume(_RKLAMMER);
|
|
consume(_RKLAMMER);
|