Ответ 1
asm volatile("" ::: "memory");
создает барьер памяти уровня компилятора, заставляющий оптимизатор не переупорядочивать доступ к памяти через барьер.
Например, если вам нужно получить доступ к некоторому адресу в определенном порядке (возможно, потому, что эта область памяти фактически поддерживается другим устройством, а не памятью), вы должны уметь сообщать об этом компилятору, иначе он может просто оптимизировать ваши шаги ради эффективности.
Предположим, что в этом сценарии вы должны увеличивать значение в адресе, читать что-то и увеличивать другое значение в соседнем адресе.
int c(int *d, int *e) {
int r;
d[0] += 1;
r = e[0];
d[1] += 1;
return r;
}
Проблема заключается в компиляторе (gcc
в этом случае) может изменить ваш доступ к памяти, чтобы получить лучшую производительность, если вы попросите его (-O
). Возможно, это приведет к последовательности инструкций, как показано ниже:
00000000 <c>:
0: 4603 mov r3, r0
2: c805 ldmia r0, {r0, r2}
4: 3001 adds r0, #1
6: 3201 adds r2, #1
8: 6018 str r0, [r3, #0]
a: 6808 ldr r0, [r1, #0]
c: 605a str r2, [r3, #4]
e: 4770 bx lr
Вышеуказанные значения для d[0]
и d[1]
загружаются одновременно. Предположим, что это то, чего вы хотите избежать, тогда вам нужно сказать компилятору, чтобы не изменять порядок доступа к памяти и использовать asm volatile("" ::: "memory")
.
int c(int *d, int *e) {
int r;
d[0] += 1;
r = e[0];
asm volatile("" ::: "memory");
d[1] += 1;
return r;
}
Итак, вы получите свою последовательность команд, как вы хотите:
00000000 <c>:
0: 6802 ldr r2, [r0, #0]
2: 4603 mov r3, r0
4: 3201 adds r2, #1
6: 6002 str r2, [r0, #0]
8: 6808 ldr r0, [r1, #0]
a: 685a ldr r2, [r3, #4]
c: 3201 adds r2, #1
e: 605a str r2, [r3, #4]
10: 4770 bx lr
12: bf00 nop
Следует отметить, что это всего лишь компиляция временного барьера памяти, чтобы избежать компилятора для изменения порядка доступа к памяти, поскольку он не добавляет дополнительных инструкций на уровне аппаратного обеспечения для сброса памяти или ожидания загрузки или хранения. ЦП могут по-прежнему изменять порядок доступа к памяти, если у них есть архитектурные возможности, а адреса памяти находятся на normal
вместо strongly ordered
или device
(ref).