2011-01-11 3 views
2

Я нашел Q & на один веб:встроенных программы

Q: Что лучше полукокс, короткий или ИНТ типа для оптимизации?

A: По возможности, лучше избегать с использованием символов char и short как местных переменных. Для типов char и короткий компилятор должен уменьшить размер локальной переменной до 4 или после каждого задания. Это , называемый расширением знака для подписанных переменных и нулевым расширением для переменных без знака. Она осуществляется путем сдвига регистра влево на 24 или 16 бит , сопровождаемый знаком или без знака сдвига вправо на том же количестве , принимая две инструкции (нуль-расширение без знака полукокса принимает одну инструкцию). Эти сдвиги можно избежать, используя int и unsigned int для локальных переменных. Это особенно важно для расчетов , которые сначала загружают данные в локальные переменные, а затем обрабатывают данные внутри локальных переменных. Даже если данные вводятся и выводятся как 8- или 16-разрядные количества, стоит , рассматривая их как 32-разрядные количества.

Это все верно? Я думал, что лучше избегать char и short из-за арифметического преобразования (скорее всего, они будут преобразованы в ints или longs, и это заставит компилятор генерировать дополнительные инструкции).

В: Как уменьшить накладные расходы на функциональные вызовы в системах на базе ARM?

A: Избегайте функций с параметром, который частично передается в регистре и частично в стеке (разделенный аргумент). Это не эффективно обрабатывается текущими компиляторами: все аргументы регистра помещаются в стек.

· Избегайте функций с переменным количеством параметров. Функции Varargs. ...

Что касается «varargs» - это потому, что аргументы передаются по стеку? Что такое функция с аргументами, частично переданными в регистрах, а частично через стек, вы могли бы привести пример?

Можем ли мы сказать, что передаваемые аргументы функции (или регистры или стек) сильно зависят от архитектуры?

Спасибо!

+5

Если вы зададите такие длинные цитаты в своем вопросе, не могли бы вы также обратиться к оригиналу, чтобы мы знали, откуда это взялось? –

+2

Передано до тех пор, пока не будут добавлены ссылки. –

+1

Он, по-видимому, исходит от: http://technology-shettyprasad.blogspot.com/2010/07/embedded-systems-questions-for.html –

ответ

1

Что касается «списков параметров» - это это потому что аргументы будут переданы через стек? Что такое функция с аргументами, частично переданными в регистрах , а частично через стек, , можете ли вы привести пример?

если у вас есть функция, как:

int my_func(int v1, int v2) 

Компилятор может использовать внутренний регистр процессора для передачи аргументов v1, v2 при вызове функции.

, если у вас есть:

int my_func(int v1, int v2, ...., int v10) 

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

Можем ли мы сказать, что функция пути аргументы передаются (либо регистры или стек) сильно зависит от архитектуры ?

Да, это также сильно зависит от компилятора.

1

Я бы не подумал, что уменьшение размера при назначении 8 или 16 бит будет иметь место при назначении большего значения. Например, если функция возвращает char, зачем ей вообще нужно изменять значение при назначении char? Может быть исключение, если бы были некоторые операции, которые можно было выполнить только с большими переменными, но в зависимости от компилятора и процессора я не уверен, что это часто возникает.

+0

На ARM регистры равны 32 бит, если при загрузке из памяти ldrb будет заполнять верхние биты регистра нулями, но если вы хотите, чтобы он был подписанным символом, вам потребуется дополнительная пара инструкций для подписи. И поскольку вы выполняете другие операции, подписанные или неподписанные, вам необходимо сохранить его до 8 бит. Если вам не было интересно перекатываться на 255 или + 127/-128, вы могли бы использовать его как int и значительно сократить количество инструкций. –

+0

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

+0

char myfun (int a) {return (a); } становится и r0, r0, # 0xFF, bx lr, где использование int было бы просто bx lr. –

2
  1. Да, согласно стандарту, почти все вычисления и сравнения выполняются со встроенными типами, которые имеют ширину не менее int. Поэтому использование меньших типов «только» экономит место и, с другой стороны, может иметь накладные расходы.
  2. Varargs должны использовать стек, поскольку соответствующие макросы, которые обрабатывают эти аргументы, обычно используют указатель, чтобы отслеживать фактическое положение обрабатываемого аргумента.
+0

varargs также вынуждают условную петлю вращаться до тех пор, пока не будет обнаружен последний arg, что имеет последствия для отказов в прогнозировании ветвлений. –

+0

Re 2: Это не настоящее требование, хотя это самый простой способ реализации. Varargs могут частично регистрироваться, частично стекировать. –

+0

@Bart: именно поэтому у меня был «обычно» там. –

7

Проще говоря: этот совет по оптимизации вводит в заблуждение. Не обязательно неправильно, но неполно.

