jcxz 241 27 апреля, 2021 Опубликовано 27 апреля, 2021 · Жалоба Дано: typedef __packed u64 u64p32; struct FocQ { union { struct { u32 amplitude; u32 angle; }; u64p32 ampl_angle; }; s32 reduI; } focQ; Присваивание (вариант 1): u32 j, j1; ... *(u64 *)&focQ.ampl_angle = j1 | (u64)j << 32; Результат компиляции (обрезал всё кроме самой записи): ... 0x65A0 STR R0,[R4, #+88] 0x65E1 STR R1,[R4, #+92] Хммм.... Почему не STRD? Присваивание (вариант 2): u32 j, j1; ... *(u64 *)&focQ.amplitude = j1 | (u64)j << 32; Результат компиляции (обрезал всё кроме самой записи): 0xE9C4 0x0116 STRD R0,R1,[R4, #+88] Теперь как и ожидалось - STRD. Но почему эти 2 вроде идентичных выражения приводят к разному результату?? Почему в 1-м случае не STRD, а 2 STR? PS: Если ampl_angle объявить как u64 и присваивать просто (focQ.ampl_angle = j1 | (u64)j << 32), то получаю STRD естественно. Но тогда у самой focQ появляется выравнивание на 64 бита, что не комильфо. Кстати: #define __align4 __attribute__ ((aligned (4))) struct FocQ { union { struct { u32 amplitude; u32 angle; }; u64 __align4 ampl_angle; }; s32 reduI; } focQ; ... u32 j, j1; ... focQ.ampl_angle = j1 | (u64)j << 32; Опять даёт 2 STR вместо STRD. Хотя вроде ничего не мешает применить тут STRD. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SII 0 27 апреля, 2021 Опубликовано 27 апреля, 2021 · Жалоба Возможно, компилятор (точней, его разработчики) считает, что, поскольку LDRD/STRD работают с двумя словами, то они работают с одним двойным словом -- а значит, нужно выравнивание на границу двойного слова (что не так, им достаточно выравнивания на границу слова); если выравнивания нет, то компилятор использует пары команд LDR и STR. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlexRayne 7 28 апреля, 2021 Опубликовано 28 апреля, 2021 · Жалоба потомушта обращение по невыравненому адресу требует специальных команд доступа, а обычные ЛД/СТ вызовут икслючение шины. может поэтому? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 183 28 апреля, 2021 Опубликовано 28 апреля, 2021 · Жалоба 8 часов назад, SII сказал: ...если выравнивания нет, то компилятор использует пары команд LDR и STR. После приведения к *(u64 *), вроде как, компилятор теряет информацию о выравнивании и вправе грузить кусок памяти u64 как ему угодно - STR/STRD/STM, что, собственно, мы и видим. 54 минуты назад, AlexRayne сказал: может поэтому? Нет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 28 апреля, 2021 Опубликовано 28 апреля, 2021 · Жалоба Виной всему был порванный презерватив __packed. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 183 28 апреля, 2021 Опубликовано 28 апреля, 2021 · Жалоба Попробовал на Keil-е с ARM Compiler 6. На -O0 дает пару STR. На > -O0 всегда STRD. P.S. Keil не дает сделать typedef __attribute__((packed)) u64 u64p32; пишет "warning: 'packed' attribute ignored [-Wignored-attributes]". Если же поместить атрибут перед объявлением самого элемента struct FocQ { union { struct { u32 amplitude; u32 angle; }; __attribute__((packed)) u64 ampl_angle; }; s32 reduI; } focQ; то ассемблерный выхлоп не пострадает (по прежнему STRD), но Keil справедливо выдаст предупреждение "warning: taking address of packed member 'ampl_angle' of class or structure 'FocQ::(anonymous)' may result in an unaligned pointer value [-Waddress-of-packed-member]" на строке *(u64 *)&focQ.ampl_angle = j1 | (u64)j << 32; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 241 28 апреля, 2021 Опубликовано 28 апреля, 2021 · Жалоба 2 часа назад, AlexRayne сказал: потомушта обращение по невыравненому адресу требует специальных команд доступа, а обычные ЛД/СТ вызовут икслючение шины. может поэтому? Во-первых: "обращения по невыравненому адресу" - там нет, адрес выровнен. Во-вторых: LDR/STR в Cortex-M как раз вполне нормально работают с невыровненным доступом (с настройками "по умолчанию"). 1 час назад, VladislavS сказал: Виной всему был порванный презерватив __packed. В последнем куске кода (ниже "Кстати") нету __packed. Специально его привёл, чтобы показать что от __packed не зависит. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 28 апреля, 2021 Опубликовано 28 апреля, 2021 · Жалоба Когда программист начинает мудрить с упаковками, выравниваниями и приведениями типов указателей, то компилятор правильно делает, что перестраховывается. Ну не смог он на 100% гарантировать, что SRD в этом месте будет по слову выровнен. Пусть уж лучше два str будет. У меня был на компиляторе ARM v6 случай, когда я схлопотал LDM с невыровненым адресом из-за приведения типов указателей. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 241 28 апреля, 2021 Опубликовано 28 апреля, 2021 · Жалоба 41 минуту назад, Arlleex сказал: Попробовал на Keil-е с ARM Compiler 6. На -O0 дает пару STR. На > -O0 всегда STRD. Я все примеры компилировал на "medium" оптимизации. Но сейчас проверил на "High, balanced" - результат аналогичный. 10 минут назад, VladislavS сказал: Когда программист начинает мудрить с упаковками, выравниваниями и приведениями типов указателей, то компилятор правильно делает, что перестраховывается. Вообще-то (если Вы не обратили внимания) то я явно приводил тип указателя к u64 * при присваивании. Заметьте - не __packed u64 *, не u64 __align4 *, а просто u64 *. Что должно говорить компилятору обращаться со значением по этому указателю как с u64. Таким приведением типа указателя я явно говорю компилятору что u64 - выровнено. И кроме того - сравните внимательнее "вариант 1" и "вариант 2": их сравнение противоречит вашему высказыванию. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 28 апреля, 2021 Опубликовано 28 апреля, 2021 · Жалоба 8 минут назад, jcxz сказал: Таким приведением типа указателя я явно говорю компилятору что u64 - выровнено. Что именно в приведении к (u64 *) говорит о том что до приведения там всё было выровнено? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 241 28 апреля, 2021 Опубликовано 28 апреля, 2021 · Жалоба Только что, VladislavS сказал: Что именно в приведении к (u64 *) говорит о том что до приведения там всё было выровнено? Само приведение. PS: Ещё раз - Сравните "вариант 1" и "вариант 2". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Kabdim 0 28 апреля, 2021 Опубликовано 28 апреля, 2021 · Жалоба Цитата Other instructions cannot be pipelined after STR with register offset. STR can only be pipelined when it follows an LDR, but nothing can be pipelined after the store. Even a stalled STRnormally only takes two cycles, because of the write buffer. LDRD and STRD cannot be pipelined with preceding or following instructions. However, the two words are pipelined together. So, this operation requires three cycles when not stalled из шпаргалки CORTEX-M4 INSTRUCTION TIMING Возможно STR может параллельно выполнитья с другими командами. Версия с D ставит конвеер колом. => они равноценны для компилятора с точки зрения времени исполнения и размера. Если он видит что возможен приход на конвер инструкции до str и первой str то он использует 32 битную версию, если видит что нет - ставит STRD. На 100% за такую интерпретацию не ручаюсь. мало ли что там у ИАРа в кишках скрыто. А вообще совет - бросайте считать такты и команды, это уровень компиляторописателей. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 28 апреля, 2021 Опубликовано 28 апреля, 2021 · Жалоба Вы слишком много хотите от компилятора. Меня, например, больше напрягает, когда он (по моей указке) молча вот так делает constexpr uint8_t *x = (uint8_t *)1; volatile uint64_t y = *(uint64_t *)x; MOVS R0,#+1 LDRD R0,R1,[R0, #+0] STRD R0,R1,[SP, #+0] Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrBearManul 0 28 апреля, 2021 Опубликовано 28 апреля, 2021 · Жалоба 21 минуту назад, Kabdim сказал: А вообще совет - бросайте считать такты и команды, это уровень компиляторописателей. Это же повышение своего профессионального уровня. Да и нельзя доверять всё чужим дядькам-комплиляторостроителям. Я, вот, с большим интересом слежу за этой темой! Хотя компиляторы не строю. Кстати, за доку спасибо!!! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 241 28 апреля, 2021 Опубликовано 28 апреля, 2021 · Жалоба 1 час назад, Kabdim сказал: Возможно STR может параллельно выполнитья с другими командами. Версия с D ставит конвеер колом. => они равноценны для компилятора с точки зрения времени исполнения и размера. Если он видит что возможен приход на конвер инструкции до str и первой str то он использует 32 битную версию, если видит что нет - ставит STRD. На 100% за такую интерпретацию не ручаюсь. мало ли что там у ИАРа в кишках скрыто. А вообще совет - бросайте считать такты и команды, это уровень компиляторописателей. С чего Вы вообще взяли что я "считаю такты"??? Вообще-то цель моя была: обеспечить атомарную запись в 2 32-битных слова. И нет - они не равноценны и не могут быть быть равноценными, потому что одна STRD - атомарна, 2 STR - не атомарны. (т.е. - команда STRD не может быть прервана посередине прерыванием). Вообще совет - бросайте думать за других, у вас это плохо получается. PS: И даже "считать такты" как Вы выразились (а точнее - писать оптимально) во многих задачах необходимо, там где мало вычислительных ресурсов и требуется производительность или минимальное потребление. И нет - это не только тема компиляторописателей, но и задача хорошего программиста. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться