2013-11-25 6 views
8

В msgpcc (GCC для микроконтроллеров MSP430) manual авторы писали:Почему ИНТ предпочитали вместо (без знака) полукокса для малых чисел в MSP430-GCC

Используйте Int вместо CHAR или неподписанные символ, если вы хотите небольшое целое внутри функции. Полученный код будет более эффективным, и в большинстве случаев хранение фактически не будет потрачено впустую.

Почему int более эффективен?

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

+1

AFAIK MSP430 не имеет никакого значения задержки в инструкции между 8-битовые и 16-битовые операнды. Мне тоже любопытно. –

+1

Я хотел бы добавить, что замечательная вещь, которую я люблю о '(u) int_ (fast | minimum) (8 | 16 | 32) _t', заключается в том, что вы можете указать, какую оптимизацию вы хотите, и, как правило, разрешить обработчик компилятора Это. Если вы хотите использовать как можно меньше места и вам нужно представить до 20 000, используйте '(u) int_least16_t', но если вы используете что-то для тяжелых вычислений, которое вы хотите быстро, вы можете использовать' (u) int_fast16_t' в значительной степени без необходимости беспокоиться о том, какой тип он использует, используя под капотом. – rjp

ответ

3

В целом, не обязательно конкретный для этого процессора, он имеет отношение к расширению знака и маскировке, требуя дополнительных инструкций для правильного внедрения исходного кода на 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   
+0

+1, хотя стоит отметить, что использование более крупных типов параметров может привести к увеличению использования стека, что Полагаю, это может быть проблемой, когда ресурсы ограничены. – Groo

+0

Да, это все игра производительности и оптимизации ... Хотелось посадить крошечные семена о том, почему меньше не обязательно лучше (относительный термин). –

5

Общее эмпирическое правило: Процессоры быстрее всего работают при использовании целых чисел своего родного слова.

Это, конечно, зависит от архитектуры, см. Ответы на this similar question для получения более подробных разъяснений по этому вопросу.

5

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

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

Кроме того, в разделе «Размер переменных», он говорит:.

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

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

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

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

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

+1

Задача компилятора состоит в том, чтобы обеспечить отсутствие проблем с выравниванием, и он не будет тратить больше места, чем вы, используя 16-битную переменную, в которой работала бы 8-разрядная. Вы существенно переместили отступ от неявного процесса к явному. –

+0

@CoryNelson Я согласен - это связано с компилятором, а не во время выполнения. Однако вы ошибаетесь в своем заявлении о том, что он не занимает больше памяти. Вы пытались скомпилировать как GCC, так и IAR? Они оба различаются по-разному, и вы получаете радикально другой размер кода, если не будете осторожны (без учета оптимизации). Кажется, это связано с заполнением. – bblincoe

1

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

+1

Я думаю, вы ошибаетесь. Компилятор не будет генерировать код для обхода от 255 до 0. MSP430 имеет байт-ориентированные инструкции, и компилятор просто будет использовать команду 'add.b' вместо' add'. –

+0

@Corvus Это правильно. MSP430 имеет 27 инструкций с большинством инструкций, доступных в версиях с расширением .B (8 бит) и .W (16 бит). – bblincoe

+0

ОК, хороший момент в этом случае, а не на других процессорах. С тех пор я был MSP430! Я уверен, что есть и другие случаи (а не просто простое приращение), где дополнительный И должен быть выпущен, хотя ... –