内嵌汇编代码中的有些"memory"似乎不必要

130 views
Skip to first unread message

Parmenides

unread,
Jun 26, 2011, 1:41:00 PM6/26/11
to Linux-...@zh-kernel.org
在读一些底层代码时不可避免地要涉及到一些内嵌汇编语句。有些内嵌汇编语句为了向编译器声明内嵌汇编指令以非显式的方式修改了内存
,从而要求编译器不要将内存变量的值优化到寄存器中。这是通过在内嵌汇编语句的损坏列表中声明"memory"来实现的。但是,有些实际的代码中虽然声明了"memory",但是我看不出有什么必要这样做。例如:

68/**
69 * atomic_sub_and_test - subtract value from variable and test result
70 * @i: integer value to subtract
71 * @v: pointer of type atomic_t
72 *
73 * Atomically subtracts @i from @v and returns
74 * true if the result is zero, or false for all
75 * other cases.
76 */
77static inline int atomic_sub_and_test(int i, atomic_t *v)
78{
79 unsigned char c;
80
81 asm volatile(LOCK_PREFIX "subl %2,%0; sete %1"
82 : "+m" (v->counter), "=qm" (c)
83 : "ir" (i) : "memory"); <---- 为何要做这样的声明?
84 return c;
85}
86

这里,v->counter已经在输出列表中声明了,所以编译器已经知道对它的修改;c显然是局部变量,编译器并不关心局部变量是否修改,而且即使c被缓冲到寄存器中,对它的修改也在输出列表中声明了。其实,增加这样一个声明最多也就是会对代码的性能有些影响,并不会导致程序的错误。但是,我不太明白为什么要加上"memory"。这段代码选自2.6.34版本的linux/arch/x86/include/asm/atomic.h文件,该文件中有几个其它函数都有类似的情况,所以看起来不是偶然的。可能我并没有考虑全面,或许这样声明有些特殊的考虑,所以想请教大家,能否帮忙解释一下。谢谢!
_______________________________________________
Linux 内核开发中文邮件列表
Linux-...@zh-kernel.org
http://zh-kernel.org/mailman/listinfo/linux-kernel
Linux 内核开发中文社区: http://zh-kernel.org

wjcdx

unread,
Jun 27, 2011, 2:14:33 AM6/27/11
to Parmenides, Linux-...@zh-kernel.org
于 2011-6-27 1:41, Parmenides 写道:
> 在读一些底层代码时不可避免地要涉及到一些内嵌汇编语句。有些内嵌汇编语句为了向编译器声明内嵌汇编指令以非显式的方式修改了内存
> ,从而要求编译器不要将内存变量的值优化到寄存器中。这是通过在内嵌汇编语句的损坏列表中声明"memory"来实现的。但是,有些实际的代码中虽然声明了"memory",但是我看不出有什么必要这样做。例如:
>
> 68/**
> 69 * atomic_sub_and_test - subtract value from variable and test result
> 70 * @i: integer value to subtract
> 71 * @v: pointer of type atomic_t
> 72 *
> 73 * Atomically subtracts @i from @v and returns
> 74 * true if the result is zero, or false for all
> 75 * other cases.
> 76 */
> 77static inline int atomic_sub_and_test(int i, atomic_t *v)
> 78{
> 79 unsigned char c;
> 80
> 81 asm volatile(LOCK_PREFIX "subl %2,%0; sete %1"
> 82 : "+m" (v->counter), "=qm" (c)
> 83 : "ir" (i) : "memory");<---- 为何要做这样的声明?
> 84 return c;
> 85}
> 86
>
> 这里,v->counter已经在输出列表中声明了,所以编译器已经知道对它的修改;c显然是局部变量,编译器并不关心局部变量是否修改,
这里“编译器并不关心局部变量是否修改”从何得知?

> 而且即使c被缓冲到寄存器中,对它的修改也在输出列表中声明了。其实,增加这样一个声明最多也就是会对代码的性能有些影响,并不会导致程序的错误。但是,我不太明白为什么要加上"memory"。这段代码选自2.6.34版本的linux/arch/x86/include/asm/atomic.h文件,该文件中有几个其它函数都有类似的情况,所以看起来不是偶然的。可能我并没有考虑全面,或许这样声明有些特殊的考虑,所以想请教大家,能否帮忙解释一下。谢谢!
我认为这里的问题就在于INPUT/OUTPUT中的 "m" Constraint,其是否起到
Modify/Clobber字串中的"memory"的作用的问题
可以参看gcc的文档,上面并没有关于"m"会刷新寄存器的描述,只是说"m"表明该
操作数来自于内存。

