技术文章: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之前的图

科技分类资讯推荐

打破美日垄断!这家民企让C919用上中国“飞机棉” - 天天要闻

打破美日垄断!这家民企让C919用上中国“飞机棉”

数据显示,今年前5个月,重庆民营企业实现进出口1442.3亿元,占重庆外贸进出口总值的49.2%,撑起了重庆外贸经济的半壁江山。其中,有一家民营企业正以其独特的创新活力与市场敏锐度,在新材料、新应用等工业化细分领域不断实现技术突破。 点石成金一粒沙到超能纤维的“逆袭”将一粒沙变成一根纤维,再将这些纤维精密地编织...
所谓“大而美”法案或将继续扩大美债规模 - 天天要闻

所谓“大而美”法案或将继续扩大美债规模

美国所谓“大而美”法案7月1日在国会参议院得到通过,当前还需要得到众议院的通过才能提交给美国总统签字。如果该法案最终通过并成为法律,预计将对已创下纪录的美国联邦政府债务增加压力。美国国会预算办公室估....
解码哈药618 突围路径:从产品矩阵到生态构建的行业示范 - 天天要闻

解码哈药618 突围路径:从产品矩阵到生态构建的行业示范

当 2025 年 "618" 电商大促成为检验消费市场韧性的试金石,哈药以国民药企的战略定力与创新突破,构建起一套 "传统赛道筑基 + 新兴领域破局" 的增长模型。在保健品行业竞争白热化的背景下,这家企业通过多品牌协同、产品创新迭代与数字化营销破圈,不仅巩固了细分市场领导地位,更以全链路生态布局为大健康产业提供了可复制...
更快,更强,更纯粹!超薄极致电竞利器ROG绝神OLED显示器 - 天天要闻

更快,更强,更纯粹!超薄极致电竞利器ROG绝神OLED显示器

熟悉鼠鼠我的朋友都知道我是一个游戏爱好者,无论是喊上朋友们一起开黑还是自己沉浸式体验制作精良的3A大作,都能在平时繁重的牛马生活之余带给我放松和快乐。作为重度游戏爱好者,外设的选择自然是马虎不得,这其中我最为看重的就是能够直接影响平时游戏体
坐飞机和高铁分别可以携带什么样的充电宝? - 天天要闻

坐飞机和高铁分别可以携带什么样的充电宝?

来源:【江西发布】近日民航局禁止携带没有3C标识、被召回范围的充电宝上机规定引发关注坐飞机和高铁分别可以携带什么样的充电宝?充电宝上飞机乘坐飞机时,充电宝只能在手提行李中携带或随身携带,严禁在托运行李中携带。
小米YU7“封神” 国产新能源汽车“新王换旧王” - 天天要闻

小米YU7“封神” 国产新能源汽车“新王换旧王”

摘要:新能源的新格局,雏形已现。凤凰网科技 出品2025年6月26日夜晚,小米旗下首款SUV车型小米YU 7正式发布。这款以豪华、高性能、极致体验、先进安全性为特征的SUV车型,犹如一颗重磅核弹投入本就不平静的新能源车市,激起千层浪。
百度前副总裁璩静开医美诊所,人均消费2218元 - 天天要闻

百度前副总裁璩静开医美诊所,人均消费2218元

红星资本局7月2日消息,百度前副总裁璩静在华为总部坂田基地附近开了一家医美诊所。据公开资料,璩静名下新增一家存续企业——深圳大为诊所。该诊所成立于2024年12月23日,璩静持股比例为100%,认缴出资额为100万元,经营范围为诊所服务等。
千里智行,常用常新,传祺向往S7 开启重磅OTA升级 - 天天要闻

千里智行,常用常新,传祺向往S7 开启重磅OTA升级

7月2日,传祺向往S7 OTA如期而至,OTA 2.0版本正式全量推送。本次升级新增16项功能,31项 功能升级和57项体验优化,主要涉及智能座舱、智能辅助驾驶、娱乐系统、车机交互等多个维度,旨在为用户提供常用常新的出行体验,功能强大又好用。