当我在挖掘原始的Xbox内核代码时,我注意到有时当它为端口I / O设置寄存器时,它会为edx
分配一个32位值,即使in
和out
指令仅将edx
的低16位用作端口地址。举个例子:
mov edx, 0FFFF8004h
in ax, dx
or ax, 1
out dx, ax
add edx, 1Eh
in ax, dx
or ax, 2
out dx, ax
mov edx, 0FFFF8002h
...
在其他地方(例如SMBus读写),它不一致;有时它会将16位值分配给dx
,有时将32位值分配给edx
。
如果从不使用高16位,那么为它们指定非零位是什么意思?
答案 0 :(得分:2)
我的猜测是作为微优化完成,以避免不存在的危险和/或不显着的性能损失。
例如,程序员最初可能写了类似的东西:
66| BA 8004 mov dx, 8004h
66| ED in ax, dx
66| 83 C8 01 or ax, 1
66| EF out dx, ax
66| 83 C2 1E add dx, 1Eh
然后他决定用add dx
替换add edx
以保存字节并消除解码操作数大小前缀的性能损失:
66| BA 8004 mov dx, 8004h
66| ED in ax, dx
66| 83 C8 01 or ax, 1
66| EF out dx, ax
83 C2 1E add edx, 1Eh
然后他在当代的英特尔优化手册中读到了这一点:
因为Pentium II和Pentium III处理器可以执行代码 顺序,指令不需要立即相邻的摊位 发生。例2-7还包含部分停顿。
示例2-7 Pentium II和Pentium III处理器的部分寄存器停顿
MOV AL, 8 MOV EDX, 0x40 MOV EDI, new_value ADD EDX, EAX ; Partial stall accessing EAX
他自己的代码现在看起来很相似,因此他通过将16位MOV
指令替换为您在示例中看到的32位指令来避免部分寄存器停顿。 (实际上,我认为ADD
指令不会停止,IN
和OUT
指令应该给MOV
指令足够的时间退休。)
是的,这些微观优化将毫无意义。即使它们确实节省了一两个CPU周期,与执行I / O指令所需的时间相比,性能增益也是微不足道的。但看到微软员工这样做并不奇怪。我在微软代码中看到了比这更糟糕的东西,至少在90年代他们似乎对微优化非常着迷。
您看到的不一致也不足为奇。微软本可以让许多不同的程序员在Xbox内核上工作,并且可以轻松地从Windows或其他项目中包含代码。