<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><br class=""><div><br class=""><blockquote type="cite" class=""><div class="">On Jan 1, 2018, at 18:20, John McCall &lt;<a href="mailto:rjmccall@apple.com" class="">rjmccall@apple.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><div class=""><br class="Apple-interchange-newline">On Jan 1, 2018, at 5:51 PM, David Zarzycki via swift-dev &lt;<a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;">Hi Michael,<div class=""><br class=""></div><div class="">I reduced it down to a simple test case. I was wrong about this requiring two or more dyn_casts. This actually affects any C++ code that uses the “if (auto x = y(z))” convention. What follows is the reduction (compiled with “clang++ -O3 -c” if it matters):</div><div class=""><br class=""></div><div class=""><font face="Courier" class="">// Uncomment the next line to see the expected code gen (albeit not inlined)</font></div><div class=""><font face="Courier" class="">//__attribute__((used,noinline))<br class="">int *x(void *arg) {<br class="">&nbsp; return ((long long)arg &amp; 1) ? (int *)arg : nullptr;<br class="">}<br class=""><br class="">int test(void *arg) {<br class="">&nbsp; if (auto y = x(arg))</font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; return *y;</font></div><div class=""><span class="" style="font-family: Courier;">&nbsp; return 42;</span></div><div class=""><font face="Courier" class="">}<br class=""></font><br class="">It seems like<span class="Apple-converted-space">&nbsp;</span><i class="">inlining</i><span class="Apple-converted-space">&nbsp;</span>‘x’ causes the compiler to effectively generate the following pseudo-code:</div><div class=""><br class=""></div><div class=""><font face="Courier" class="">int test(void *arg) {<br class="">&nbsp; if (arg != nullptr)</font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; if (arg &amp; 1)</font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; &nbsp; return *arg;</font></div><div class=""><font face="Courier" class="">&nbsp;&nbsp;return 42;<br class="">}<br class=""></font></div><div class=""><br class=""><div class="">Which is surprising in multiple ways and (as far as I can tell) difficult to workaround without lots of source churn.</div><div class=""><br class=""></div><div class="">Where should I file a bug?</div></div></div></div></blockquote><div class=""><br class=""></div><a href="http://bugs.llvm.org/" class="">bugs.llvm.org</a>&nbsp;would be best. &nbsp;Including both your reduced test case and the fact that it was reduced from dyn_cast patterns should make them sit up and take notice.</div></div></blockquote><div><br class=""></div><div>Thanks John,</div><div><br class=""></div></div><div>In case anybody wants to cherry-pick the fix once it is found:</div><div><span class="Apple-tab-span" style="white-space:pre">        </span><a href="https://bugs.llvm.org/show_bug.cgi?id=35790" class="">https://bugs.llvm.org/show_bug.cgi?id=35790</a></div><div><br class=""><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">John.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><div class=""><div class=""><br class=""></div><div class="">Dave</div><div class=""><br class=""></div><div class=""><br class=""><blockquote type="cite" class=""><div class="">On Jan 1, 2018, at 13:10, David Zarzycki via swift-dev &lt;<a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><div class=""><div class="">I don’t have the IR handy. You can easily generate it for yourself though. Just drop the following into any file (I use swift/lib/AST/Type.cpp) and recompile swift.</div><div class=""><br class=""></div><div class=""><font face="Courier" class="">Decl *my_test_function(Type t) {</font></div><div class=""><font face="Courier" class="">&nbsp; return t-&gt;getClassOrBoundGenericClass();</font></div><div class=""><font face="Courier" class="">}<br class=""></font><div class=""><br class=""><div class=""><br class=""><blockquote type="cite" class=""><div class="">On Jan 1, 2018, at 12:53, Michael Gottesman &lt;<a href="mailto:mgottesman@apple.com" class="">mgottesman@apple.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="">Do you have the llvm-ir handy?<br class=""><br class=""><blockquote type="cite" class="">On Jan 1, 2018, at 11:30 AM, David Zarzycki via swift-dev &lt;<a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a>&gt; wrote:<br class=""><br class="">Hello,<br class=""><br class="">I noticed recently that the code gen of CanType::getClassOrBoundGenericClass() could be better and along the way I found a clang/LLVM bug. Where exactly, I do not know, although my bet is the LLVM optimizer.<br class=""><br class="">When more than one dyn_cast() happens in a row, LLVM/clang emits redundant and pointless nullptr checks. Both Apple clang-900.0.39.2 and clang/llvm top-of-tree generate essentially the same code:<br class=""><br class="">&lt;+35&gt;: movb &nbsp;&nbsp;0x8(%rbx), %cl &nbsp;; getKind()<br class="">&lt;+38&gt;: testq &nbsp;%rbx, %rbx &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;; XXX - nullptr check after deref is pointless<br class="">&lt;+41&gt;: je &nbsp;&nbsp;&nbsp;&nbsp;0x1377df6 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;; &lt;+54&gt;<br class="">&lt;+43&gt;: cmpb &nbsp;&nbsp;$0x12, %cl &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;; isa&lt;ClassType&gt;()<br class="">&lt;+46&gt;: jne &nbsp;&nbsp;&nbsp;0x1377df6 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;; &lt;+54&gt;<br class="">&lt;+48&gt;: addq &nbsp;&nbsp;$0x10, %rbx &nbsp;&nbsp;&nbsp;&nbsp;; (void*)this + offsetof(ClassType, TheDecl)<br class="">&lt;+52&gt;: jmp &nbsp;&nbsp;&nbsp;0x1377e06 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;; &lt;+70&gt;<br class="">&lt;+54&gt;: xorl &nbsp;&nbsp;%eax, %eax &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;; the default return value (nullptr)<br class="">&lt;+56&gt;: testq &nbsp;%rbx, %rbx &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;; XXX - another pointless nullptr check?<br class="">&lt;+59&gt;: je &nbsp;&nbsp;&nbsp;&nbsp;0x1377e09 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;; &lt;+73&gt;<br class="">&lt;+61&gt;: cmpb &nbsp;&nbsp;$0x29, %cl &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;; isa&lt;BoundGenericClassType&gt;()<br class="">&lt;+64&gt;: jne &nbsp;&nbsp;&nbsp;0x1377e09 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;; &lt;+73&gt;<br class="">&lt;+66&gt;: addq &nbsp;&nbsp;$0x18, %rbx &nbsp;&nbsp;&nbsp;&nbsp;; (void*)this + offsetof(BoundGenericClassType, TheDecl)<br class="">&lt;+70&gt;: movq &nbsp;&nbsp;(%rbx), %rax &nbsp;&nbsp;&nbsp;; load the decl pointer<br class="">&lt;+73&gt;: popq &nbsp;&nbsp;%rbx<br class="">&lt;+74&gt;: retq &nbsp;&nbsp;<br class=""><br class="">I’ve tried adding different “nonnull” spellings in various parts of both Swift and LLVM’s casting machinery, but with no luck. The only thing that seems to work is to create a free function that takes a non-null “const TypeBase *” parameter and then have CanType::getClassOrBoundGenericClass() call that.<br class=""><br class="">FWIW – I *suspect* this is because LLVM’s casting machinery internally converts traditional pointers into C++ references before ultimately calling classof(&amp;Val).<br class=""><br class="">Before I file a bug against clang/llvm, might I be missing something? Can anybody think of a good workaround?<br class=""><br class="">Dave<br class="">_______________________________________________<br class="">swift-dev mailing list<br class=""><a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-dev" class="">https://lists.swift.org/mailman/listinfo/swift-dev</a><br class=""></blockquote><br class=""></div></div></blockquote></div><br class=""></div></div></div></div>_______________________________________________<br class="">swift-dev mailing list<br class=""><a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-dev" class="">https://lists.swift.org/mailman/listinfo/swift-dev</a><br class=""></div></blockquote></div><br class=""></div></div>_______________________________________________<br class="">swift-dev mailing list<br class=""><a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-dev" class="">https://lists.swift.org/mailman/listinfo/swift-dev</a></div></blockquote></div></div></blockquote></div><br class=""></body></html>