View Issue Details

IDProjectCategoryView StatusLast Update
0038267FPCCompilerpublic2021-01-03 15:49
Reporterrunewalsh Assigned ToFlorian  
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Fixed in Version3.3.1 
Summary0038267: 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 InformationSubtly related to 35827 :D
TagsNo tags attached.
Fixed in Revision47933, 47977
FPCOldBugId
FPCTarget-
Attached Files

Activities

runewalsh

2020-12-28 02:47

reporter  

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.
folding.pas (2,824 bytes)   

runewalsh

2020-12-28 15:46

reporter   ~0127863

Um, change the category to 'Compiler' please, I probably misclicked.

runewalsh

2020-12-28 17:57

reporter   ~0127868

In fact, seems that nothing is folded in the middle of an expression, integers demonstrate the same behaviour.

Serge Anvarov

2020-12-28 19:34

reporter   ~0127870

In Delphi, this is also the case. Without parentheses, the strings do not fold.

Florian

2020-12-29 16:55

administrator   ~0127900

> 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?

runewalsh

2020-12-29 17:54

reporter   ~0127908

Last edited: 2020-12-29 21:15

View 4 revisions

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.
folding_int.pas (870 bytes)   

runewalsh

2021-01-02 19:39

reporter   ~0128030

Thank you, and forgive my premature conclusions about ALL integers being affected, not just ±1. :D

ajax16384

2021-01-03 15:49

reporter   ~0128050

@Florian please take a look at https://bugs.freepascal.org/view.php?id=38299
changes from this this issue commits might introduced regression

Issue History

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