RISC-V Optimization Guide(笔记)

官网发表的文章地址:RISC-V Optimization Guide
B站有人做过解读视频,这篇文章也是看视频时做的笔记:视频地址

一、标量整数优化

1.1 常量的具体化

使用lui/addiw将立即数加载至寄存器,当立即数低12位的最高位为1时,需要特殊处理,提前补值0x800

具体的推导过程见:https://zhuanlan.zhihu.com/p/374235855

1.2 有效使用x0寄存器

1)将目标寄存器置0

正确做法如下:

mv x10, x0
or
li x10, 0

不要使用下面方法,因为会有一个读寄存器x10额外的开销。

xor x10, x10, x10
and x10, x10, x0
andi x10, x10, 0
sub x10, x10, x10

2)善于将x0作为指令的源操作数

x0可以折叠到任何指令中作为源操作数(有些情况还可以用作目的操作数),所以避免使用额外指令将0先加载到寄存器中。 下表列出了可以通过谨慎使用 x0 来消除临时寄存器的情况。
在这里插入图片描述

1.3 有效利用指令的立即数域

尽量将范围符合立即数域编码的常量编码到立即数域,而不是通过额外的指令加载到寄存器再使用。

比如访问一个数组,a0存放的是数组基地址,8offset。应该用:

ld t0, 8(a0)

而不是:

addi a1, a0, 8
ld t0, (a1)

这部分的扩展资料:https://www.bilibili.com/video/BV1pN411H7Y3

1.4 善于利用常量池

对64bit的立即数常量,使用常量池。如果该常量在程序中用到多次,收益则会更大。

将一个64bit的数加载至寄存器:

li a0, 0x123456789abcde1

其背后的逻辑可能是,要耗费32byte:

lui a0,0x92
addiw a0,a0,-1493
slli a0,a0,0xc
addi a0,a0,965
slli a0,a0,0xd
addi a0,a0,-1347
slli a0,a0,0xc
addi a0,a0,-543

如果我们使用常量池,常量可以在16个字节中加载,8个字节用于常量,8个字节用于加载它所需的指令。

1:
  auipc a0, %pcrel_hi(large_constant)
  ld a0, %pcrel_lo(1b)(a0)
...

.section .rodata
.p2align 3
large_constant:
  .dword 0x123456789abcde1

1.5 使用典型的mov指令

使用汇编器 MV 助记符(可转换为 ADDI rd, rs1, 0)将值从一个寄存器复制到另一个寄存器。 例如使用:

mv x10, x11

优先于以下任何指令:

or x10, x11, x0
ori x10, x11, 0
xor x10, x11, x0
xori x10, x11, 0

1.6 使用条件mov代替分支指令

处理器进行分支预测的代价是很高的,一旦分支预测错误,就需要清空流水线,重新开始读取。通过把分支指令替换成条件move是编译器的常见优化,实际上是将控制流的依赖转换成数据流的依赖。而这种转换通常会用到zicond 扩展,也就是czero.eqzczero.nez指令。

czero.eqz rd, rs1, rs2	// if rs2==0 then rd=rs1 else rd=0
czero.nez rd, rs1, rs2	// if rs2!=0 then rd=rs1 else rd=0

原始分支指令版本:

  beqz a0, 1f
  li a0, constant1
  j 2f
1:
  li a0, constant2
2:

初步优化后的指令版本:

li t2, constant1
li t3, (constant2 - constant1)
czero.nez t3, t3, a0
add a0, t3, t2

如果能确定constant112bit范围,还持续优化:

li t3, (constant2 - constant1)
czero.nez t3, t3, a0
addi a0, t3, constant1

如果没有zicond 扩展指令,还可以使用seqz和逻辑组合来达成条件move

li t2, constant1
li t3, constant2
seqz t0, a0			// if a0==0 then t0=1 else t0=0
addi t0, t0, -1		// if t0==1 then t0置为全0 else t0置为全1
xor t1, t2, t3
and t1, t1, t0
xor a0, t1, t3		// if t1是全0 then result=t3 else result=t2

1.7 代码段的Padding

分支跳转的目标或者函数地址的起始能够Padding在一个Cache行的开头地址上,对于整个跳转来说都是比较好的操作。所以在编译一个函数时,会在其结束的时候进行Padding从而占满Cache行,或者在函数的开头Padding让其位于Cache行的开头地址。

  • 函数之间对齐padding使用0 (illegal instruction)
  • 函数内部对齐padding使用Nop或C.Nop
  • 因为在函数内部的执行频率高,乱序执行情况下,流水线在遇见非法指令后可能就不执行后续指令了
  • 而控制流如果传递到函数之间,极有可能是程序出错了,非法指令反而会帮助debug

