<HTML>
This might prove quite complicated to implement. Writing a similar test function and modifying my node dump to get what I need (the node dump tool does its work before the second pass, so inlined functions aren't expanded), I get a very complicated node tree for a single inlined function call to "floor" with a parameter of type Single:<br>
<br>
----<br>
<br>
<blockn resultdef="SmallInt" pos="21,92" flags="nf_pass1_done,nf_no_lvalue", complexity="255"><br>
...<statementn resultdef="$void" pos="21,92", complexity="255"><br>
......<tempcreaten resultdef="$void" pos="21,92" flags="nf_pass1_done,nf_is_funcret", complexity="0"><br>
.........<size>2</size><br>
.........<temptypedef>SmallInt</temptypedef><br>
.........<tempinfo>$000000005E511570</tempinfo><br>
.........<tempinit /><br>
......</tempcreaten><br>
...</statementn><br>
...<statementn resultdef="$void" pos="21,92", complexity="255"><br>
......<tempcreaten resultdef="$void" pos="21,92" flags="nf_pass1_done", complexity="0"><br>
.........<size>8</size><br>
.........<temptypedef>Double</temptypedef><br>
.........<tempinfo>$000000005E5114F0</tempinfo><br>
.........<tempinit /><br>
......</tempcreaten><br>
...</statementn><br>
...<statementn resultdef="$void" pos="21,92", complexity="255"><br>
......<assignn resultdef="$void" pos="21,92" flags="nf_pass1_done", complexity="5"><br>
.........<temprefn resultdef="Double" pos="21,92" flags="nf_pass1_done,nf_write", complexity="1"><br>
............<temptypedef>Double</temptypedef><br>
............<tempinfo>$000000005E5114F0</tempinfo><br>
............<tempflags>ti_may_be_in_reg</tempflags><br>
.........</temprefn><br>
......</assignn><br>
......<typeconvn resultdef="Double" pos="21,91" flags="nf_pass1_done", complexity="3" convtype="tc_real_2_real"><br>
.........<vecn resultdef="Single" pos="21,91" flags="nf_pass1_done", complexity="2"><br>
............<loadn resultdef="<no type symbol>" pos="21,77" flags="nf_pass1_done", complexity="1"><br>
...............<symbol>TESTSINGLES</symbol><br>
............</loadn><br>
.........</vecn><br>
.........<typeconvn resultdef="<no type symbol>" pos="21,89" flags="nf_pass1_done", complexity="1" convtype="tc_int_2_int"><br>
............<loadn resultdef="SmallInt" pos="21,89" flags="nf_pass1_done", complexity="1"><br>
...............<symbol>X</symbol><br>
............</loadn><br>
.........</typeconvn><br>
......</typeconvn><br>
...</statementn><br>
...<statementn resultdef="$void" pos="21,92", complexity="255"><br>
......<assignn resultdef="$void" pos="21,92" flags="nf_pass1_done", complexity="255"><br>
.........<typeconvn resultdef="SmallInt" pos="21,92" flags="nf_pass1_done,nf_absolute", complexity="1" convtype="tc_equal"><br>
............<temprefn resultdef="SmallInt" pos="21,92" flags="nf_pass1_done,nf_write,nf_is_funcret", complexity="1"><br>
...............<temptypedef>SmallInt</temptypedef><br>
...............<tempinfo>$000000005E511570</tempinfo><br>
...............<tempflags>ti_may_be_in_reg</tempflags><br>
............</temprefn><br>
.........</typeconvn><br>
......</assignn><br>
......<typeconvn resultdef="SmallInt" pos="21,92" flags="nf_pass1_done", complexity="255" convtype="tc_int_2_int"><br>
.........<subn resultdef="Int64" pos="21,92" flags="nf_pass1_done", complexity="255"><br>
............<inlinen resultdef="Int64" pos="21,92" flags="nf_pass1_done", complexity="1" inlinenumber="in_trunc_real"><br>
...............<temprefn resultdef="Double" pos="21,92" flags="nf_pass1_done", complexity="1"><br>
..................<temptypedef>Double</temptypedef><br>
..................<tempinfo>$000000005E5114F0</tempinfo><br>
..................<tempflags>ti_may_be_in_reg</tempflags><br>
...............</temprefn><br>
............</inlinen><br>
.........</subn><br>
.........<typeconvn resultdef="Int64" pos="21,92" flags="nf_pass1_done", complexity="255" convtype="tc_int_2_int"><br>
............<typeconvn resultdef="Byte" pos="21,92" flags="nf_pass1_done,nf_explicit,nf_internal", complexity="255" convtype="tc_bool_2_int"><br>
...............<ltn resultdef="Boolean" pos="21,92" flags="nf_pass1_done", complexity="255"><br>
..................<calln resultdef="Double" pos="21,92" flags="nf_pass1_done", complexity="255"><br>
.....................<procname>$fpc_frac_real(Double):Double;</procname><br>
.....................<callparan resultdef="Double" pos="21,92", complexity="1"><br>
........................<third-branch /><br>
........................<temprefn resultdef="Double" pos="21,92" flags="nf_pass1_done", complexity="1"><br>
...........................<temptypedef>Double</temptypedef><br>
...........................<tempinfo>$000000005E5114F0</tempinfo><br>
...........................<tempflags>ti_may_be_in_reg</tempflags><br>
........................</temprefn><br>
.....................</callparan><br>
..................</calln><br>
...............</ltn><br>
...............<realconstn resultdef="Double" pos="21,92" flags="nf_pass1_done", complexity="2"><br>
..................<value> 0.0000000000000000E+000</value><br>
...............</realconstn><br>
............</typeconvn><br>
.........</typeconvn><br>
......</typeconvn><br>
...</statementn><br>
...<statementn resultdef="$void" pos="21,92", complexity="1"><br>
......<tempdeleten resultdef="$void" pos="21,92" flags="nf_pass1_done", complexity="0"><br>
.........<release_to_normal>FALSE</release_to_normal><br>
.........<temptypedef>Double</temptypedef><br>
.........<temptype>tt_persistent</temptype><br>
.........<tempinfo>$000000005E5114F0</tempinfo><br>
......</tempdeleten><br>
...</statementn><br>
...<statementn resultdef="$void" pos="21,92", complexity="1"><br>
......<tempdeleten resultdef="$void" pos="21,92" flags="nf_pass1_done", complexity="0"><br>
.........<release_to_normal>TRUE</release_to_normal><br>
.........<temptypedef>SmallInt</temptypedef><br>
.........<temptype>tt_persistent</temptype><br>
.........<tempinfo>$000000005E511570</tempinfo><br>
......</tempdeleten><br>
...</statementn><br>
...<statementn resultdef="$void" pos="21,92", complexity="1"><br>
......<temprefn resultdef="SmallInt" pos="21,92" flags="nf_pass1_done,nf_is_funcret", complexity="1"><br>
.........<temptypedef>SmallInt</temptypedef><br>
.........<tempinfo>$000000005E511570</tempinfo><br>
.........<tempflags>ti_may_be_in_reg</tempflags><br>
......</temprefn><br>
...</statementn><br>
</blockn><br>
<div>----<br>
</div><div><br>
</div><div>Because it's a test function, the result type is SmalInt rather than LongInt due to the compiler options, but the effect is the same. Most of the attributes and flags I can ignore, but it's going to be a mammoth task to check all of these nodes and confirm that the function is what it's meant to be. Don't get me wrong, it can be done, but I'm worried it will take the compiler a disproportionately long time doing so.<br>
<br>
Still, at the same time, this is an example where the node dump is useful, if still needing some work.<br>
<br>
Gareth aka. Kit<br>
</div><br>
<br>
<br>
<span style="font-weight: bold;">On Mon 04/02/19 19:28 , "J. Gareth Moreton" gareth@moreton-family.com sent:<br>
</span><blockquote style="BORDER-LEFT: #F5F5F5 2px solid; MARGIN-LEFT: 5px; MARGIN-RIGHT:0px; PADDING-LEFT: 5px; PADDING-RIGHT: 0px">
I might hold on this for a little bit until I get more out of my node outputting feature, since I need to study the nodes produced by an inlined Floor function carefully. For example, Floor's formal parameter is further passed separately into Trunc and Frac - normally it's not a problem, but if the actual parameter is a complex expression (i.e. isn't a simple constant or variable), then it may produce even more nodes as it's calculated twice, once for Trunc and once for Frac... or it's computed beforehand and put into a temporary store that's hidden from the programmer. I won't know for sure until I study the nodes and make a good contingency.<br>
<br>
<div>I'll likely make 3 versions of the floor function (not including the Pascal version that already exists, which the compiler can fall back on if it's dealing with the "Extended" type, for example), one that uses SSE2, one that uses SSE4.1 (which introduces the ROUNDSD instruction) and one that uses AVX (which is effectively identical to the SSE4.1 one, albeit using the AVX functions).</div><div><br>
</div><div>The node optimisation is definitely the better choice, thinking about it now, also because if the compiler determines that the parameters are of type Single, it can use the single-precision SSE instructions rather than converting from Single to Double and back again. I just feel like this is possibly a little bloated because it's the kind of optimisation that belongs to an internal function rather than one in a supplementary unit... unless you want to promote "floor" and similar functions from the Math unit into internal functions through the System unit.<br>
</div><br>
This is proving to be a fascinating learning experience, not just of coding but also of design and discussion!<br>
<br>
Gareth aka. Kit<br>
<br>
<br>
<span style="font-weight: bold;">On Mon 04/02/19 20:04 , "Florian Klämpfl" florian@freepascal.org sent:<br>
</span><blockquote style="BORDER-LEFT: #F5F5F5 2px solid; MARGIN-LEFT: 5px; MARGIN-RIGHT: 0px; PADDING-LEFT: 5px; PADDING-RIGHT: 0px">Am 04.02.19 um 17:47 schrieb J. Gareth Moreton:
<br>
<span style="color: rgb(102, 102, 102);">> Oh whoops, sorry about that and not replying to the list.
</span><br>
<span style="color: rgb(102, 102, 102);">>
</span><br>
<span style="color: rgb(102, 102, 102);">> I'll try not to screw up. Generally I think Double is preferred because
</span><br>
<span style="color: rgb(102, 102, 102);">> then everything uses SSE2 and no awkward ferrying of data between it and
</span><br>
<span style="color: rgb(102, 102, 102);">> the floating-point stack is required (come to think of it, only Win64
</span><br>
<span style="color: rgb(102, 102, 102);">> actually requires the presence of SSE2 and refuses to install if it's
</span><br>
<span style="color: rgb(102, 102, 102);">> not present).
</span><br>
<span style="color: rgb(102, 102, 102);">>
</span><br>
<span style="color: rgb(102, 102, 102);">> Given that Florian prefers a node micro-optimisation for functions like
</span><br>
<span style="color: rgb(102, 102, 102);">> floor, it should be easy enough to check if the input is of type Single
</span><br>
<span style="color: rgb(102, 102, 102);">> or Double, and drop out if it's Extended (falling back to the actual
</span><br>
<span style="color: rgb(102, 102, 102);">> source code).
</span><br>
<br>
Well, in case of a node optimization in combination with inline I do not
<br>
see it as a real micro optimization as it results in the best code which
<br>
is not the case if it is ifdef'ed assembler code in a unit which is most
<br>
of the time not used (fpc x86-64 rtl is build with -Cfsse2 normally).
<br>
_______________________________________________
<br>
fpc-devel maillist - <a href="javascript:top.opencompose(" target="_blank" fpc-devel@lists.freepascal.org','','','')"="">fpc-devel@lists.freepascal.org</a>
<br>
<a target="_blank" ?redirect="<a" href="http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel">http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel</a>"><span style="color: red;">http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel</span>
<br>
<br>
<br>
</blockquote>
_______________________________________________<br>
fpc-devel maillist - <a href="javascript:top.opencompose('fpc-devel@lists.freepascal.org','','','')">fpc-devel@lists.freepascal.org</a><br>
<a target="_blank" href="parse.php?redirect=<a href="http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel">http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel</a>"><span style="color: red;">http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel</span></a><br>
<br>
</blockquote></HTML>