Мой компилятор MIPS сумасшедший или я без ума от выбора MIPS? - PullRequest
6 голосов
/ 06 октября 2011

Я использую процессор MIPS (PIC32) во встроенном проекте, но я начинаю сомневаться в своем выборе.Я понимаю, что процессор RISC, такой как MIPS, будет генерировать больше команд, чем можно было бы ожидать, но я не думал, что так будет.Вот фрагмент из списка разборки:

225:                         LATDSET = 0x0040;
    sw          s1,24808(s2)
    sw          s4,24808(s2)
    sw          s4,24808(s2)
    sw          s1,24808(s2)
    sw          s4,24808(s3)
    sw          s4,24808(s3)
    sw          s1,24808(s3)

226:                         {

227:                             porte = PORTE;
    lw          t1,24848(s4)
    andi        v0,t1,0xffff
    lw          v1,24848(s6)
    andi        ra,v1,0xffff
    lw          v1,24848(s6)
    andi        ra,v1,0xffff
    lw          v0,24848(s6)
    andi        t2,v0,0xffff
    lw          a2,24848(s5)
    andi        v1,a2,0xffff
    lw          t2,24848(s5)
    andi        v1,t2,0xffff
    lw          v0,24848(s5)
    andi        t2,v0,0xffff

228:                             if (porte & 0x0004)
    andi        t2,v0,0x4
    andi        s8,ra,0x4
    andi        s8,ra,0x4
    andi        ra,t2,0x4
    andi        a1,v1,0x4
    andi        a2,v1,0x4
    andi        a2,t2,0x4

229:                                 pst_bytes_somi[0] |= sliding_bit;
    or          t3,t4,s0
    xori        a3,t2,0x0
    movz        t3,s0,a3
    addu        s0,t3,zero
    or          t3,t4,s1
    xori        a3,s8,0x0
    movz        t3,s1,a3
    addu        s1,t3,zero
    or          t3,t4,s1
    xori        a3,s8,0x0
    movz        t3,s1,a3
    addu        s1,t3,zero
    or          v1,t4,s0
    xori        a3,ra,0x0
    movz        v1,s0,a3
    addu        s0,v1,zero
    or          a0,t4,s2
    xori        a3,a1,0x0
    movz        a0,s2,a3
    addu        s2,a0,zero
    or          t3,t4,s2
    xori        a3,a2,0x0
    movz        t3,s2,a3
    addu        s2,t3,zero
    or          v1,t4,s0
    xori        a3,a2,0x0
    movz        v1,s0,a3

Это похоже на безумное количество инструкций для простого чтения / записи и тестирования переменных по фиксированным адресам.На другом процессоре я, вероятно, мог бы довести каждую инструкцию C до примерно 1,3 инструкции, не прибегая к рукописному asm.Очевидно, что тактовая частота довольно высока, но она не в 10 раз выше, чем у другого процессора (например, dsPIC).

У меня настроена оптимизация на максимум.Мой компилятор C ужасен (это gcc 3.4.4)?Или это типично для MIPS?

Ответы [ 6 ]

6 голосов
/ 06 октября 2011

Наконец-то разобрался с ответом.Список разборки вводит в заблуждение.Компилятор выполняет развертывание цикла, и то, что мы видим под каждым оператором C, на самом деле в 8 раз больше команд, потому что оно развертывает цикл в 8 раз.Инструкции не по последовательным адресам!Отключение разворачивания цикла в опциях компилятора приводит к следующему:

225:                         LATDSET = 0x0040;
    sw          s3,24808(s2)
226:                         {
227:                             porte = PORTE;
    lw          t1,24848(s5)
    andi        v0,t1,0xffff
228:                             if (porte & 0x0004)
    andi        t2,v0,0x4
229:                                 pst_bytes_somi[0] |= sliding_bit;
    or          t3,t4,s0
    xori        a3,t2,0x0
    movz        t3,s0,a3
    addu        s0,t3,zero
230:                 

Паника по всем.

3 голосов
/ 06 октября 2011

Я думаю, что ваш компилятор ведет себя неправильно ... Проверьте, например, это утверждение:

228:                             if (porte & 0x0004)
    andi        t2,v0,0x4  (1)
    andi        s8,ra,0x4  (2)
    andi        s8,ra,0x4  (3)
    andi        ra,t2,0x4  (4)
    andi        a1,v1,0x4  (5)
    andi        a2,v1,0x4  (6)
    andi        a2,t2,0x4  (7)

Очевидно, что существуют инструкции, которые в основном ничего не делают.Инструкция (3) не делает ничего нового, так как сохраняет в s8 тот же результат, который вычисляется инструкцией (2).Инструкция (6) также не имеет никакого эффекта, так как она переопределяется следующей инструкцией (7), я полагаю, что любой компилятор, который выполняет некоторую фазу статического анализа, по крайней мере удалит инструкции (3) и (6).

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

Я думаю, что ваш компилятор не справляется с оптимизацией скомпилированного кода.

2 голосов
/ 06 октября 2011

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

Чтобы ответить на вопрос, я бы сказал, что вы с ума сошли, выбрав MIPS или, что еще важнее, выбрав его, не узнав сначала немного о ISA MIPS и о том, почему он так плох и насколько вам неэффективно.мириться с тем, если вы хотите его использовать.Я бы выбрал ARM для встраиваемых систем с низким энергопотреблением в большинстве ситуаций, или еще лучше Intel Atom, если вы можете позволить себе немного больше энергопотребления.

Редактировать: На самом деле, вторая причинаВы можете быть сумасшедшим ... Судя по комментариям, вы используете 16-битные целые числа.Никогда не следует использовать типы C, меньшие чем * int, за исключением массивов или структур, которые будут распределяться большими числами (либо в массиве, либо каким-либо другим способом, например, связанным списком / деревом / и т. Д.).Использование малых типов никогда не даст никакой выгоды, кроме экономии места (что не имеет значения, пока у вас не будет большого числа значений такого типа) и почти наверняка менее эффективно, чем использование «обычных» типов.В случае с MIPS разница огромна.Переключитесь на int и посмотрите, исчезнет ли ваша проблема.

0 голосов
/ 06 октября 2011

Я попытался скомпилировать следующий код с CodeSourcery MIPS GCC 4.4-303 с -O4.Я попробовал это с uint32_t и uint16_t:

#include <stdint.h>
void foo(uint32_t PORTE, uint32_t pst_bytes_somi[], uint32_t sliding_bit) {
    uint32_t LATDSET = 0x0040;
    {
        uint32_t porte = PORTE;
        if (porte & 0x0004)
            pst_bytes_somi[0] |= sliding_bit;
        if (porte & LATDSET)
            pst_bytes_somi[1] |= sliding_bit;
    }
}

Вот разборка с целыми числами uint32_t:

        uint32_t porte = PORTE;
        if (porte & 0x0004)
   0:   30820004    andi    v0,a0,0x4
   4:   10400004    beqz    v0,18 <foo+0x18>
   8:   00000000    nop
./foo32.c:7
            pst_bytes_somi[0] |= sliding_bit;
   c:   8ca20000    lw  v0,0(a1)
  10:   00461025    or  v0,v0,a2
  14:   aca20000    sw  v0,0(a1)
./foo32.c:8
        if (porte & LATDSET)
  18:   30840040    andi    a0,a0,0x40
  1c:   10800004    beqz    a0,30 <foo+0x30>
  20:   00000000    nop
./foo32.c:9
            pst_bytes_somi[1] |= sliding_bit;
  24:   8ca20004    lw  v0,4(a1)
  28:   00463025    or  a2,v0,a2
  2c:   aca60004    sw  a2,4(a1)
  30:   03e00008    jr  ra
  34:   00000000    nop

Вот разборка с целыми числами uint16_t:

        if (porte & 0x0004)
   4:   30820004    andi    v0,a0,0x4
   8:   10400004    beqz    v0,1c <foo+0x1c>
   c:   30c6ffff    andi    a2,a2,0xffff
./foo16.c:7
            pst_bytes_somi[0] |= sliding_bit;
  10:   94a20000    lhu v0,0(a1)
  14:   00c21025    or  v0,a2,v0
  18:   a4a20000    sh  v0,0(a1)
./foo16.c:8
        if (porte & LATDSET)
  1c:   30840040    andi    a0,a0,0x40
  20:   10800004    beqz    a0,34 <foo+0x34>
  24:   00000000    nop
./foo16.c:9
            pst_bytes_somi[1] |= sliding_bit;
  28:   94a20002    lhu v0,2(a1)
  2c:   00c23025    or  a2,a2,v0
  30:   a4a60002    sh  a2,2(a1)
  34:   03e00008    jr  ra
  38:   00000000    nop

Как вы можете видеть, каждый оператор C отображается в две-три инструкции.Использование 16-битных целых чисел делает функцию только на одну инструкцию длиннее.

0 голосов
/ 06 октября 2011

Единственное, о чем я могу думать, это, возможно, , возможно, , компилятор может вводить дополнительные бессмысленные инструкции для согласования скорости ЦП с гораздо более низкой скоростью шины данных. Даже этого объяснения недостаточно, поскольку инструкции сохранения / загрузки также имеют избыточность.

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

Где вы взяли компилятор? Я обнаружил, что некоторые из «легких» источников часто содержат довольно ужасные инструменты. Мои друзья-разработчики встраиваемых систем обычно собирают свои собственные цепочки инструментов, иногда получая намного лучших результатов.

0 голосов
/ 06 октября 2011

Вы включили оптимизацию компилятора? В неоптимизированном коде много избыточности.

...