<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=""> 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 style="font-family: Courier;" class=""> 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=""> 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>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 <<a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a>> 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=""> 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="">https://lists.swift.org/mailman/listinfo/swift-dev<br class=""></div></blockquote></div><br class=""></div></body></html>