- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我进行了一个简单的实验,将 if-else 与仅 if(具有预设的默认值)进行比较。示例:
void test0(char c, int *x) {
*x = 0;
if (c == 99) {
*x = 15;
}
}
void test1(char c, int *x) {
if (c == 99) {
*x = 15;
} else {
*x = 0;
}
}
cmovne
)。
void test2(char c, int *x, int *y) {
*x = 0;
*y = 0;
if (c == 99) {
*x = 15;
*y = 21;
}
}
void test3(char c, int *x, int *y) {
if (c == 99) {
*x = 15;
*y = 21;
} else {
*x = 0;
*y = 0;
}
}
test2(char, int*, int*):
cmp dil, 99
mov DWORD PTR [rsi], 0
mov DWORD PTR [rdx], 0
je .L10
rep ret
.L10:
mov DWORD PTR [rsi], 15
mov DWORD PTR [rdx], 21
ret
test3(char, int*, int*):
cmp dil, 99
je .L14
mov DWORD PTR [rsi], 0
mov DWORD PTR [rdx], 0
ret
.L14:
mov DWORD PTR [rsi], 15
mov DWORD PTR [rdx], 21
ret
mov
s 在
je
之前或之后完成.
mov
不是总是更好吗? s 跳转后,为了节省管道刷新?如果是这样,为什么优化器(gcc6.2 -O3)不使用更好的方法?
最佳答案
For the functions above, I got the exact same assembly code (using cmovne).
test0 PROC
cmp BYTE PTR [c], 99
mov eax, DWORD PTR [x]
mov DWORD PTR [eax], 0
jne SHORT LN2
mov DWORD PTR [eax], 15
LN2:
ret 0
test0 ENDP
test1 PROC
mov eax, DWORD PTR [x]
xor ecx, ecx
cmp BYTE PTR [c], 99
setne cl
dec ecx
and ecx, 15
mov DWORD PTR [eax], ecx
ret 0
test1 ENDP
test1
为您提供利用
SETNE
的无分支代码指令(一个条件集,它将根据条件代码将其操作数设置为 0 或 1 - 在本例中为
NE
)结合一些位操作以产生正确的值。
test0
使用条件分支跳过将 15 赋值给
*x
.
test0
将是您握住优化器的手并让它生成无分支代码的方式。至少,这是我脑海中闪过的第一个念头。但事实上,事实并非如此!优化器能够识别
if
/
else
成语并相应优化!在
test0
的情况下无法进行相同的优化,你试图超越它。
However when adding an extra variable ... The assembly suddenly becomes different
test3
所做的。 (但不适用于
test2
,与我们上面的分析一致,表明优化器可能比不寻常的更能识别标准模式)。但是 GCC 不会这样做。同样,不能保证执行特定的优化。
It seems that the only difference is if the top "mov"s are done before or after the "je".
Now (sorry my assembly is a bit crude), isn't it always better to have the movs after the jump, in order to save pipeline flushes?
ret
并不重要指令或者它是
mov
指令。
ret
紧跟在条件分支之后的指令是如果您正在手工编写汇编代码并且不知道使用
rep ret
指令。这是
a trick necessary for certain AMD processors that avoids a branch-prediction penalty .除非您是 assembly 专家,否则您可能不会知道这个技巧。但是编译器可以,并且也知道当您专门针对没有这种怪癖的 Intel 处理器或不同代的 AMD 处理器时,没有必要这样做。
mov
更好。 s 在分支之后,但不是因为您建议的原因。现代处理器(我相信这是 Nehalem 和更高版本,但如果我需要验证,我会在
Agner Fog's excellent optimization guides 中查找)在某些情况下能够进行宏操作融合。基本上,宏操作融合意味着 CPU 的解码器将两个符合条件的指令合并为一个微操作,从而节省流水线所有阶段的带宽。一个
cmp
或
test
指令后跟条件分支指令,如您在
test3
中看到的, 有资格进行宏操作融合(实际上,还有其他条件必须满足,但此代码确实满足这些要求)。在
cmp
之间调度其他指令和
je
,正如您在
test2
中看到的那样, 使宏操作融合成为不可能,可能使代码执行得更慢。
mov
放置
je
的说明紧接在
cmp
之后,保留宏操作融合的能力:
test2a(char, int*, int*):
mov DWORD PTR [rsi], 0 ; do the default initialization *first*
mov DWORD PTR [rdx], 0
cmp dil, 99 ; this is now followed immediately by the conditional
je .L10 ; branch, making macro-op fusion possible
rep ret
.L10:
mov DWORD PTR [rsi], 15
mov DWORD PTR [rdx], 21
ret
test2
的目标代码之间的另一个区别和
test3
是代码大小。感谢优化器发出的用于对齐分支目标的填充,
test3
的代码比
test2
大 4 个字节.然而,这不太可能是足够重要的差异,特别是如果这段代码不是在一个紧密循环中执行的,它保证在缓存中很热。
test2
中所做的那样编写代码? ?
c
的情况下,您要两次写入内存。等于 99,在 c
的情况下不节省不等于 99。test2b(char, int*, int*):
xor eax, eax ; pre-zero the EAX register
xor ecx, ecx ; pre-zero the ECX register
cmp dil, 99
je Done
mov eax, 15 ; change the value in EAX if necessary
mov ecx, 21 ; change the value in ECX if necessary
Done:
mov DWORD PTR [rsi], eax ; store our final temp values to memory
mov DWORD PTR [rdx], ecx
ret
eax
和 ecx
)并且实际上可能不会更快。你必须对它进行基准测试。或者相信编译器会在实际最佳时发出此代码,例如当它内联了像 test2
这样的函数时。在一个紧密的循环内。 c
每次调用该函数时,都会在 99 和非 99 之间快速来回交替。 (参见 Agner Fog's "Optimizing subroutines in assembly language",第 70-71 页。)关于c++ - if else 比 if + default 快吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41359023/
自从我开始工作(约 6 年)以来,我一直是 .NET 的一员。最近在做一个使用Django的项目,需要并行学习Python。很多时候我碰到的 Python 代码看起来很简单,但我就是看不懂。这是其中之
谁能解释一下 JLS §8.4.8.4 中提到的“严格的default-abstract 和default-default 冲突规则” . 它们是否在 JLS 中定义?我似乎找不到他们的定义。 最佳答
我在我的启动图像通用项目中添加了“Default.png,Default-568h@2x.png,Default@2x.png”这三个文件,我有三个不同的图像,分辨率与苹果中提到的完全相同文档,适用于
我试图在删除 AWS RDS MySQL 数据库后删除默认的数据库参数组,但出现以下错误 Failed to delete default.mysql8.0: Default DBParameterG
我想使用 firebase 云函数发送通知,所以我尝试使用 firebase.messaging().getToken() 获取 token ,但我不断收到错误消息: TypeError: fireb
无法通过 Instagram 登录我的应用。我正在使用 react-native instagram 包,但我面临这个问题,因为 _react3.default.creteRef() 不是一个函数。引
从 Rust 1.6 开始,当前特征 Default定义为, pub trait Default { fn default() -> Self; } 为什么不是这个 pub trait Def
在我的第一次代码审查(不久前)中,我被告知在所有 switch 语句中包含默认子句是一种很好的做法。我最近想起了这个建议,但不记得其理由是什么。现在对我来说听起来很奇怪。 始终包含默认语句是否有合理的
这个错误很奇怪。在 firebase 中 react native 有什么问题我已经通过 npm install 安装了 firebase这是我的代码 import React, {Component
对于以下 3 种编译情况: gcc -o helloc hello.c (1) g++ -o hellocpp hello.cpp
我有一个 switch 语句。它几乎可以正常工作,但是它不仅显示一个案例,还显示选定的案例,然后显示默认案例。这是我的代码: var people = { names: ["Sam", "Tim"
这个问题在这里已经有了答案: Default keyword in Swift parameter (1 个回答) 关闭 6 年前。 我试图理解前置条件函数并遇到了“= default”。快速谷歌和
禁止!配置的服务帐户无权访问。服务帐户可能已被撤销。用户“system:serviceaccount:default:default”无法获取命名空间“mycomp-services-process”
我一直在我的 React 中广泛使用命名导出和默认导出,我遇到了这 2 个相似的语法。 从'./Button'导出默认值; export { default } from './Button'; 有人
我很困惑什么时候使用 .prototype 来扩展一个对象,什么时候不使用它。像下面的部分代码,为什么不在FacebookApi.defaults中使用.prototype,难道.prototype只
这个问题在这里已经有了答案: What is the difference between "var=${var:-word}" and "var=${var:=word}"? (4 个答案) 关闭
我想创建一个数据类基类,其中子类中的所有字段都自动可选且默认为无(如果未提供默认值)。 下面的代码……几乎可以满足我的要求,但又不完全是。它出错的方式就像我从未编写过 __init_subclass_
所以我有三个 Typescript 文件: 配置/env/development.ts import { Config } from '../config'; class DevConfig {
我在一个名为 Activity 的表中添加了一个名为 Ordinal 的新列。问题是我给了它一个 UNIQUE 约束,将它设置为允许 NULL(尽管我最终不会想要这个。我只需要将它设置为那个以使脚本更
嗨,我是 struts2 的新手,在我的项目中,我在注册页面使用 json-default 扩展,并使用validation.xml 文件验证它,在同一个项目中,我在登录页面使用 struts-def
我是一名优秀的程序员,十分优秀!