1.8 将字符数组对齐到更大的对齐单位

如果CPU不支持快速非对齐访问,那么在连续访问字符数组(元素大小8bit)时,lw/sw指令从4字节边界访问,ld/sd8字节边界访问,效率会高很多。

1.9 使用移位指令取出前导位和末尾位(leading/trailing bits)

如将x5的低12位取出:

slli  x6, x5, 20
srli x7, x6, 20

而不是:

lui x6, 1
addi x7, x6, -1
and x8, x7, x5

二、标量浮点优化

2.1 与整数优化相似的部分

  1. 尽量使用尽可能短的代码序列实现同样的功能。
  2. 加载立即数0的折叠。
  3. 内存访问对齐。

2.2 高效控制舍入模式

为什么要舍入? 因为单精度浮点数只取23位尾数(除去隐藏位),而一些运算不可避免的得到的尾数会超过23位,因此需要考虑舍入。

RISC-V的浮点计算舍入模式有两种:静态模式和动态模式。

  • 静态舍入模式:浮点指令的编码中有3位作为舍入模式域,RISC-V架构支持如下五种合法的舍入模式。除此之外,如果舍入模式编码为101或者110 ,则为非法模式;如果舍入模式编码111 ,则意味着使用动态舍入模式。
    在这里插入图片描述
    并不是所有的指令都有舍入模式,根据指令编码格式,以下的指令存在舍入模式的
    浮点运算指令:fadd fsub fmul fdiv fsqrt
    浮点乘加指令:fmadd fmsub fnmadd fnmsub
    浮点转换指令:fcvt.w.s fcvt.s.w fcvt.uw.s fcvt.s.uw
    
  • 动态舍入模式:如果使用动态舍入模式,则使用fcsr寄存器中的舍入模式域。fcsr 寄存器包含舍入模式域。不同的舍入模式编码同样如上图所示,仅支持五种合法的舍入模式。如果 fcsr 寄存器中的舍入模式域指定为非法的舍入模式,则后续浮点指令会产生非法指令异常。

浮点优化,尽可能使用静态模式:

fadd.s f10, f10, f11, rtz

而不是通过csr读写指令来设置FPCSR.FRM:

csrrwi t0, frm, 1      ; 1 = rtz
fadd.s f10, f10, f11
fsrm t0

三、向量优化

3.1 保留v0寄存器作为mask register来使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/462638.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

uniapp 利用uni-list 和 uni-load-more 组件上拉加载列表

列表的加载动作,在移动端开发中随处可见,笔者也是经常用到。今天正好有空,做一个总结,方便以后使用。uniapp 利用uni-list 和 uni-load-more 组件上拉加载列表操作步骤如下:1、资料准备 1)、uni-load-more…

【安全类书籍-3】XSS跨站脚剖析与防御

