jcxz 236 25 февраля, 2019 Опубликовано 25 февраля, 2019 · Жалоба Дано: IAR V7.80.4.12462/W32 for ARM. Имеется функция: inline u32 AtomicSwp(u32 volatile *ptr, u32 arg) { u32 i; do i = __LDREX(ptr); while (__STREX(arg, ptr)); return i; } осуществляющая атомарный обмен содержимого *ptr и значения arg. При оптимизации не выше Low эта функция не инлайнится и всё работает ок. Но при высоких уровнях оптимизации, функция инлайнится (чего собственно и хочется) и возникают проблемы в её работе. Имеется фрагмент кода: static u32 volatile configMdf = 0; j = AtomicSwp(&configMdf, 0); ... При определённых значениях ключей условной компиляции, значение j дальнейшим кодом может не использоваться. При этом компилятор (видя это) зачем-то выбрасывает(!!!) (оптимизирует ) саму инструкцию LDREX из кода. В результате получается совершенно неработоспособный код (STREX всё время возвращает флаг==1, что приводит к зацикливанию). На лицо явный баг IAR-а: LDREX - это не LDR и просто так её нельзя выбрасывать: ??ConfigExec_6: (+1) 00000082 0xF104 0x000C ADD R0,R4,#+12 ;в R0 получаем адрес configMdf, но самого чтения нет 00000086 0x2100 MOVS R1,#+0 00000088 0xE840 0x1200 STREX R2,R1,[R0] ;естественно - в R2 всегда будет устанавливаться == 1, приводящая к зацикливанию на ??ConfigExec_6 0000008C 0x2A00 CMP R2,#+0 0000008E 0xD1F8 BNE.N ??ConfigExec_6 Но встаёт вопрос: ЧТО ДЕЛАТЬ? Кроме того что писать в поддержку IAR. Как можно обойти этот баг и заставить IAR оставлять LDREX даже если читаемое значение далее не используется? "Выключить оптимизацию" или "объявить AtomicSwp() (это целое семейство функций у меня) как не позволительную для inline" или "переписать AtomicSwp() на работу через критические секции (запрет прерываний)" - не предлагать, это самоочевидно. Ранее тут как-то было обсуждение указателей на функции с модификатором volatile. Что вызов таких функций не должен удаляться компилятором. Но IAR не даёт взять указатель от __LDREX() Или я не правильно пытаюсь. Может есть какие-то другие пути решения? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 25 февраля, 2019 Опубликовано 25 февраля, 2019 · Жалоба А если просто в AtomicSwp добавить к объявлению "u32 i" volatile? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 236 25 февраля, 2019 Опубликовано 25 февраля, 2019 · Жалоба 6 минут назад, aaarrr сказал: А если просто в AtomicSwp добавить к объявлению "u32 i" volatile? Хммм.... помогает. Я перепробовал разное: и пытался сделать volatile-указатель на __LDREX() и использовать префикс __root, а вот об этом не подумал.... Правда теперь ради этой переменной создаётся стековый фрейм в функции и выполняется запись j в стек - добавляется много лишних операций.... Но на безрыбье и рак - рыба. Спасибо! PS: А может найдётся решение получше? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_pv 78 25 февраля, 2019 Опубликовано 25 февраля, 2019 · Жалоба а если вернуть из функции неволатильную копию i, тогда вроде как всё что до этого трогать не должен, а вот после, j=k может и выкидывать за ненадобностью. inline u32 AtomicSwp(u32 volatile *ptr, u32 arg) { volatile u32 i; do i = __LDREX(ptr); while (__STREX(arg, ptr)); u32 k = i; // k = *((u32*)&i);??? return k; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
k155la3 27 26 февраля, 2019 Опубликовано 26 февраля, 2019 · Жалоба Посмотрите среди этого "не сильно" документированного Summary of extended keywords This table summarizes the extended keywords: Extended keyword Description __absolute Makes references to the object use absolute addressing __arm Makes a function execute in ARM mode __big_endian Declares a variable to use the big-endian byte order __fiq Declares a fast interrupt function __interwork Declares a function to be callable from both ARM and Thumb mode __intrinsic Reserved for compiler internal use only __irq Declares an interrupt function __little_endian Declares a variable to use the little-endian byte order __nested Allows an _?_irq declared interrupt function to be nested, that is, interruptible by the same type of interrupt __no_alloc, __no_alloc16 Makes a constant available in the execution file __no_alloc_str, __no_alloc_str16 Makes a string literal available in the execution file __no_init Places a data object in non-volatile memory __noreturn Informs the compiler that the function will not return __packed Decreases data type alignment to 1 __pcrel Used internally by the compiler for constant data when the --ropi compiler option is used __ramfunc Makes a function execute in RAM __root Ensures that a function or variable is included in the object code even if unused __ro_placement Places const volatile data in read-only memory. __sbrel Used internally by the compiler for constant data when the --rwpi compiler option is used __stackless Makes a function callable without a working stack __swi Declares a software interrupt function __task Relaxes the rules for preserving registers __thumb Makes a function execute in Thumb mode __weak Declares a symbol to be externally weakly linked Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 236 26 февраля, 2019 Опубликовано 26 февраля, 2019 · Жалоба 14 часов назад, _pv сказал: а если вернуть из функции неволатильную копию i, тогда вроде как всё что до этого трогать не должен, а вот после, j=k может и выкидывать за ненадобностью. Но от минусов, которые я описал в сообщении выше, это не спасёт. 4 часа назад, k155la3 сказал: Посмотрите среди этого "не сильно" документированного Конечно я туда смотрел в первую очередь - нет там ничего подходящего. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_pv 78 26 февраля, 2019 Опубликовано 26 февраля, 2019 · Жалоба 39 minutes ago, jcxz said: Но от минусов, которые я описал в сообщении выше, это не спасёт. то есть k кладётся на стэк, а i нет? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 26 февраля, 2019 Опубликовано 26 февраля, 2019 · Жалоба 15 часов назад, jcxz сказал: Но встаёт вопрос: ЧТО ДЕЛАТЬ? Кроме того что писать в поддержку IAR. Думаю ответ будет очевидным: пробуйте последнюю версию. А если вчистую на ASM эту функцию написать? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 236 26 февраля, 2019 Опубликовано 26 февраля, 2019 · Жалоба 41 минуту назад, _pv сказал: то есть k кладётся на стэк, а i нет? Результирующий код с k = i; абсолютно ничем не отличается от кода без этой строчки. Как и следовало ожидать. 19 минут назад, VladislavS сказал: Думаю ответ будет очевидным: пробуйте последнюю версию. Надо будет конечно. Пока работаю с этой. Цитата А если вчистую на ASM эту функцию написать? Тогда смысл использования LDREX/STREX теряется. Хочется чтобы они инлайнились, не производя лишнего кода. Писать отдельной функцией (на асме) неоптимально, так как тогда оптимальнее будет использовать реализацию этой функции через критическую секцию (запрет прерываний) - такой вариант инлайнится без багов и даст меньше кода, чем отдельная функция с LDREX/STREX. Получается, что из-за этого бага вообще нет смысла использования интринсинков LDREX/STREX в IAR-е :(((((((( PS: У меня все функции атомарного чтения-модификации-записи существуют в двух вариантах: на механизме эксклюзивного доступа (LDREX/XTREX) и на критических секциях (запрет прерываний). И первый и второй варианты - inline-функции. И есть #define, который включает тот или другой вариант. До сих пор компилил проект со вторым состоянием ключа, потому что помнится когда то давно при переключении ключа в первое состояние, что-то начинало глючить. Тогда не разобрался и просто переключил его во второе состояние. Сейчас решил разобраться и обнаружил такую проблему. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 26 февраля, 2019 Опубликовано 26 февраля, 2019 · Жалоба 15 минут назад, jcxz сказал: Надо будет конечно. Пока работаю с этой. Ну это как раз несложно. На последнем те же яйца. volatile uint32_t arg1; volatile uint32_t arg2; arg1=GPIOA->IDR; arg2=GPIOB->IDR; AtomicSwp(&arg1,arg2); Получаем // 37 volatile uint32_t arg1; // 38 volatile uint32_t arg2; // 39 arg1=GPIOA->IDR; LDR.N R1,??DataTable3_1 ;; 0x40010808 // 40 arg2=GPIOB->IDR; // 41 AtomicSwp(&arg1,arg2); LDR.N R4,??DataTable3_2 LDR R2,[R1, #+0] STR R2,[SP, #+0] MOV R2,SP LDR R1,[R1, #+1024] STR R1,[SP, #+4] LDR R1,[SP, #+4] ??main_0: STREX R0,R1,[R2] CMP R0,#+0 BNE.N ??main_0 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 236 26 февраля, 2019 Опубликовано 26 февраля, 2019 · Жалоба 2 минуты назад, VladislavS сказал: Ну это как раз несложно. На последнем те же яйца. Это 8.32.2? Ну вот - похоже нужно писать в поддержку Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 26 февраля, 2019 Опубликовано 26 февраля, 2019 · Жалоба Попробовал вот так inline uint32_t AtomicSwp(uint32_t volatile *ptr, uint32_t arg) { volatile uint32_t i; do i = __LDREX(ptr); while (__STREX(arg, ptr)); return i; } Вроде отпустило? // 37 volatile uint32_t arg1; // 38 volatile uint32_t arg2; // 39 arg1=GPIOA->IDR; LDR.N R1,??DataTable3_1 ;; 0x40010808 LDR R2,[R1, #+0] STR R2,[SP, #+0] // 40 arg2=GPIOB->IDR; // 41 AtomicSwp(&arg1,arg2); MOV R2,SP LDR R1,[R1, #+1024] STR R1,[SP, #+4] LDR R1,[SP, #+4] ??main_0: MOV R0,SP LDREX R0,[R0] STR R0,[SP, #+4] STREX R0,R1,[R2] CMP R0,#+0 BNE.N ??main_0 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 236 26 февраля, 2019 Опубликовано 26 февраля, 2019 · Жалоба Только что, VladislavS сказал: Попробовал вот так Вроде отпустило? Мы это уже обсуждали. См. сообщения выше. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 26 февраля, 2019 Опубликовано 26 февраля, 2019 · Жалоба Ну ок, более подробно некогда разбираться. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Kabdim 0 26 февраля, 2019 Опубликовано 26 февраля, 2019 · Жалоба 45 минут назад, jcxz сказал: Хочется чтобы они инлайнились, не производя лишнего кода. Писать отдельной функцией (на асме) неоптимально А IAR не умеет lto с ассемблерными вставками? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться