我现在正在尝试下面的事情:
global func_
func_:
push rbp
mov rbp, rsp
mov rax,[rdi]
mov rbx,[rsi]
cmp rbx,1
je done
dec rbx
mov rsi,1
loop1:
shl rsi, 1
dec rbx
jnz loop1
or rax,rsi
mov [rdi],rax
mov rcx,15
mov rax,11
movq xmm1,rcx
movq xmm0, rax
xorpd xmm0, xmm1
movq rax, xmm0
mov [rdi],rax
mov rsp, rbp
pop rbp
ret
done:
or rax,1
mov [rdi],rax
mov rsp, rbp
pop rbp
ret
到目前为止,代码实际上没有意义,我将需要使用XMM [](128位按位操作),这个汇编代码应该编译成一个对象并链接到Fortran代码,我将:
! Compile:
!gfortran -c testassembly.F90;
!nasm -f elf64 assembly_func.asm;
!gfortran -o run testassembly.o assembly_func.o;
!./run
a = 10
b = 4
call func(a,b)
到目前为止,一切都很清楚,现在如果我为此会发生什么。 OpenMP平行化我的代码,即:
!$omp do schedule(dynamic,1)
a = 10
b = 4
call func(a,b)
!$omp end do
换句话说,汇编中的寄存器是否存在物理存在?或者它们将以某种方式在OpenMP线程本地?如果他们被分享,竞争条件和类似的东西怎么样?
我希望我足够清楚。
答案 0 :(得分:3)
每个线程都有自己的一组寄存器。当线程在不同的内核上执行时,这是显而易见的,因为每个内核都包含一整套寄存器。当多个线程分时共享同一个物理内核时,当执行切换到另一个线程时会保存用户可见寄存器的状态,然后在执行切换回原始线程时进行恢复(上下文保存/恢复),从而给出了每个线程专门在寄存器上运行的错觉。
至于那些寄存器的物理存在,现代的x86 CPU在它们的核心中没有称为RAX,RBX等的固定单元。它们借用旧的RISC概念,而它们所拥有的是大量的寄存器寄存器文件(实际上,现代x86 CPU基本上是RISC内核,每个CISC指令被分成一组简单的操作,称为微操作的核心)。该文件中的每个寄存器都可以通过称为寄存器重命名的过程充当RAX。例如,这允许独立指令并行执行,即使它们使用相同的寄存器,例如
mov [rdi], rax
xor rax, rax
在这种情况下,第二条指令对第一条指令没有数据依赖性,因为rax
的内容只是被覆盖。但是如果有一个RAX寄存器,则CPU必须首先完成第一条指令的写入到存储器级,然后第二条指令才能使用RAX。通过寄存器重命名,第二条指令只是从文件写入另一个寄存器,从那时起用作RAX。