目录 内容简介 作用 下载地址 内容简介 这本书涵盖以下几点: XSS攻击原理:解释XSS是如何利用Web应用未能有效过滤用户输入的缺陷,将恶意脚本注入到网页中,当其他用户访问时被执行,实现攻击者的目的,例如窃取用户会话凭证、实施钓鱼攻击等。 XSS分类:分为存储型XSS(…

MongoDB——linux中yum命令安装及配置

一、创建mongodb-org-3.4.repo文件 vi /etc/yum.repos.d/mongodb-org-3.4.repo 将下面内容添加到创建的文件中 [mongodb-org-3.4] nameMongoDB Repository baseurlhttps://repo.mongodb.org/yum/amazon/2013.03/mongodb-org/3.4/x86_64/ gpgcheck1 enabled1 gpgkeyhttps://www…

力扣每日一题 矩阵中移动的最大次数 DP

Problem: 2684. 矩阵中移动的最大次数 复杂度 ⏰ 时间复杂度: O ( n m ) O(nm) O(nm) 🌎 空间复杂度: O ( n m ) O(nm) O(nm) Code class Solution { public int maxMoves(int[][] grid){int n grid.length;int m grid[0].length;int[][] f new int[n][m]…

sqllab第二十五A关通关笔记

知识点: 数值型注入双写绕过 oorranand这里不能用错误注入(固定错误回显信息)联合注入 测试发现跟25关好像一样,就是过滤了and or # 等东西 构造payload:id1/0 发现成功运算了,这是一个数值型的注入 构造payload:id…

MySQL基础架构

文章目录 MySQL基础架构一、连接器 - 建立连接,权限认证二、查缓存 - 提高效率三、分析器 - 做什么四、优化器 - 怎么做五、执行器 - 执行语句六、存储引擎1、存储引擎的概述2、存储引擎的对比3、存储引擎的命令4、存储引擎的选择 MySQL基础架构 大体来说&#xff…

【数据结构】二叉树OJ题(C语言实现)

✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅ ✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨ 🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿&#x1…

Ubuntu 14.04:安装 PaddleOCR 2.3

目录 一、说明 1.1 如何选择版本 1.2 查看 github 中的 PaddleOCR 版本 二、安装 2.1 安装前环境准备 2.2 下载包 2.3 解压 2.4 安装依赖库 异常处理:Read timed out. 2.5 下载推理模型:inference 2.5.1 模型存放位置 2.5.2 模型下载链接 2.5.…

云原生部署手册02:将本地应用部署至k8s集群

(一)部署集群镜像仓库 1. 集群配置 首先看一下集群配置: (base) ➜ ~ multipass ls Name State IPv4 Image master Running 192.168.64.5 Ubuntu 22.04 LTS1…

MySQL--深入理解MVCC机制原理

什么是MVCC? MVCC全称 Multi-Version Concurrency Control,即多版本并发控制,维持一个数据的多个版本,主要是为了提升数据库的并发访问性能,用更高性能的方式去处理数据库读写冲突问题,实现无锁并发。 什…

k8s之图形界面DashBoard【九】

文章目录 9. DashBoard9.1 部署Dashboard9.2 使用DashBoard 镇场 9. DashBoard 之前在kubernetes中完成的所有操作都是通过命令行工具kubectl完成的。其实,为了提供更丰富的用户体验,kubernetes还开发了一个基于web的用户界面(Dashboard&…

VMware ESXi 8.0U1d macOS Unlocker OEM BIOS 集成网卡驱动和 NVMe 驱动 (集成驱动版)

VMware ESXi 8.0U1d macOS Unlocker & OEM BIOS 集成网卡驱动和 NVMe 驱动 (集成驱动版) 发布 ESXi 8.0U1 集成驱动版,在个人电脑上运行企业级工作负载 请访问原文链接:https://sysin.org/blog/vmware-esxi-8-u1-sysin/,查看最新版。原…

Spark-Scala语言实战(2)(在IDEA中安装Scala,超详细配图)

之前的文章中,我们学习了如何在windows下下载及使用Scala,但那对一个真正想深入学习Scala的人来说,是不够的,今天我会给大家带来如何在IDEA中安装Scala。同时,希望我的文章能帮助到你,如果觉得我的文章写的…

STM32(TIM定时器中断)

理论知识 定时器定时中断 接线图 定时器工作配置步骤 定时中断和内外时钟源选择 定时器中需要使用的函数 程序实现效果: void TIM_DeInit(TIM_TypeDef* TIMx); **// 恢复定时器的缺省配置**void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef*TIM…

SwiftUI动画之几何匹配

SwiftUI动画之几何匹配 记录一下 日常开发中经常使用到的滑块功能 如何同工几何匹配快速制作点击动画 import SwiftUIstruct MatchedGeometryEffestExamle: View {let categories ["Home", "Popular", "Saved"]State var selecedTitle "…

Artemis Finance引领Metis流动性质押,并启动积分空投活动

在以太坊可扩展性解决方案中, Optimism、Arbitrum等Layer2链主要面临两个问题:欺诈/有效性证明以及去中心化排序器Sequencers。在实际的发展过程中,Optimism或Arbitrum等Layer2链仍然侧重于在欺诈证明和有效性证明方面进行努力,在…

MATLAB 矩阵

【MATLAB】(四)MATLAB在线性代数中的应用_线性代数在matlab中的应用-CSDN博客 矩阵的秩 rank rank(a) 矩阵的逆矩阵 inv inv(a) 矩阵的特征值eig和特征向量D [V,D]eig(a) 特征值 deig(a) 特征向量D [V…

【 c 语言 】指针入门

🎈个人主页:豌豆射手^ 🎉欢迎 👍点赞✍评论⭐收藏 🤗收录专栏:C语言 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步&…

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:Swiper)

滑块视图容器,提供子组件滑动轮播显示的能力。 说明: 该组件从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 子组件 可以包含子组件。 说明: 子组件类型:系统组件和自定义组…

Python基础入门 --- 4.循环语句

文章目录 Python基础入门第四章:4.1 while循环语句4.1.1 while循环的嵌套4.2 for循环语句4.2.1 range语句4.2.2 变量作用域4.2.3 for循环的嵌套应用 4.3 循环中断 continue和break Python基础入门 第四章: 4.1 while循环语句 语法结构: w…