Hi Michael,

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):

// Uncomment the next line to see the expected code gen (albeit not inlined)
//__attribute__((used,noinline))
int *x(void *arg) {
  return ((long long)arg & 1) ? (int *)arg : nullptr;
}

int test(void *arg) {
  if (auto y = x(arg))
    return *y;
  return 42;
}

It seems like inlining ‘x’ causes the compiler to effectively generate the 
following pseudo-code:

int test(void *arg) {
  if (arg != nullptr)
    if (arg & 1)
      return *arg;
  return 42;
}

Which is surprising in multiple ways and (as far as I can tell) difficult to 
workaround without lots of source churn.

Where should I file a bug?

Dave


> On Jan 1, 2018, at 13:10, David Zarzycki via swift-dev <swift-dev@swift.org> 
> wrote:
> 
> 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.
> 
> Decl *my_test_function(Type t) {
>   return t->getClassOrBoundGenericClass();
> }
> 
> 
>> On Jan 1, 2018, at 12:53, Michael Gottesman <mgottes...@apple.com 
>> <mailto:mgottes...@apple.com>> wrote:
>> 
>> Do you have the llvm-ir handy?
>> 
>>> On Jan 1, 2018, at 11:30 AM, David Zarzycki via swift-dev 
>>> <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:
>>> 
>>> Hello,
>>> 
>>> 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.
>>> 
>>> 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:
>>> 
>>> <+35>: movb   0x8(%rbx), %cl  ; getKind()
>>> <+38>: testq  %rbx, %rbx      ; XXX - nullptr check after deref is pointless
>>> <+41>: je     0x1377df6       ; <+54>
>>> <+43>: cmpb   $0x12, %cl      ; isa<ClassType>()
>>> <+46>: jne    0x1377df6       ; <+54>
>>> <+48>: addq   $0x10, %rbx     ; (void*)this + offsetof(ClassType, TheDecl)
>>> <+52>: jmp    0x1377e06       ; <+70>
>>> <+54>: xorl   %eax, %eax      ; the default return value (nullptr)
>>> <+56>: testq  %rbx, %rbx      ; XXX - another pointless nullptr check?
>>> <+59>: je     0x1377e09       ; <+73>
>>> <+61>: cmpb   $0x29, %cl      ; isa<BoundGenericClassType>()
>>> <+64>: jne    0x1377e09       ; <+73>
>>> <+66>: addq   $0x18, %rbx     ; (void*)this + 
>>> offsetof(BoundGenericClassType, TheDecl)
>>> <+70>: movq   (%rbx), %rax    ; load the decl pointer
>>> <+73>: popq   %rbx
>>> <+74>: retq   
>>> 
>>> 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.
>>> 
>>> FWIW – I *suspect* this is because LLVM’s casting machinery internally 
>>> converts traditional pointers into C++ references before ultimately calling 
>>> classof(&Val).
>>> 
>>> Before I file a bug against clang/llvm, might I be missing something? Can 
>>> anybody think of a good workaround?
>>> 
>>> Dave
>>> _______________________________________________
>>> swift-dev mailing list
>>> swift-dev@swift.org <mailto:swift-dev@swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-dev
>> 
> 
> _______________________________________________
> swift-dev mailing list
> swift-dev@swift.org
> https://lists.swift.org/mailman/listinfo/swift-dev

_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev

Reply via email to