LLVM 后端执行流程

异构计算程序工作流程

在这里插入图片描述

图4-1中的LLVM后端的主要功能是代码生成,其中包括若干指令生成分析转换pass,将LLVM IR 转换为特定目标架构的机器代码

LLVM 流水线结构

在这里插入图片描述

输入指令经过图4-2中的各个阶段,从最初的LLVM IR,逐步演化为SelectionDAG、MachineDAG、MachineInstr,最后由MCInst 输出可执行的二进制代码或汇编代码

这其中经过的各个阶段是不同的分析转换pass,主要包括指令选择(Instrunction Selection)、指令调度(Instrunction Scheduling), 寄存器分配(Register Allocation)、以及代码发射(Code Emission)

不同目标后端应根据实际需要,对不同pass做定制化。指令选择、指令调度和寄存器分配是后端流程中最重要的3个组成部分

LLVM 后端执行流程

SelectionDAG 的创建

首先,SelectionDAGBuilder 模块遍历LLVM IR中每一函数,以及函数中的每一个基本块,并将其中的指令转换成SDNode对象,整个基本块相应地转换为Selection DAG 对象。SelectDAG 对象的创建过程采用窥孔优化算法,DAG中每个节点的内容仍是LLVM IR指令

在这里插入图片描述

图4-3以一个C/C++语言实现的函数为例,显示了LLVM IR 与 SelectionDAG的对应关系

图4-3的LLVM IR 中只有一个基本块。当SelectionDAGBuilder模块检测到IR指令时,调用相应的visit()函数

例如,如果IR指令为sdiv操作,则调用visitSDIV() 函数,将两个操作数保存为SD-Vaule对象,并从DAG中获取SDNode节点,以ISD::SDIV作为操作符

  • 在图4-3所示的sdiv节点中,操作数0为%add,操作数1为%c

用类似的方法处理完所有IR指令后,IR被转换为如图4-3所示的SelectionDAG。每个DAG表示一个基本块中的计算,不同的基本块与不同的DAG关联

DAG中的节点表示计算,节点之间的边可以有不同的含义。DAG中的每个SDNode节点会维护一个记录,其中保存了本节点对其他节点的各种依赖关系

这些依赖关系可能是数据依赖(本节点使用了其他节点定义的值),也可能是控制流依赖(本节点的指令必须在其他节点的指令执行后才能执行)

这种依赖关系通过SDValue对象表示,SDValue对象中封装了指向关联节点的指针和被影响结果的的序列号。也可以说,DAG中的操作顺序通过DAG边的使用-定值关系确定

例如,图4-3中的sdiv节点中有一条输出边连接到add节点,这意味着add节点定义了一个会被sdive中使用的值

因此,add操作必须在sdiv节点之前执行。SelectionDAG中的节点依赖关系可总结为如下三类

  • 黑色箭头表述数据流依赖。数据流依赖表示当前节点依赖前一节点的结果。DAG中大部分节点依赖关系是数据流依赖
  • 虚线彩色箭头表示非数据流链依赖。链依赖可以防止副作用节点,确定两个不相关指令的顺序。例如,如果加载和保存指令访问的是相同的内存位置,就必须确保它们的执行顺序与其在原程序中的顺序一致。图中的CopyToReg节点操作必须在RET_FLAG节点之前发生,因为它们之间是链依赖
  • 彩色箭头表示粘合(glue)依赖。粘合依赖是用来防止两个指令调度后被分开,即它们中间不能插入其他指令

将IR转换为DAG很重要,因为可以让代码生成器使用基于树的模式匹配指令选择算法。此时的SelectionDAG与目标设备无关,但对于具体目标设备而言,DAG中有些指令可能不合法。因为不同目标设备支持的指令集不同,指令集中的指令IR指令可能没有对应关系

  • 例如,x86不支持sdiv而是支持sdivrem

合法化

由SelectionDAGBuilder 模块输出的SelectionDAG 不是机器指令,不能做指令选择。在生成机器指令之前,DAG节点还要经过几个转换阶段,其中合法化(legalization)是最重要的阶段

执行合法化的原因是SelectionDAGBuilder 模块构造SDNode节点中的指令操作数类型和操作不一定能被目标平台支持。因此,SDNode节点的合法化及操作数类型的合法化和操作的合法化

目标平台一般不可能为IR中的所有操作提供指令支持。因此,操作合法化的目的是将这些平台不支持的操作三种方式转换成平台支持的操作

    1. 扩展(Expansion): 即用一组操作来模拟一个操作
    1. 提升(Promotion): 即将数据转换成更大的类型来支持操作
    1. 定制(Custom): 即通过目标平台相关的钩子程序(hook) 实现合法化