Оказывается, ваш источник был CodeProject. Он утверждает, что в основном он говорит об оптимизации для ARM.

Во-первых, он сильно зависит от процессора, как обрабатываются символы и короткие. В зависимости от архитектуры конверсии могут быть нулевыми или минимальными затратами, в зависимости от того, когда и как они происходят - во время загрузки, типа операции, какие инструкции могут выполняться параллельно и по сути могут быть бесплатными, в зависимости от остальной части кода - например, на архитектуре C64 TI DSP, которая может запускать 8 операций за цикл. Обычно наиболее эффективным будет «собственный» целочисленный размер, но он также зависит от того, откуда поступают данные - может быть более эффективным загрузить, изменить и сохранить обратно char/short data, чем загружать и конвертировать в int, изменять и хранить обратно как char/short. Или это может быть не так - это зависит от архитектуры и выполняемых операций. Компилятор часто лучше разбирается в том, делать это для вас или нет.

Во-вторых, во многих архитектурах char и short так же быстро, как и int, особенно если вычисление позволяет избежать неявных преобразований в int. Примечание: это легко испортить в C, например, «x = y + 1», что приводит к преобразованию до int (если x & y являются символом или коротким), но хорошо, что почти все компиляторы достаточно умны, чтобы оптимизируйте конверсию для вас.Многие другие случаи наличия локального символа char/short заставят компилятор оптимизировать любые конверсии в зависимости от того, как они используются позже. Этому способствует тот факт, что в типичных процессорах переполнение/обертка символа char/short - это тот же результат, что и вычисление его как int и преобразование в хранилище (или просто обращение к этому регистру как char/short в более позднем операция - получение преобразования для «свободного»).

В своем примере:

int wordinc (int a) 
{ 
    return a + 1; 
} 
short shortinc (short a) 
{ 
    return a + 1; 
} 
char charinc (char a) 
{ 
    return a + 1; 
} 

Во многих архитектурах/компиляторов, это будет работать одинаково быстро на практике.

В-третьих, в некоторых архитектурах char/short есть быстрее, чем int. Примером может служить встроенная архитектура с натуральным размером 8 или 16 бит (по общему признанию, не тот вид развития, о котором вы думаете сейчас).

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

С другой стороны, ЕСЛИ компилятор недостаточно умен, чтобы скрыть его от вас, локальные символы char/shorts передаются как аргументы другим функциям (особенно не файло-локальные «статические» функции) may entail up-conversions to int. Опять же, в соответствии с выше, компилятор может быть достаточно умным, чтобы скрыть преобразование.

Я сделать согласен с этим утверждением в начале сайта вы цитируете:

Хотя ряд руководств доступны для оптимизации кода C, не является заменой имея полное знание о компилятор и машина, для которой вы программируете.

1

На некоторых процессорах неподписанный символ является самым быстрым типом. На некоторых он будет последовательно медленнее, чем int. В ARM символ без знака, который хранится в памяти, должен работать с той же скоростью, что и int, хранящийся в памяти, но неподписанный символ, хранящийся в регистре, часто должен быть «нормализован» до значения 0-255 за счет стоимости инструкция; беззнаковый короткий должен быть «нормализован» до 0-65535 за счет двух инструкций. Я бы ожидал, что хороший компилятор сможет устранить много ненужных нормализаций либо путем работы с 65536 раз значением интереса, либо путем наблюдения за тем, что верхние биты не будут иметь значения; Я не знаю, в какой степени фактические компиляторы делают одно из этих действий.

Кстати, стоит отметить, что, хотя стандарт C требует, чтобы добавление 1 к 16-разрядному беззнаковому целому, содержащее 65 535, должно давать нуль (не 65 536), аналогичного требования для целых чисел со знаком не существует. Компилятор был бы свободен рассматривать подписанный короткий или подписанный символ как int, когда он хранится в регистре, и как его тип подходящего размера при хранении в памяти. Таким образом, использование подписанных типов позволит избежать необходимости в дополнительных инструкциях по усечению стоимости.

1

Это зависит от цели и/или компилятора. Это также зависит от того, что вы хотите оптимизировать, использования памяти, пространства кода или времени выполнения.

Что касается вызовов функций ARM, ARM ABI определяет стандарт, который будет соответствовать большинству компиляторов ARM. Это довольно бесполезный ответ, так как вы обычно не выполняете или не называете вариационную функцию, если вы на самом деле не нуждаетесь в ней.

Вполне возможно, что компилятор обеспокоен эффективностью генерации кода; это ваша экспертная система для цели, и продолжайте плодотворную работу.Беспокоитесь об оптимизации только тогда, когда вы знаете, что это необходимо (т. Е. Когда показано, что в противном случае это слишком медленно или слишком велико).

Смежные вопросы