【实验】编译原理——编译器认知实验

系列文章目录

学习笔记

【学习笔记】编译原理——第一章 编译引论

【学习笔记】编译原理——第二章 词法分析

实验

【实验】编译原理——编译器认知实验



一、实验目的

本实验的目的是了解工业界常用的编译器 GCC 和 LLVM,熟悉编译器的安装 和使用过程,观察编译器工作过程中生成的中间文件的格式和内容,了解编译器 的优化效果,为编译器的学习和构造奠定基础。

二、实验内容

本实验主要的内容为在 Linux 平台上安装和运行工业界常用的编译器 GCC 和 LLVM,如果系统中没有安装,则需要首先安装编译器,安装完成后编写简单的测 试程序,使用编译器编译,并观察中间输出结果。
对于 GCC 编译器,完成编译器安装和测试程序编写后,按如下步骤完成:
查看编译器的版本
使用编译器编译单个文件
使用编译器编译链接多个文件
查看预处理结果:g++ -E hello.c -o hello.i
查看语法分析树:g+±fdump-tree-all hello.c
查看中间代码生成结果:Code generation result: g+±fdump-rtl-all hello.c
查看生成的目标代码(汇编代码):g++–S hello.c –o hello.s

对于 LLVM 编译器,完成编译器安装和测试程序编写后,按如下步骤完成:
查看编译器的版本
使用编译器编译单个文件
使用编译器编译链接多个文件
查看编译流程和阶段:clang -ccc-print-phases test.c -c
查看词法分析结果:clang test.c -Xclang -dump-tokens
查看词法分析结果 2:clang test.c -Xclang -dump-raw-tokens
查看语义分析结果:clang test.c -Xclang -ast-dump
查看语义分析结果 2:clang test.c -Xclang -ast-view
查看编译优化的结果:clang test.c -S -mllvm -print-after-all
查看生成的目标代码结果: clang test.c –S

三、实验步骤

  1. 编译器安装
    在Linux系统下安装GCC、Clang、LLVM。
    sudo apt-get install Clang
    sudo apt-get install LLVM
    
  2. 编写测试程序
    需要注意的是,不但要求对单个 C 文件进行编译,还要求对多个 C 文件一起编译和链接。
  3. 运行编译器进行观测
    分别运行 GCC 和 LLVM 编译器,首先要学习编译器的基本使用方法,其次要通过编译选项查看分析编译器的中间结果,及其与输入源码之间的对应关系,最后使用-O0、-O1、-O2 和-O3 分别使用两个编译器对输入程序进行优化编译,并对比 GCC 和 LLVM 优化后程序的运行效率。
  4. 编写实验报告
    根据观测结果编写实验报告。

实验结果

4.1 G++

①查看编译器版本
在Visual Studio Code中查看G++编译器版本
在这里插入图片描述

②编译单个文件

③编译链接多个文件
在这里插入图片描述

④查看预处理结果:g++ -E hello.cpp -o hello.i

⑤查看语法分析树:g+±fdump-tree-all hello.cpp
在hello.cpp.001t.tu中生成相关语法树,部分文件内容
在这里插入图片描述

在这里插入图片描述

⑥查看中间代码生成结果: g++ -fdump-rtl-all hello.cpp
编译生成如下文件:
在这里插入图片描述

在hello.cpp.192r.expand文件中可以看到如下代码,目的是使得内存边界对齐。
在这里插入图片描述

⑦查看生成的目标代码(汇编代码):g++ -S hello.cpp -o hello.s
运行命令生成hello.s文件,虽然目前还未学过汇编代码,但是能够看到我们在源码中定义的变量name和number均以.string的形式在汇编代码中出现。

在这里插入图片描述

4.2 LLVM

①查看编译器的版本
运行clang –version 和clang++ --version都能查看到编译器的版本。
在这里插入图片描述

②使用编译器编译单个文件

③使用编译器编译链接多个文件

④查看编译流程和阶段:clang++ -ccc-print-phases hello.cpp -c
在这里插入图片描述

⑤查看词法分析结果:clang++ -c hello.cpp -Xclang -dump-tokens
在这里插入图片描述

