Mips-编译优化总结
优化实现概览前端
函数内联中端
单赋值形式
全局代码移动
全局值编号
全局常量折叠
代数恒等变换
等价指令变换
激进死代码删除
基本块合并后端
全局寄存器图着色分配
局部寄存器OPT分配
立即数乘除优化
指令选择优化
寄存器选择优化具体优化实现函数内联实现方式函数内联有两种实现方式:
写在中端,将函数基本块插入Call的位置,删除Call语句,处理Return,变量重命名。
写在前端,在生成中间代码时如果遇到了Call节点,直接生成一遍该Call调用函数的中间代码。难点与解决方案第一种是最开始想到的方案,好处是可以插入优化后的函数,但比较大的问题是变量的重命名,处理起来比较麻烦,稍有不慎就会出错。
因此我们选择第二种方案作为解决方案,由于中间代码生成的过程本来就是在不断的创建变量、使用变量,将内联做到此处可以让其和正常的代码归一处理,只需要考虑该函数是否适合内联即可。
如图,ToIntermediate即为我在语法树生成中间代码的方法,在这里展示的是CallNode中的ToIntermediate,在这里我调用了FuncDefNode的ToIntermediate将其内联 ...
ARMv8 学习
ARMv8 初步
ARMv8 定义了两种执行状态,AArch64 和 AArch 32
AArch64 最多可以在寄存器中传递 8 个参数
AArch32 最多可以在寄存器中传递 4 个参数
ARMv8 中,执行发生在 4 个异常级别之一,异常级别决定了特权级别。
异常级别
解释
EL0
普通用户的用户程序
EL1
操作系统内核,通常说是有特权的
EL2
Hypervisor(虚拟机管理程序)
EL3
底层固件,包括安全监视器
ARMv8 也提供了两种安全状态:安全状态和非安全状态,这种保护使得普通操作系统和受信操作系统可以安全的同时运行在同一操作系统上。
ARMv8 中 EL3 的安全监视器充当普通和安全世界之间切换的网关
AArch 64 异常级别和安全状态组织形式如下
AArch 32 异常级别和安全状态组织形式如下
只能通过改变异常级别来改变执行状态。对异常的处理可能从AArch32更改为AArch64,从异常返回可能从AArch64更改为AArch32。
不能反着来是因为一个AArch32操作系统不能承载64位的应 ...
VirtualBox 系统盘无损扩容
使用 Linux 虚拟机的过程中出现了系统盘空间不足的问题,挂载了新的空间也不行,这是由于实际上并没有扩容系统盘的原因。现总结无损扩容系统盘的方法:
第一步在 VBox 里面扩容磁盘
此时打开虚拟机会发现仍然空间不足,因为新增的这部分磁盘仍然不可用。
第二步查看系统盘是哪一个,输入 df -h 查看,挂载点为根目录,即\的即为系统盘,记住它的名字
第三步
扩容分区,管理员权限下输入parted
输入print /dev/sda查看磁盘分区信息和扩容目标分区的编号
对照一下之前记住的名字和大小,就知道要扩容哪一个编号。
输入resize 对应编号,输入结束点(就是在现有结束点上加上你扩容的大小)
1234(parted)resizepart 4警告: 分区 /dev/sda4 正被使用。你确定要继续吗?是/Yes/否/No? yes 结束点? [21GB]? 30GB
此时只是扩展了分区大小,但这部分仍然没有被文件系统管理,所以仍然无法使用
第四步
退出 p ...
QEMU + GDB + VSCode 图形化调试
本篇以调试 rust_shyper 为例:
写在开头阅读本篇前假定您目前已有正确配置如下:
Qemu
aarch64-none-elf 交叉工具链(特别是aarch64-none-elf-gdb)
VSCode
阅读本篇前假定您目前可以正确做到如下:
make debug 无报错
make gdb 无报错
即您可以到达这个界面:
左为 make debug右为 make gdb
配置 VsCode 调试第一步
运行 VsCode,安装扩展 GDB Debug
第二步
配置 .vscode/launch.json 或者点击调试下的齿轮打开 .vscode/launch.json
内容填写格式如下
123456789101112131415161718{ // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: ht ...
Rust学习(三)
泛型
提高代码复用能力
泛型是具体类型或其他属性的抽象代替
编写的代码不是最终的代码、而是一种模板,里面有一些“占位符”
编译器在编译时将“占位符”替换为具体的类型。
函数泛型例如:fn largest<T>(list:&[T]) -> T{ ... }
结构体泛型12345678910111213141516struct User<T>{ x: T, y: T,}struct Users<T, U>{ x: T, y: U,}fn main() { let integer = User {x: 5, y: 10}; let double = User {x: 1.0, y: 2.0}; let mix = User {x: 5, y: 10.0};}
枚举泛型123456789enum Option<T> { Some(T) ...
Rust学习(二)
Rust 语法学习一般 Struct定义
和 C 语言一样,是一种自定义的数据类型
和 C 语言一样,为相关联的值命名,打包成有意义的组合
建立
使用 struct 关键字,并为整个 struct 命名。
在花括号内,为所有字段(Filed)定义名称和类型
123456struct User { username:String, email:String, sign_in_count:u64, active:bool,}
实例化
想要使用 struct, 需要创建 struct 的实例;
为每个字段指定具体值
无需按声明的顺序指定
123456let user1 = User { email: String::from("acb@123.com"), username: String::from("Nikky"), active: true, sign_in_count: 556,};
访问与赋值
使用点标记法
123456789let mut ...
Rust学习(一)
环境配置安装RustRust官网:官网安装好后可以运行命令cargo --version检测,出现版本号则安装完毕
VsCode配置习惯了使用专用编辑器的我对此感到十分痛苦。
我一共安装了三个:
rust-analyzer:它会实时编译和分析你的 Rust 代码,提示代码中的错误,并对类型进行标注。
rust syntax:语法高亮
CodeLLDB:进行调试。
第一次调试时可能会出现报错,提示无法连接什么的,这时候需要挂一个梯子去官网下载vsix,然后在VsCode插件安装中选择通过vsix安装插件即可。
通过cargo新建项目cargo new 项目名称例如,在一个空文件夹下执行该命令:cargo new HelloWorld,文件结构如下:/src/main.rs为源代码/Cargo.lock为编译后生成的,负责追踪项目依赖的精确版本/Cargo.tomlCargo的配置格式,其中:
pacakge 配置包的项目名,项目版本,项目作者,Rust版本
dependencies 列出项目的依赖项在rust里面,代码的包称作crate.
cargo命令cargo bul ...
操作系统文件系统复习
磁盘有效化一个磁盘要想真正变得有用,一般要按顺序经历以下的过程
物理格式化(低级格式化):一般在磁盘出厂时进行,主要是给磁道划分扇区,排查错误扇区。
分区:由软件进行,比如FDISK
逻辑格式化(高级格式化):建立文件系统
安装操作系统。
文件定义是指一组带标识(标识即为文件名)的、在逻辑上有完整意义的信息项的序列。信息项:构成文件内容的基本单位(单个字节,或多个字节),各信息项之间具有顺序关系。也就是说,文件内容是由信息项组成的。
组成文件体、文件说明
文件体文件内容
文件说明文件存储和管理的相关信息,比如文件名、文件内部标识、文件存储地址、访问权限、访问时间。
文件系统数据结构文件控制块(FCB)定义保存管理文件所需的所有有关信息(文件属性或元数据)
内容
基本信息:文件名、物理位置、文件逻辑结构、文件物理结构
访问控制信息:文件所有者、访问权限
使用信息:创建时间、上一次修改时间、当前使用信息。
文件逻辑结构我们用户看到的文件表面上的行文结构,举一个这样的例子:程序员在写代码时其实考虑的都是文件的逻辑结构,比如顺序文件,索引文件(什么一级索引,多级索引,B树索引,Hash ...
操作系统磁盘复习
主引导扇区定义硬盘的0柱面、0磁头、1扇区称为主引导扇区。主引导扇区是在硬盘分区时由分区软件写入的(FDISK),因而不属于任何操作系统,所以分区时不进行操作系统引导扇区的写入。
组成前446字节为启动代码(BootLoader)后面64字节是分区表(DPT),一共可以记录4个分区。最后有2个字节是幻数,标识这是一个被分区的硬盘硬盘分区有三种,主磁盘分区、扩展磁盘分区、逻辑分区。主分区只能有一个是激活(活动)的,其余是未激活。分出主分区后,其余的部分可以分成扩展分区,一般是剩下的部分全部分成扩展分区,也可以不全分,剩下的部分就浪费了。扩展分区不能直接使用,必须分成若干逻辑分区。所有的逻辑分区都是扩展分区的一部分。
DPT表项
磁盘分类固定头磁盘磁头相对于盘片径向方向固定的,称为固定头磁盘,每个磁道一个磁头。
活动头磁盘磁头可移动的、可以来回伸缩定位磁道的,称为活动头磁盘
固定盘磁盘磁盘永久固定在磁盘驱动器内,称为固定盘磁盘。
可换盘磁盘磁盘可移动和替换的,称为可换盘磁盘。
磁盘地址与块号的转换先记忆一个知识,一个逻辑块号的大小为一个扇区的大小。一般情况下、先填满扇区、再填满磁道、再 ...
编译总结感想
编译总结
课程收获161次提交记录…….在大二的时候久闻编译强度之大,终于在这一学期也是让我真正的亲身体会了一把,但回首这几个月,除了De不出Bug时那绝望的心情,我更多的时候收获的是每一次提交时的自豪与满足。每一次De出Bug、实现功能的成就感。对编译器的理解也是从一开始抓着别人问我该做什么,变成了我知道我该做什么,我写的哪里还有不足等等。这些提升都是实打实的提升。我对编译器的理解也是随着我实践的深入逐渐清晰,原来大一大二时在我眼里十分神秘的编译器也逐渐变得明朗。这种成长的感觉非常棒,足以抵消强度之大的流言。
而且,我认为大家都说编译强度大,我现在更多的倾向是他们没有合理安排自己的时间所导致的,因为我虽然提交次数很多,但我在一学期中并没有特别明显的感受到编译实验带来的时间上的压力,这是因为我对此在开学就有一定的规划,我听取了学长们的建议,结合自己的实际下定决心从开学开始开发,到国庆就完成了不带优化的编译器的实现。这让我后面的时间极其宽松,我甚至可以放着编译实验一周而去做更为急迫的事情。也因此虽然在最后我的时间也不是很充足,但我也不像很多人一样完全缺乏时间进行优化。让我得以取得了一个较 ...














