Это ошибка оптимизации? - PullRequest
4 голосов
/ 23 января 2011

Вот некоторые результаты моего компилятора на ассемблере.Это компилятор MPLAB C30 C, основанный на GCC v3.23, для dsPIC33FJ128GP802, 16-битного умеренно высокоскоростного DSP / MCU.

212:               inline uint16_t ror_16(uint16_t word, int num)
213:               {
 078C4  608270     and.w w1,#16,w4
 078C6  DE0204     lsr w0,w4,w4
 078C8  780101     mov.w w1,w2
 078CA  EA8102     com.w w2,w2
 078CC  EA8183     com.w w3,w3
 078CE  610170     and.w w2,#16,w2
 078D0  DD0002     sl w0,w2,w0
 078D2  700004     ior.w w0,w4,w0
214:                num &= 16; // limit to 16 shifts
215:                return (word >> num) | (word << (16 - num));
216:               }
 078D4  060000     return

В частности меня интересует следующее:

and.w w1,#16,w4         AND W1 with 16, storing result in W4
lsr w0,w4,w4            Logical shift right W0 by W4 times storing result in W4
mov.w w1,w2             Move W1 to W2
com.w w2,w2             Logical complement of W2 stored in W2
com.w w3,w3             Logical complement of W3 stored in W3   <-- This line is confusing me
and.w w2,#16,w2         AND W2 with 16, storing result in W2
sl w0,w2,w0             (Logical) shift left W0 left by W2 times storing result in W0
ior.w w0,w4,w0          Inclusive OR of W0 and W4 stored in W0
return                  Return from function

W0..W15 - массив из шестнадцати 16-разрядных регистров на кристалле.

Фактически это упрощает до (в примитивном RTL):

W4 := W1 & 16
W4 := W0 LSR W4
W1 := W2
W2 := COM W2
W3 := COM W3
W2 := W2 & 16
W0 := W0 SL W2
W0 := W0 | W4
return

СейчасМеня смущает, почему он вычисляет дополнение к W3, когда передается только два переданных аргумента (W0 и W1 - он использует массив W для передачи аргументов в функции для функций с меньшими аргументами.) W3 никогда не используется в вычислениях,и никогда не возвращается.На самом деле, он даже не содержит данных: в нем ничего не хранится, и только вызываемый будет иметь некоторые данные (хотя функции не обязаны сохранять W0..W7, поэтому вызываемый не долженполагаться на это.) Почему это включено в код?Это просто ошибка компилятора или ошибка, или я что-то упустил?

И это не просто этот код - я вижу ту же странность в других частях кода.Даже код, предназначенный для вычисления таких вещей, как дополнения 16-битной переменной, всегда использует два регистра.Это меня потеряло!

1 Ответ

2 голосов
/ 23 января 2011

Функция не закодирована, чтобы ограничить счет до 16 (что я подозреваю, вы имеете в виду от 0 до 16), но ограничивает его до 0 или 16.

Вместо

num &= 16

Вы, возможно, хотите

num > 16 ? (num & 15) : num

Re: вопрос, поскольку функция встроенная, на нее можно ответить, только взглянув на то, где она используется. Возможно, W3 используется для чего-то в окружающем коде. Или это может быть «ошибка», но та, которая влияет только на производительность, но не корректность.

Если num может быть только 0 или 16 (как в вашем коде), то (16 - num) также может быть только 16 или 0, поэтому C30 может делать «вычитание» с дополнением и маской.

К вашему сведению, когда я не подключаюсь, в C30 я получаю:

34:                uint16_t ror_16(uint16_t word, int num)
35:                {
 05AF4  608170     and.w 0x0002,#16,0x0004
 05AF6  DE0102     lsr 0x0000,0x0004,0x0004
 05AF8  EA8081     com.w 0x0002,0x0002
 05AFA  6080F0     and.w 0x0002,#16,0x0002
 05AFC  DD0001     sl 0x0000,0x0002,0x0000
 05AFE  700002     ior.w 0x0000,0x0004,0x0000
36:                    num &= 16; // limit to 16 shifts
37:                    return (word >> num) | (word << (16 - num));
38:                }
 05B00  060000     return

Я мог бы закодировать это как

34:                uint16_t ror_16(uint16_t word, int num)
35:                {
 05AF4  780100     mov.w 0x0000,0x0004
36:                    num &= 15; // mod 16
 05AF6  60806F     and.w 0x0002,#15,0x0000
37:                    return (num == 0) ? word : ((word >> num) | (word << (16 - num)));
 05AF8  320004     bra z, 0x005b02
 05AFA  DE1080     lsr 0x0004,0x0000,0x0002
 05AFC  100070     subr.w 0x0000,#16,0x0000
 05AFE  DD1000     sl 0x0004,0x0000,0x0000
 05B00  708100     ior.w 0x0002,0x0000,0x0004
38:                }
 05B02  780002     mov.w 0x0004,0x0000
 05B04  060000     return
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...