Haftungsausschluss: Der folgende Text enthält Details, die nur für Delphi 10.2.1 gelten (und auch 10.2.2), die etwas gemacht zu haben, schlimmer über inlining und RVO scheint:
Der Code vom Compiler erzeugt unterscheidet sich tatsächlich (unabhängig von der Compiler-Version), wie Sie leicht sehen können, wenn Sie in das Disassemblierungsfenster schauen.
Lässt diese Routine nehmen:
procedure Main;
var
i: Integer;
s: string;
begin
i := 0;
s := IntToStr(i);
s := i.ToString;
end;
lassen Sie uns dies nun laufen und schauen in die Demontage-Fenster den Code der Compiler erzeugt zu überprüfen:
Dies ist, was Sie mit Delphi bekam 10.1:
Project1.dpr.14: s := IntToStr(i);
00419810 8D55F8 lea edx,[ebp-$08]
00419813 8B45FC mov eax,[ebp-$04]
00419816 E80DA4FFFF call IntToStr
Project1.dpr.15: s := i.ToString;
0041981B 8D55F4 lea edx,[ebp-$0c]
0041981E 8B45FC mov eax,[ebp-$04]
00419821 E802A4FFFF call IntToStr
00419826 8D45F8 lea eax,[ebp-$08]
00419829 8B55F4 mov edx,[ebp-$0c]
0041982C E843D2FEFF call @UStrLAsg
und das ist, was Sie mit 10.2.1 bekommen (und auch 10.2.2):
Project1.dpr.14: s := IntToStr(i);
00419B04 8D55F8 lea edx,[ebp-$08]
00419B07 8B45FC mov eax,[ebp-$04]
00419B0A E8C5A2FFFF call IntToStr
Project1.dpr.15: s := i.ToString;
00419B0F 33C0 xor eax,eax
00419B11 55 push ebp
00419B12 68499B4100 push $00419b49
00419B17 64FF30 push dword ptr fs:[eax]
00419B1A 648920 mov fs:[eax],esp
00419B1D 8D55F4 lea edx,[ebp-$0c]
00419B20 8B45FC mov eax,[ebp-$04]
00419B23 E8ACA2FFFF call IntToStr
00419B28 8D45F8 lea eax,[ebp-$08]
00419B2B 8B55F4 mov edx,[ebp-$0c]
00419B2E E805D0FEFF call @UStrLAsg
00419B33 33C0 xor eax,eax
00419B35 5A pop edx
00419B36 59 pop ecx
00419B37 59 pop ecx
00419B38 648910 mov fs:[eax],edx
00419B3B 68509B4100 push $00419b50
00419B40 8D45F4 lea eax,[ebp-$0c]
00419B43 E8D4CCFEFF call @UStrClr
00419B48 C3 ret
00419B49 E9CEC3FEFF jmp @HandleFinally
00419B4E EBF0 jmp $00419b40
Jetzt ist die Millionen-Dollar-Frage, was ist die ganze Extra-Anleitung da ?!
Die zusätzlichen Anweisungen, die Sie in beiden Compilern sehen können, sind das Ergebnis der fehlenden so genannten Rückgabewertoptimierung. Wie Sie vielleicht wissen, behandelt der Compiler Ergebnisse von Funktionen, die einen verwalteten Typ (wie eine Zeichenfolge) aufweisen, als versteckten var-Parameter. Wenn der Compiler das Inlining ausführt, wird dieser Parameter nicht beseitigt und die Variable s
wird direkt an die IntToStr
übergeben, wie beim direkten Aufruf. Es reserviert vielmehr eine temporäre Variable, die es verwendet, um an die IntToStr
übergeben und dann diese Variable an s
(das ist die call @UStrLAsg
Sie sehen dort 3 Zeilen nach dem IntToStr
Anruf).
Wie oben erwähnt, scheint es eine Regression in 10.2 oder 10.2.1 zu geben, wo sie etwas über die temporäre Variablenbereinigung direkt nach dem Inline-Aufruf änderten (das sind die zusätzlichen Anweisungen davor und danach).
gemeldet als RSP-19439.
Fortsetzung folgt ...
Es gibt keinen Unterschied. "ToString" ist inline, daher erzeugt der Compiler im Wesentlichen das gleiche Ergebnis. – Victoria
Es ist das gleiche Ergebnis und Geschwindigkeit, wenn ich mit 'VarStr: = (VarInt + 1) .ToString' –
Ja. In beiden Fällen muss zuerst der Ausdruck 'VarInt + 1' ausgewertet werden. – Victoria