编译原理之代码生成

前面提到了经过了词法分析->语法分析->语义分析->中间代码优化,最后的阶段便是在目标机器上运行的目标代码的生成了。目标代码生成阶段的任务是:将此前的中间代码转换成特定机器上的机器语言或汇编语言,这种转换程序便被称为代码生成器。

1. 程序移植性和编译器模块设计的关系

之所以将编译原理分成这种多阶段多模块的组织形式,本质的考虑其实只有两个方面:
一、代码复用:尽可能在不增加程序员工作量的前提下,增加应用程序的可移植性。
可我们知道不同机器的机器指令集和硬件结构,千差万别,而前面又提到了为了将程序的执行效率提升到最大,显然是需要将软件按照硬件特性极尽可能地定制化优化,其实现在AI芯片的发展趋势也是这种思想的另一面体现。现今AI芯片为了加速深度学习为代码的超强度计算效率,出现了针对具体程序架构定制化芯片的需求,如CPU->GPU的发展,便是GPU迎合了深度学习单轮多次简单运算的需求,CPU->FPGA的矩阵运算侧重也是Facebook引领的另一硬件绑定具体软件计算需求的工程案例,而最为极端者莫过于当下Google推出的TPU计算芯片,完全剔除不必要的硬件设备,根据Google的深度学习Tensorflow架构定制化的计算芯片,更是以极致的定制化获取比CPU计算速度高200倍的显著成果。)。

所以再一次验证了“银弹”理论,如果有问题解决不了,那就加一层抽象层了。所以提高代码移植性的集大成者Java,便是通过引入JVM将应用程序层和具体硬件层隔开。


图1. Java-多目标机

显然对于Java程序可以共享一套“词法分析+语法分析+语义分析+中间代码优化引擎”这一套前端套件,而针对不同机型的定制化目标代码生成器则可以通过官方渠道的支持和更新来组装成自己所需的后端套件组。这样便可以让程序员尽可能地有较多的自由编写的空间,极大地提升代码可移植性,而不像C++编写的DLL库,即便采用复杂的COM规则,极为小心地编写,但也可能因为编译器版本不同导致移植性不通过。

二、特定机器的优化器和生成器复用:针对特定机器的目标代码生成和优化器的工作极为复杂精深,有一套成功的,当然要尽可能复用它。

由于代码生成阶段的目标代码和具体计算机的结构有关,如指令格式、字长以及寄存器的个数和种类,并与指令的语义和所用操作系统等都密切相关,特别是高级语言的语义功能复杂,并且计算机硬件结构多样性都给代码生成的理论研究带来很大的复杂性,因此实际实现起来是非常困难的。所以难得生成一款后端的代码生成器,当然是想让它可以独立出来,被多次组装参与其他编译器的生产过程。


图2. 多种语言-一种目标机型

这种情况被称为定计算机情况:当限定某种计算机时,而高级语言为多种情况下所设计的中间语言,应能充分反映限定计算机的特点称MSIL(Machine Specific Intermediate language)。对这种机器的所有编译程序在分析阶段都生成MSIL,在实现一个编译程序时,尽量把编译过程的大量工作放在代码生成阶段,即MSIL到目标程序的翻译上,以减轻不同语言翻译的分析任务。因不管多少种高级语言,MSIL到目标程序的代码生成只需做一次即可。

当然也正是这种组织特性,让本来是集团作战的编译器生成工作,现如今变得不再是难以企及。同时也让各行各业根据自身需求和侧重点不同,甚至可以定制化自己的行业的专属语言(Domain Specific Language)变得可实现。

2. 代码生成的优化手段:寄存器分配

说了这么多,其实只需要明白代码生成器是结合目标机器平台定制化的一套后端套件,这也是为何业界的主流计算机都是按照x86、x64_86这些业界标准来设计的,如果你家公司另辟蹊径自己设计出一套硬件体系,即便你能设计生产出来,但你确定IT界会有下游供应商给你设计类似于代码生成器这种配套套件吗?

衡量最终生成的目标代码的质量无非是从两个方面来进行评估:空间占用和运行效率,这其中涉及到诸多和具体硬件绑定的细节,大多数都属于难度高且并不通用的范畴。而寄存器的使用规则则是少数具有通用的手段,故而可以借分析寄存器分配来分析一下目标代码优化和生成过程。

