技术文章:scf编译器对C语言的逻辑运算符的优化

2022年10月16日20:12:32 科技 1285

在各种编程语言里,逻辑运算符都是要短路的。

C语言为例:

if (p && p->x > 0) p->x++;

当指针p是NULL的时候,对成员变量p->x的读写会导致段错误,所以如果&&之前的条件p是NULL就要把后面的p->x跳过去。

这样才能保证代码的正常运行。

如果语言本身不支持逻辑运算符的短路,那么代码就只能这么写了:

if (p) {

if (p->x > 0) p->x++;

}

要多写一个if条件。

逻辑运算符的结果只有0或1两种。

在编程里,逻辑运算符既可以作为if / while / for的条件表达式还可以参与普通运算

if (i > 0 && j > 1 && k > 2) return -1; // 条件表达式

n = i > 0 && j > 1 && k > 2; // 普通运算

在对逻辑运算符进行优化时,必须同时考虑这两种情况

第2种情况下,如果逻辑运算符在计算前2个条件时短路了,必须把计算结果写入最后一个逻辑运算符对应的临时变量

最后一个逻辑运算符的计算结果,才是整个表达式的结果,也是对n赋值的结果。

如果只是在if语句里作为条件表达式,逻辑运算的结果不需要写到临时变量里,直接根据比较结果跳转到对应的分支就可以了。

技术文章:scf编译器对C语言的逻辑运算符的优化 - 天天要闻

赋值运算的语法树

第2种情况的语法树如图,参与赋值运算的是第2个&&对应的临时变量。

如果在i > 0 或 j > 1时短路的话,它们设置的是第1个&&的值:编译器在短路跳转时必须给第2个&&设置运算结果,否则之后的n = ...的结果就不对了。

逻辑运算符生成中间代码的时候,实际上并不知道它的结果以后会被怎么使用[捂脸]

从上图中也可以看出=号在更上面(if也是在更上面),实际上,在处理&&运算符时只能看到它的2个条件表达式,看不到更上层的程序逻辑。

技术文章:scf编译器对C语言的逻辑运算符的优化 - 天天要闻

if条件的语法树

如果硬要去看更高层的逻辑,就会破坏模块封装性,让遍历语法树生成中间代码的代码变得复杂、难看。

scf框架在这里的处理是:

1,先给所有逻辑运算符的临时变量设置上结果,把进一步的优化放到以后

技术文章:scf编译器对C语言的逻辑运算符的优化 - 天天要闻

if的情况

最初的中间代码是这样的,可以看到每个cmpteq运算之后都紧跟着setcc

其中cmp是比较大小,结果可以是>、==、<、>=、<=、!=。

teq是比较是不是0,结果只有2种:== 0,!= 0。

技术文章:scf编译器对C语言的逻辑运算符的优化 - 天天要闻

赋值的情况

在有逻辑运算符的情况下,在cmp之后必然跟着teq去判断逻辑结果是不是0。

例如上图中的:

cmp i, 0

setgt v_8_16/&&

jle : teq v_8_16/&&

跳转的目标代码是:

teq v_8_16/&&

setnz v_8_25/&&

jz : assign v_8_6/n; v_8_25/&&

数字表示的是行列号,v_8_16/&&表示第8行第16列的&&运算符对应的临时变量

可以看出,在最初的中间代码里,逻辑运算符并没有“真正的短路”:虽然跳过了第2个比较条件,但并没有跳过逻辑运算。

之所以这样,就是因为(生成中间代码时)没法确定逻辑结果接下来还有没有用。

既然没法确定,编译器就只能先当它有用:代码里遇到这种情况,是一定会做保守处理的。

所以说,不管是程序员还是数学家,一般都是悲观主义者[捂脸]

2,跳转优化时,对这个问题进一步的优化。

如果一个跳转的目标位置是一个绝对跳转,就可以把它优化成跳转到这个绝对跳转的目标位置。

if a jcc's destination is a jmp, then optimize its destination to the jmp's.

这是对跳转的基本优化。

实际上,如果跳转之前对逻辑结果设置了false,而跳转的目标又是检测这个结果的话,那么检测结果也是false[呲牙]这是跳转优化的另一条规则。

所以说,在cmp触发了jle (<=) 的情况下,那么它俩之间的setgt (>) 就肯定是0

进而导致目标位置的teq也是0

进而导致目标位置的setnz也是0

进而导致目标位置的jz被触发,

所以,jle的地址就是jz的地址

但在jle之前要把setnz的目标变量也设置一下,使用的设置指令是setgt:与最初触发跳转的条件一致。

技术文章:scf编译器对C语言的逻辑运算符的优化 - 天天要闻

跳转优化之后的中间代码

从上图可以看出,经过跳转优化之后,测试逻辑结果的teq运算消失了,与teq对应的jz跳转也消失了:

逻辑运算符被短路到了接下来的赋值运算。

赋值运算只使用最后一个临时变量v_8_25。

对中间临时变量v_8_16的设置是多余的,接下来的问题是怎么消除它。