`m'
A memory operand is allowed, with any kind of address that the
machine supports in general. Note that the letter used for the
general memory constraint can be re-defined by a back end using the
|TARGET_MEM_CONSTRAINT| macro.

我有另外一个疑问,就是volatile和"memory"功能是否重复?晚上回去再研究一下文档

Brook

unread,
Jun 27, 2011, 2:23:43 AM6/27/11
to Parmenides, Linux-...@zh-kernel.org
我不熟悉c嵌入汇编的语法格式。用gcc -S -O2编译你的这段代码,得到了这样的语句:
subl %edi,(%rsi);
sete %al;
说明c变量是保存在寄存器 al内的。是不是你对于"memory"声明的理解上有问题?



--------------------------------------------------
From: "Parmenides" <mobile.p...@gmail.com>
Sent: Monday, June 27, 2011 1:41 AM
To: <Linux-...@zh-kernel.org>
Subject: 内嵌汇编代码中的有些"memory"似乎不必要

Parmenides

unread,
Jul 1, 2011, 12:00:11 PM7/1/11
to wjcdx, Linux-...@zh-kernel.org
> 这里“编译器并不关心局部变量是否修改”从何得知?
"memory" 只作用于全局存储,因为只有全局存储在并发的环境中才有可能被外部修改(例如,其他线程、中断处理程序等)。
从当前代码看来,这种外部修改是不可预测的,编译器在搞不清楚外部情况时不宜对访问全局存储的代码做优化。

>
> 而且即使c被缓冲到寄存器中,对它的修改也在输出列表中声明了。其实,增加这样一个声明最多也就是会对代码的性能有些影响,并不会导致程序的错误。但是,我不太明白为什么要加上"memory"。这段代码选自2.6.34版本的linux/arch/x86/include/asm/atomic.h文件,该文件中有几个其它函数都有类似的情况,所以看起来不是偶然的。可能我并没有考虑全面,或许这样声明有些特殊的考虑,所以想请教大家,能否帮忙解释一下。谢谢!
>
> 我认为这里的问题就在于INPUT/OUTPUT中的 "m"

> Constraint,其是否起到Modify/Clobber字串中的"memory"的作用的问题


> 可以参看gcc的文档,上面并没有关于"m"会刷新寄存器的描述,只是说"m"表明该操作数来自于内存。
> `m' A memory operand is allowed, with any kind of address that the machine
> supports in general. Note that the letter used for the general memory
> constraint can be re-defined by a back end using the TARGET_MEM_CONSTRAINT
> macro. 我有另外一个疑问,就是volatile和"memory"功能是否重复?晚上回去再研究一下文档

既然c是局部变量,自然也就不存在外部修改的问题。所以,我认为这里加"memory"好像是多虑了。

关于volatile的作用,很多文献中只是简单描述为“保证内嵌汇编按原来的顺序执行,禁止gcc对其做优化”(大概是这个意思)。
但是,从gcc的文档看来关于它的作用,准确的描述应该是“防止内嵌汇编在优化时被删除”。是否删除主要看内嵌汇编有没有
副作用。如果内嵌汇编指定了输出操作数,就认为内嵌汇编没有副作用;否则就认为可能有副作用。没有副作用的内嵌汇编
在之后如果输出操作数没有用到,那么就可以在优化时将内嵌汇编删除;如果可能有副作用,那么就意味着可能存在gcc没有意识
到的内存修改,这样gcc就不能贸然地做优化删除,否则会导致程序的逻辑错误。

但是,即使内嵌汇编用volatile修饰,在做优化编译时它与周围代码的相对位置还是有可能被调整的。而"memory"可以防止出现这
种情况,因为如果内嵌汇编中存在不可预测的内存变量修改,那么重排指令的顺序可能会导致逻辑上的错误。例如,如果锁原语
不用"memory"修改,那么其后面的临界区中修改临界资源的指令可能会因为指令重排而跑到锁原语的前面。这样就不能遵循先加锁
再访问临界资源的原则了。

简言之,volatile用于确保内嵌汇编不会因为优化而删除;而"memory"用于将内嵌汇编的位置固定,防止编译器的指令重排。这是我
的理解,可能有不准确的地方,仅供参考。