Q: 为什么在代码生成时要考虑充分利用寄存器?
A: 因为当变量值存在寄存器时,引用的变量值可直接从寄存器中取,减少对内存的存取次数,这样便可提高运行速度。因此如何充分利用寄存器是提高目标代码运行效率的重要途径。

Q: 寄存器分配的原则是什么?
A: (1)逻辑有效范围内尽量保留: 当生成某变量的目标代码时,尽量让变量的值或计算结果保留在寄存器中,直到寄存器不够分配时为止。
 (2) 逻辑块出口处,和内存中的源数据同步:当到基本块出口时,将变量的值存放在内存中,因为一个基本块可能有多个后继结点或多个前驱结点,同一个变量名在不同前驱结点的基本块内出口前存放的R可能不同,或没有定值,所以应在出口前把寄存器的内容放在内存中,这样从基本块外入口的变量值都在内存中
 (3) 及时释放,提升寄存器使用效率:对于在一个基本块内后边不再被引用的变量所占用的寄存器应尽早释放,以提高寄存器的利用效率。

可以看到在进行缓存淘汰更新时我们采用了LRU策略,LRU策略是属于经典的“线性思维”–即过去常被使用的,在未来也会常被使用。而这里寄存器则不能采用“线性思维”,因为我们看自己的代码都知道,变量的使用虽然在局部范围还算符合“局部性原理”,但是稍微放宽到一定尺度上的变量集使用情况,则发现更多是无序的。所以在进行寄存器分配策略的研究上,只能比较粗暴点,事先将目标代码再次遍历一遍,将变量的使用情况事先整理好,并用所谓“待用信息链”的数据结构来保存每个变量的使用情况。这种策略并非LRU那种后视推导逻辑,而是耍赖的先知般论断逻辑,但是考虑到一旦将目标代码的寄存器使用效率最大化,则无疑是一劳永逸的,故而也是划算的。

变量的待用信息链计算方法
前面根据寄存器的使用原则可以看到,寄存器的分配是以基本块为单位的,因为基本块作为程序流的最小单元,存在着数据同步和异步的问题,故而在进行寄存器分配时,要审核的代码范围只需要涉及到当前基本块即可。

首先为任一变量设置两个信息链:待用信息链和活跃变量信息链。

考虑到处理的方便,可假定对基本块中的变量在出口处都是活跃的,而对基本块内的临时变量可分为两种情况处理。
  a) 一般情况下基本块内的临时变量在出口处都认为是不活跃的。
  b) 如果中间代码生成时的算法允许某些临时变量在基本块外可以被引用时,则这些临时变量也是活跃的。
  
在基本块内计算变量的使用信息链(觉得采用栈式更符合这种信息链的更新情况),步骤如下:

① 对各基本块的符号表中的”待用信息”栏和”活跃信息”栏置初值,即把”待用信息”栏置”非待用”,对”活跃信息”栏按在基本块出口处是否为活跃而置成”活跃”或”非活跃”。现假定变量都是活跃的,临时变量都是非活跃的。  
② 倒着来从基本块出口到基本块入口由后向前依次处理每个四元式。对每个四元式i:A:=B op C,依次执行下述步骤:
  a) 把符号表中变量A的待用信息和活跃信息附加到四元式i上。
  b) 把符号表中变量A的待用信息栏和活跃信息栏分别置为 “非待用” 和 “非 活跃”。由于在i中对A的定值只能在i以后的四元式才能引用,因而对i以前的四元式来说A是不活跃也不可能是待用的。
  c) 把符号表中B和C的待用信息和活跃信息附加到四元式i上。
  d) 把符号表中B和C的待用信息栏置为”i”,活跃信息栏置为”活跃”。

说的麻烦,举个例子就好了:

  (1) T∶=A-B(2) U∶=A-C(3) V∶=T+U(4) D∶=V+U

加上信息链条之后,则标记情况如下

  (1) T【(3)L】:= A【(2)L】 - B【FL】(2) U【(3)L】:= A【FL】 - C【FL】(3) V【(4)L】:= T【FF】 + U【(4)L】(4) D【FL】:= V【FF】 + U【FF】

