https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78685
--- Comment #10 from Richard Biener <rguenth at gcc dot gnu.org> --- (In reply to Tom de Vries from comment #8) > Created attachment 44333 [details] > proof of concept patch > > I ran into the same problem with guality test-case pr54200.c, which fails > for Og. > > The relevant part of the test-case is: > ... > int __attribute__((noinline,noclone)) > foo (int z, int x, int b) > { > if (x == 1) > { > bar (); > return z; > } > else > { > int a = (x + z) + b; > return a; /* { dg-final { gdb-test 20 "z" "3" } } */ > } > } > ... > > The problem is that the '(x + z) + b' calculation has a temporary register > which gets allocated the register that holds 'z', so when we get to the > gdb-test line, z is no longer available. > > Using this patch I managed to print the correct value of z at the gdb-test > line. > > The patch uses clobbers in gimple to mark the out-of-scope point, purely > because that's similar to what was already done for local array variables, > and I thought that was the fastest path to getting a proof of concept > working. It's more accurate to model this as some sort of use in gimple, and > doing so may prevent gimple optimizations which wreck debug info, but > perhaps that's not necessary, I suppose that depends on which optimizations > are enabled in Og. > > Anyway, at expand we emit a use for the clobber which seems to do the trick. An interesting idea but I think this will cause excessive spilling and come at a compile-time cost. The idea of -Og was to have performance closer to -O1 here and with this we approach -O0 in assigning stack slots to all user variables? This is a general conflict of interest of course. Your patch shouldn't prevent any optimization at the GIMPLE level (like completely eliding local variables) but definitely they'll keep things live at RTL level. Given for the testcase at hand the issue is "suboptimal" choice of register allocation I wonder if we can adjust the RA / DF to consider liveness to extend always up to the next sequence point. That is, it is reasonable to lose track of z in int a = (x + z) + b; but only after x + z is computed. So a different approach would be to see this as an issue with the way debug consumers "step" now that we emit column debug information? That said, starting with GCC 8 we now have # DEBUG BEGIN_STMT markers: <bb 4> [local count: 856416479]: # DEBUG BEGIN_STMT _1 = x_4(D) + z_7(D); a_9 = _1 + b_8(D); # DEBUG a => a_9 # DEBUG BEGIN_STMT they are also present on RTL as (debug_insn 21 20 0 (debug_marker) "t.c":11 -1 (nil)) which means we _could_ somehow use those for code-generation (in DF analysis to extend lifetimes somehow). Of course if we do we have to emit those always to not get code-gen differences -g vs. -g0. Maybe the RA could also be generally changed to use a not-LRU style preferencing of available registers to choose from. In the end nothing saves us from "spilling" things if we really want to be able to access all final values of registers up to the point they go out of scope... So another idea would be instead of like -O0 assigning the main location to the stack we spill no longer used vars during LRA? We'd still have to somehow know until when that spill slot needs to live (and afterwards can be re-used).