wjcdx

unread,
Jul 3, 2011, 8:23:54 AM7/3/11
to Parmenides, Linux-...@zh-kernel.org
于 2011/7/2 0:00, Parmenides 写道:
>> 这里“编译器并不关心局部变量是否修改”从何得知?
> "memory" 只作用于全局存储,因为只有全局存储在并发的环境中才有可能被外部修改(例如,其他线程、中断处理程序等)。
> 从当前代码看来,这种外部修改是不可预测的,编译器在搞不清楚外部情况时不宜对访问全局存储的代码做优化。
>

内外是相对的。见文档:

If your assembler instructions access memory in an unpredictable
fashion, add ‘memory’ to the list of clobbered registers. This will
cause GCC to not keep memory values cached in registers across the
assembler instruction and not optimize stores or loads to that memory.

这里是从“asm ()”为视角来表达内外的,即“asm ()”内的指令外内,为“我”;之外
的都是外,包括函数内部的其他语句。

static inline void atomic_dec(atomic_t *v)
{
asm volatile(LOCK_PREFIX "decl %0"
: "+m" (v->counter));
}

static inline int atomic_dec_and_test(atomic_t *v)
{
unsigned char c;

asm volatile(LOCK_PREFIX "decl %0; sete %1"


: "+m" (v->counter), "=qm" (c)

: : "memory");
return c != 0;
}

对比可以发现,使用了"memory" clobber的atomic_sub_and_test需要返回值,而
该返回值使用到在"asm ()"中修改过变量;
可以参考内核中其他的代码如arch/powerpc/include/asm/atomic.h及其他的对asm
用法具有演示性的代码,只要是 符合上面条件的都有"memory",返回值为void的
的没有使用"memory".
PS: ARM的atomic.h中,没有使用"memory",但观察发现,arm的所有原子操作实现
中,都没有使用"memory",这应该与ARM的 RISC体系结构有关。


以上仅仅说明,"memory"是有必要的,并没有详细说明为什么是必要的。
以下纯粹的是个人理解,并不严谨。
GCC首先是一个C语言编译器,可以对C语言的代码进行编译,生成汇编代码。在从C
到汇编的过程中,在保证正确的情况下,可以任他发挥(优化)。 但该发挥领域
至汇编而止,而"asm ()"中嵌入的恰是汇编代码,处在了GCC发挥领域的边界。但
GCC相对于其他编译器,仍然是智能的,因为他可以替程序员选择所要使用的寄存
器;但GCC 也没有剥夺程序员选择寄存器的权利。这些智能也不是凭空产生的,必
须要程序员告诉GCC指令模板、操作数的信息(哪一个变量?存在哪里?等)、注
意事项。操作数信息是constraint modifiers & constraints, 注意事项就是,在
这条"asm ()"中,使用了哪些寄存器,是否修改了内存变量等,即被修改了,在这
条"asm ()"之后,不要直接用相应寄存器的值,或者内存变量必须重新从内存中读
取。这几种信息各司其职,各有各的用途,但也偶有重叠,如文档所
说"unpredictable fashion",间接说明还是可以有predictable的部分的。(我也
不清楚怎样才是predictable:-) )

在这个例子中,在"asm ()"之外,要使用在"asm ()"中修改过的变量c,那在"asm
()"中,就有责任告诉GCC: hi~ body, c was modified by me, you'd better do
not cache and reload it before you use it.

GCC-Inline-Assembly-HOWTO
<http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html>[http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
<http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html>] 中的
一个例子:


Now we’ll perform some action on some registers/variables and compare
the value.

||
------------------------------------------------------------------------

__asm__ __volatile__( "decl %0; sete %1"
: "=m" (my_var), "=q" (cond)
: "m" (my_var)
: "memory"
);

------------------------------------------------------------------------

Here, the value of my_var is decremented by one and if the resulting
value is|0|then, the variable cond is set. We can add atomicity by
adding an instruction "lock;\n\t" as the first instruction in assembler
template.

In a similar way we can use "incl %0" instead of "decl %0", so as to
increment my_var.

Points to note here are that (i) my_var is a variable residing in
memory. (ii) cond is in any of the registers eax, ebx, ecx and edx. The
constraint "=q" guarantees it. (iii)*And we can see that memory is there
in the clobber list. ie, the code is changing the contents of memory.*


