C语言 为什么更多的x86指令比更少更快?



我已经阅读了关于x86处理器内部发生的事情大约半年了。因此,我决定尝试一下x86汇编的乐趣,为了保持简单,我只从80386指令开始。(我正在努力学习,而不是优化)

我有一款几个月前用C语言编写的游戏,所以我用汇编代码从头开始重写了位图比特化功能。我没有得到的是,循环的主要像素绘图体与C代码(这是18条指令)比我的汇编代码(这只有7条指令,我几乎100%肯定它不会跨越缓存线边界)更快。

所以我的主要问题是为什么18条指令比7条指令花的时间少?在底部,我有两个代码片段。

p。每种颜色都是8位索引。C代码:

{
for (x = 0; x < src.w; x++)
00D35712  mov         dword ptr [x],0                       // Just initial loop setup
00D35719  jmp         Renderer_DrawBitmap+174h (0D35724h)   // Just initial loop setup
00D3571B  mov         eax,dword ptr [x]  
00D3571E  add         eax,1  
00D35721  mov         dword ptr [x],eax  
00D35724  mov         eax,dword ptr [x]  
00D35727  cmp         eax,dword ptr [ebp-28h]  
00D3572A  jge         Renderer_DrawBitmap+1BCh (0D3576Ch)  
{
*dest_pixel = renderer_trans[renderer_light[*src_pixel][light]][*dest_pixel][trans];
// Start of what I consider the body
00D3572C  mov         eax,dword ptr [src_pixel]  
00D3572F  movzx       ecx,byte ptr [eax]  
00D35732  mov         edx,dword ptr [light]  
00D35735  movzx       eax,byte ptr renderer_light (0EDA650h)[edx+ecx*8]  
00D3573D  shl         eax,0Bh  
00D35740  mov         ecx,dword ptr [dest_pixel]  
00D35743  movzx       edx,byte ptr [ecx]  
00D35746  lea         eax,renderer_trans (0E5A650h)[eax+edx*8]  
00D3574D  mov         ecx,dword ptr [dest_pixel]  
00D35750  mov         edx,dword ptr [trans]  
00D35753  mov         al,byte ptr [eax+edx]  
00D35756  mov         byte ptr [ecx],al  
dest_pixel++;
00D35758  mov         eax,dword ptr [dest_pixel]  
00D3575B  add         eax,1  
00D3575E  mov         dword ptr [dest_pixel],eax  
src_pixel++;
00D35761  mov         eax,dword ptr [src_pixel]  
00D35764  add         eax,1  
00D35767  mov         dword ptr [src_pixel],eax  
// End of what I consider the body
}
00D3576A  jmp         Renderer_DrawBitmap+16Bh (0D3571Bh)  

和我写的汇编代码:(esi为源像素,edi为屏幕缓冲区,edx为光照级别,ebx为透明度级别,ecx为该行宽度)

drawing_loop:
00C55682  movzx       ax,byte ptr [esi]  
00C55686  mov         ah,byte ptr renderer_light (0DFA650h)[edx+eax*8]  
00C5568D  mov         al,byte ptr [edi]  
00C5568F  mov         al,byte ptr renderer_trans (0D7A650h)[ebx+eax*8]  
00C55696  mov         byte ptr [edi],al  
00C55698  inc         esi  
00C55699  inc         edi  
00C5569A  loop        drawing_loop (0C55682h)  
// This isn't just the body this is the full row plotting loop just like the code above there

对于上下文,像素是用LUT点亮的,透明度也是用LUT完成的。伪C代码:

//transparencyLUT[new][old][transparency level (0 = opaque, 7 = full transparency)]
//lightLUT[color][light level (0 = white, 3 = no change, 7 = full black)]
dest_pixel = transparencyLUT[lightLUT[source_pixel][light]]
[screen_pixel]
[transparency];

让我恼火的是我是如何使用与C代码几乎相同的指令,但只是更少的指令?

如果你需要更多的信息,我很乐意提供更多,我只是不希望这是一个巨大的问题。我真的很好奇,因为我对x86汇编编程有点陌生,想更多地了解我们的cpu是如何工作的。

我唯一的猜测是乱序执行引擎不喜欢我的代码,因为它所有的内存访问都移动到同一个寄存器。

并非所有指令都需要相同的时间,现代CPU实现可以并行执行(部分)某些指令(只要一个不读取前一个写入的数据并且所需单元不冲突)。最新版本会翻译"机器";指令转换成更低层次的,非常简单的指令,这些指令被安排在CPU的各个单元上尽可能并行地执行,使用大量的影子寄存器(即,一条指令可以在之后使用%eax(旧值)的一个副本中的值,另一条指令将新值写入%eax(新值)的另一个副本中,从而进一步解耦指令。他们为了表现而不择手段……

相关内容

  • 没有找到相关文章

最新更新