Почему для малых целых чисел в MSP430-GCC предпочтительнее int, чем unsigned char

В руководстве msgpcc (GCC для микроконтроллеров MSP430) авторы писали:

Используйте int вместо char или unsigned char, если вы хотите небольшое целое число внутри функции. Созданный код будет более эффективным, и в большинстве случаев хранение фактически не теряется.

Зачем int эффективнее?

UPD. И почему (u)int_fast8_t в mspgcc, определенном для (unsigned) char не (unsigned) int, Насколько я понимаю, (u)int_fast*_t должен быть определен для наиболее эффективного типа с достаточным размером.

4 ответа

Решение

В общем, это не обязательно относится к этому процессору, оно связано с расширением и маскированием знака, что требует дополнительных инструкций для точной реализации исходного кода на языке C. 8-битное значение со знаком в 16-, 32- или 64-битном процессоре МОЖЕТ включать дополнительные инструкции для расширения знака. 8-битное добавление на 32-битном процессоре может потребовать дополнительных инструкций для и с 0xFF и т. Д.

Вы должны провести несколько простых экспериментов, это заняло несколько итераций, но я быстро нашел что-то, что показало разницу.

unsigned int fun ( unsigned int a, unsigned int b )
{
    return(a+b)<<3;
}

unsigned char bfun ( unsigned char a, unsigned char b )
{
    return(a+b)<<3;
}


 int sfun (  int a,  int b )
{
    return(a+b)<<3;
}

 char sbfun (  char a,  char b )
{
    return(a+b)<<3;
}

производит

00000000 <fun>:
   0:   0f 5e           add r14,    r15 
   2:   0f 5f           rla r15     
   4:   0f 5f           rla r15     
   6:   0f 5f           rla r15     
   8:   30 41           ret         

0000000a <bfun>:
   a:   4f 5e           add.b   r14,    r15 
   c:   4f 5f           rla.b   r15     
   e:   4f 5f           rla.b   r15     
  10:   4f 5f           rla.b   r15     
  12:   30 41           ret         

00000014 <sfun>:
  14:   0f 5e           add r14,    r15 
  16:   0f 5f           rla r15     
  18:   0f 5f           rla r15     
  1a:   0f 5f           rla r15     
  1c:   30 41           ret         

0000001e <sbfun>:
  1e:   8f 11           sxt r15     
  20:   8e 11           sxt r14     
  22:   0f 5e           add r14,    r15 
  24:   0f 5f           rla r15     
  26:   0f 5f           rla r15     
  28:   0f 5f           rla r15     
  2a:   4f 4f           mov.b   r15,    r15 
  2c:   30 41           ret         

Msp430 имеет версии инструкций в виде слова и байта, так что простое сложение или вычитание не должно делать отсечение или расширение знака, которое вы ожидаете при использовании переменных размером меньше регистра. Как программист, мы могли бы знать, что собирались кормить sbfun только очень маленькими числами, но компилятор не должен и должен добросовестно реализовывать наш код в письменном виде, генерируя больше кода между sfun и sbfun. Нетрудно провести эти эксперименты с различными компиляторами и процессорами, чтобы увидеть это в действии, единственная уловка - создать код, который процессор не имеет простых инструкций для решения.

другой пример

unsigned int fun ( unsigned int a, unsigned int b )
{
    return(a+b)>>1;
}

unsigned char bfun ( unsigned char a, unsigned char b )
{
    return(a+b)>>1;
}

производит

00000000 <fun>:
   0:   0f 5e           add r14,    r15 
   2:   12 c3           clrc            
   4:   0f 10           rrc r15     
   6:   30 41           ret         

00000008 <bfun>:
   8:   4f 4f           mov.b   r15,    r15 
   a:   4e 4e           mov.b   r14,    r14 
   c:   0f 5e           add r14,    r15 
   e:   0f 11           rra r15     
  10:   4f 4f           mov.b   r15,    r15 
  12:   30 41           ret         

Общее практическое правило заключается в том, что процессоры быстрее всего работают с целыми числами их собственного размера слова.

Это, конечно, полностью зависит от архитектуры, см. Ответы на этот похожий вопрос для получения дополнительной информации по этому вопросу.

TI опубликовала примечание по применению для этой темы для своих микроконтроллеров Tiva-C (формально Stellaris).

В разделе "Введение" в таблице представлен список факторов, влияющих на производительность и размер. Метка фактора Размер переменной гласит, что "использование переменных меньше оптимальных может означать дополнительные инструкции для подписи или беззнакового расширения...".

Также в разделе "Размер переменных" указано:

"Когда локальные переменные меньше размера регистра, то обычно требуется дополнительный код. На части Stellaris это означает, что локальные переменные размера байта и полуслова (char и short int соответственно) требуют дополнительного кода. Так как код перенесен из В 8-битном или 16-битном микроконтроллере могут быть преобразованы локальные объекты в меньшие размеры (чтобы избежать слишком большой проблемы), это означает, что такой код будет работать медленнее и занимать больше места для кода, чем необходимо ".

Пожалуйста, смотрите: http://www.ti.com/lit/an/spma014/spma014.pdf

Следующее обрабатывается компилятором, но все еще актуально для рассматриваемой проблемы:

MSP430 - это 16-битный микропроцессор. Символ только 8-битный и требует упаковки, чтобы все слова были выровнены. Например, 3 символа не будут правильно выровнены в памяти. Вместо этого используйте целое число, которое является 16-разрядным и всегда будет выровнено.

Когда вы используете переменные размеры, кратные 16 (например, 16 и 32), вы также можете использовать память более эффективно. Вы не закончите с отступами, чтобы выровнять память.

int соответствует собственному размеру рассматриваемого процессора (16 бит), поэтому при запросе магазина unsigned char переменной, компилятору, возможно, придется выдавать дополнительный код, чтобы гарантировать, что значение находится между 0 и 255.

Другие вопросы по тегам