>> 而且即使c被缓冲到寄存器中,对它的修改也在输出列表中声明了。其实,增加这样一个声明最多也就是会对代码的性能有些影响,并不会导致程序的错误。但是,我不太明白为什么要加上"memory"。这段代码选自2.6.34版本的linux/arch/x86/include/asm/atomic.h文件,该文件中有几个其它函数都有类似的情况,所以看起来不是偶然的。可能我并没有考虑全面,或许这样声明有些特殊的考虑,所以想请教大家,能否帮忙解释一下。谢谢!
>>
>> 我认为这里的问题就在于INPUT/OUTPUT中的 "m"
>> Constraint,其是否起到Modify/Clobber字串中的"memory"的作用的问题
>> 可以参看gcc的文档,上面并没有关于"m"会刷新寄存器的描述,只是说"m"表明该操作数来自于内存。
>> `m' A memory operand is allowed, with any kind of address that the machine
>> supports in general. Note that the letter used for the general memory
>> constraint can be re-defined by a back end using the TARGET_MEM_CONSTRAINT
>> macro. 我有另外一个疑问,就是volatile和"memory"功能是否重复?晚上回去再研究一下文档
> 既然c是局部变量,自然也就不存在外部修改的问题。所以,我认为这里加"memory"好像是多虑了。
>
> 关于volatile的作用,很多文献中只是简单描述为“保证内嵌汇编按原来的顺序执行,禁止gcc对其做优化”(大概是这个意思)。
> 但是,从gcc的文档看来关于它的作用,准确的描述应该是“防止内嵌汇编在优化时被删除”。是否删除主要看内嵌汇编有没有
> 副作用。如果内嵌汇编指定了输出操作数,就认为内嵌汇编没有副作用;否则就认为可能有副作用。没有副作用的内嵌汇编
> 在之后如果输出操作数没有用到,那么就可以在优化时将内嵌汇编删除;如果可能有副作用,那么就意味着可能存在gcc没有意识
> 到的内存修改,这样gcc就不能贸然地做优化删除,否则会导致程序的逻辑错误。
>
> 但是,即使内嵌汇编用volatile修饰,在做优化编译时它与周围代码的相对位置还是有可能被调整的。而"memory"可以防止出现这
> 种情况,因为如果内嵌汇编中存在不可预测的内存变量修改,那么重排指令的顺序可能会导致逻辑上的错误。例如,如果锁原语
> 不用"memory"修改,那么其后面的临界区中修改临界资源的指令可能会因为指令重排而跑到锁原语的前面。这样就不能遵循先加锁
> 再访问临界资源的原则了。
>
> 简言之,volatile用于确保内嵌汇编不会因为优化而删除;而"memory"用于将内嵌汇编的位置固定,防止编译器的指令重排。这是我
> 的理解,可能有不准确的地方,仅供参考。

谢谢! 关于这点,我的理解是:
① "memory"的作用,如上所述no cache,no optimization,同步对内存的操作指令
② volatile作用要分类讨论了,呵呵:)
A. volatile修饰变量,说明该变量会被外部修改,每次必须从源重新读取;
B. volatile修饰语句,如asm指令,保证指令顺序不被编译器打乱。
总之,volatile就是禁止优化,该怎么样,还怎么样,不要抄近道,耍小聪明;)

另外,再引一段HOWTO中关于volatile的描述:

5.4 Volatile ...?

If you are familiar with kernel sources or some beautiful code like
that, you must have seen many functions declared as volatile or
__volatile__ which follows an asm or __asm__. I mentioned earlier
about the keywords asm and __asm__. So what is this volatile?

If our assembly statement must execute where we put it, (i.e. must
not be moved out of a loop as an optimization), put the keyword
volatile after asm and before the ()’s. So to keep it from moving,
deleting and all, we declare it as

asm volatile ( ... : ... : ... : ...);

Use __volatile__ when we have to be verymuch careful.

Parmenides

unread,
Jul 13, 2011, 4:04:55 PM7/13/11
to wjcdx, Linux-...@zh-kernel.org
> 对比可以发现,使用了"memory" clobber的atomic_sub_and_test需要返回值,而该返回值使用到在"asm ()"中修改过变量;
> 可以参考内核中其他的代码如arch/powerpc/include/asm/atomic.h及其他的对asm用法具有演示性的代码,只要是
> 符合上面条件的都有"memory",返回值为void的的没有使用"memory".

好像这不是一个规律,例如在include/asm/bitops.h中,

static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
{
int oldbit;

asm("bts %2,%1\n\t"
"sbb %0,%0"
: "=r" (oldbit), ADDR
: "Ir" (nr));
return oldbit;
}

>
> 以上仅仅说明,"memory"是有必要的,并没有详细说明为什么是必要的。
> 以下纯粹的是个人理解,并不严谨。
> GCC首先是一个C语言编译器,可以对C语言的代码进行编译,生成汇编代码。在从C到汇编的过程中,在保证正确的情况下,可以任他发挥(优化)。

> 但该发挥领域至汇编而止,而"asm


> ()"中嵌入的恰是汇编代码,处在了GCC发挥领域的边界。但GCC相对于其他编译器,仍然是智能的,因为他可以替程序员选择所要使用的寄存器;但GCC

> 也没有剥夺程序员选择寄存器的权利。这些智能也不是凭空产生的,必须要程序员告诉GCC指令模板、操作数的信息(哪一个变量?存在哪里?等)、注
> 意事项。操作数信息是constraint modifiers & constraints, 注意事项就是,在这条"asm


> ()"中,使用了哪些寄存器,是否修改了内存变量等,即被修改了,在这条"asm
> ()"之后,不要直接用相应寄存器的值,或者内存变量必须重新从内存中读取。

我做了一个实验,测试一下"memory"的效果。C源代码如下:

#include <stdio.h>

typedef struct {
volatile int counter;
} atomic_t;
#define LOCK_PREFIX ""
#define ATOMIC_INIT(i) { (i) }

static inline int atomic_dec_and_test(atomic_t *v)
{
unsigned char c;

asm volatile(LOCK_PREFIX "decl %0; sete %1"
: "+m" (v->counter), "=qm" (c)

); <----- 这里去掉了"memory"
return c != 0;
}

void tst(void)
{
atomic_t x = ATOMIC_INIT(1);
int r = atomic_dec_and_test(&x);
if (r) printf("yes\n");
else printf("no\n");
}

命令行上用gcc -S -O tst.c 编译,得到下列汇编代码:

tst:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $1, -4(%ebp)
#APP
decl -4(%ebp); sete %al
#NO_APP
testb %al, %al <---- 在内嵌汇编之后用al寄存器存放c变量
je .L2
subl $12, %esp
pushl $.LC0
call puts
addl $16, %esp
jmp .L5
.L2:
subl $12, %esp
pushl $.LC1
call puts
addl $16, %esp
.L5:
leave
ret

加上"memory"之后,同样的编译获得的汇编代码:

... ...
#APP
decl -4(%ebp); sete %al
#NO_APP
testb %al, %al <--- 在有"memory"的情况下仍然用al寄存器存放c变量
... ...

gcc并没有按我们预想的那样在内嵌汇编语句之后重新从内存中将c的值装入寄存器。

> 这几种信息各司其职,各有各的用途,但也偶有重叠,如文档所
> 说"unpredictable fashion",间接说明还是可以有predictable的部分的。(我也不清楚怎样才是predictable :-)
> )

我认为只要在内嵌汇编语句的输出列表中声明的操作数都是predictable修改,因为gcc对这些修改时明确了解的。所谓unpredictable修改,至少有两种情况。
一是在gcc看不见的程序外部的修改,例如在并发环境中另外一个进程或中断处理程序对全局变量的修改。二是有些具有副作用的指令。例如,一些串操作
指令就不能明确地指明修改的内存,这样gcc也就无法通过输出操作数来了解对内存的修改了。

>
> 谢谢! 关于这点,我的理解是:
> ① "memory"的作用,如上所述no cache,no optimization,同步对内存的操作指令
> ② volatile作用要分类讨论了,呵呵:)
> A. volatile修饰变量,说明该变量会被外部修改,每次必须从源重新读取;

这个volatile是C语言的关键字。

> B. volatile修饰语句,如asm指令,保证指令顺序不被编译器打乱。
> 总之,volatile就是禁止优化,该怎么样,还怎么样,不要抄近道,耍小聪明;)
>

这个volatile是gcc的扩展。关于它的作用,gcc的手册有如下描述:

If an asm has output operands, GCC assumes for optimization purposes
the instruction has no side effects except to change the output
operands. This does not mean instructions with a side effect cannot be
used, but you must be careful, because the compiler may eliminate them
if the output operands aren't used, or move them out of loops, or
replace two with one if they constitute a common subexpression. Also,
if your instruction does have a side effect on a variable that
otherwise appears not to change, the old value of the variable may be
reused later if it happens to be found in a register.

You can prevent an asm instruction from being deleted by writing the
keyword volatile after the asm. For example:

#define get_and_set_priority(new) \
({ int __old; \
asm volatile ("get_and_set_priority %0, %1" \
: "=g" (__old) : "g" (new)); \
__old; })

The volatile keyword indicates that the instruction has important
side-effects. GCC will not delete a volatile asm if it is reachable.
(The instruction can still be deleted if GCC can prove that
control-flow will never reach the location of the instruction.) Note
that even a volatile asm instruction can be moved relative to other
code, including across jump instructions. For example, on many targets
there is a system register which can be set to control the rounding
mode of floating point operations. You might try setting it with a
volatile asm, like this PowerPC example:

asm volatile("mtfsf 255,%0" : : "f" (fpenv));
sum = x + y;

This will not work reliably, as the compiler may move the addition
back before the volatile asm. To make it work you need to add an
artificial dependency to the asm referencing a variable in the code
you don't want moved, for example:

asm volatile ("mtfsf 255,%1" : "=X"(sum): "f"(fpenv));
sum = x + y;

Similarly, you can't expect a sequence of volatile asm instructions to
remain perfectly consecutive. If you want consecutive output, use a
single asm. Also, GCC will perform some optimizations across a
volatile asm instruction; GCC does not "forget everything" when it
encounters a volatile asm instruction the way some other compilers do.

An asm instruction without any output operands will be treated
identically to a volatile asm instruction.

归纳一下:
1. 单纯声明了输出操作数的内嵌汇编语句就认为没有副作用。
2. 没有副作用的内嵌汇编语句会被优化。例如:内嵌汇编语句之后如果输出操作数没后被使用就可以删除该内嵌汇编语句。
也可以调整内嵌汇编语句的位置,或者做公共子表达式的合并。
3. 加上volatile后内嵌汇编语句就被gcc认为有副作用。
4. 有副作用的内嵌汇编语句不会被删除。
5. 但是,gcc不是禁止对有副作用内嵌汇编语句的所有优化,它可以调整这种内嵌汇编语句的位置。

由此可见,仅仅说volatile禁止了gcc对内嵌汇编语句的优化是比较笼统的,准确的表述应该是"禁止删除用volatile修饰的内嵌汇编语句"。

关于"memory"gcc手册的描述如下:


If your assembler instructions access memory in an unpredictable
fashion, add `memory' to the list of clobbered registers. This will
cause GCC to not keep memory values cached in registers across the
assembler instruction and not optimize stores or loads to that memory.

