View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0038267 | FPC | Compiler | public | 2020-12-28 02:47 | 2021-01-03 15:49 |
Reporter | runewalsh | Assigned To | Florian | ||
Priority | normal | Severity | minor | Reproducibility | always |
Status | resolved | Resolution | fixed | ||
Fixed in Version | 3.3.1 | ||||
Summary | 0038267: String constants don't fold in the middle of an expression | ||||
Description | 'litA' + 'litB' + 'litC' + 'litD' + CreateDynamicString() merges literals into one constant 'litAlitBlitClitD'. While: CreateDynamicString() + 'litA' + 'litB' + 'litC' + 'litD' concatenates everything at runtime. Program attached shows that this can result in some overhead. Add to it the overhead of 3×sizeof(pointer) for the header of each non-folded string. Originally I built a long HTML preface this way, which was mostly static, but had dynamic parts, one of which is of course encountered almost immediately: const LE = LineEnding; chunk := '<html lang=' + GetBaseLang() + ... + LE + ... + LE + '<style>' + LE + '.grid > div {' + LE + ' white-space: pre-wrap;' + LE + ' overflow-wrap: break-word;' + LE + ' hyphens: auto;' + LE + ' line-height: 1.5;' + LE + ... many lines more ... so I cut around 20 Kb of executable size of 600 by manually wrapping groups of compile-time constants into parentheses. | ||||
Additional Information | Subtly related to 35827 :D | ||||
Tags | No tags attached. | ||||
Fixed in Revision | 47933, 47977 | ||||
FPCOldBugId | |||||
FPCTarget | - | ||||
Attached Files |
|
|
folding.pas (2,824 bytes)
{$mode objfpc} {$longstrings+} label start1, end1, start2, end2, start3, end3; var s: string; begin writeln('31 concatenated string literals, completely folded:'); start1: s := 'Once like a Great House' + LineEnding + 'founded on sand,' + LineEnding + 'Stood our Temple' + LineEnding + 'whose pillars on troubles were based.' + LineEnding + 'Now mischievous spirits, bound,' + LineEnding + 'in dim corners stand,' + LineEnding + 'Rotted columns, but' + LineEnding + 'with iron-bound bands embraced' + LineEnding + 'Cracked, crumbling marble,' + LineEnding + 'tempered on every hand,' + LineEnding + 'By strong steel' + LineEnding + 'forged in fire and faith.' + LineEnding + 'Shackled, these wayward servants' + LineEnding + 'serve the land,' + LineEnding + 'The Temple secured' + LineEnding + 'by the Builder’s grace.'; end1: writeln(Copy(s, 1, 0), PtrUint(CodePointer(@end1) - CodePointer(@start1)), ' b of code'); writeln; writeln('1 dynamic string concatenated with 31 literals, they could fold but didn''t at all:'); start2: s := Copy('', 1, 0) + 'Once like a Great House' + LineEnding + 'founded on sand,' + LineEnding + 'Stood our Temple' + LineEnding + 'whose pillars on troubles were based.' + LineEnding + 'Now mischievous spirits, bound,' + LineEnding + 'in dim corners stand,' + LineEnding + 'Rotted columns, but' + LineEnding + 'with iron-bound bands embraced' + LineEnding + 'Cracked, crumbling marble,' + LineEnding + 'tempered on every hand,' + LineEnding + 'By strong steel' + LineEnding + 'forged in fire and faith.' + LineEnding + 'Shackled, these wayward servants' + LineEnding + 'serve the land,' + LineEnding + 'The Temple secured' + LineEnding + 'by the Builder’s grace.'; end2: writeln(Copy(s, 1, 0), PtrUint(CodePointer(@end2) - CodePointer(@start2)), ' b of code'); writeln; writeln('16 literals concatenated with 1 dynamic string and 15 more literals, first 16 folded but last 15 did not:'); start3: s := 'Once like a Great House' + LineEnding + 'founded on sand,' + LineEnding + 'Stood our Temple' + LineEnding + 'whose pillars on troubles were based.' + LineEnding + 'Now mischievous spirits, bound,' + LineEnding + 'in dim corners stand,' + LineEnding + 'Rotted columns, but' + LineEnding + 'with iron-bound bands embraced' + LineEnding + Copy('', 1, 0) + 'Cracked, crumbling marble,' + LineEnding + 'tempered on every hand,' + LineEnding + 'By strong steel' + LineEnding + 'forged in fire and faith.' + LineEnding + 'Shackled, these wayward servants' + LineEnding + 'serve the land,' + LineEnding + 'The Temple secured' + LineEnding + 'by the Builder’s grace.'; end3: writeln(Copy(s, 1, 0), PtrUint(CodePointer(@end3) - CodePointer(@start3)), ' b of code'); writeln; end. |
|
Um, change the category to 'Compiler' please, I probably misclicked. |
|
In fact, seems that nothing is folded in the middle of an expression, integers demonstrate the same behaviour. |
|
In Delphi, this is also the case. Without parentheses, the strings do not fold. |
|
> In fact, seems that nothing is folded in the middle of an expression, integers demonstrate the same behaviour. Which version? trunk? It should. Can you please provide an example? |
|
Almost trunk (r64223 of 18 december). When I recreated the code again, the problem was briefly gone, so I thought I was imagining things when I said that integers are subjected too. But I'm not imagining things, they just (as I see now) depend on the type and the platform. For example, the code attached prints: on x86-32 -O4: with x: (u)int32: 3 b / 3 b (still 20 b / 1010 b under -O1, not that big problem I suppose) with x: (u)int64: 6 b / 608 b with x: (u)int16: 5 b / 306 b with x: (u)int8: 3 b / 305 b on x86-64 -O4: with x: (u)int32: 3 b / 3 b with x: (u)int64: 4 b / 4 b with x: (u)int16: 5 b / 306 b with x: (u)int8: 3 b / 305 b People usually don't sum hundreds of integers in a row, but 1) sometimes they do (for readability, and of course under 10 let alone 100), 2) strings are the worst as, especially without multiline literals, concatenating many of them has completely plausible use cases. folding_int.pas (870 bytes)
label start0, end0, start1, end1; var x: int16; begin x := random(2); writeln('x := ', x); writeln; start0: x := 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+ 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+ 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+ 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+x; end0: writeln('x := 1 + 1 + ...100 times ... + x, x = ', x, ': '); writeln(SizeUint(CodePointer(@end0) - CodePointer(@start0)), ' b of code'); writeln; start1: x := x+ 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+ 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+ 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+ 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1; end1: writeln('x := x + 1 + 1 + ...100 times ..., x = ', x, ': '); writeln(SizeUint(CodePointer(@end1) - CodePointer(@start1)), ' b of code'); end. |
|
Thank you, and forgive my premature conclusions about ALL integers being affected, not just ±1. :D |
|
@Florian please take a look at https://bugs.freepascal.org/view.php?id=38299 changes from this this issue commits might introduced regression |
Date Modified | Username | Field | Change |
---|---|---|---|
2020-12-28 02:47 | runewalsh | New Issue | |
2020-12-28 02:47 | runewalsh | File Added: folding.pas | |
2020-12-28 15:46 | runewalsh | Note Added: 0127863 | |
2020-12-28 17:09 | Florian | Category | FCL => Compiler |
2020-12-28 17:09 | Florian | FPCTarget | => - |
2020-12-28 17:57 | runewalsh | Note Added: 0127868 | |
2020-12-28 19:34 | Serge Anvarov | Note Added: 0127870 | |
2020-12-29 16:55 | Florian | Note Added: 0127900 | |
2020-12-29 17:54 | runewalsh | Note Added: 0127908 | |
2020-12-29 17:54 | runewalsh | File Added: folding_int.pas | |
2020-12-29 17:55 | runewalsh | Note Edited: 0127908 | View Revisions |
2020-12-29 18:00 | runewalsh | Note Edited: 0127908 | View Revisions |
2020-12-29 21:15 | runewalsh | Note Edited: 0127908 | View Revisions |
2021-01-02 18:20 | Florian | Assigned To | => Florian |
2021-01-02 18:20 | Florian | Status | new => resolved |
2021-01-02 18:20 | Florian | Resolution | open => fixed |
2021-01-02 18:20 | Florian | Fixed in Version | => 3.3.1 |
2021-01-02 18:20 | Florian | Fixed in Revision | => 47933, 47977 |
2021-01-02 19:39 | runewalsh | Note Added: 0128030 | |
2021-01-03 15:49 | ajax16384 | Note Added: 0128050 |