考虑以下小函数:
void foo(int* iptr) {
iptr[10] = 1;
__asm__ volatile ("nop"::"r"(iptr):);
iptr[10] = 2;
}
使用gcc,这将编译为:
foo:
nop
mov DWORD PTR [rdi+40], 2
ret
void foo(int* iptr) {
iptr[10] = 1;
__asm__ volatile ("nop"::"r"(iptr):"memory");
iptr[10] = 2;
}
foo:
mov DWORD PTR [rdi+40], 1
nop
mov DWORD PTR [rdi+40], 2
ret
void foo2(int* iptr, long* lptr) {
iptr[10] = 1;
lptr[20] = 100;
__asm__ volatile ("nop"::"r"(iptr):);
iptr[10] = 2;
lptr[20] = 200;
}
所需的行为是让编译器优化对LPTR[20]
的第一次写入,而不是对IPTR[10]
的第一次写入。“memory”
clobber无法实现这一点,因为它意味着必须同时执行以下两个写操作:
foo2:
mov DWORD PTR [rdi+40], 1
mov QWORD PTR [rsi+160], 100 ; lptr[10] written unecessarily
nop
mov DWORD PTR [rdi+40], 2
mov QWORD PTR [rsi+160], 200
ret
有什么方法可以告诉接受gcc扩展asm语法的编译器,asm的输入包括指针和它可以指向的任何东西吗?
这是正确的;要求将指针作为内联asm的输入,并不意味着指向的内存也是输入或输出,或者两者兼而有之。通过寄存器输入和寄存器输出,对于所有gcc所知,您的asm只是通过掩蔽低位来对齐指针,或者添加一个常数。(在这种情况下,您希望它优化掉一个死存储。)
简单的选项是ASM Volatile
和“Memory”
Clobber1。
您所要求的更窄更具体的方法是使用“虚拟”内存操作数以及寄存器中的指针。您的asm模板没有引用这个操作数(除了可能在asm注释中查看编译器选择了什么)。它告诉编译器您实际读取、写入或读取+写入哪个内存。
如果使用[]
未指定大小,则会告诉GCC相对于该指针访问的任何内存都是输入、输出或输入/输出操作数。如果使用[10]
或[some_variable]
,则会告诉编译器具体的大小。对于运行时可变大小,gcc实际上忽略了iptr[size+1]
不是输入的一部分的优化。
GCC记录了这一点,因此支持它。我认为,如果数组元素类型与指针相同,或者如果是char
,则不会违反严格别名。
(来自GCC手册)
一个x86示例,其中字符串内存参数的长度未知。
asm("repne scasb"
: "=c" (count), "+D" (p)
: "m" (*(const char (*)[]) p), "0" (-1), "a" (0));
在内联asm示例中,这是一个广泛存在的bug,通常不会被检测到,因为asm被包装在一个函数中,而这个函数没有内联到任何调用程序中,这些调用程序会诱使编译器重新排序存储以进行合并,从而消除死存储。
GNU C内联asm语法是围绕向编译器描述单个指令而设计的。其目的是用“m”
或“=m”
操作数约束告诉编译器内存输入或内存输出,然后编译器选择寻址模式。
在内联asm中编写整个循环需要注意确保编译器确实知道发生了什么(或者asm volatile
加上“memory”
clobber),否则,在更改周围代码或启用允许跨文件内联的链接时优化时,您会冒着损坏的风险。
另请参见使用内联程序集对数组进行循环,以使用asm
语句作为循环体,但仍在C中执行循环逻辑。使用实际(非虚)“m”
和“=m”
操作数,编译器可以在其选择的寻址模式中使用位移来展开循环。
脚注1:“memory”
clobber使编译器像对待非内联函数调用一样对待asm(可以读取或写入任何内存,但转义分析已经证明没有转义的本地内存除外)。转义分析包括asm语句本身的输入操作数,也包括任何早期调用可能存储指针的任何全局变量或静态变量。因此,通常本地循环计数器不必围绕带有“memory”
clobber的asm
语句溢出/重新加载。
asm volatile
对于确保asm没有被优化掉是必要的,即使其输出操作数未被使用(因为您需要发生未声明的写入内存的副作用)。
或者对于仅由asm读取的内存,如果相同的输入缓冲区包含不同的输入数据,则需要asm再次运行。如果没有volatile
,asm语句可以从循环中CSEd出来。(“memory”
clobber不会使优化器在考虑asm
语句是否需要运行时将所有内存视为输入。)
没有输出操作数的ASM
是隐式的volatile
,但最好将其显式化。(GCC手册中有一节是关于asm volatile的)。
例如,ASM(“...sum an array...”:“=r”(sum):“r”(pointer),“r”(end_pointer):“memory”)
有一个输出操作数,因此不是隐式易失性的。如果你用它
arr[5] = 1;
total += asm_sum(arr, len);
memcpy(arr, foo, len);
total += asm_sum(arr, len);
如果没有volatile
,第二个asm_sum
可以优化掉,假设具有相同输入操作数(指针和长度)的相同asm将产生相同的输出。对于任何不是其显式输入操作数的纯函数的asm,都需要volatile
。如果它没有优化掉,那么“memory”
clobber将具有要求内存同步的预期效果。
问题内容: 我试图“ stopPropagation”以防止单击li内的元素(链接)时关闭TwitterBootstrap导航栏下拉菜单。 在Angular中,看起来像指令是执行此操作的地方?所以我有: …但是该方法不属于元素: 我把指令与 有什么建议么? 问题答案: “当前一些指令(即ng:click)停止事件传播。这阻止了与依赖于捕获此类事件的其他框架的互操作性。” - …并且能够在没有指令的
我的理解是,当编写gcc样式的内联asm时,您必须非常具体和准确地了解所有的输入和输出参数(和clobbers),这样编译器就会确切地知道如何为代码分配寄存器,以及它可以对那些寄存器的值和asm代码可能读取和/或修改的任何内存假设什么。编译器使用这些信息尽可能地优化周围的代码(如果它认为内联asm对任何东西都没有影响,甚至完全删除它)。对此不够具体可能会导致不正确的行为,因为编译器是根据您的不正确
我正在使用YourKit Java Profiler分析我的webapp。webapp运行在tomcat 7 v30上,我可以看到JVM的堆大约是30兆,但Tomcat.exe正在使用200兆,并且一直在增加。 截图:http://i.imgur.com/Zh9NGJ1.png(左边是Java使用了多少内存,右边是tomcat.exe的Windows使用情况) 我尝试过为tomcat添加不同的标志
问题内容: 我正在尝试扩展库以进行集成,并通过将config设置为自动(可移植)来实现,这意味着以编程方式添加元素。(我知道可以通过Hibernate 或EclipseLInk来实现,但是- 可移植性)。我也想避免仅用于此单一目的。 我可以动态创建一个,并用指定包中的元素填充它(通过Reflections库)。当我尝试将其提供给提供程序时,问题就开始了。我能想到的唯一方法是设置一个,但我想不出什么
现在,我知道没有内联的保证,但是。。。 给定以下内容: 我们有: 编译成: 然而... 编译成: 这真的很让人难过。 为什么打给PMF的电话没有被内联?PMF是一个不变的表情!