Reputation: 13
I make some assembly test code which just compare with character, gcc makes jle / jg combination always whether condition contains equal or not.
example 1.
if ( 'A' < test && test < 'Z' )
0x000000000040054d <+32>: cmp BYTE PTR [rbp-0x1],0x41
0x0000000000400551 <+36>: jle 0x40056a <main+61>
0x0000000000400553 <+38>: cmp BYTE PTR [rbp-0x1],0x59
0x0000000000400557 <+42>: jg 0x40056a <main+61>
example 2.
if ( 'A' <= test && test <= 'Z' )
0x000000000040054d <+32>: cmp BYTE PTR [rbp-0x1],0x40
0x0000000000400551 <+36>: jle 0x40056a <main+61>
0x0000000000400553 <+38>: cmp BYTE PTR [rbp-0x1],0x5a
0x0000000000400557 <+42>: jg 0x40056a <main+61>
I thought it's problem about optimization, but GCC gave same result even if I compile with -O0 option.
How can I get JL/JG through 'A'< sth<'Z' and JLE/JGE through 'A'<=sth<='Z'?
Upvotes: 1
Views: 479
Reputation: 20120
One can see that first comparison is against [x41...x59] range. Second comparison is against [x40...x5a] range. Basically, compiler makes it into
if ( 'A'-1 < test && test < 'Z'+1 )
and then generates the same code
UPDATE
Just to make clear why I think compiler prefers JL vs JLE. JLE depends on flag values being updated (ZF=1) but JL doesn't. Therefore, JLE will introduce dependencies which potentially could hurt instruction level parallelism, even if instruction timing itself is the same
So, clear choice - transform code to use simpler instructions.
Upvotes: 2
Reputation: 58782
In general, you can't force the compiler to emit a particular instruction. In this case, you might succeed if you get rid of the constant so the compiler won't be able to adjust it. Note that due to the nature of your expression, the compiler will probably still reverse one of the tests, and thus bring in an equals. You might be able to work around that by using goto
. Obviously, both of these changes will generate worse code.
Upvotes: 1