0
点赞
收藏
分享

微信扫一扫

UCC编译器学习笔记15


关于结构体中,位域成员的赋值原理:

struct PTE
{
int offset : 12;
int pgNo : 20;
}
struct PTE pte = {64,3};

给pte赋值,其实就是 (3<<12) | 64

原理:由于struct PTE占32位,3想赋值给第二个成员,而64想赋值给第一个成员,而64的高12位一定会为0的(这是程序员肯定会控制的)

在 C 语言中,&number 的类型是指针类型,但在汇编指令中,我们使用符号 number 即可表示一个地址常量,

int number;
int arr[4][5];
int * ptr1 = &number;
int * ptr2 = arr[2];
对应的汇编//
ptr1:.long number
ptr2:.long arr + 40

中间代码生成简介

在语法分析和语义检查阶段,我们始终在与语句 Statement、表达式 Expression 和外部

声明 ExternalDeclaration 这 3 个概念打交道。通过声明,我们最终建立起了相应的类型结构,

并在符号表中保存了相关标识符的类型信息,到了中间代码生成阶段,我们就不再需要处理

外部声明 ExternalDeclaration 了,只需要为语句表达式生成相应的中间代码即可。文件

ucl\tranexpr.c 用于为表达式生成中间代码,文件名 tranexpr 是 Translate Expression 的缩写,

而 ucl\transtmt.c 则用于为语句生成中间代码。

由此,基本块成了点,而“控制流的转移”就成了有向边,我

们可把整个程序的动态执行的路线看成数据结构中的“图”,这个由基本块构成的图被称为

控制流图 Control Flow Graph,简写为 CFG。后续的分析和优化都是基于“控制流图”这样

的数据结构进行。需要说明的是,UCC 编译器的中间代码优化工作只在基本块中进行,并

没有进行函数间(过程间)的代码优化,因此 UCC 编译器在划分基本块时,并没有把函数

调用当作基本块的最后一条指令,其实是不太对的,因为基本块的意思是,内部从前往后执行,不会产生跳转,但是函数调用其实就是CPU发生了跳转的,只是又跳回来了而已。

UCC编译器学习笔记15_赋值

c语言中的短路运算:

而对于布尔表达式来说,我们并不会

对整个表达式进行求值,而是生成相应的跳转指令,对于 a&&b 而言,当 a 为假时不论 b
为何值
,a&&b 的值都为假,所以此时我们并不需要对 b 进行求值。若把“a&&b”换成

“f()&&g()”,则当 f()的返回值为假时,我们不需要对函数 g()进行求值,此时 g()函数根本

就没有被调用,这就是 C 语言中的短路运算。

UCC编译器学习笔记15_控制流_02    UCC编译器学习笔记15_基本块_03



举报

相关推荐

0 条评论