几个基本的优化:

  1. 用iaddl代替irmovl, opl,效果显著
  2. 删去不必要的andl,效果显著
  3. 改变判断分支(大多数是正数),效果显著
  4. 实现Load Forwarding,效果显著
  5. 函数结束时使用自己的epilogue,效果一般

Unrolling相关:

  1. 通过合并相邻两个循环,把mrmovl和rmmovl拆开,效果显著
  2. 32, 16, 8, 4, 1分段处理,效果显著,我用这个方法做到过7.2左右

Jump Table

由Duff’s Device引申出来的想法,代替了我原来那个32-16-8-4-1程序。 很好用的一个技巧,配合unrolling就不需要不断比较i和len的大小了。 比如len=15的时候,只要跳转到倒数第15个复制段落,就可以挨个做下来,而不需要多余的判断。 具体的实现可以想想x86里的情况,假设几个复制段落的标签为Loop1, Loop2, …

jump: .long Loop1 .long Loop2 …

之后就只要取出jump + (len - 1) * 4处的值,然后跳到这个位置就行了。 跳的时候还有个技巧,最简单的是把这个值push到栈,然后再ret。这样的话bubble很多。

考虑到这个模拟器里代码段是不受保护的,也就是说运行的时候可以动态修改内存中的代码,于是在跳转的地方写个jmp 0,然后运行的时候动态把这个0改掉就行。

另外要注意用这个方法的时候得手动写几个nop,或者在改内存的语句和jmp语句之间加几个其他命令,因为y86模拟器是默认程序不会修改自己的代码的(p328 灰色背景部分)。

用这个方法的时候还有一些细节可以优化,就不列举了。另外不知道利用自我修改这个特点能不能做出更神奇的效果呢?

比如我还想到另一种类似的方法,让程序从头到尾运行,不跳转,而是在程序运行时动态的插入ret语句直接把程序运行流掐断。我还没试过,有兴趣的同学可以试一试。

不知道还有没有其他的优化方法,欢迎讨论~