<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body text="#000000" bgcolor="#FFFFFF">
<div class="moz-cite-prefix">Am 07.11.2019 um 01:42 schrieb Ben
Grasset via fpc-pascal:<br>
</div>
<blockquote type="cite"
cite="mid:CAL4d7FggB0cBckfwddV6aLnZLCARoc_3Wz2dC2kA79VSWtALPQ@mail.gmail.com">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<div dir="ltr">
<div dir="ltr">On Wed, Nov 6, 2019 at 7:33 PM Ben Grasset <<a
href="mailto:operator97@gmail.com" moz-do-not-send="true">operator97@gmail.com</a>>
wrote:<br>
</div>
<div class="gmail_quote">
<blockquote class="gmail_quote" style="margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">
<div dir="ltr">
<div class="gmail_quote">
<div>Encouraging typecasting (which cares only about the
sizes of the types involved, nothing else) at the
programmer level is far more error-prone in a variety
of ways.<br>
</div>
</div>
</div>
</blockquote>
<div><br>
</div>
<div>Also: it's slower in many cases, because it tends to
involve "if" statements that *remain* as if statements in
the final generated assembly code, whereas a static check
would allow for simply generating *only* the code for the
path that's actually taken.</div>
</div>
</div>
</blockquote>
This is not true. If the compiler can prove at compile time that the
if-condition is constant then the branch that is not taken is
removed at the node level. It doesn't even remotely reach the code
generation phase. (I just checked that yesterday when I implemented
IsManagedType() and wondered about missing "unreachable code"
warnings).<br>
<br>
Take a look at the test for IsManagedType():<br>
<br>
=== code begin ===<br>
<br>
program tismngd1;<br>
<br>
{$mode objfpc}<br>
{$modeswitch advancedrecords}<br>
<br>
uses<br>
TypInfo;<br>
<br>
var<br>
gError: LongInt = 0;<br>
<br>
function NextErrorCode: LongInt; inline;<br>
begin<br>
Inc(gError);<br>
Result := gError;<br>
end;<br>
<br>
generic procedure TestType<T>(aIsMngd: Boolean); inline;<br>
begin<br>
if IsManagedType(T) <> aIsMngd then begin<br>
Writeln('IsManagedType(', PTypeInfo(TypeInfo(T))^.Name, ')
failure; expected: ', aIsMngd, ', got: ', IsManagedType(T));<br>
Halt(NextErrorCode);<br>
end;<br>
NextErrorCode;<br>
end;<br>
<br>
type<br>
TTestLongInt = record<br>
a: LongInt;<br>
end;<br>
<br>
TTestAnsiString = record<br>
a: AnsiString;<br>
end;<br>
<br>
TTestManaged = record<br>
a: LongInt;<br>
class operator Initialize(var aTestManaged: TTestManaged);<br>
end;<br>
<br>
TTestObj = object<br>
a: LongInt;<br>
end;<br>
<br>
TTestObjAnsiString = object<br>
a: AnsiString;<br>
end;<br>
<br>
class operator TTestManaged.Initialize(var aTestManaged:
TTestManaged);<br>
begin<br>
aTestManaged.a := 42;<br>
end;<br>
<br>
type<br>
TProcVar = procedure;<br>
TMethodVar = procedure of object;<br>
<br>
TDynArrayLongInt = array of LongInt;<br>
TStaticArrayLongInt = array[0..4] of LongInt;<br>
TStaticArrayAnsiString = array[0..4] of AnsiString;<br>
<br>
TEnum = (eOne, eTwo, eThree);<br>
TSet = set of (sOne, sTwo, sThree);<br>
<br>
begin<br>
specialize TestType<LongInt>(False);<br>
specialize TestType<Boolean>(False);<br>
specialize TestType<ShortString>(False);<br>
specialize TestType<AnsiString>(True);<br>
specialize TestType<UnicodeString>(True);<br>
specialize TestType<WideString>(True);<br>
specialize TestType<Single>(False);<br>
specialize TestType<TProcVar>(False);<br>
specialize TestType<TMethodVar>(False);<br>
specialize TestType<Pointer>(False);<br>
specialize TestType<IInterface>(True);<br>
specialize TestType<TObject>(False);<br>
specialize TestType<TTestLongInt>(False);<br>
specialize TestType<TTestAnsiString>(True);<br>
specialize TestType<TTestManaged>(True);<br>
specialize TestType<TTestObj>(False);<br>
specialize TestType<TTestObjAnsiString>(True);<br>
specialize TestType<TDynArrayLongInt>(True);<br>
specialize TestType<TStaticArrayLongInt>(False);<br>
specialize TestType<TStaticArrayAnsiString>(True);<br>
specialize TestType<TEnum>(False);<br>
specialize TestType<TSet>(False);<br>
Writeln('Ok');<br>
end.<br>
<br>
=== code end ===<br>
<br>
Thanks to the node level optimization I mentioned the assembly code
of the main function will look like this (in this case
x86_64-win64):<br>
<br>
=== code begin ===<br>
<br>
.section .text.n_main,"ax"<br>
.balign 16,0x90<br>
.globl main<br>
main:<br>
.globl PASCALMAIN<br>
PASCALMAIN:<br>
.Lc122:<br>
.Lc123:<br>
# Temps allocated between rbp-8 and rbp+0<br>
.seh_proc main<br>
# [62] begin<br>
pushq %rbp<br>
.seh_pushreg %rbp<br>
.Lc124:<br>
.Lc125:<br>
movq %rsp,%rbp<br>
.Lc126:<br>
leaq -48(%rsp),%rsp<br>
.seh_stackalloc 48<br>
movq %rbx,-8(%rbp)<br>
.seh_savereg %rbx, 40<br>
.seh_endprologue<br>
call fpc_initializeunits<br>
# [63] specialize TestType<LongInt>(False);<br>
addl $1,TC_$P$TISMNGD1_$$_GERROR(%rip)<br>
movl TC_$P$TISMNGD1_$$_GERROR(%rip),%eax<br>
# [64] specialize TestType<Boolean>(False);<br>
addl $1,TC_$P$TISMNGD1_$$_GERROR(%rip)<br>
movl TC_$P$TISMNGD1_$$_GERROR(%rip),%eax<br>
# [65] specialize TestType<ShortString>(False);<br>
addl $1,TC_$P$TISMNGD1_$$_GERROR(%rip)<br>
movl TC_$P$TISMNGD1_$$_GERROR(%rip),%eax<br>
# [66] specialize TestType<AnsiString>(True);<br>
addl $1,TC_$P$TISMNGD1_$$_GERROR(%rip)<br>
movl TC_$P$TISMNGD1_$$_GERROR(%rip),%eax<br>
# [67] specialize TestType<UnicodeString>(True);<br>
addl $1,TC_$P$TISMNGD1_$$_GERROR(%rip)<br>
movl TC_$P$TISMNGD1_$$_GERROR(%rip),%eax<br>
# [68] specialize TestType<WideString>(True);<br>
addl $1,TC_$P$TISMNGD1_$$_GERROR(%rip)<br>
movl TC_$P$TISMNGD1_$$_GERROR(%rip),%eax<br>
# [69] specialize TestType<Single>(False);<br>
addl $1,TC_$P$TISMNGD1_$$_GERROR(%rip)<br>
movl TC_$P$TISMNGD1_$$_GERROR(%rip),%eax<br>
# [70] specialize TestType<TProcVar>(False);<br>
addl $1,TC_$P$TISMNGD1_$$_GERROR(%rip)<br>
movl TC_$P$TISMNGD1_$$_GERROR(%rip),%eax<br>
# [71] specialize TestType<TMethodVar>(False);<br>
addl $1,TC_$P$TISMNGD1_$$_GERROR(%rip)<br>
movl TC_$P$TISMNGD1_$$_GERROR(%rip),%eax<br>
# [72] specialize TestType<Pointer>(False);<br>
addl $1,TC_$P$TISMNGD1_$$_GERROR(%rip)<br>
movl TC_$P$TISMNGD1_$$_GERROR(%rip),%eax<br>
# [73] specialize TestType<IInterface>(True);<br>
addl $1,TC_$P$TISMNGD1_$$_GERROR(%rip)<br>
movl TC_$P$TISMNGD1_$$_GERROR(%rip),%eax<br>
# [74] specialize TestType<TObject>(False);<br>
addl $1,TC_$P$TISMNGD1_$$_GERROR(%rip)<br>
movl TC_$P$TISMNGD1_$$_GERROR(%rip),%eax<br>
# [75] specialize TestType<TTestLongInt>(False);<br>
addl $1,TC_$P$TISMNGD1_$$_GERROR(%rip)<br>
movl TC_$P$TISMNGD1_$$_GERROR(%rip),%eax<br>
# [76] specialize TestType<TTestAnsiString>(True);<br>
addl $1,TC_$P$TISMNGD1_$$_GERROR(%rip)<br>
movl TC_$P$TISMNGD1_$$_GERROR(%rip),%eax<br>
# [77] specialize TestType<TTestManaged>(True);<br>
addl $1,TC_$P$TISMNGD1_$$_GERROR(%rip)<br>
movl TC_$P$TISMNGD1_$$_GERROR(%rip),%eax<br>
# [78] specialize TestType<TTestObj>(False);<br>
addl $1,TC_$P$TISMNGD1_$$_GERROR(%rip)<br>
movl TC_$P$TISMNGD1_$$_GERROR(%rip),%eax<br>
# [79] specialize TestType<TTestObjAnsiString>(True);<br>
addl $1,TC_$P$TISMNGD1_$$_GERROR(%rip)<br>
movl TC_$P$TISMNGD1_$$_GERROR(%rip),%eax<br>
# [80] specialize TestType<TDynArrayLongInt>(True);<br>
addl $1,TC_$P$TISMNGD1_$$_GERROR(%rip)<br>
movl TC_$P$TISMNGD1_$$_GERROR(%rip),%eax<br>
# [81] specialize TestType<TStaticArrayLongInt>(False);<br>
addl $1,TC_$P$TISMNGD1_$$_GERROR(%rip)<br>
movl TC_$P$TISMNGD1_$$_GERROR(%rip),%eax<br>
# [82] specialize TestType<TStaticArrayAnsiString>(True);<br>
addl $1,TC_$P$TISMNGD1_$$_GERROR(%rip)<br>
movl TC_$P$TISMNGD1_$$_GERROR(%rip),%eax<br>
# [83] specialize TestType<TEnum>(False);<br>
addl $1,TC_$P$TISMNGD1_$$_GERROR(%rip)<br>
movl TC_$P$TISMNGD1_$$_GERROR(%rip),%eax<br>
# [84] specialize TestType<TSet>(False);<br>
addl $1,TC_$P$TISMNGD1_$$_GERROR(%rip)<br>
movl TC_$P$TISMNGD1_$$_GERROR(%rip),%eax<br>
# [85] Writeln('Ok');<br>
call fpc_get_output<br>
movq %rax,%rbx<br>
leaq _$TISMNGD1$_Ld3(%rip),%r8<br>
movq %rbx,%rdx<br>
movl $0,%ecx<br>
call fpc_write_text_shortstr<br>
call fpc_iocheck<br>
movq %rbx,%rcx<br>
call fpc_writeln_end<br>
call fpc_iocheck<br>
# [86] end.<br>
call fpc_do_exit<br>
movq -8(%rbp),%rbx<br>
leaq (%rbp),%rsp<br>
popq %rbp<br>
ret<br>
.seh_endproc<br>
.Lc121:<br>
<br>
=== code end ===<br>
<br>
As you can see the compiler basically optimized everything except
the increment of the gError variable away, because it determined it
can do so. And this was *without* any explicit optimizations
enabled.<br>
<br>
Regards,<br>
Sven<br>
</body>
</html>