整数加法中过多的中间存储指令

时间:2016-05-21 22:53:27

标签: c gcc assembly x86

背景: static void StartLoginForm() { Form frm = new Form(); frm.ShowDialog(); frm.Focus();//Didn't work for me frm.Activate();//Also didn't work for me } 优化级别的GCC 6.1生成此程序集:

$(document).ready(function(){
var url = window.location.href;

$('.dropdown-menu-fw li').removeClass('active');
$('.dropdown-menu-fw li a').filter(function() {
    return this.href == url;
}).parent().addClass('active');

$('.dropdown-fw').removeClass('selected open');
$('.dropdown-menu-fw li a[href="'+ url+'"]').closest(".dropdown-fw").addClass('open selected');
// $('.dropdown-menu-fw li a').parentsUntil(".dropdown-fw").addClass('open');
});

这个功能:

-O3

其中 test ecx, ecx je .L8 xor r8d, r8d xor eax, eax .L7: xor r9d, r9d add eax, DWORD PTR [rdi+r8*4] ; adding a[i] setc r9b add eax, DWORD PTR [rsi+r8*4] ; adding b[i] mov r11d, eax ; excessive mov (#1) setc r10b mov DWORD PTR [rdx+r8*4], r11d ; storing at s[i] add r8, 1 movzx r10d, r10b cmp ecx, r8d lea eax, [r10+r9] ; sorcery (#2) ja .L7 rep ret .L8: xor eax, eax ret limb_t add( const limb_t *a, const limb_t *b, limb_t *s, int n ) { limb_t c = 0, t = 0; for (int i = 0; i < n; ++i) { t = a[i] + c; c = t < a[i]; t += b[i]; c += t < b[i]; s[i] = t; } return c; } a是等长b个肢的整数,以32位单位(四肢,数字)的连续序列存储在内存中Little Endian(也就是说,第一个是最不重要的肢体)。

此函数会添加两个非负加数sn,将总和存储在a中,并返回进位b。临时变量s保存当前的sum limb,并启用ct场景。

正如我从集会中推断的那样,

  • a == s寄存器包含b == s addend的基地址,
  • rdi寄存器包含a addend的基地址,
  • rsi寄存器保存基地址b,总和,
  • rdx注册了s,随身携带和eax,临时,
  • 的帐户
  • c注册保留t,循环计数器,
  • r8注册保留i,加数和总和的长度。

我的第一个问题是:

1。为什么ecx寄存器中的n寄存器值的中间存储在将其移动到存储器eax(当前的总和)之前会发生?

我没有看到r11d寄存器的任何其他用法,但对于这种过度的存储操作;并且[rdx + r8*4]指令实际上允许从r11寄存器移动,为什么不从那里移动值?

我的第二个问题是:

2。这个带有mov指令和携带值的巫术是什么?

eax

实际计算的是什么? lea = lea eax, [r10+r9] ; sorcery (#2) + lea?并且,在这种情况下,为什么我们必须使用此r10指令清除每个循环迭代的高位r9

r10

1 个答案:

答案 0 :(得分:2)

第一个似乎是“错过优化”的编译器错误。

第二个需要为c生成t = a[i] + c;大小dword,并且通过使用不同的方法扩展两个逻辑值来实现这一点,这些方法无疑是奇怪的:

t < a[i];xor r9d, r9dsetc r9b执行,但t < b[i]setc r10bmovzx r10d, r10b对执行。它并不是很明显,但这可能有合理的指令调度原因。

添加两个逻辑值是由lea eax, [r10+r9]完成的,而add代替cmp有两个原因。首先,它不会影响标志,因此可以在jawhitep.slice(minIndex, minIndex+nbWords)之间插入标记。其次,它可以在第三个寄存器中产生输出。

另一种可能性是首先添加两个逻辑值,只扩展结果。不确定这是否是更好的方法。此外,一个临时登记就足够了。