Перейти к содержанию
    

Оптимизация нарушает работу механизма эксклюзивного доступа.

Дано: 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 дальнейшим кодом может не использоваться. При этом компилятор (видя это) зачем-то выбрасывает(!!!) (оптимизирует :shok: ) саму инструкцию 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()  :sad:  Или я не правильно пытаюсь.

Может есть какие-то другие пути решения?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 минут назад, aaarrr сказал:

А если просто в AtomicSwp добавить к объявлению "u32 i" volatile?

Хммм.... помогает. Я перепробовал разное: и пытался сделать volatile-указатель на __LDREX() и использовать префикс __root, а вот об этом не подумал.... :smile:

Правда теперь ради этой переменной создаётся стековый фрейм в функции и выполняется запись j в стек - добавляется много лишних операций.... :sad:  Но на безрыбье и рак - рыба. Спасибо! :smile:

 

PS: А может найдётся решение получше?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

а если вернуть из функции неволатильную копию 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;
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Посмотрите среди этого "не сильно" документированного

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 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

14 часов назад, _pv сказал:

а если вернуть из функции неволатильную копию i, тогда вроде как всё что до этого трогать не должен, а вот после, j=k может и выкидывать за ненадобностью.

Но от минусов, которые я описал в сообщении выше, это не спасёт.  :sad:

4 часа назад, k155la3 сказал:

Посмотрите среди этого "не сильно" документированного

Конечно я туда смотрел в первую очередь - нет там ничего подходящего.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

39 minutes ago, jcxz said:

 Но от минусов, которые я описал в сообщении выше, это не спасёт.  :sad:

то есть k кладётся на стэк, а i нет?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

15 часов назад, jcxz сказал:

Но встаёт вопрос: ЧТО ДЕЛАТЬ? Кроме того что писать в поддержку IAR.

Думаю ответ будет очевидным: пробуйте последнюю версию.

А если вчистую на ASM эту функцию написать?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

41 минуту назад, _pv сказал:

то есть k кладётся на стэк, а i нет?

Результирующий код с k = i; абсолютно ничем не отличается от кода без этой строчки. Как и следовало ожидать.

19 минут назад, VladislavS сказал:

Думаю ответ будет очевидным: пробуйте последнюю версию.

Надо будет конечно. Пока работаю с этой.

Цитата

А если вчистую на ASM эту функцию написать?

Тогда смысл использования LDREX/STREX теряется. Хочется чтобы они инлайнились, не производя лишнего кода. Писать отдельной функцией (на асме) неоптимально, так как тогда оптимальнее будет использовать реализацию этой функции через критическую секцию (запрет прерываний) - такой вариант инлайнится без багов и даст меньше кода, чем отдельная функция с LDREX/STREX.

Получается, что из-за этого бага вообще нет смысла использования интринсинков LDREX/STREX в IAR-е  :((((((((

 

PS: У меня все функции атомарного чтения-модификации-записи существуют в двух вариантах: на механизме эксклюзивного доступа (LDREX/XTREX) и на критических секциях (запрет прерываний). И первый и второй варианты - inline-функции. И есть #define, который включает тот или другой вариант. До сих пор компилил проект со вторым состоянием ключа, потому что помнится когда то давно при переключении ключа в первое состояние, что-то начинало глючить. Тогда не разобрался и просто переключил его во второе состояние. Сейчас решил разобраться и обнаружил такую проблему.  :sad:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 минуты назад, VladislavS сказал:

Ну это как раз несложно. На последнем те же яйца.

Это 8.32.2? Ну вот - похоже нужно писать в поддержку  :sad:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Попробовал вот так

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Только что, VladislavS сказал:

Попробовал вот так

Вроде отпустило?

Мы это уже обсуждали. См. сообщения выше.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

45 минут назад, jcxz сказал:

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

А IAR не умеет lto с ассемблерными вставками?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...