You will also want to add the volatile keyword if the memory affected
is not listed in the inputs or outputs of the asm, as the `memory'
clobber does not count as a side-effect of the asm. If you know how
large the accessed memory is, you can add it as input or output but if
this is not known, you should add `memory'.

由此可见,volatile的作用是防止内嵌汇编语句被优化删除,而"memory"的作用是防止gcc对内存读写的优化。

但是,这段描述中我有两个不太理解的地方。
1. This will cause GCC to not keep memory values cached in registers
across the assembler instruction
这里"across"是什么意思,是指内嵌汇编语句之后,还是内嵌汇编语句的前后?

2. not optimize stores or loads to that memory
除了不将内存值cache到寄存器中,还有什么内存的stores和loads需要优化?

> 另外,再引一段HOWTO中关于volatile的描述:
>
> 5.4 Volatile ...?
>
> If you are familiar with kernel sources or some beautiful code like that,
> you must have seen many functions declared as volatile or __volatile__ which
> follows an asm or __asm__. I mentioned earlier about the keywords asm and
> __asm__. So what is this volatile?
>
> If our assembly statement must execute where we put it, (i.e. must not be
> moved out of a loop as an optimization), put the keyword volatile after asm
> and before the ()'s. So to keep it from moving, deleting and all, we declare
> it as
>
> asm volatile ( ... : ... : ... : ...);
>
> Use __volatile__ when we have to be verymuch careful.
>
>
>
>

> --------------080908070806000102010108--1/4

Reply all
Reply to author
Forward
0 new messages