<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Fri, Mar 16, 2018 at 2:09 PM, Lawrence Crowl <span dir="ltr">&lt;<a href="mailto:Lawrence@crowl.org" target="_blank">Lawrence@crowl.org</a>&gt;</span> wrote:<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">There are machines that do not define the behavior of some instructions<br>
with some arguments and/or in come contexts.  Are those machines<br>
erroneous?<br></blockquote><div><br>It depends?  (There was the notorious Intel division bug, for example.)<br>But generally speaking, no.  It&#39;s the compiler&#39;s job to model the abstract<br>machine on the target computer, and that would generally mean avoiding<br>such constructs.  (But see below.)<br><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">The meaning of &quot;x trusts y&quot; is &quot;x relies on the (promised) behavior of<br>
y&quot;.  I see no trust in your interpretation because the compiler does<br>
not rely on any behavior on the part of the programmer.  Your view is<br>
blind obedience.<br></blockquote><div><br>Yes.  I&#39;m glad you understand.  Programs are written later than the compiler,<br>and therefore programmers have a better model of what the compiler will do<br>than compilers will have about what programmers will do.  (And programmers<br>are intelligent people while compilers are stupid machines.)<br><br>Therefore, when a compiler is about to make a decision that it does not<br>understand what a program is doing, it must trust that the programmer<br>correctly expressed a computational intention, and produce instructions<br>that (with blind obedience) model what the program contains.<br><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
In contrast, in &quot;the compiler trusts the programmer to not write wrong<br>
programs&quot;, there is demonstrable trust on the part of the compiler.<br></blockquote><div><br>That is the exact opposite of trust.<br><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class="gmail-">
&gt; The compiler still has as-if latitude.  As-if transformations maintain<br>
&gt; the actions of the written program.<br>
<br>
</span>As-if only has meaning with respect to an abstract machine.  The issue<br>
here is what you think the abstract machine should be.<br></blockquote><div><br>That was clear from K&amp;R; when the abstract machine maps cleanly onto<br>CPU instruction sets, perform the obvious mapping and then produce the<br>results from that mapping.<br><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class="gmail-">
&gt; Assuming undefined behavior doesn&#39;t happen does not.<br>
</span>That assumption is the trust.<br></blockquote><div><br>That assumption is the literal opposite of trust.  The compiler says to the<br>programmer that despite the fact that the programmer has written a section<br>of code, the compiler will refuse to compile it, often silently.<br><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">In this phrase you are trying to impose a change to the C/C++ abstract<br>
machine.  The standard defines the abstract machine; you do not.  If you<br>
want to change that machine, you need to change the standard.<br></blockquote><div><br>Choosing not to define behavior is not defining behavior.<br><br>Compilers choosing to not compile any code path that provably has undefined<br>behavior is stupid and pernicious and driven by optimizationism.  When the<br>compiler detects that some piece of code must execute undefined behavior,<br>it should map that code onto the actual machine in the way the code is written.<br><br>That does not involve changing the standard, since the standard already says<br>that it has no requirements for this code.  It&#39;s the compilers that need to change.<br>(Of course, every time more undefined behavior is added to the standard, it<br>only encourages the misguided compiler writers to do more of the same, so that<br>should be avoided.)<br><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Atomic ints are a very special case because programners cannot anticipate<br>
or avoid undefined behavior.  The operations on atomic ints must be<br>
fully closed.  Those constraints do not apply elsewhere.<br></blockquote><div><br>But they should.  They very, very should.<br><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class="gmail-">
&gt; But C and C++ already have the maximum possible stupidity of allowing<br>
&gt; floating-point expressions to be calculated at different precisions, so<br>
&gt; that it is literally possible for the expression a + b == a + b to be<br>
&gt; false when the operands are normal floating-point values.  And everyone<br>
&gt; seems to accept that with equanimity.  Optimization, naturally.<br>
<br>
</span>No, not optimization.  Some floating-point hardware had operations that<br>
were no commutative.  IIRC, one was IBM 360 floating point.  Machines<br>
still run this instruction set.  This license in the standard merely<br>
reflects the underlying hardware space.<br></blockquote><div><br>Why are you mentioning commutativity?  I didn&#39;t say <font face="monospace, monospace">a + b == b + a</font>,<br>i said <font face="monospace, monospace">a + b == a + b</font>.  And you&#39;re wrong.  The exact reason for this<br>is that the Intel 8087 floating-point processor had extended-precision<br>registers, and compilers, for the sake of optimization (of course!) chose<br>to keep intermediate results in extended precision rather than truncate<br>them to the lower precision.  But when they needed to spill those registers<br>to memory, they would spill them in reduced-precision mode.  So even<br>when two parts of an expression are identical, it can be that one is in a<br>register and one is in memory, and they therefore have different values.<br><br>SSE instructions do away with the extended precision and this problem.<br>See &lt;<a href="https://gcc.gnu.org/onlinedocs/gcc-4.5.3/gcc/i386-and-x86_002d64-Options.html#index-mcpu-1294">https://gcc.gnu.org/onlinedocs/gcc-4.5.3/gcc/i386-and-x86_002d64-Options.html#index-mcpu-1294</a>&gt;.<br><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">This statement seems inconsistent.  Since I can make a pointer to any<br>
variable, then it must be in memory.<br></blockquote><div><br>No.  You cannot make a pointer to any variable, you can make a pointer<br>to any variable that&#39;s in memory.  And to make that pointer, you need to<br>know or figure out where that variable is.  And it&#39;s still legitimate for the<br>underlying machine to deal with pointers in such a way that pointers<br>can only move within a particular region of storage and not between<br>regions, although that&#39;s also a dying artifact of Intel architecture.<br><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">No, that&#39;s not why we had the register keyword.  We had the register<br>
keyword because some programmers were not happy with the simple<br>
mapping of the abstract machine to the hardware.  They wanted a means<br>
to override the mapping.  The &#39;cannot take the address&#39; part is a<br>
consequence, not a cause.</blockquote><div><br>Just as <font face="monospace, monospace">inline</font> expresses the intent that a function or variable should be<br>expanded inline, but in the language means only that the definition must<br>appear in every compilation unit that uses it, so too does <font face="monospace, monospace">register</font> express<br>the intent that a variable should be kept in a register (or at least that it will be<br>very frequently accessed) but in the language means only that its address<br>may not be taken.</div></div></div></div>