Jump to content

    
Sign in to follow this  
Pavel V.

GCC Warning: left shift count >= width of type

Recommended Posts

Компилирую следующий код:

 

template<uint32_t pin>
class Pin
{
public:
    void Test()
    {
        if(pin < 16) {
1:            g_test &= ~(0x03UL << (pin * 2));
        }
        else
        {
            g_test &= ~(0x03UL << ((pin - 16) * 2));
        }
    }
};

int main()
{
    Pin<22> test;
    test.Test();
}

 

На строчку 1 компилятор ругается:

 

source/main.cpp: In member function 'void Pin<pin>::Test() [with long unsigned int pin = 22ul]':
source/main.cpp:30:12:   instantiated from here
source/main.cpp:18:4: warning: left shift count >= width of type [enabled by default]

 

Код компилируется и работает правильно. Оптимизатор, естественно, выкидывает ненужный код, т.к. pin константа (что видно по листингу).

Как убрать это сообщение?

Share this post


Link to post
Share on other sites

Для этого можно использовать частичную специализацию шаблонов. Завести дополнительную шаблонный класс, вычисляющий нужную маску и сделать для него две специализации, для pin < 16 и для pin >= 16.

template<uint32_t pin>
class Pin
{
// warning: brain-compiled code ahead
   template<bool pinLessThen16>
   struct Mask
   { 
      enum {value =  ~(0x03UL << (pin * 2)) }; 
   };

   template<>
   struct Mask<false>
   { 
      enum {value =  ~(0x03UL << ((pin - 16) * 2)) }; 
   };

public:
    void Test()
    {
      g_test &= Mask<(pin < 16)>::value;
    }
};

Share this post


Link to post
Share on other sites
Для этого можно использовать частичную специализацию шаблонов. Завести дополнительную шаблонный класс, вычисляющий нужную маску и сделать для него две специализации, для pin < 16 и для pin >= 16.

Спасибо за идею! В итоге так и сделал, только использовал анонимный параметр, что избавило от необходимости в вызове писать условие pin < 16.

Специализацию шаблона нельзя выполнять внутри класса, поэтому вынес наружу.

 

namespace IO
{
    template<uint32_t pin, bool = (pin < 16)>
    struct ConfigurationMask
    {
        static inline uint32_t Clear() { return ~(0x03UL << (pin * 2)); }
        static inline uint32_t SelSet(Configuration configuration) { return (((uint32_t)configuration >> 4) & 0x03UL) << (pin * 2); }
        static inline uint32_t ModeSet(Configuration configuration) { return (((uint32_t)configuration >> 2) & 0x03UL) << (pin * 2); }
    };

    template<uint32_t pin>
    struct ConfigurationMask<pin, false>
    {
        static inline uint32_t Clear() { return ~(0x03UL << ((pin - 16) * 2)); }
        static inline uint32_t SelSet(Configuration configuration) { return (((uint32_t)configuration >> 4) & 0x03UL) << ((pin - 16) * 2); }
        static inline uint32_t ModeSet(Configuration configuration) { return (((uint32_t)configuration >> 2) & 0x03UL) << ((pin - 16) * 2); }
    };

    template<Port port, uint32_t pin, ActiveState activestate>
    class Pin
    {
        static_assert((pin < 32), "Pin number must be <= 31");

    public:
        /*
         * Set Configuration
         */
        static void SetConfiguration(Configuration configuration)
        {
            ...
            SEL0 &= ConfigurationMask<pin>::Clear();
            SEL0 |= ConfigurationMask<pin>::SelSet(configuration);
            MODE0 &= ConfigurationMask<pin>::Clear();
            MODE0 |= ConfigurationMask<pin>::ModeSet(configuration);
            ...
        }
    };
}

Share this post


Link to post
Share on other sites
            SEL0 &= ConfigurationMask<pin>::Clear();
            SEL0 |= ConfigurationMask<pin>::SelSet(configuration);
            MODE0 &= ConfigurationMask<pin>::Clear();
            MODE0 |= ConfigurationMask<pin>::ModeSet(configuration);

LPC17 ?

Тоже наткнулся на такую заразу со сдвигами («больше ширины» либо «сдвиг на отрицательное значение» в зависимости от константы и ветки if (shift < 32)).

        if (shift < 32) {
            LPC_SC->PCLKSEL0 = (LPC_SC->PCLKSEL0 & ~(0x03 << shift))
                             | (CLKPWR_PCLKSEL_CCLK_DIV_1 << shift);
        } else {
            LPC_SC->PCLKSEL1 = (LPC_SC->PCLKSEL1 & ~(0x03 << (shift-32)))
                             | (CLKPWR_PCLKSEL_CCLK_DIV_1 << (shift-32));
        }

Сначала по-быстрячку сделал shift локальной переменной функции. Оптимизатор всё делает нормально, а предупреждение пропадает. Потом нарисовал такое (в рабочий код ещё не интегрировал, в тесте с ключиком -S всё красиво):

#include <stdint.h>

template<unsigned width, unsigned position, unsigned reg_bits = 32>
struct field_traits
{
enum {
	reg_index = position / reg_bits,
	shift = position % reg_bits,
	unshifted_mask = (1UL << width) - 1,
	mask = unshifted_mask << shift
};
static unsigned value(unsigned val) { return (val & unshifted_mask) << shift; }
static unsigned place(unsigned reg) { return reg & ~mask; }
static unsigned insert(unsigned reg, unsigned val) { return place(reg) | value(val); }
};

struct params {
volatile uint32_t reg0, reg1;
};

params p;

template<unsigned pin>
struct tst
{
typedef field_traits<2, 2*pin> traits;
static void Setup(unsigned v)
{
#if 1
	traits::reg_index == 0 ? p.reg0 = traits::insert(p.reg0,v)
	                       : p.reg1 = traits::insert(p.reg1,v);
#else
	// Имея уверенность (или при соответствующем описании целевой структуры)
	// можно и так:
	volatile uint32_t *preg = &p.reg0 + traits::reg_index;
	*preg = traits::insert(*preg,v);
#endif
}
};


typedef tst<1> tst1;
typedef tst<15> tst15;
typedef tst<16> tst16;
typedef tst<18> tst18;
typedef tst<31> tst31;

void foo1()  { tst1::Setup(0); }
void foo15() { tst15::Setup(1); }
void foo16() { tst16::Setup(2); }
void foo18() { tst18::Setup(2); tst18::Setup(1);}
void foo31() { tst31::Setup(3); }

Share this post


Link to post
Share on other sites
LPC17 ?

Тоже наткнулся на такую заразу со сдвигами («больше ширины» либо «сдвиг на отрицательное значение» в зависимости от константы и ветки if (shift < 32)).

Он самый! :)

 

Сначала по-быстрячку сделал shift локальной переменной функции. Оптимизатор всё делает нормально, а предупреждение пропадает. Потом нарисовал такое (в рабочий код ещё не интегрировал, в тесте с ключиком -S всё красиво):

Здорово, такой вариант мне больше нравится :) Попробую использовать.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this