Hello /prog/riders.
I've stumbled upon a problem when I tried to OPTIMIZE a topologic sort function for a geometry package. Here's the gist of it: extern "C"
{
#include <stdint.h>
}
enum {LEFT = 1u, RIGHT = 2u, BOTH = 3u};
int main()
{
bool side = true;
const bool side_const = true;
uint_fast8_t n;
const uint_fast8_t a = side ? LEFT : RIGHT,
b = LEFT;
const uint_fast8_t A = side_const ? LEFT : RIGHT,
B = LEFT;
uint_fast8_t c = side ? LEFT : RIGHT,
d = LEFT;
uint_fast8_t C = side_const ? LEFT : RIGHT,
D = LEFT;
n |= a; // warning: conversion to ‘uint_fast8_t’ from ‘int’ may alter its value
n |= b;
n |= A;
n |= B;
n |= c; // warning: conversion to ‘uint_fast8_t’ from ‘int’ may alter its value
n |= d; // warning: conversion to ‘uint_fast8_t’ from ‘int’ may alter its value
n |= C; // warning: conversion to ‘uint_fast8_t’ from ‘int’ may alter its value
n |= D; // warning: conversion to ‘uint_fast8_t’ from ‘int’ may alter its value
}
As you can see the compiler evaluated the expressions for b,A and B and didn't complain about type conversion. Why then, does it need to convert my fast uints to slow ints in the case of a,c,d,C and D?
I compiled with $ gcc -std=c++98 -Wconversion bittwiddling.cpp.
My compiler version is $ gcc -V
gcc (GCC) 4.3.2 20081105 (Red Hat 4.3.2-7)
Name:
Anonymous2009-04-08 16:28
Because the enum isn't unsigned to begin with and the compiler only optimizes where it safely can.
Name:
Anonymous2009-04-08 16:51
>>2
Thanks for the tip. I've modified the code to pure C: #include <stdint.h>
const uint_fast8_t LEFT = 1u, RIGHT = 2u, BOTH = 3u;
int main()
{
uint_fast8_t side = 0;
const uint_fast8_t side_const = 1;
uint_fast8_t n;
// warning: conversion to ‘uint_fast8_t’ from ‘int’ may alter its value
const uint_fast8_t a = ((side == 0) ? LEFT : RIGHT), // Here
b = LEFT;
const uint_fast8_t A = ((side_const == 0) ? LEFT : RIGHT), // Here
B = LEFT;
uint_fast8_t c = (0 ? LEFT : RIGHT),
d = LEFT;
uint_fast8_t C = (1 ? LEFT : RIGHT),
D = LEFT;
if(side == 0)
c = LEFT;
else
c = RIGHT;
n |= a;
n |= b;
n |= A;
n |= B;
n |= c;
n |= d;
n |= C;
n &= D;
}
The warnings on bitwise operations are gone but now they've moved to the ternary operator. Changing constness on any of the variables doesn't seem to matter. This is weird.
Integer promotion -- the 8-bit quantities are being widened to int in the expressions. Try adding explicit casts.
Name:
Anonymous2009-04-08 18:39
>>11
That works but I'm at a loss. Why does the compiler feel the need to promote an integer that isn't being modified? There should be no difference between if(side == 0)
c = LEFT;
else
c = RIGHT;
and c = (side == 0) ? LEFT : RIGHT
shouldn't it?
>>15
I must be doing something wrong, then.
I'll need to check if packing the masks into the fast integer type is worthwhile. If the fast type is going to get promoted to a higher rank int on every bitwise op then I might as well use that rank in the first place. >>17
I know. I was fighting caffeine deprivation at the time.
>>12
the ternany operator is an expression and if-then-else is a statement
Name:
Anonymous2009-04-29 9:50
>>23
Good idea! >>26 OP, this is vitally important
I don't think it is. >>31
Go suck on a garden hose. >>33
Oh. I see. Makes sense.
Name:
342009-04-29 11:37
It seems that this line: const uint_fast8_t a = ((side == 0) ? LEFT : RIGHT);
will be compiled to this (-O0): ; line 11
cmpb $0, -10(%ebp) ; (side == 0) ? ...
jne .L2
movzbl LEFT, %eax
movb %al, -22(%ebp) ; ??? = LEFT
jmp .L3
.L2:
movzbl RIGHT, %eax
movb %al, -22(%ebp) ; ??? = RIGHT
.L3:
movzbl -22(%ebp), %eax
movb %al, -7(%ebp) ; a = ???
; line 12
but an if statement like this: if(side == 0)
c = LEFT;
else
c = RIGHT;
results in ; line 14-17
cmpb $0, -10(%ebp) ; if(side == 0)
jne .L6
movzbl LEFT, %eax
movb %al, -5(%ebp) ; c = LEFT
jmp .L7
.L6:
movzbl RIGHT, %eax
movb %al, -5(%ebp) ; c = RIGHT
.L7:
; line 18
How should I write my code to check if gcc will be able to optimize this? Would declaring a, c and side as volatile suffice?
Because I can't make heads or tails out of this code (-O2; a,b,side are declared volatile): movb $0, -5(%ebp) ; side
movb $0, -6(%ebp) ; a
movb $0, -7(%ebp) ; c
movzbl -5(%ebp), %eax
cmpb $1, %al
sbbl %eax, %eax
addl $2, %eax
movb %al, -6(%ebp)
movzbl -5(%ebp), %eax
testb %al, %al
je .L8
movb $2, -7(%ebp)
addl $16, %esp
xorl %eax, %eax
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.p2align 4,,7
.p2align 3
.L8:
movb $1, -7(%ebp)
addl $16, %esp