Search code examples
c++templatesbit-manipulationcompiler-optimizationbit-shift

C++ Bit Shift With Same Constant in Opposite Directions, Different Result With Minor Code Changes


I have a template function

template< uint8_t HOW_FAR_CONSTANT, uint8_t START_CONSTANT, uint8_t ORIGINAL_CONSTANT>
uint8_t Foo();

In Foo I do something like this

const uint8_t OFFSET_CONSTANT = ( START_CONSTANT + HOW_FAR_CONSTANT );
const uint8_t RESULT_CONSTANT = ( ( ORIGINAL_CONSTANT << OFFSET_CONSTANT ) >> OFFSET_CONSTANT );

And it does not truncate the bits, it results in:

ORIGINAL: 10101010
RESULT: 10101010

However, if I make a slight modification

const uint8_t OFFSET_CONSTANT = ( START_CONSTANT + HOW_FAR_CONSTANT );
const uint8_t RESULT_0_CONSTANT = ( ORIGINAL_CONSTANT << OFFSET_CONSTANT );
const uint8_t RESULT_CONSTANT = ( RESULT_0_CONSTANT >> OFFSET_CONSTANT );

I get

ORIGINAL: 10101010
RESULT 0 (lets say OFFSET_CONSTANT is 2): 10101000
RESULT: 00101010

I am wondering if this is a bad compiler optimization. Can anyone explain this?

UPDATE:

Tried this on compiler explorer, its definitely standard behavior and not a bad compiler optimization.


Solution

  • There is neither optimization. There is a truncation due to storing a result of a shift operation in an object of the type uint8_t.

    const uint8_t RESULT_0_CONSTANT = ( ORIGINAL_CONSTANT << OFFSET_CONSTANT );
    

    When the shift operation is performed the integral promotions are applied to operands.

    So in this expression

    const uint8_t RESULT_CONSTANT = ( ( ORIGINAL_CONSTANT << OFFSET_CONSTANT ) >> OFFSET_CONSTANT );
                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    

    the sub-expression ( ORIGINAL_CONSTANT << OFFSET_CONSTANT ) has the type int instead of uint8_t.

    From the C++ Standard (5.8 Shift operators)

    1. 1 The shift operators << and >> group left-to-right. The operands shall be of integral or unscoped enumeration type and integral promotions are performed.