例如,LLVM IR 的sdiv只计算商,而x86除法指令计算得到商和余数,并分别保存在两个寄存器中。因为指令选择可区分sdivrem和sdiv,因此,当目标平台不支持sdiv时,需要在合法化阶段将sdiv扩展到sdivrem指令

在这里插入图片描述

目标平台相关信息可通过TargetLowering接口传递给SelectionDAG,如图4-4所示

LLVM后端会实现该接口,并描述如何将LLVM IR指令用合法的SelectionDAG操作实现。例如,x86的TargetLowering构造合法函数通过Expand标志来标识需要扩展的节点

当SelectionDAGLegalize::LegalizeOp()方法检测到sdiv节点的Expand标志时,便可用sdivrem替换sdiv节点

与此类似,与目标平台相关的合并方法可识别节点组合模式,并决定是否合并某些节点组合以提高指令选择质量

类型合法化的目的是保证后续的指令选择处理的数据类型都合法。合法数据是目标平台原生支持的数据类型,目标平台的td文件中会为每一种数据类型定义关联的寄存器类如:

def FPRegs : RegisterClass<"SP", [f32], 32, (sequence "F%u", 0, 31)>
def DFPRegs : RegisterClass<"SP", [f64], 64, (add D0, D1, D2, D3, D4, D5, D6, D7, D8, D9)>

FPRegs 寄存器类定义了一组32个从F0~F31单精度浮点类型的寄存器,DFPRegs 寄存器类定义了一组16个从D0~D15双精度浮点类型的寄存器

如果平台的td文件的寄存器类没有定义相应的数据类型,则对平台来说,该数据类型就是非法数据类型。非法数据类型必须被删除,或者视非法数据类型不同,做相应处理

如果非法数据类型为标量,则可以将较小的非法类型转换为较大的合法类型。例如,平台只支持i32,那么i1/i8/i16都要提升到i32,使其合法化

或者将较大的非法类型拆分成多个小的合法类型。例如,如果目标平台只支持i32,那么加法的i64操作数就是非法类型。在这种情况下,可通过整数扩展(integer expansion),将i64操作数分解成两个i32操作数,并产生相应的节点,使其合法化

如果非法数据类型为矢量,则可以将大的非法矢量操作拆分成多个,可以被平台支持的,小的矢量。或者将非法矢量操作数标量化(scalarizing),即在不支持SIMD的平台上,将矢量拆分为多个标量进行运算

指令选择

SelectionDAG 对象经过合法化和其他优化处理,DAG中的节点被映射为目标指令,这个映射过程称为指令选择

指令选择是LLVM后端中的一个重要阶段。这个阶段的输入是经过合法化的SelectionDAG。从耗时方面来说,指令选择占用了后端编译总耗时的一半。指令选择通过节点模式匹配完成DAG到DAG的转换,将SelectionDAG 节点转换为目标指令节点,也就是将LLVM IR指令转换为机器指令,所以转换后的DAG又称为machineDAG,可以用来执行基本块中的运算

LLVM的指令是一种在TableGen辅助下实现的基于表的指令选择机制。目标平台的后端可以在SelectionDAGISel::Select()函数中通过定制代码处理某些指令

其他指令通过TableGen生成的匹配表(MatcherTable)和SelectCode()函数,由LLVM默认的指令选择过程完成ISD和平台ISD到机器指令节点的映射

  • 例如,在x86后端中,经过合法化的sdivrem操作就是由定制代码做指令选择
  • Select()函数的输入SDNode节点如果是sdivrem,会选择对应的x86指令IDIV32r,并生成一个MachineSD节点

MachineSD 节点是SDNOde的子集,其内容是平台机器指令,但仍然以DAG节点的是形式表手。以下三种类型指令表达可在同一个DAG中共存:一般LLVM ISD节点(如ISD::ADD)、平台相关ISD节点(如X86ISD::RET_FLAG)和平台指令(如X86::ADD32ri8)

指令调度

指令选择完成后得到以machineDAG格式表示的基本块,其内容虽然是机器指令,但仍然是以DAG形式存在

而CPU/GPU 不能执行DAG,只能执行指令的线性序列。因此,需要在machineDAG上进行指令调度,确定基本块中指令的执行顺序,将DAG节点线性化

指令调度分为寄存器分配前(pre-RA) 指令调度和寄存器分配后(post-RA) 指令调度。最简单的寄存器分配前指令调度是指将DAG中的节点按拓扑结构排序,在考虑指令级的并行性的同时,生成线性发射指令序列。经过该阶段后的指令转换为MachineInstr格式的3地址。此后,DAG表示形式不再使用,可以销毁