这样根据信息链表法,在每次运算到一个表达式时,如果寄存器数目不够,即无空余寄存器可用,则可以遍历一下当前在寄存器中的变量的待用信息链,然后选择接下来最远将被调用的变量释放其所占用寄存器,分配寄存器的算法为:

  ① 如果B的现行值在某寄存器Ri中,且该寄存器只包含B的值,或者BA是同一标识符,或B在该四元式后不会再被引用,则可选取Ri作为所需的寄存器R,并转(4);
  ② 如果有尚未分配的寄存器,则从中选用一个Ri为所需的寄存器R,并转(4);
  ③ 从已分配的寄存器中选取一个Ri作为所需寄存器R,其选择原则为:占用该寄存器的变量值同时在主存中,或在基本块中引用的位置最远,这样对寄存器Ri所含的变量和变量在主存中的情况必须先做如下调整:即对RVALUE[Ri]中的每一变量M,如果M不是AAVALUE[M]不包含M,则需完成以下处理;
  a) 生成目标代码ST Ri,M即把不是A的变量值由Ri中送入内存中;
  b) 如果M不是B,则令AVALUE[M]={M},否则,令AVALUE[M]={M, Ri};
  c) 删除RVALUE[Ri]中的M;
  ④ 给出R,返回。

至此可以看到,单纯是寄存器分配便是需要较多数据结构配合和工作时间消耗的,管中窥豹,可以看到代码生成器的一个部件工作量便是很复杂的。

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

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

相关文章

前端案例-跟随鼠标移动的天使

📋 个人简介 💖 作者简介:大家好,我是阿牛,全栈领域新星创作者。😜📝 个人主页:馆主阿牛🔥🎉 支持我:点赞👍收藏⭐️留言&#x1f4d…

前端代码在线编辑器:codepen、codesandbox

文章目录 单文件在线编辑器项目级在线编辑器 推荐两个前端代码在线编辑器 单文件在线编辑器:https://codepen.io/pen/ 项目级在线编辑器:https://codesandbox.io/ 单文件在线编辑器 codepen 相信使用 element-ui组件库的小伙伴应该知道 codepen在线编…

vue前端生成二维码并提供二维码下载

在一个管理后台的开发过程中使用到了需要前端自行生成分享二维码,并提供二维码下载功能,网上的解决方案很多,最终自己做完的思路和代码整理记录方便后续学习使用! vue版本为2.x 具体实现步骤: 下载安装依赖&#xff0…

总结本人学习b站黑马前端课程,各部分案例汇总

目录 1.Ajax: 对应课程: b站黑马JavaScript的Ajax案例代码——新闻列表案例 b站黑马JavaScript的Ajax案例代码——评论列表案例 b站黑马JavaScript的Ajax案例代码——聊天机器人案例 b站黑马JavaScript的Ajax案例代码——图书管理案例 2.ES6面向对…

前端——动态生成表格

案例分析 因为表格数据是不断更新的,我们需要js 动态生成。 这里我们模拟数据,自己定义好数据。 数据我们采取对象形式存储。所有的数据都是放到tbody里面的行里面。因为行很多,我们需要循环创建多个行(对应多少人)每…

Methodot低代码电影票房管理系统实战案例(二):前端低代码搭建系统后台

本次系统后台实战将使用Methodot应用工厂中的前端低代码组件完成搭建,无需注册域名、购买云服务器、虚拟机等,可在Methodot云端一体化完成开发、交付、访问、运维,3s即可部署至线上 免运维,在Methodot上可直接开发部署到线上 本次…

c语言源码代码生成器,SoEasyPlatform 代码生成器

介绍 一款轻量级开源的代码生成器,相对较动软代码生成器而言要轻量的多,支持多种数据库,所用到dll组件也都在github有源码,代码非常的简单有点基础的看源码可以把生成的项目改成自已的风格。 特色 该代码生成器最大的特点就三个简单 ,无需安装,生成的代码 简单并且有教学…

基于GPT-4的免费代码生成工具

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

前端直接生成GIF动态图实践

前言 去年在博客中发了两篇关于GIF动态生成的博客,GIF图像动态生成-JAVA后台生成和基于FFmpeg的Java视频Mp4转GIF初探,在这两篇博客中都是采用JAVA语言在后台进行转换。使用JAVA的同学经过自己的改造和开发也可以应用在项目上。前段时间有朋友私下问&…

