argument registers and -g

On Mips, we have argument registers which are treated as scratch registers with a live in.

This will not work with -g -O0 because the arguments to the function will not be displayable after they are clobbered.

I'm guess others have solved this problem.

Is there a preferred way?

Reed

Not quite sure what you mean. Can you elaborate, perhaps by showing some dwarf or MachineInstrs?

-eric

Hi Reed

I think what you need is DWARF location lists. See 2.6.4 here http://www.dwarfstd.org/doc/040408.1.html

I think you'd need to mark the values as being in a register location from the function start address, then at the point where they are saved to the stack add a new location to the list for the stack location.

Unfortunately i don't know if we support this or how to go about adding it, but i'm pretty sure thats the DWARF feature you need.

Thanks,
Pete

suppose:

void foo(int i) { // i is passed in a0 register
     int j = i * 370;
     // i is never used again
     //// lots of deep expression code so that the a0 gets used again because it's a scratch register.
    // this is okay, because we don't need it, but now in the debugger
    // we can't display i because it has been clobbered.

.....

Hi Guys,

Pete's comment made Reed's question make sense to me :slight_smile:

Pete is essentially correct, with some complications. You need to track the location of the arguments as they're going through code generation. Look at the llvm.dbg.value intrinsic as a guideline on how to track a variable through compilation and any saves should be marked.

We do support location lists in general (optimized code or code with many variables are impossible without it), but in the case you mention here:

void foo(int i) { // i is passed in a0 register
   int j = i * 370;
   // i is never used again
   //// lots of deep expression code so that the a0 gets used again because it's a scratch register.
  // this is okay, because we don't need it, but now in the debugger
  // we can't display i because it has been clobbered.

you can treat it as "optimized" out. I can't think of a target that has this problem at the moment so you may need to look into what it would take to save the value out to the stack and then track it that way. I'm not a fan of that since that would mean that debug code gen is different from normal code gen. In general, this is a hard problem and there aren't any obvious solutions that I know about. One thing you'll want to make sure is that a variable has a proper address tag so that when it is clobbered you can express the lack of location to the user.

-eric

Hi Guys,

Pete's comment made Reed's question make sense to me :slight_smile:

Pete is essentially correct, with some complications. You need to track the location of the arguments as they're going through code generation. Look at the llvm.dbg.value intrinsic as a guideline on how to track a variable through compilation and any saves should be marked.

We do support location lists in general (optimized code or code with many variables are impossible without it), but in the case you mention here:

void foo(int i) { // i is passed in a0 register
  int j = i * 370;
  // i is never used again
  //// lots of deep expression code so that the a0 gets used again because it's a scratch register.
// this is okay, because we don't need it, but now in the debugger
// we can't display i because it has been clobbered.

you can treat it as "optimized" out. I can't think of a target that has this problem at the moment so you may need to look into what it would take to save the value out to the stack and then track it that way. I'm not a fan of that since that would mean that debug code gen is different from normal code gen. In general, this is a hard problem and there aren't any obvious solutions that I know about. One thing you'll want to make sure is that a variable has a proper address tag so that when it is clobbered you can express the lack of location to the user.

Only thing i can think here is to always insert the saves from arguments into the stack then have an optimization to remove those saves if the values are unused (MachineDCE might already handle this?). That optimization wouldn't run at O0 so you'd get the same behavior with and without -g, but at the expense of slightly worse code in non-debug -O0 builds.

Pete

Yeah, except having debug information avoid perturbing code gen is one of those "thou shalt avoid" commandments :slight_smile:

That said in the case he's talking about it's basically treating the incoming argument as another variable so having it list as not in a range is somewhat acceptable. There's some support in dwarf4 for trying to keep track of what a variable would be had a computation not been deleted (i.e. useless). Not quite what we're talking about here since the variable has basically ceased to exist.

Also, a lot of debuggers will keep track of incoming values at function start. Unless something is clobbering the argument registers in the prologue it shouldn't be a problem for a debugger to just keep the value off to the side.

-eric

Hi Guys,

Pete's comment made Reed's question make sense to me :slight_smile:

Pete is essentially correct, with some complications. You need to track the location of the arguments as they're going through code generation. Look at the llvm.dbg.value intrinsic as a guideline on how to track a variable through compilation and any saves should be marked.

We do support location lists in general (optimized code or code with many variables are impossible without it), but in the case you mention here:

void foo(int i) { // i is passed in a0 register
int j = i * 370;
// i is never used again
//// lots of deep expression code so that the a0 gets used again because it's a scratch register.
// this is okay, because we don't need it, but now in the debugger
// we can't display i because it has been clobbered.

you can treat it as "optimized" out. I can't think of a target that has this problem at the moment so you may need to look into what it would take to save the value out to the stack and then track it that way. I'm not a fan of that since that would mean that debug code gen is different from normal code gen. In general, this is a hard problem and there aren't any obvious solutions that I know about. One thing you'll want to make sure is that a variable has a proper address tag so that when it is clobbered you can express the lack of location to the user.

Only thing i can think here is to always insert the saves from arguments into the stack then have an optimization to remove those saves if the values are unused (MachineDCE might already handle this?). That optimization wouldn't run at O0 so you'd get the same behavior with and without -g, but at the expense of slightly worse code in non-debug -O0 builds.

Yeah, except having debug information avoid perturbing code gen is one of those "thou shalt avoid" commandments :slight_smile:

Ah, but thats why i suggested doing this entirely based on the optimization flag. So always generate the stores to the stack (whether in debug mode or not), but only remove the stores if O1 or higher.

Pete

But it just seems... wrong to generate worse code at O0 on purpose :slight_smile:

-eric

Hit send too soon...

but it'll probably work at the risk of producing worse code even at O1 if the optimizer doesn't notice them for some reason - though that's a bug of a different sort.

-eric