鉴于此代码:
#include <stdio.h>
int main(int argc, char **argv)
{
int x = 1;
printf("Hello x = %d\n", x);
}
Run Code Online (Sandbox Code Playgroud)
我想在内联汇编中访问和操作变量 x 。理想情况下,我想使用内联汇编更改其值。GNU 汇编器,并使用 AT&T 语法。
假设我想从双核 x64 CPU 上的这些寄存器(以及所有这些)中读取值。我怎样才能做到这一点?我可以简单地写一些类似的东西:
uint64_t rax = 0, rbx = 0;
__asm__ __volatile__ (
/* read value from rbx into rbx */
"movq %%rdx, %0;\n"
/* read value from rax into rax*/
"movq %%rax, %1;\n"
/* output args */
: "=r" (rbx), "=r" (rax)
: /* no input */
/* clear both rdx and rax */
: "%rdx", "%rax"
);
Run Code Online (Sandbox Code Playgroud)
然后只是打印出来rax和rbx?干杯
以下 16 字节原子操作是否正确实现?还有更好的选择吗?
typedef struct {
uintptr_t low;
uintptr_t high;
} uint128_atomic;
uint128_atomic load_relaxed(uint128_atomic const *atomic)
{
uint128_atomic ret;
asm volatile("xor %%eax, %%eax\n"
"xor %%ebx, %%ebx\n"
"xor %%ecx, %%ecx\n"
"xor %%edx, %%edx\n"
"lock; cmpxchg16b %1"
: "=A"(ret)
: "m"(*atomic)
: "cc", "rbx", "rcx");
return ret;
}
bool cmpexch_weak_relaxed(
uint128_atomic *atomic,
uint128_atomic *expected,
uint128_atomic desired)
{
bool matched;
uint128_atomic e = *expected;
asm volatile("lock; cmpxchg16b %1\n"
"setz %0"
: "=q"(matched), "+m"(atomic->ui)
: "a"(e.low), "d"(e.high), "b"(desired.low), "c"(desired.high)
: "cc");
return matched;
} …Run Code Online (Sandbox Code Playgroud) 介绍
Kahan 求和/补偿求和是解决编译器无法尊重数字关联属性的技术。截断误差导致 (a+b)+c 不完全等于 a+(b+c),从而在较长的和序列上累积不希望的相对误差,这是科学计算中的常见障碍。
任务
我希望 Kahan 求和的最佳实现。我怀疑使用手工汇编代码可以实现最佳性能。
尝试
下面的代码使用三种方法计算 [0,1] 范围内的 1000 个随机数的总和。
标准求和:累积均方根相对误差的朴素实现,其增长为 O(sqrt(N))
Kahan summation [g++]:使用 c/c++ 函数“csum”进行补偿求和。评论中的解释。请注意,某些编译器可能具有使此实现无效的默认标志(请参见下面的输出)。
Kahan summation [asm]:使用与“csum”相同的算法实现为“csumasm”的补偿求和。评论中的神秘解释。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
extern "C" void csumasm(double&, double, double&);
__asm__(
"csumasm:\n"
"movsd (%rcx), %xmm0\n" //xmm0 = a
"subsd (%r8), %xmm1\n" //xmm1 - r8 (c) | y = b-c
"movapd %xmm0, %xmm2\n"
"addsd %xmm1, %xmm2\n" //xmm2 + xmm1 (y) | b = a+y
"movapd %xmm2, %xmm3\n"
"subsd %xmm0, %xmm3\n" …Run Code Online (Sandbox Code Playgroud) 我试图理解atomic_forced_read定义的目的,它经常出现在malloc.c的GNU libc实现中。
我不太擅长内联汇编,但看起来这会返回完全相同的值,并且类型与输入值相同。我在这里缺少什么?
原子强制读取定义在atomic.h中
523 #ifndef atomic_forced_read
524 # define atomic_forced_read(x) \
525 ({ __typeof (x) __x; __asm ("" : "=r" (__x) : "0" (x)); __x; })
526 #endif
Run Code Online (Sandbox Code Playgroud)
链接到atomic.h
https://code.woboq.org/userspace/glibc/include/atomic.h.html
main为什么我不能在基本 asm 内联中使用局部变量?它只允许在扩展汇编中使用,但为什么会这样呢?
(我知道局部变量在返回地址之后位于堆栈上(因此一旦函数返回就不能使用),但这不应成为不使用它们的原因)
以及基本汇编的示例:
int a = 10; //global a
int b = 20; //global b
int result;
int main() {
asm ( "pusha\n\t"
"movl a, %eax\n\t"
"movl b, %ebx\n\t"
"imull %ebx, %eax\n\t"
"movl %eax, result\n\t"
"popa");
printf("the answer is %d\n", result);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
扩展的例子:
int main (void) {
int data1 = 10; //local var - could be used in extended
int data2 = 20;
int result;
asm ( "imull %%edx, %%ecx\n\t"
"movl %%ecx, %%eax"
: "=a"(result) …Run Code Online (Sandbox Code Playgroud) 我试图用rep movsb指令创建我的 memcpy 代码。当优化被禁用时,它适用于任何尺寸。但是,当我启用优化时,它没有按预期工作。
我从Intel® 64 and IA-32 Architectures Optimization Reference Manual section 3.7.6 中阅读了有关 memcpy 的增强 movsb 。我来到了 libc 源代码,我看到 libc 的默认 memcpy 使用 SSE 而不是movsb.
因此,我想比较memcpy 的SSE 指令和rep movsb之间的性能。但是现在,我发现它有些不对劲。
#include <stdio.h>
#include <string.h>
inline static void *my_memcpy(
register void *dest,
register const void *src,
register size_t n
) {
__asm__ volatile(
"mov %0, %%rdi;"
"mov %1, …Run Code Online (Sandbox Code Playgroud) 某些使用goto限定符的扩展汇编语句无法使用 GCC 10.1.0 进行编译。具体来说,
int foo(int count)
{
asm goto ("dec %0; jb %l[stop]"
: "+r" (count)
:
:
: stop);
return count;
stop:
return 0;
}
Run Code Online (Sandbox Code Playgroud)
(这是GCC 扩展 asm 文档中的一个示例)无法使用消息编译expected ‘:’ before string constant。删除"+r" (count)和dec %0允许它成功编译,但无论我在何时尝试在与 goto 标签相同的 asm 语句中提供输出操作数时,它都会以同样的方式出错。
如何asm()在cython中调用C语言的内联汇编函数?我尝试了一个简单的asm("mov $eax, 0x1") or __asm__(). 它 cythonizes 很好,直到asm-call,然后给我以下错误:
NameError:名称“asm”未定义
我将我的代码编译为python setup.py build_ext --inplace && python runids.py
我试图准确理解谷歌的DoNotOptimize()运作方式。
为了完整起见,以下是它的定义(对于 clang 和非常量数据):
template <class Tp>
inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) {
asm volatile("" : "+r,m"(value) : : "memory");
}
Run Code Online (Sandbox Code Playgroud)
据我了解,我们可以在如下代码中使用它:
start_time = time();
bench_output = run_bench(bench_inputs);
result = time() - start_time;
Run Code Online (Sandbox Code Playgroud)
为了确保基准保持在关键部分:
start_time = time();
DoNotOptimize(bench_inputs);
bench_output = run_bench(bench_inputs);
DoNotOptimise(bench_output);
result = time() - start_time;
Run Code Online (Sandbox Code Playgroud)
具体来说,我不明白的是为什么这保证(是吗?)run_bench()不会移到上面start_time = time()。
(有人在这个评论中问过这个问题,但我不明白答案)。
据我了解,上面DoNotOptimze()做了几件事:
value进入堆栈,因为它是通过 C++ 引用传递的。您不能有指向寄存器的指针,因此它必须位于内存中。value现在位于堆栈上,因此随后破坏内存(如在 asm 约束中完成的那样)将迫使编译器假设value通过调用DoNotOptimize(value).+r,m …benchmarking inline-assembly compiler-optimization google-benchmark instruction-reordering
inline-assembly ×10
c ×8
gcc ×4
x86-64 ×3
c++ ×2
assembly ×1
atomic ×1
benchmarking ×1
cython ×1
fast-math ×1
glibc ×1
goto ×1
libc ×1
optimization ×1
sse ×1