利用JS代码完成动态生成表格案例及解析

思路&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content&…

屏蔽必应(bing)搜索引擎点开一个页面下面会出现“浏览 6 个相关页面”的网页推荐方法

如以上图片显示&#xff0c;“浏览 6 个相关页面” 的推荐内容是网页里面的js实现的&#xff0c;无法取消&#xff0c;微软官方也回复说不能关闭的&#xff0c;只能通过浏览器的屏蔽广告插件可以实现&#xff1a; 我用的是这个uBlock Origin插件根据这位大佬的帖子安装的&…

基于chatgpt-on-wechat的微信个人对话机器人搭建

1.开源项目选定 现在gpt很火,git中大佬们都创建了很多高星项目,我这里选用了chatgpt-on-wechat(项目地址:https://github.com/zhayujie/chatgpt-on-wechat),这个项目在扩展时也很舒服,大家可以去拉下来看看,学习源码才能方便后续的扩展 2.服务器选定 国内服务:前置条件需要走…

【模仿】调用微信聊天功能和分享功能

今天整理个不是问题的问题&#xff0c;没学到啥&#xff0c;主要完成功能&#xff1a; 老大要求能调用手机号码然后通过微信聊&#xff0c; 我去&#xff0c;说白了老大看到了应用-通讯录plus-的微信功能&#xff0c;要我模仿。 首先&#xff0c;坑啊&#xff0c;我以为是开放…

iOS微信QQ聊天界面的UI框架以及Socket简单实现群聊功能

7.1日更新 Python3 TCP Demo相关 https://blog.csdn.net/Deft_MKJing/article/details/80851879 2.2日更新&#xff0c;socket简易群聊通信&#xff0c;之前实现的是静态本地聊天模拟 最新版本Demo传送门 1.需要的先下载下来&#xff0c;先开启SocketSeverce 2 这个服务器代…

JetChat-简仿微信聊天应用

Swift5.0编写的简仿微信聊天应用&#xff0c;完美支持表情键盘、单聊、群聊、本地消息会话缓存、朋友圈、白天和黑夜主题模式 Examples - 主要界面展示 聊天朋友圈 白天模式黑夜模式 主要技术运用 聊天功能采用RxSwiftMVVM响应式架构设计&#xff0c;通过ViewModel合理过渡处…

程序员聊天必备表情包,收好不谢

现在聊天用表情代替文字已经是潮流了&#xff0c;往往一张图片比文字更能表达内心的想法&#xff0c;今天我们就来了解下程序员聊天时都用些什么表情。 程序员怒产品 &#xff1a; 被吐槽写BUG时怎么办 产品又来提需求 产品又要改需求&#xff0c;怎么办 产品说&#xff0c;这个…

【华为云技术分享】云图说|全新华为云云备份服务:为您的数据提供三合一的保障

云上道路千万条&#xff0c;数据安全第一条。当不幸在云上发生病毒袭击、误删除、软件故障等“车祸”时&#xff0c;如果没有事先对数据进行保护&#xff0c;业务将会中断&#xff0c;并且将导致数据丢失、损坏的后果&#xff01; 华为云云备份就像安全气囊&#xff0c;关键时…

云存储——华为网盘

华为网盘 编辑本段信息 [1] 华为网盘是华为 软件公司&#xff08;下简称 华为公司&#xff0c;华为投资控 [2] 股有限公司的子公司&#xff09;旗下的互联网存储服务。首次注册为5G容量&#xff0c;可以通过各种渠道来获得更多 网络存储空间。可以当作U盘使用,但比优盘方便安全…

利用群晖nas备份华为手机数据

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、确保手机和nas处于同一局域网二、nas启用smb服务&#xff0c;并且设置正确1.启用smb服务2.在设置最小SMB协议时&#xff0c;会有提示不安全因数的可能。但是…

阿里云/华为云云盘挂载步骤

参拷文章&#xff1a;linux centos7 磁盘分区、挂载 初始化Linux数据盘&#xff08;fdisk&#xff09; 挂在的相关指令 #查看磁盘及分区信息 fdisk -l看到vdb没有启用 对/dev/vdb进行分区操作 fdisk /dev/vdb总结输入&#xff1a;n > p > 回车 > 回车 》 回车 》 …