1
6
我的尝试。。。在这里举行的演示派对上,我的音乐创作让我头痛(或者更可能是在这里旅行),所以我放弃了
所以我选择了回避,只复制2个16位的单词,然后以Jester的方式进行了重组(我几乎要发布
稍短一点的(指令计数)变体(使用
|
2
5
必须有一个更简单的方法:-D
|
3
5
如果不按要求触摸第二个寄存器,很难有效地执行此操作
. 注释中唯一不会影响性能的建议是使用64位常量
这在Intel Sandybridge系列CPU和AMD Ryzen上具有1个时钟吞吐量(和3个周期延迟)。但在推土机家族中,每4个时钟只有一个。( http://agner.org/optimize/ , https://uops.info/ )
你不能这样做
生成x86-64机器代码的完全自包含片段的另一种方法是,将常量与指令内联并跳过它,而不引用外部常量(例如,对于外壳代码,或者因为您不希望该常量在缓存中处于热状态)。
从正确性角度来看,这与使用立即数的指令没有区别。NASM列表:
它确实会从与代码相同的页面加载数据,但在页面表设置下,不可能使页面可执行但不可读,因此在纯指令可以工作的情况下,这是不可能失败的。不过,它将耗尽L1D缓存中的缓存线和dTLB项,以及L1i缓存和iTLB项。如果条目仅在iTLB中是热的,它甚至可能在dTLB中丢失,并且可能在L1d缓存中丢失(但可能在L2缓存中命中;大多数CPU都有一些非独占的统一缓存,可以通过这些缓存进行指令提取。请参阅 this 更多关于性能的信息—混合代码和数据的好处不足。) 存储/重新加载:紧凑但延迟高Jester在“2个商店/1个换货”评论中的建议很紧凑,但会导致 store-forwarding stall on all CPUs except in-order Atom (Silvermont之前):
这可能是
最小总尺寸版本
,尤其是如果您有一个堆栈框架,可以使用
标准方式更快,使用第二个寄存器
(其他标准方式为
避免这样做可能是值得的 确切地 如果性能重要,请回答您的问题。 E、 g.保存/恢复其他15个通用寄存器中的一个,无论您在做什么,都可以将其用作临时寄存器。理想的情况是围绕整个函数,因此可以使用scratch reg在循环内进行广播。或者直接重击而不先保存,如果你可以快速重新加载或重放的话。
这有2个周期的延迟(对于rax),即使没有mov消除。我们将原始RAX与复制(零扩展)并行地转移到RBX中。如果EAX已经过零扩展,那么如果您正在为消除mov的CPU进行优化,则可以在RBX中移动拷贝: Intel's implementation 覆盖mov目标时释放mov消除跟踪资源。但如果不消除mov,CPU的延迟会更高,从而将mov置于关键路径上。(冰湖的微码更新禁用mov消除。/叹气。) 推送/弹出在RBX的关键路径中引入了存储/重新加载功能,因此,如果您确实必须在每次广播中都这样做,请明智地选择scratch reg,而不是为整个循环或功能释放一个额外的寄存器。
或BMI2,
或者使用SSE2(x86-64的基线)。如果首先可以使用xmm0而不是rax:
大多数CPU上的1个周期延迟(SlowShuffle Core2/K8除外,您可以使用
如果您这样做的话,将RAX复制到XMM0或从XMM0复制RAX的成本将是最大的,比如4到6个周期的往返,具体取决于微体系结构,再加上无序排列。(例如uops信息 Zen2 latency tests include a movd/movq round trip measured at 6 cycles ). 这将重击xmm0,这可能没问题,也可能没问题。
但是,如果您在整数值的整个过程中都使用xmm0,则可以避免这一成本。您可以在xmm寄存器中进行标量整数计算(忽略上层字节的情况)。说明如下
|
Ilya Loskutov · 无法将单词加载到寄存器中 2 年前 |
Ari157 · x86_64 Linux程序集中的逻辑与实现 2 年前 |
Arya · 汇编语言中的“标签”——操作码 2 年前 |
S1mple · 通过gcc生成64位共享库时的“未定义的主引用” 2 年前 |
R0M2 · 为什么“GCC”忽略汇编代码的-fno pic 2 年前 |
Akagi Akira · 如何在gnu汇编程序中组装MIPS cpu 2 年前 |