Can compilers optimize double boolean negation in conditional expressions?

Consider the following hypothetical type:

typedef struct Stack { unsigned long len; void **elements; } Stack; 

And the following hypothetical macros for working with a type (purely to increase readability). In these macros, I assume that this argument is of type (Stack *), and not just Stack (I cannot worry about typing a _ Generic expression here.)

 #define stackNull(stack) (!stack->len) #define stackHasItems(stack) (stack->len) 

Why am I not just using !stackNull(x) to check for elements on the stack? I thought it would be a little less efficient (read: not at all noticeable at all, but I thought it was interesting) than just checking stack->len , because that would lead to double negation. In the following case:

 int thingy = !!31337; printf("%d\n", thingy); if (thingy) doSomethingImportant(thingy); 

The string "1 \ n" would be printed, and it would be impossible to optimize the conditional (well, in fact, only impossible if the thingy variable did not have a constant initializer or was changed before the test, In this case, we say that 31337 is not a constant), because (!!x) guaranteed to be either 0 or 1 .

But I wonder if the compilers will optimize something like the following

 int thingy = wellOkaySoImNotAConstantThingyAnyMore(); if (!!thingy) doSomethingFarLessImportant(); 

Will it be optimized for actual use (thingy) in the if statement, as if the if were written as

 if (thingy) doSomethingFarLessImportant(); 

If so, will it expand to (!!!!!thingy) and so on? (however, this is a slightly different question, since it can be optimized in any case !thingy is !!!!!thingy regardless of, for example, -(-(-(1))) = -1.)

In the title of the question, I said โ€œcompilersโ€, which I mean that I ask if this compiler does any , however I am particularly interested in how GCC will behave in this case, since it is my choice compiler.

+6
source share
1 answer

This seems like a pretty reasonable optimization and a quick test using godbolt with this code ( watch it live ):

 #include <stdio.h> void func( int x) { if( !!x ) { printf( "first\n" ) ; } if( !!!x ) { printf( "second\n" ) ; } } int main() { int x = 0 ; scanf( "%d", &x ) ; func( x ) ; } 

seems to indicate that gcc good, it generates the following:

 func: testl %edi, %edi # x jne .L4 #, movl $.LC1, %edi #, jmp puts # .L4: movl $.LC0, %edi #, jmp puts # 

we can see from the first line:

 testl %edi, %edi # x 

he just uses x , without doing any operations on it, also notices that the optimizer is smart enough to combine both tests into one, because if the first condition is true , the other must be false .

Note. I used printf and scanf for side effects so that the optimizer could not optimize all the code.

+7
source

Source: https://habr.com/ru/post/979353/


All Articles