New issue
Advanced search Search tips
Starred by 1 user

Issue metadata

Status: Assigned
Owner:
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Windows
Pri: 2
Type: Bug

Blocking:
issue 636111



Sign in to add a comment

Clang's NRVO debug info is still poor

Project Member Reported by yoichio@chromium.org, Jul 5

Issue description

What steps will reproduce the problem?
(1) Build following code. (you can download it from
 https://chromium-review.googlesource.com/c/chromium/src/+/1126694)
(2) Set a break point on the bottom of |GetFoo()| function and run.

struct Foo {
  STACK_ALLOCATED();
  Foo() = default;
  Foo(Foo&& other) { x = other.x; }
  int x;

 private:
  DISALLOW_COPY_AND_ASSIGN(Foo);
};

static Foo GetFoo() {
  Foo foo;
  foo.x = 3;
#if DCHECK_IS_ON()
  DCHECK(foo.x);
#endif
  return foo;  // Break point here losts |foo|.
}

TEST_F(NGLayoutSelectionTest, Foobar) {
  Foo bar = GetFoo();
  EXPECT_EQ(3, bar.x);
}

What is the expected result?
Visual studio debugger shows |foo|.

What happens instead?
It is lost in debugger view while showing the message
"Variable is optimized away and not available."

If I remove the #if close, it shows.
Actually |foo.x = 3| is a for-loop and the return row is a only place
to view final value in this function with other local variables. 
That's really prohibiting me debugging code.


 
Cc: tikuta@chromium.org
Labels: OS-Windows
What happens if you pass --fno-elide-constructors flag? 
https://stackoverflow.com/questions/8758152/disabling-gs-return-value-optimisation
Could you tell me how do you pass such flags with gn ?
Cc: r...@chromium.org h...@chromium.org
Summary: Visual studio loses optimized variables (was: Visual studio looses optimized variables )
Blocking: 636111
It looks clang-cl doesn't have "--fno-elide-constructors" option.
https://clang.llvm.org/docs/UsersManual.html#clang-cl
And also we're using "/Od" option already.
Ah, clang has the flag.
https://github.com/llvm-project/llvm-project-20170507/blob/b2b804a99452ff4d41643cd9f29043986fadff6c/clang/include/clang/Driver/Options.td#L842

But you need to pass the flag like -Xclang -fno-elide-constructors to clang-cl.
It made skia build failed. 
$ autoninja skia
ninja.exe skia -j 1120 -l 56
[1/1] LINK(DLL) skia.dll skia.dll.lib skia.dll.pdb
FAILED: skia.dll skia.dll.lib skia.dll.pdb
C:/src/build/depot_tools/win_tools-2_7_6_bin/python/bin/python.exe ../../build/toolchain/win/tool_wrapper.py link-wrapper environment.x86 False link.exe /nologo /IMPLIB:./skia.dll.lib /DLL /OUT:./skia.dll /PDB:./skia.dll.pdb @./skia.dll.rsp
SkDisplacementMapEffect.obj : error LNK2001: unresolved external symbol "private: __thiscall GrContextPriv::GrContextPriv(class GrContextPriv const &)" (??0GrContextPriv@@AAE@ABV0@@Z)
SkLightingImageFilter.obj : error LNK2001: unresolved external symbol "private: __thiscall GrContextPriv::GrContextPriv(class GrContextPriv const &)"
(??0GrContextPriv@@AAE@ABV0@@Z)
,,,


Hmm, does that fails on lld too?
Looks similar.
target_cpu = "x86"
enable_nacl = false
is_component_build = true
is_debug = true
use_lld = true
use_goma = true

ninja.exe skia -j 1120 -l 56
[1/1] LINK(DLL) skia.dll skia.dll.lib skia.dll.pdb
FAILED: skia.dll skia.dll.lib skia.dll.pdb
ninja -t msvc -e environment.x86 -- ../../third_party/llvm-build/Release+Asserts/bin/lld-link.exe /nologo /IMPLIB:./skia.dll.lib /DLL /OUT:./skia.dll
/PDB:./skia.dll.pdb @./skia.dll.rsp
../../third_party/llvm-build/Release+Asserts/bin\lld-link.exe: error: undefined symbol: ??0GrContextPriv@@AAE@ABV0@@Z
>>> referenced by C:\src\build\src\chrome3\src\third_party\skia\src\gpu\GrContextPriv.h:299
>>>               obj/skia/skia/GrBackendTextureImageGenerator.obj:(?contextPriv@GrContext@@QAE?AVGrContextPriv@@XZ)
>>> referenced by C:\src\build\src\chrome3\src\third_party\skia\src\gpu\GrContextPriv.h:302
>>>               obj/skia/skia/GrBackendTextureImageGenerator.obj:(?contextPriv@GrContext@@QBE?BVGrContextPriv@@XZ)


../../third_party/llvm-build/Release+Asserts/bin\lld-link.exe: error: undefined symbol: ??0GrResourceProviderPriv@@AAE@ABV0@@Z
>>> referenced by C:\src\build\src\chrome3\src\third_party\skia\src\gpu\GrResourceProviderPriv.h:33
>>>               obj/skia/skia/GrBackendTextureImageGenerator.obj:(?priv@GrResourceProvider@@QAE?AVGrResourceProviderPriv@@XZ)


../../third_party/llvm-build/Release+Asserts/bin\lld-link.exe: error: undefined symbol: ??0GrContextPriv@@AAE@ABV0@@Z
>>> referenced by obj/skia/skia/GrBitmapTextureMaker.obj

Hmm, seems clang's bug.

I confirmed that the flag does not work even on non-debug build.
Also I tried to specify /Ob[012] in debug build and those did not work too.
But I cannot do anymore.

Owner: r...@chromium.org
Status: Assigned (was: Untriaged)
I'd recommend against using -fno-elide-constructors. It was never tested and implemented on Windows.

I'll try to look at this at some point.
I wasn't able to reproduce with this simple program:

#include <cassert>

struct Foo {
  Foo() = default;
  Foo(Foo &&other) { x = other.x; }
  int x;

private:
  Foo(const Foo &o) = delete;
  Foo &operator=(const Foo &o) = delete;
  __attribute__((annotate("blink_stack_allocated")))
  void * operator new(size_t) = delete;
  void *operator new(size_t, void *) = delete;
};

static Foo GetFoo() {
  Foo foo;
  foo.x = 3;
  assert(foo.x == 3);
  return foo;  // Break point here losts |foo|.
}
int main() {
  Foo bar = GetFoo();
  assert(bar.x == 3);
}

I compiled with just clang-cl -Z7 t.cpp, and I could put a breakpoint on the return statement in VS and see foo. I'm trying in Chromium now.
Cc: inglorion@chromium.org
Summary: Clang's NRVO debug info is still poor (was: Visual studio loses optimized variables )
I understand the issue now.

Foo is not trivially copyable, so it is passed and returned indirectly by address. The caller of GetFoo allocates space for the return value, and passes it in as the first register parameter, RCX for x64.

CodeView is capable of describing variable locations as being in memory pointed to by some register plus an offset, so in this case we say that 'foo' is in memory at RCX+0. This variable location is valid up until the DCHECK, which performs a function call, which clobbers RCX, and the variable is "optimized out".

For some reason Bob's register hack isn't firing.
> For some reason Bob's register hack isn't firing.

r312034 adds support for translating some previously unsupported DWARF expressions - among them emulating DW_OP_deref by changing the type from Foo to Foo&, which we needed for NRVO. It seems we are able to encode the NRVO location of foo just fine here; only we lose track of where the variable lives later on (rax+0, perhaps?).

Sign in to add a comment