为什么这个编译器障碍不强制执行排序?

我正在查看Atmel网站上的文档,我遇到了这个例子 ,他们解释了重新排序的一些问题。

这是示例代码:

#define cli() __asm volatile( "cli" ::: "memory" ) #define sei() __asm volatile( "sei" ::: "memory" ) unsigned int ivar; void test2( unsigned int val ) { val = 65535U / val; cli(); ivar = val; sei(); } 

在这个例子中,他们正在实现一个类似于关键区域的机制。 cli指令禁用中断,sei指令启用它们。 通常,我会保存中断状态并恢复到该状态,但我离题了……

他们注意到的问题是,在启用优化的情况下,第一行上的除法实际上会在cli指令之后移动到。 当您尝试尽可能在最短的时间内进入关键区域时,这可能会导致一些问题。

为什么如果cli()MACRO扩展为内联asm明显破坏内存,这怎么可能呢? 编译器如何在此语句之前或之后自由移动?

另外,我修改了代码以在__asm volatile("" ::: "memory");forms的每个语句之前包含内存屏障__asm volatile("" ::: "memory"); 它似乎没有改变任何东西。

我还从cli()和sei()MACRO中删除了内存clobber,生成的代码是相同的。

当然,如果我将test2函数参数声明为volatile,则不会重新排序,我认为这是因为volatile函数不能针对其他volatile语句(技术上是内联函数)重新排序。 我的假设是否正确?

可以针对易失性内联asm对易失性访问进行重新排序吗?

可以针对易失性内联asm重新排序非易失性访问吗?

有点奇怪的是,Atmel声称他们需要内存崩溃来强制执行与asm相关的易失性访问的排序。 这对我没有任何意义。

如果编译器障碍不适合这个,那么我怎样才能防止任何外部代码“泄漏”到关键区域?

如果有人能说清楚,我会很感激。

谢谢