如果逻辑运算只是作为if的条件的话,那么最后一个逻辑结果也是不需要的

3,基于活跃变量分析的优化,

算术运算会使用最后一个逻辑结果的临时变量,if条件不使用任何逻辑结果的临时变量,这在临时变量的活跃度上可以体现出来。

不活跃的临时变量DAG上去掉就行了。

技术文章:scf编译器对C语言的逻辑运算符的优化 - 天天要闻

最终的优化结果

对n的赋值运算只使用临时变量v_8_25,可以看出它是前面基本块的出口活跃变量,被保留了下来。

如果是if条件,因为所有的临时变量都不活跃,在DAG优化之后就只剩下比较和跳转了[呲牙]

如下图:

技术文章:scf编译器对C语言的逻辑运算符的优化 - 天天要闻

if最终的图

上图是if条件的最终的图,下图是跳转优化之后、DAG优化之前的图。

可以看到,所有的setgt都被去掉了。

技术文章:scf编译器对C语言的逻辑运算符的优化 - 天天要闻

if之前的图

科技分类资讯推荐

浙江首家县域级虚拟电厂资源接入省级平台 - 天天要闻

浙江首家县域级虚拟电厂资源接入省级平台

潮新闻客户端 通讯员 范金凯5月30日,国网杭州市萧山区供电公司所属浙江中新电力工程建设有限公司打造的萧山双碳大脑虚拟电厂成功接入浙江省电力负荷管理中心省级平台,并获得新型主体资质,成为全省首家接入该平台的县域级虚拟电厂。
美团闪购不考数学 - 天天要闻

美团闪购不考数学

1每年618,电商平台都能人头打成狗头,今年登场的嘉宾更是重量级。美团闪购疯了,都开始参加618了,代言人樊振东拿着球拍一拍一拍把价格打下来了嘿。电商们这么多年都打累了吧?花里胡哨的活儿已经整完了吧?已经开始打默契拳踢友谊赛了是吧?
小米米家洗衣机 Pro 蓝氧洗烘 10kg 开售,国补价 1727 元起 - 天天要闻

小米米家洗衣机 Pro 蓝氧洗烘 10kg 开售,国补价 1727 元起

IT之家 5 月 31 日消息,小米米家洗衣机 Pro 蓝氧洗烘 10kg 现已在京东平台开售,售价 2399 元,叠加 9 折优惠券、8 折国补,到手价 1727 元起。据介绍,这款产品支持蓝氧护衣洗,可有效去除 6 大类、35 种常见污渍;达到超高洗净比 1.27,远超国家标准 1.03;支持 30 种洗烘护程序,针对羊毛衫、羽绒服、真丝、冲锋衣、运..
华硕推出 NUC 15 Pro 迷你主机:Ultra 5-225H,5799 元 - 天天要闻

华硕推出 NUC 15 Pro 迷你主机:Ultra 5-225H,5799 元

IT之家 5 月 31 日消息,华硕现已在京东上架 NUC 15 Pro 迷你主机,该机搭载英特尔酷睿 Ultra 5-225H + 16GB RAM + 512GB SSD,定价为 5799 元,国补后 4239.2 元。这款迷你主机整体造型简约,采用哑光工艺,尺寸为 117x112x54mm,体积为 0.7L,搭载 14 核心 14 线程英特尔酷睿 Ul
外卖骑手们的“流量”副业 - 天天要闻

外卖骑手们的“流量”副业

奶茶铺女店员手中的五六杯饮品接连砸向外卖骑手花田,那一瞬间,狼狈至极的他不会知道,800万短视频流量也即将砸向他。这场激烈又寻常的外卖纠纷,若不是因为花田送餐时胸前佩戴的运动相机的记录,或许会被永远淹没在上海4月这个工作日午高峰时分。花田将相机里的事发视频剪辑发布在自己的短视频账号里。之后的几天里,这个...
上汽贾健旭:余总说我们不太像国企,尚界铺天盖地华为顶天立地 - 天天要闻

上汽贾健旭:余总说我们不太像国企,尚界铺天盖地华为顶天立地

IT之家 5 月 31 日消息,在今日的未来汽车先行者大会上,上海汽车集团股份有限公司总裁贾健旭说,公司现在要 ALL IN 华为。“余总(IT之家注:华为常务董事、终端 BG 董事长余承东)调侃我们不太像国企,我很汗颜…… 我们要拿出私企人的性格、做国企人的企业。…… 尚界铺天盖地,华为顶天立地!”贾健旭强调,上汽要坚持...
小米 REDMI 显示器 G27 开售:200Hz 刷新率,669 元 - 天天要闻

小米 REDMI 显示器 G27 开售:200Hz 刷新率,669 元

IT之家 5 月 31 日消息,小米 REDMI 显示器 G27 现已在京东等平台开售,支持 1080P 分辨率、200Hz 刷新率,售价 669 元。据介绍,这款新品配备一块 27 英寸 1920x1080 分辨率 200Hz Fast IPS 面板,显示器峰值亮度 400 尼特,静态对比度 1000:1,GtG 响应速度 1ms,显示器支持 8-Bit