https://bugs.llvm.org/show_bug.cgi?id=39901

            Bug ID: 39901
           Summary: clobbered return value from this-adjustment thunk
                    returning a member pointer
           Product: clang
           Version: trunk
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: enhancement
          Priority: P
         Component: LLVM Codegen
          Assignee: unassignedclangb...@nondot.org
          Reporter: h...@chromium.org
                CC: llvm-bugs@lists.llvm.org, neeil...@live.com,
                    richard-l...@metafoo.co.uk

Consider the following example, targeting 32-bit x86:

struct X;
typedef void (X::*memptr)();

struct A {
  virtual memptr f();
};

struct B {
  virtual memptr f();
};

struct C : A, B {
  C();
  memptr f() override __attribute__((noinline)) { return nullptr; };
};

C::C() {}


$ clang -cc1 -triple i686 -emit-llvm -o - a.cc -O3
[...]
define linkonce_odr void @_ZThn4_N1C1fEv({ i32, i32 }* noalias sret
%agg.result, %struct.C* %this) unnamed_addr #1 comdat align 2 {
entry:
  %tmp = alloca { i32, i32 }, align 4
  %0 = getelementptr inbounds %struct.C, %struct.C* %this, i32 -1, i32 1
  %1 = bitcast %struct.B* %0 to %struct.C*
  tail call void @_ZN1C1fEv({ i32, i32 }* nonnull sret %tmp, %struct.C* nonnull
%1)
  ret void
}


Note that the sret value from @_ZN1C1fEv gets dropped!

The -O0 IR looks like this:

define linkonce_odr void @_ZThn4_N1C1fEv({ i32, i32 }* noalias sret
%agg.result, %struct.C* %this) unnamed_addr #0 comdat align 2 {
entry:
  %retval = alloca { i32, i32 }, align 4
  %this.addr = alloca %struct.C*, align 4
  %tmp = alloca { i32, i32 }, align 4
  store %struct.C* %this, %struct.C** %this.addr, align 4
  %this1 = load %struct.C*, %struct.C** %this.addr, align 4
  %0 = bitcast %struct.C* %this1 to i8*
  %1 = getelementptr inbounds i8, i8* %0, i32 -4
  %2 = bitcast i8* %1 to %struct.C*
  tail call void @_ZN1C1fEv({ i32, i32 }* sret %tmp, %struct.C* %2)
  %3 = load { i32, i32 }, { i32, i32 }* %tmp, align 4
  store { i32, i32 } %3, { i32, i32 }* %retval, align 4
  %4 = load { i32, i32 }, { i32, i32 }* %retval, align 4
  store { i32, i32 } %4, { i32, i32 }* %agg.result, align 4
  ret void
}

Note that the thunk is passing its %tmp alloca into the tail-called function.
That's not allowed: a tail-call function is not supposed to access alloca's
from the caller. Because of that, the subsequent copy from %tmp to %agg.result
gets optimized away.

Interestingly, this doesn't happen for all sret values, such as a regular
struct. I could only reproduce with a member pointer.

-- 
You are receiving this mail because:
You are on the CC list for the bug.
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to