在 C++ 中使用 uint64_t 的上半部分的指令/内在?

如何解决在 C++ 中使用 uint64_t 的上半部分的指令/内在?

想象以下代码:

Try it online!

uint64_t x = 0x81C6E3292A71F955ULL;
uint32_t y = (uint32_t) (x >> 32);

y 接收 64 位整数的较高 32 位部分。我的问题是是否有任何内在函数或任何 CPU 指令可以在不进行移动和移位的情况下在单个操作中执行此操作?

至少 CLang(在上面的 Try-it-online 中链接)为此创建了两条指令 mov rax,rdishr rax,32,所以要么 CLang 不做这样的优化,要么不存在这样的特殊指令.

如果存在像 movhi dst_reg,src_reg 这样的假想单指令就好了。

解决方法

如果有更好的方法来对任意 uint64_t 进行位域提取,编译器就会使用它。 (至少在理论上;编译器确实错过了优化,他们的选择有时会偏向延迟,即使它会花费更多的 uops。)

对于无法用纯 C 语言以编译器已经很容易理解的方式有效表达的内容,您只需要内在函数。(或者如果您的编译器很笨,无法发现明显的.)

您可以想象输入值来自两个 32 位值相乘的情况,那么在某些 CPU 上编译器使用加宽 mul r32 已经生成两个独立的结果可能是值得的32 位寄存器,而不是 imul r64,r64 + shr reg,32,如果它可以轻松使用 EAX/EDX。但除了 gcc -mtune=silvermont 或其他调整选项,您不能编译器那样做。


shr reg,32 具有 1 个周期延迟,并且可以在大多数现代 x86 微体系结构 (https://uops.info/) 上的 1 个以上执行端口上运行。唯一可能希望的是它可以将结果放在不同的寄存器中,而不会覆盖输入。

大多数现代非 x86 ISA 都类似于具有 3 操作数指令的 RISC,因此移位指令可以复制和移位,这与编译器需要 mov 的 x86 移位不同除了 shr 如果以后还需要原始 64 位值,或者(对于小函数)需要不同寄存器中的返回值。

有些 ISA 具有位域提取指令。 PowerPC 甚至有一个有趣的旋转和掩码指令 (rlwinm)(掩码是由立即数指定的位范围),它与普通移位指令不同。编译器将根据需要使用它 - 不需要内在函数。 https://devblogs.microsoft.com/oldnewthing/20180810-00/?p=99465


x86 使用 BMI2 has rorx rax,rdi,32 进行复制和旋转,而不是在同一寄存器内卡住移位。在不内联的独立版本中,返回 uint32_t 的函数可以/应该使用它而不是 mov+shr,因为调用者已经不得不忽略 RAX 中的高垃圾。 (x86-64 System V 和 Windows x64 都将返回值定义为仅与 arg 的 C 类型匹配的寄存器宽度;例如,返回 uint32_t 表示 RAX 的高 32 位 不是 返回值的一部分,并且可以保存任何东西。通常它们为零,因为写入 32 位寄存器隐式地将零扩展到 64,但是像 return bar() 之类的东西 bar 返回 uint64_t 可以让 RAX 保持不变而无需截断它;实际上优化的尾调用是可能的。)

rorx 没有内在函数;编译器应该知道什么时候使用它。 (但是 gcc/clang -O3 -march=haswell 错过了这个优化。)https://godbolt.org/z/ozjhcc8Te

如果编译器在循环中执行此操作,则它可以将 32 放在 shrx reg,reg,reg 的寄存器中作为复制和移位。或者更愚蠢的是,它可以使用 pext0xffffffffULL << 32 作为掩码。但这比 shrx 更糟糕,因为延迟更高。

AMD TBM(仅限推土机系列,非 Zen)具有直接形式的 bextr(位域提取),并且它以 1 uop (https://agner.org/optimize/) 高效运行。 https://godbolt.org/z/bn3rfxzch 显示 gcc11 -O3 -march=bdver4(挖掘机)使用 bextr rax,0x2020,而 clang 错过了该优化。 gcc -march=znver1 使用 mov + shr,因为 Zen 删除了尾随位操作以及 XOP 扩展。

Standard BMI1 bextr 需要寄存器中的位置/长度,在 Intel CPU 上是 2 uop,因此它是垃圾。它确实有一个内在的,但我建议不要使用它。 mov+shr 在 Intel CPU 上速度更快。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res