gpt4 book ai didi

assembly - 条件分支的失败侧是否更有效?将其作为错误处理端是个好主意吗?

转载 作者:行者123 更新时间:2023-12-03 04:59:20 26 4
gpt4 key购买 nike

考虑一个调用另一个函数并检查错误的函数。假设函数 CheckError() 在失败时返回 0,其他数字表示成功。

第一个版本:成功分支或失败到错误处理代码(位于函数中间)。

    CALL   CheckError
TEST EAX,EAX ;check if return value is 0
JNZ Normal
ErrorProcessing:
... ;some error processing code here
Normal:
... ;some usual code here

第二个版本因错误而采取分支,或者落入正常路径。错误处理代码位于函数末尾。

    CALL   CheckError
TEST EAX,EAX
JZ ErrorProcessing
Normal:
... ;some usual code here
ErrorProcessing:
... ;some error processing code here
<小时/>

这两种方法哪一种更好?为什么?

我个人认为第一个代码具有更好的代码结构(更具可读性和可编程性),因为代码很紧凑。然而,我也认为第二个代码通常具有更好的速度(在无错误的情况下),因为未采取的条件跳转需要 2-3 个时钟周期(也许我在这里太挑剔)比采取的要少。

无论如何,我发现我测试的所有编译器在编译 if 语句时都使用第一个模型。例如:

if (GetActiveWindow() == NULL)
{
printf("Error: can't get window's handle.\n");
return -1;
}
printf("Succeed.\n");
return 0;

这应该编译为(没有任何 exe 入口例程):

    CALL [GetActiveWindow]    ;if (GetActiveWindow() == NULL)
TEST EAX,EAX
JNZ CodeSucceed
;printf("Error.......\n"); return -1
PUSH OFFSET "Error.........\n"
CALL [Printf]
ADD ESP,4
OR EAX,0FFFFFFFFH
JMP Exit

CodeSucceed: ;printf("Succeed.\n"); return 0
PUSH OFFSET "Succeed.\n"
CALL [Printf]
ADD ESP,4
XOR EAX,EAX
Exit:
RETN

最佳答案

就条件跳转本身的循环计数而言,您构建代码的方式绝对没有区别。唯一重要的是分支是否被正确预测。如果是,则分支成本个周期。如果不是,分支将花费数十甚至数百个周期。硬件中的预测逻辑并不取决于代码的结构方式,你基本上无法控制它(CPU 设计者尝试过“提示”,但结果证明是净损失)(但请参阅“Why is it faster to process a sorted array than an unsorted array?”) “了解高级算法决策如何产生巨大差异)。

但是,还有另一个因素需要考虑:“热度”。如果“错误处理”代码几乎永远不会被实际使用,那么最好将其移出行外 - 方式移出行,到可执行镜像的自己的子部分 - 这样它就不会浪费 I-cache 中的空间。做出关于何时执行此操作的准确决定是 profile-guided optimization 最有值(value)的好处之一 - 我想仅次于决定每个功能甚至每个基本 block 是否优化空间或速度。

只有当您将其作为学习练习或实现一些无法实现的东西时,在手动编写汇编时,可读性才应该是首要考虑的问题更高级的语言(例如上下文切换的核心)。如果您这样做是因为需要从关键的内部循环中挤出循环,并且它不会变得不可读,那么您可能需要进行更多的循环压缩。

关于assembly - 条件分支的失败侧是否更有效?将其作为错误处理端是个好主意吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39091120/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com