寄存器分配后指令调度处理MachineInstr格式的机器指令,并可以利用物理寄存器信息和硬件架构特性,根据性能指标需要,对指令顺序做调整

寄存器分配

经过指令阶段产生的代码是SSA形式的,代码中可以使用无限多的虚拟寄存器,而硬件平台的物理寄存器数量是有限的

如果物理寄存器数量不足以容纳所有虚拟寄存器,虚拟寄存器则会溢出(spill)到内存。因此,寄存器分配的目的是为虚拟寄存器分配物理寄存器,并优化寄存器分配过程,使虚拟寄存器的溢出代价最小化

虚拟寄存器到物理寄存器的映射有两种方式

  • 直接映射和间接映射

直接映射利用TargetRegisterInfo 和 MachineOperand 类获取加载/保存指令插入位置,间接映射利用VirtRegMap类处理加载/保存指令

LLVM中的寄存器分配算法有四种

  • 基本寄存器分配
  • 快速寄存器分配
  • PBQP 寄存器分配
  • 贪厌寄存器分配

在这里插入图片描述

寄存器分配过程依赖其他分析pass的分析结果,其中最重要的是寄存器合并(register coalese) pass 和虚拟寄存器重写(virtual register rewrite) pass

由于二地址转换过程中生成复制指令,从而引入了新的虚拟寄存器,这对后续的物理寄存器分配带来了压力

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

管理数据必备;侦听器watch用法详解,vue2与vue3中watch的变化与差异

目录 一、侦听器&#xff08;watch&#xff09;是什么&#xff1f; 二、Vue2中的watch&#xff08;Options API&#xff09; 2.1、函数式写法 2.2、对象式写法 ①对象式基础写法 ②回调函数handler ③deep属性 ④immediate属性 三、Vue3中的watch 3.1、向下兼容&#xff…

两句话让LLM逻辑推理瞬间崩溃!!

一道简单的逻辑问题&#xff0c;竟让几乎所有的LLM全军覆没&#xff1f; 对于人类来说&#xff0c;这个名为「爱丽丝梦游仙境」&#xff08;AIW&#xff09;的测试并不算很难—— 「爱丽丝有N个兄弟&#xff0c;她还有M个姐妹。爱丽丝的兄弟有多少个姐妹&#xff1f;」 稍加思考…

LeetCode1143最长公共子序列

题目描述 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删除某些字符&#xff08…

redis windos修复版本

遇到的问题: Django的channel插件连接安装在windows上的redis报错: unknown command BZPOPMIN, channels-redis版本和redis不兼容导致.解决方案: 更新Redis版本. 微软官方维护的 Redishttps://github.com/microsoftarchive/redis/releases 2016年后就不更新了, 版本停留在了3.x…

学生信息管理(C语言)

学生信息管理 (1)问题描述 学生信息包括:学号,姓名,年龄,性别,出生年月,地址,电话,E-mail等。试设计一学生信息管理系统,使之能提供以下功能: 系统以菜单方式工作学生信息录入功能(学生信息用文件保存)---输入学生信息浏览功能---输出查询、排序功能---算法1、…

前后端实现文件上传进度条-实时进度

后端接口代码&#xff1a; PostMapping("/upload")public ResponseEntity<String> handleFileUpload(RequestParam("file") MultipartFile file) {try {// 获取文件名String fileName file.getOriginalFilename();// 创建上传目标路径Path targetPa…

CentOS7 MySQL5.7.35主从 不停机搭建 以及配置

如需安装MySQL&#xff0c;参照MySQL 5.7.35 安装教程 https://blog.csdn.net/CsethCRM/article/details/119418841一、主&从 环境信息准备 1.1.查看硬盘信息&#xff0c;确保磁盘够用&#xff08;主&从&#xff09; df -h1.2.查看内存信息 &#xff08;主&从&am…

C++ 贪心算法——跳跃游戏、划分字母区间

一&#xff1a;跳跃游戏 55. 跳跃游戏 题目描述&#xff1a;给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1…

解决阿里云的端口添加安全组仍然无法扫描到

发现用线上的网站扫不到这个端口&#xff0c;这个端口关了&#xff0c;但是没有更详细信息了 我用nmap扫了一下我的这个端口&#xff0c;发现主机是活跃的&#xff0c;但是有防火墙&#xff0c;我们列出云服务器上面的这个防火墙list&#xff0c;发现确实没有5566端口 参考&a…

Mac环境下,简单反编译APK