Loc=XXXX 表示该字符或字符串所对应的行数及位置
Int ‘int’ , 表⽰ int 代表整型
Identifier ‘main’, 表⽰ main 是⼀个标识符
numeric_constant ‘XXXXXX’,表⽰数值常量
l_paren ‘(‘ , 表示左括号

⑥查看词法分析结果 2:clang test.c -Xclang -dump-raw-tokens

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

可以看到词法分析2比词法分析1更加详细,比如对空格‘ ’也同样进行了分析。

⑦查看语义分析结果:clang test.c -Xclang -ast-dump
语义分析部分终端显示较多,以下截取部分进行展示:
在这里插入图片描述

可以看到,从命名空间开始分析
UsingDirectiveDecl 0x35e7158 <hello.cpp:4:1, col:17> col:17 Namespace 0x2fa7ab8 ‘std’
再到分析函数,FunctionDecl 0x35e71c8 <line:6:1, col:16> col:5 BubbleSort ‘int (void)’
层层分析,最后到定义的字符串
StringLiteral 0x35e73a8 col:19 ‘const char [12]’ lvalue “XXXXXX”

⑧查看编译优化的结果:
部分代码如图所示:
在这里插入图片描述

⑨查看生成的目标代码结果: clang++ hello.cpp –S
查看生成的汇编代码:
在这里插入图片描述
在这里插入图片描述

4.3 G++编译器优化

⽤编写的100*100矩阵相乘的C++代码,使用G++编译器并⽤不同编译优化选项,如分别运行以下命令:

g++ matrix.cpp -O0 -o matrix0
g++ matrix.cpp -O1 -o matrix1
g++ matrix.cpp -O2 -o matrix2
g++ matrix.cpp -O3 -o matrix3

运行结果如图所示:
在这里插入图片描述

时间对比如下:
在这里插入图片描述

可以看出 O1,O2,O3 三种优化选择能够明显提升矩阵乘法运算的效率。

4.4 LLVM编译器优化

⽤编写的100*100矩阵相乘的C++代码,使用LLVM编译器并⽤不同编译优化选项,如分别运行以下命令:

clang++ matrix.cpp  -o clang_matrix
clang++ matrix.cpp -O0 -o clang_matrix0
clang++ matrix.cpp -O1 -o clang_matrix1
clang++ matrix.cpp -O2 -o clang_matrix2
clang++ matrix.cpp -O3 -o clang_matrix3

运行结果如下图所示:
在这里插入图片描述

时间对比如下:
在这里插入图片描述

可以看出 O1,O2,O3 三种优化选择能够明显提升矩阵乘法运算的效率。

4.5 G++和LLVM优化对比

在这里插入图片描述

由上述柱状图可以看出,在矩阵乘法这个程序上,在相同规模的情况下,在⽆优化,和 -O0 优化的编译情况下,G++编译器的运行时间小于LLVM编译器。在 O2,O3 优化的编译情况下,两者的效率不分上下。但是在O1优化情况下G++效率比LLVM大得多,程序运行时间更短。

五、实验心得

①通过本实验,我了解了编译过程中的每个过程⽣成的⽂件,
②了解了编译器的常⽤选项,包括⼀些优化参数
③通过使用不同的编译器,调用不同的优化参数,体会到这些参数对程序运行带来的不同影响

  • 6
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目:C0编译器的设计与实现(10周) C0语言的语法结构定义如下: ->[] {} -> int id {, id}; -> ( int id | void id) '(' ')' ->void main'(' ')' ->'{' [] '}' -> {} -> | | '{''}' | | | | | | ; ->if '('')' [else ] ->while '(' ')' ->; ->id = ; ->return ['(' ')'] ; ->scanf '(' id ')'; ->printf '(' [ ] ')'; -> [+|-] { (+|-) } -> {(*|/) } -> id|'(' ')' | num | ->id '(' ')' 其中,id代表标识符,num代表整数,其含义及构成方式与C语言相一致;C0源程序中的变量需先定义后使用,其作用域与生存期与C语言相一致;自定义函数可超前使用(调用在前,定义在后)。 根据上面给定的C0文法及其说明和下列定义的假想栈式指令系统,按递归下降分析法设计并实现该C0语言的编译器,生成栈式目标代码;编写栈式指令系统的解释执行程序,输出目标代码的解释执行结果。 假想的栈式指令系统表 LIT 0 a 将常数值取到栈顶,a为常数值 LOD t a 将变量值取到栈顶,a为相对地址,t为层差 STO t a 将栈顶内容送入某变量单元中,a为相对地址,t为层差 CAL 0 a 调用函数,a为函数地址 INT 0 a 在运行栈中为被调用的过程开辟a个单元的数据区 JMP 0 a 无条件跳转至a地址 JPC 0 a 条件跳转,当栈顶值为0,则跳转至a地址,否则顺序执行 ADD 0 0 次栈顶与栈顶相加,退两个栈元素,结果值进栈 SUB 0 0 次栈顶减去栈顶,退两个栈元素,结果值进栈 MUL 0 0 次栈顶乘以栈顶,退两个栈元素,结果值进栈 DIV 0 0 次栈顶除以栈顶,退两个栈元素,结果值进栈 RED 0 0 从命令行读入一个输入置于栈顶 WRT 0 0 栈顶值输出至屏幕并换行 RET 0 0 函数调用结束后,返回调用点并退栈
编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译原理实验编译

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值