编译原理实验二·了解GCC和LLVM·熟悉使用过程·观察中间文件·了解编译器优化效果

了解GCC和LLVM·熟悉使用过程·观察中间文件·了解编译器优化效果

实验目的和内容:

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

实验过程与步骤:

本实验主要的内容为在 Linux 平台上安装和运行工业界常用的编译器GCC和LLVM,如果系统中没有安装,则需要首先安装编译器,安装完成后编写简单的测试程序,使用编译器编译,并观察中间输出结果。

(1)对于 GCC 编译器,完成编译器安装和测试程序编写后,按如下步骤完成:
1.查看编译器的版本
2.使用编译器编译单个文件
3.使用编译器编译链接多个文件
4.查看预处理结果:gcc -E hello.c -o hello.i
5.查看语法分析树:gcc -fdump-tree-all hello.c
6.查看中间代码生成结果:gcc -fdump-rtl-all hello.c
7.查看生成的目标代码(汇编代码):gcc –S hello.c –o hello.s
(2)对于 LLVM 编译器,完成编译器安装和测试程序编写后,按如下步骤完成:
1.查看编译器的版本
2.使用编译器编译单个文件
3.使用编译器编译链接多个文件
4.查看编译流程和阶段:clang -ccc-print-phases test.c -c
5.查看词法分析结果:clang test.c -Xclang -dump-tokens
6.查看词法分析结果 2:clang test.c -Xclang -dump-raw-tokens
7.查看语法分析结果:clang test.c -Xclang -ast-dump
8.查看语法分析结果 2:clang test.c -Xclang -ast-view
9.查看编译优化的结果:clang test.c -S -mllvm -print-after-all
10.查看生成的目标代码结果:clang test.c –S
(3)要求:
编写测试程序:可以使用语言认知部分的 C 语言程序,或者其他的 C 语言程序作为编译器的输入进行观测。需要注意的是,不但要求对单个C文件进行编译,还要求对多个C文件一起编译和链接。
运行编译器进行观测:分别运行 GCC 和 LLVM 编译器,首先要学习编译器的基本使用方法,其次要通过编译选项查看分析编译器的中间结果,及其与输入源码之间的对应关系,最后使用-O0、-O1、-O2和-O3分别使用两个编译器对输入程序进行优化编译,并对比 GCC 和 LLVM 优化后程序的运行效率。

运行效果截图

准备环境

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

GCC编译

查看编译器的版本
在这里插入图片描述
使用编译器编译单个文件

//main.c
#include <stdio.h>
int main()
{
    int a;
    a = 1;
    a++;
    printf("%d\n", a);
    return 0;
}

在这里插入图片描述

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

//a.h
#include <stdio.h>
int a = 1;

//a.c
#include <stdio.h>
#include "a.h"
int main()
{
    printf("a = %d\n", a);
    return 0;
}

在这里插入图片描述
4.2.4查看预处理结果:gcc -E hello.c -o hello.i
在这里插入图片描述
在这里插入图片描述
4.2.5查看语法分析树:gcc -fdump-tree-all hello.c
在这里插入图片描述
在这里插入图片描述
4.2.6查看中间代码生成结果:gcc -fdump-rtl-all hello.c
在这里插入图片描述
在这里插入图片描述
4.2.7查看生成的目标代码(汇编代码):gcc –S hello.c –o hello.s
在这里插入图片描述

   .file	"main.c"
   .text
   .section	.rodata
.LC0:
   .string	"%d\n"
   .text
   .globl	main
   .type	main, @function
main:
.LFB0:
   .cfi_startproc
   pushq	%rbp
   .cfi_def_cfa_offset 16
   .cfi_offset 6, -16
   movq	%rsp, %rbp
   .cfi_def_cfa_register 6
   subq	$16, %rsp
   movl	$1, -4(%rbp)
   addl	$1, -4(%rbp)
   movl	-4(%rbp), %eax
   movl	%eax, %esi
   movl	$.LC0, %edi
   movl	$0, %eax
   call	printf
   movl	$0, %eax
   leave
   .cfi_def_cfa 7, 8
   ret
   .cfi_endproc
.LFE0:
   .size	main, .-main
   .ident	"GCC: (GNU) 8.4.1 20200928 (Red Hat 8.4.1-1)"
   .section	.note.GNU-stack,"",@progbits

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
在这里插入图片描述

	.text
	.file	"main.c"
	.globl	main                            # -- Begin function main
	.p2align	4, 0x90
	.type	main,@function
main:                                   # @main
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$16, %rsp
	movl	$0, -4(%rbp)
	movl	$1, -8(%rbp)
	movl	-8(%rbp), %eax
	addl	$1, %eax
	movl	%eax, -8(%rbp)
	movl	-8(%rbp), %esi
	movabsq	$.L.str, %rdi
	movb	$0, %al
	callq	printf
	xorl	%eax, %eax
	addq	$16, %rsp
	popq	%rbp
	.cfi_def_cfa %rsp, 8
	retq
.Lfunc_end0:
	.size	main, .Lfunc_end0-main
	.cfi_endproc
                                        # -- End function
	.type	.L.str,@object                  # @.str
	.section	.rodata.str1.1,"aMS",@progbits,1
.L.str:
	.asciz	"%d\n"
	.size	.L.str, 4

	.ident	"clang version 12.0.1 (Red Hat 12.0.1-4.module_el8.5.0+1025+93159d6c)"
	.section	".note.GNU-stack","",@progbits
	.addrsig
	.addrsig_sym printf

优化程序运行效率对比

使用-O0、-O1、-O2和-O3分别使用两个编译器对输入程序进行优化编译,并对比 GCC 和 LLVM 优化后程序的运行效率。
使用一个纯c语言的矩阵乘法来比较

#include <sys/time.h>
#include <stdio.h>

int main()
{
    struct timeval start, end;
    gettimeofday(&start, NULL);
    int N = 100;
    int matrix_one[N][N];
    int matrix_two[N][N];
    int matrix_result[N][N];

    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            matrix_one[i][j] = (j + 1);
        }
    }
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            matrix_two[i][j] = (j + 1);
        }
    }

    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            matrix_result[i][j] = 0;
            for (int k = 0; k < N - 1; k++)
            {
                matrix_result[i][j] += matrix_one[i][k] * matrix_two[k][j];
            }
        }
    }

    gettimeofday(&end, NULL);
    long time_lag = end.tv_usec - start.tv_usec;
    printf("time : %d", time_lag);
    return 0;
}

4.4.1 GCC优化
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
4.4.2 clang优化
在这里插入图片描述
Clang显的更为严谨一些,long类型要求我们修改为ld,修改之后再来编译:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
优化后时间已经近乎瞬时完成了

  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhj12399

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值