<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="">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 style="font-family: Courier;" class="">&nbsp; return 42;</span></div><div class=""><font face="Courier" class="">}<br class=""></font><br class="">It seems like <i class="">inlining</i> ‘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>Which is surprising in multiple ways and (as far as I can tell) difficult to workaround without lots of source churn.</div><div><br class=""></div><div>Where should I file a bug?</div><div><br class=""></div><div>Dave</div><div><br class=""></div><div><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=""><meta http-equiv="Content-Type" content="text/html; charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><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="">https://lists.swift.org/mailman/listinfo/swift-dev<br class=""></div></blockquote></div><br class=""></div></body></html>