From 49aa3ff932774291a7d07e2d0e63c6190a12ca8e Mon Sep 17 00:00:00 2001 From: "J. Gareth \"Curious Kit\" Moreton" Date: Wed, 11 Dec 2024 08:38:24 +0000 Subject: [PATCH] * Case blocks are now stored more efficiently in PPU files: - Labels that are just a single value no longer store their value twice (as a one-length range). - The byte that stores the label type and the byte that indicates the presence of a 'greater' and 'less' node have been merged. - Small ordinals in labels are stored using fewer bytes. - The blockid is now unsigned, since the smallest value it can store is zero, and is stored as an unsigned LEB128 rather than a LongInt. --- compiler/nset.pas | 346 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 320 insertions(+), 26 deletions(-) diff --git a/compiler/nset.pas b/compiler/nset.pas index 3d4ae61bde..a90b851919 100644 --- a/compiler/nset.pas +++ b/compiler/nset.pas @@ -36,7 +36,7 @@ interface pcaselabel = ^tcaselabel; tcaselabel = record { unique blockid } - blockid : longint; + blockid : longword; { left and right tree node } less, greater : pcaselabel; @@ -565,26 +565,203 @@ implementation copycaselabel:=n; end; + const + ppu_labeltype_ordinal_shortint = 0; + ppu_labeltype_ordinal_shortint_range = 1; + ppu_labeltype_ordinal_byte = 2; + ppu_labeltype_ordinal_byte_range = 3; + ppu_labeltype_ordinal_smallint = 4; + ppu_labeltype_ordinal_smallint_range = 5; + ppu_labeltype_ordinal_word = 6; + ppu_labeltype_ordinal_word_range = 7; + ppu_labeltype_ordinal_longint = 8; + ppu_labeltype_ordinal_longint_range = 9; + ppu_labeltype_ordinal_longword = 10; + ppu_labeltype_ordinal_longword_range = 11; + ppu_labeltype_ordinal_int64 = 12; + ppu_labeltype_ordinal_int64_range = 13; + ppu_labeltype_ordinal_qword = 14; + ppu_labeltype_ordinal_qword_range = 15; + + ppu_labeltype_string = 16; + ppu_labeltype_string_range = 17; + + ppu_labeltype_mask = $1F; + + ppu_has_greater_branch = $40; + ppu_has_lesser_branch = $80; + procedure ppuwritecaselabel(ppufile:tcompilerppufile;p : pcaselabel); var b : byte; + IsSigned: Boolean; begin - ppufile.putboolean(p^.label_type = ltConstString); + { Store high-order flags relating to the presence of a greater and + lesser node. The label type will be OR'd to this } + b:=(ord(assigned(p^.greater)) shl 6) or (ord(assigned(p^.less)) shl 7); + if (p^.label_type = ltConstString) then begin - p^._low_str.ppuwrite(ppufile); - p^._high_str.ppuwrite(ppufile); + if p^._high_str.isequal(p^._low_str) then + begin + ppufile.putbyte(b or ppu_labeltype_string); + p^._low_str.ppuwrite(ppufile); + end + else + begin + ppufile.putbyte(b or ppu_labeltype_string_range); + p^._low_str.ppuwrite(ppufile); + p^._high_str.ppuwrite(ppufile); + end; end else begin - ppufile.putexprint(p^._low); - ppufile.putexprint(p^._high); + if p^._high = p^._low then + begin + if p^._low.signed then + begin + case p^._low.svalue of + -128..127: + begin + ppufile.putbyte(b or ppu_labeltype_ordinal_shortint); + ppufile.putbyte(Byte(p^._low.svalue)); + end; + -32768..-129, 128..32767: + begin + ppufile.putbyte(b or ppu_labeltype_ordinal_smallint); + ppufile.putword(Word(p^._low.svalue)); + end; + -2147483648..-32769, 32768..2147483647: + begin + ppufile.putbyte(b or ppu_labeltype_ordinal_longint); + ppufile.putlongint(p^._low.svalue); + end; + else + begin + ppufile.putbyte(b or ppu_labeltype_ordinal_int64); + ppufile.putint64(p^._low.svalue); + end; + end; + end + else + begin + case p^._low.uvalue of + $00..$FF: + begin + ppufile.putbyte(b or ppu_labeltype_ordinal_byte); + ppufile.putbyte(p^._low.uvalue); + end; + $100..$FFFF: + begin + ppufile.putbyte(b or ppu_labeltype_ordinal_word); + ppufile.putword(p^._low.uvalue); + end; + $10000..$FFFFFFFF: + begin + ppufile.putbyte(b or ppu_labeltype_ordinal_longword); + ppufile.putlongint(LongInt(p^._low.uvalue)); + end; + else + begin + ppufile.putbyte(b or ppu_labeltype_ordinal_qword); + ppufile.putqword(p^._low.uvalue); + end; + end; + end; + end + else + begin + { If for some reason, one is signed and one isn't, try to + determine the best type to use based on the values present} + if p^._low.signed xor p^._high.signed then + begin + if (p^._low.signed and (p^._low.svalue<0)) or + (p^._high.signed and (p^._high.svalue<0)) then + begin + if (not p^._low.signed and (p^._low.uvalue>$7FFFFFFFFFFFFFFF)) or + (not p^._high.signed and (p^._high.uvalue>$7FFFFFFFFFFFFFFF)) then + { This is a problem because at least one of the + values is out of range and should have been trapped + by the compiler or at least clamped. } + InternalError(2024121110); + + IsSigned:=True; + end + else if (not p^._low.signed and (p^._low.uvalue>$7FFFFFFFFFFFFFFF)) or + (not p^._high.signed and (p^._high.uvalue>$7FFFFFFFFFFFFFFF)) then + IsSigned:=False + else + { Signed by default } + IsSigned:=True; + end + else + IsSigned:=p^._low.signed; + + if IsSigned then + begin + if (p^._low.svalue>=-128) and (p^._low.svalue<=127) and + (p^._high.svalue>=-128) and (p^._high.svalue<=127) then + begin + ppufile.putbyte(b or ppu_labeltype_ordinal_shortint_range); + ppufile.putbyte(Byte(p^._low.svalue)); + ppufile.putbyte(Byte(p^._high.svalue)); + end + else if (p^._low.svalue>=-32768) and (p^._low.svalue<=32767) and + (p^._high.svalue>=-32768) and (p^._high.svalue<=32767) then + begin + ppufile.putbyte(b or ppu_labeltype_ordinal_smallint_range); + ppufile.putword(Word(p^._low.svalue)); + ppufile.putword(Word(p^._high.svalue)); + end + else if (p^._low.svalue>=-2147483648) and (p^._low.svalue<=2147483647) and + (p^._high.svalue>=-2147483648) and (p^._high.svalue<=2147483647) then + begin + ppufile.putbyte(b or ppu_labeltype_ordinal_longint_range); + ppufile.putlongint(p^._low.svalue); + ppufile.putlongint(p^._high.svalue); + end + else + begin + ppufile.putbyte(b or ppu_labeltype_ordinal_int64_range); + ppufile.putint64(p^._low.svalue); + ppufile.putint64(p^._high.svalue); + end; + end + else + begin + if (p^._low.svalue<=$FF) and + (p^._high.svalue<=$FF) then + begin + ppufile.putbyte(b or ppu_labeltype_ordinal_byte_range); + ppufile.putbyte(p^._low.uvalue); + ppufile.putbyte(p^._high.uvalue); + end + else if (p^._low.svalue<=$FFFF) and + (p^._high.svalue<=$FFFF) then + begin + ppufile.putbyte(b or ppu_labeltype_ordinal_word_range); + ppufile.putword(p^._low.uvalue); + ppufile.putword(p^._high.uvalue); + end + else if (p^._low.svalue<=$FFFFFFFF) and + (p^._high.svalue<=$FFFFFFFF) then + begin + ppufile.putbyte(b or ppu_labeltype_ordinal_longword_range); + ppufile.putlongint(LongInt(p^._low.uvalue)); + ppufile.putlongint(LongInt(p^._high.uvalue)); + end + else + begin + ppufile.putbyte(b or ppu_labeltype_ordinal_qword_range); + ppufile.putqword(p^._low.uvalue); + ppufile.putqword(p^._high.uvalue); + end; + end; + end; end; - ppufile.putlongint(p^.blockid); - b:=ord(assigned(p^.greater)) or (ord(assigned(p^.less)) shl 1); - ppufile.putbyte(b); + ppufile.putuleb128(p^.blockid); if assigned(p^.greater) then ppuwritecaselabel(ppufile,p^.greater); if assigned(p^.less) then @@ -598,27 +775,144 @@ implementation p : pcaselabel; begin new(p); - if ppufile.getboolean then - begin - p^.label_type := ltConstString; - p^._low_str := cstringconstnode.ppuload(stringconstn,ppufile); - p^._high_str := cstringconstnode.ppuload(stringconstn,ppufile); - end - else - begin - p^.label_type := ltOrdinal; - - p^._low:=ppufile.getexprint; - p^._high:=ppufile.getexprint; - end; - - p^.blockid:=ppufile.getlongint; b:=ppufile.getbyte; - if (b and 1)=1 then + case b and ppu_labeltype_mask of + ppu_labeltype_ordinal_shortint: + begin + p^.label_type:=ltOrdinal; + p^._low:=ShortInt(ppufile.getbyte); + p^._high:=p^._low; + end; + + ppu_labeltype_ordinal_shortint_range: + begin + p^.label_type:=ltOrdinal; + p^._low:=ShortInt(ppufile.getbyte); + p^._high:=ShortInt(ppufile.getbyte); + end; + + ppu_labeltype_ordinal_byte: + begin + p^.label_type:=ltOrdinal; + p^._low:=ppufile.getbyte; + p^._high:=p^._low; + end; + + ppu_labeltype_ordinal_byte_range: + begin + p^.label_type:=ltOrdinal; + p^._low:=ppufile.getbyte; + p^._high:=ppufile.getbyte; + end; + + ppu_labeltype_ordinal_smallint: + begin + p^.label_type:=ltOrdinal; + p^._low:=SmallInt(ppufile.getword); + p^._high:=p^._low; + end; + + ppu_labeltype_ordinal_smallint_range: + begin + p^.label_type:=ltOrdinal; + p^._low:=SmallInt(ppufile.getword); + p^._high:=SmallInt(ppufile.getword); + end; + + ppu_labeltype_ordinal_word: + begin + p^.label_type:=ltOrdinal; + p^._low:=ppufile.getword; + p^._high:=p^._low; + end; + + ppu_labeltype_ordinal_word_range: + begin + p^.label_type:=ltOrdinal; + p^._low:=ppufile.getword; + p^._high:=ppufile.getword; + end; + + ppu_labeltype_ordinal_longint: + begin + p^.label_type:=ltOrdinal; + p^._low:=ppufile.getlongint; + p^._high:=p^._low; + end; + + ppu_labeltype_ordinal_longint_range: + begin + p^.label_type:=ltOrdinal; + p^._low:=ppufile.getlongint; + p^._high:=ppufile.getlongint; + end; + + ppu_labeltype_ordinal_longword: + begin + p^.label_type:=ltOrdinal; + p^._low:=LongWord(ppufile.getlongint); + p^._high:=p^._low; + end; + + ppu_labeltype_ordinal_longword_range: + begin + p^.label_type:=ltOrdinal; + p^._low:=LongWord(ppufile.getlongint); + p^._high:=LongWord(ppufile.getlongint); + end; + + ppu_labeltype_ordinal_int64: + begin + p^.label_type:=ltOrdinal; + p^._low:=ppufile.getint64; + p^._high:=p^._low; + end; + + ppu_labeltype_ordinal_int64_range: + begin + p^.label_type:=ltOrdinal; + p^._low:=ppufile.getint64; + p^._high:=ppufile.getint64; + end; + + ppu_labeltype_ordinal_qword: + begin + p^.label_type:=ltOrdinal; + p^._low:=ppufile.getqword; + p^._high:=p^._low; + end; + + ppu_labeltype_ordinal_qword_range: + begin + p^.label_type:=ltOrdinal; + p^._low:=ppufile.getqword; + p^._high:=ppufile.getqword; + end; + + ppu_labeltype_string: + begin + p^.label_type:=ltConstString; + p^._low_str:=cstringconstnode.ppuload(stringconstn,ppufile); + p^._high_str:=TStringConstNode(p^._low_str.getcopy()); + end; + + ppu_labeltype_string_range: + begin + p^.label_type:=ltConstString; + p^._low_str:=cstringconstnode.ppuload(stringconstn,ppufile); + p^._high_str:=cstringconstnode.ppuload(stringconstn,ppufile); + end; + + else + InternalError(2024121101); + end; + + p^.blockid:=LongWord(ppufile.getuleb128); + if (b and ppu_has_greater_branch)<>0 then p^.greater:=ppuloadcaselabel(ppufile) else p^.greater:=nil; - if (b and 2)=2 then + if (b and ppu_has_lesser_branch)<>0 then p^.less:=ppuloadcaselabel(ppufile) else p^.less:=nil;