一、下载jadx包 https://github.com/skylot/jadx/releases/tag/v1.4.7 下载里面的这个&#xff1a;下载后&#xff0c;找个干净的目录解压&#xff0c;我是放在Downloads下面 二、安装及启动 下载和解压 jadx&#xff1a; 下载 jadx-1.4.7.zip 压缩包。将其解压到你希望的目…

内网安全--隧道技术代理技术

注:本文仅做技术交流,请勿非法破坏... 目录 项目: 1-Ngrok 用法 2-Frp 用法 3-Nps 用法 4-Spp 用法 工具: windows下: Proxifier(推荐~) Sockscap ccproxy Linux下: Proxychains 用法 http://t.csdnimg.cn/88Ew7 隧道技术&#xff1a;解决不出网协议上线的问…

**《Linux/Unix系统编程手册》读书笔记24章**

D 24章 进程的创建 425 24.1 fork()、exit()、wait()以及execve()的简介 425 . 系统调用fork()允许父进程创建子进程 . 库函数exit(status)终止进程&#xff0c;将进程占用的所有资源归还内核&#xff0c;交其进行再次分配。库函数exit()位于系统调用_exit()之上。在调用fo…

“RabbitMQ入门指南:从入门到起飞,这一篇就够!打造高效消息通信系统的第一步“。

1.前言 RabbitMQ是一个开源的消息代理软件&#xff0c;它实现了高级消息队列协议&#xff08;AMQP&#xff09;的标准&#xff0c;并用Erlang语言编写。作为消息代理&#xff0c;RabbitMQ接收、存储和转发消息&#xff0c;帮助应用程序之间实现异步通信。它提供了一个强大而灵活…

Qt开发技术:Q3D图表开发笔记(四):Q3DSurface三维曲面图颜色样式详解、Demo以及代码详解

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/139424086 各位读者&#xff0c;知识无穷而人力有穷&#xff0c;要么改需求&#xff0c;要么找专业人士&#xff0c;要么自己研究 红胖子网络科技博…

PawSQL优化 | 分页查询太慢?别忘了投影下推

​在进行数据库应用开发中&#xff0c;分页查询是一项非常常见而又至关重要的任务。但你是否曾因为需要获取总记录数的性能而感到头疼&#xff1f;现在&#xff0c;让PawSQL的投影下推优化来帮你轻松解决这一问题&#xff01;本文以TPCH的Q12为案例进行验证&#xff0c;经过Paw…

Redisson分布式锁原理解析

前言 首先Redis执行命令是单线程的&#xff0c;所以可以利用Redis实现分布式锁&#xff0c;而对于Redis单线程的问题&#xff0c;是其线程模型的问题&#xff0c;本篇重点是对目前流行的工具Redisson怎么去实现的分布式锁进行深入理解&#xff1b;开始之前&#xff0c;我们可以…

Vmess协议是什么意思? VLESS与VMess有什么区别?

VMess 是一个基于 TCP 的加密传输协议&#xff0c;所有数据使用 TCP 传输&#xff0c;是由 V2Ray 原创并使用于 V2Ray 的加密传输协议&#xff0c;它分为入站和出站两部分&#xff0c;其作用是帮助客户端跟服务器之间建立通信。在 V2Ray 上客户端与服务器的通信主要是通过 VMes…

ThinkPHP发邮件配置教程?群发功能安全吗?

ThinkPHP发邮件的注意事项&#xff1f;如何优化邮件发送的性能&#xff1f; 无论是用户注册、密码重置还是消息提醒&#xff0c;发送邮件都是一个常见的需求。AokSend将详细介绍如何在ThinkPHP框架中配置和发送邮件&#xff0c;帮助开发者轻松实现邮件功能。 ThinkPHP发邮件&…

43【PS 作图】颜色速途

1 通过PS让画面细节模糊&#xff0c;避免被过多的颜色干扰 2 分析画面的颜色 3 作图 参考网站&#xff1a; 色感不好要怎么提升呢&#xff1f;分享一下我是怎么练习色感的&#xff01;_哔哩哔哩_bilibili https://www.bilibili.com/video/BV1h1421Z76p/?spm_id_from333.1007.…

【Python教程】3-控制流、循环结构与简单字符串操作

在整理自己的笔记的时候发现了当年学习python时候整理的笔记&#xff0c;稍微整理一下&#xff0c;分享出来&#xff0c;方便记录和查看吧。个人觉得如果想简单了解一名语言或者技术&#xff0c;最简单的方式就是通过菜鸟教程去学习一下。今后会从python开始重新更新&#xff0…