Re: Customizing optimization for debug builds

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 04/02/2021 20:32, mark_at_yahoo via Gcc-help wrote:
> On 2/4/21 11:11 AM, Paul Smith wrote:
>> The thing that really makes me
>> want to punch my monitor is when a variable that contains critical info
>> I need is optimized out.  I don't know if it's just my code or what but
>> it seems to happen to me A LOT that the info I need is only available
>> in some register somewhere that I can't easily figure out how to
>> retrieve, because the variable was optimized away.
> 
> Drives me crazy, too, but that's what optimization does. As I posted
> previously, I can't use -O0 and/or no optimization, so I long ago made
> my peace with it. I frequently have to sprinkle my code with:
> 
> #ifdef DEBUG
> volatile
> #endif
> unsigned some_variable;

You might find it neater to have:

	#ifdef DEBUG
	#define DEBUGABLE volatile
	#else
	#define DEBUGABLE
	#endif

Then when you make the variable, you only need:

	DEBUGABLE unsigned some_variable;

> 
> And of course that can cause problems when "some_variable" is passed to:
> 
> void some_function(unsigned value) ...
> 
> and passing a volatile unsigned instead is an error. 

No, it is not an error - it is perfectly fine.  The parameter is passed
by value - the "volatile unsigned" is read and passed to the function.
It is only if the function has a pointer that you have an error :

	void some_function(unsigned * p);

Calling "some_function(&some_variable)" will fail if some_variable is
declared "volatile".



> So then it's:
> 
> unsigned some_variable;
> some_variable = ...
> volatile unsigned copy_of_variable = some_variable;
> some_function(some_variable);
> 
> ad nauseum. A real P.I.T.A.

Here is a trick you might like to try.

Let's make a silly little function:

	int foo1(int x, int y) {
	    int z = 3 + x;
	    z -= y;

	    return z + y;
	}

gcc -O2 on x86 compiles that to:

foo1:
        lea     eax, [rdi+3]
        ret

effectively:

	int foo1_optimised(int x, int y) {
	    return x + 3;
	}



That's not good for tracing or debugging the value of "z" !

But if we use this macro:

    #define establish(v) asm volatile ("" : "+g" (v))

so the function is:

    int foo2(int x, int y) {
        int z = 3 + x;
        establish(z);
        z -= y;
        establish(z);

        return z + y;
    }

Then the generated assembly is:

foo2:
        add     edi, 3
        sub     edi, esi
        lea     eax, [rsi+rdi]
        ret


The "establish" macro tells gcc that it needs to evaluate the variable
fully at that point in the code, then it must forget everything it knows
about for optimisation purposes.

An alternative formulation for the macro would be:

	#define establish(v) asm volatile ("" :: "g" (v))

This tells gcc that it needs to evaluate the variable here, but it can
remember its origins for optimisation purposes.  This leads to more
optimised code - letting the compiler generate code that matches:

	int foo2_optimised(int x, int y) {
	    int z = x + 3;
	    int t = z;
	    z -= y;
	    return t;
	}

All this without ever having to generate stack frames and put volatile
data into memory.

(I love this kind of portable inline assembly!)


> 
> 
>> I wonder if anyone has any thoughts about specific -fno-* settings I
>> can add alongside -Og which will preserve either all, or most, or even
>> just more, of the local variables rather than optimizing them away.
> 
> That would be nice (I'd need it with -O1) but I wouldn't hold my breath.
> It's likely way too deep in the many optimization passes to specifically
> turn it off for this use-case.
> 
> But I'd be pleasantly surprised to be informed otherwise.
> 




[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux