<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 <<a href="mailto:rjmccall@apple.com" class="">rjmccall@apple.com</a>> 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 <<a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a>> 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=""> return ((long long)arg & 1) ? (int *)arg : nullptr;<br class="">}<br class=""><br class="">int test(void *arg) {<br class=""> if (auto y = x(arg))</font></div><div class=""><font face="Courier" class=""> return *y;</font></div><div class=""><span class="" style="font-family: Courier;"> return 42;</span></div><div class=""><font face="Courier" class="">}<br class=""></font><br class="">It seems like<span class="Apple-converted-space"> </span><i class="">inlining</i><span class="Apple-converted-space"> </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=""> if (arg != nullptr)</font></div><div class=""><font face="Courier" class=""> if (arg & 1)</font></div><div class=""><font face="Courier" class=""> return *arg;</font></div><div class=""><font face="Courier" class=""> 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> would be best. 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 <<a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a>> 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=""> return t->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 <<a href="mailto:mgottesman@apple.com" class="">mgottesman@apple.com</a>> 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 <<a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a>> 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=""><+35>: movb 0x8(%rbx), %cl ; getKind()<br class=""><+38>: testq %rbx, %rbx ; XXX - nullptr check after deref is pointless<br class=""><+41>: je 0x1377df6 ; <+54><br class=""><+43>: cmpb $0x12, %cl ; isa<ClassType>()<br class=""><+46>: jne 0x1377df6 ; <+54><br class=""><+48>: addq $0x10, %rbx ; (void*)this + offsetof(ClassType, TheDecl)<br class=""><+52>: jmp 0x1377e06 ; <+70><br class=""><+54>: xorl %eax, %eax ; the default return value (nullptr)<br class=""><+56>: testq %rbx, %rbx ; XXX - another pointless nullptr check?<br class=""><+59>: je 0x1377e09 ; <+73><br class=""><+61>: cmpb $0x29, %cl ; isa<BoundGenericClassType>()<br class=""><+64>: jne 0x1377e09 ; <+73><br class=""><+66>: addq $0x18, %rbx ; (void*)this + offsetof(BoundGenericClassType, TheDecl)<br class=""><+70>: movq (%rbx), %rax ; load the decl pointer<br class=""><+73>: popq %rbx<br class=""><+74>: retq <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(&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>