gcc后端的主要模块的相关分析
1、tree和rtl都属于中间层;tree偏向于前端;而rtl偏向于后端。后端的主要工作过程步骤是:tree --> rtl --> 汇编程序。
2、前端调用后端的函数接口主要是expand_*系列函数集,这一系列函数的作用是完成从tree到rtl的转换。这些函数按照功能分类在以下一些文件中被实现:stmt.c calls.c expr.c explow.c expmed.c function.c optabs.c integrate.c (1) stmt.c中的expand_*函数的作用是:将前端的“语句”级别上的语法树转换为等义 的rtl。因此stmt.c中的这些expand_*函数是被前端parser最先调用的, 换句话 说,这些函数是"gcc后端"的第1功能层(顶层)。它们会调用exp*.c的一些expand_*函 数来真正完成对“表达式”的求值(也即表达式的tree --> rtx,并返回rtx),以 及调用emit-rtl.c中gen_rtx和gen_reg_rtx等功能函数。 (2) calls.也是语句级别上的,它将函数调用语句的tree转换为rtl。 (3) function.c在函数一级将tree转换为rtl (4) expr.c explow.c expmed.c完成对表达式的tree到rtx的转换。这些文件中的expand_* 函数基本可以归纳为第2功能层。它这里会将一步引用insn_emit.c文件中的gen_*等功 能函数;以及optabs.c文件中的expand_*函数。 (5) optabs.c文件中的expand_*函数作用是将基本的一元操作和二元操作转换为rtx。它属 于expand_*函数集中的第3功能层。它这里接着往下就会引用与平台相关的一些函数模 块(从md自动生成的一些程序文件,如insn-output.c、insn-emit.c等其它insn-*系列 文件) 3、后端的接口除了是expand_*系列函数集以外。另外还有两大系列接口函数:一类就是gen_*函数集,它的作用是生成rtx,它这里可能会进一步调用emit_*系列函数;另一类是emit_*函数集,它完成对rtx的封装,也即生成insn线性结构的rtl语言的程序。
4、gcc后端子系统中,由平台独立的expand_*函数集模块向平台依赖的gen_*函数集模块的操作接口主要是:optab_table[]和insn_data[]。例如,expand_binop函数中针对CODE为PLUS的表达式,它的调用过程是这样子的:首先找到PLUS表达式对应的实体optab_table[code];接着根据正确的MACHINE_MODES来找到optab_table[code].handlers[mode].insn_code;再根据这个insn_code,找到insn_data[insn_code];最后insn_data[insn_code].genfun对应上insn-emit.c文件中的gen_addsi3函数,调用这个函数会生成合适的rtl。
(1) optab_table是一个指针数组。对每一个抽象指令操作,都会有一个对应的optab实体。它的结构声明如下(在Optabs.h文件中): /* Optabs are tables saying how to generate insn bodies for various machine modes and numbers of operands. Each optab applies to one operation. For example, add_optab applies to addition. The insn_code slot is the enum insn_code that says how to generate an insn for this operation on a particular machine mode. It is CODE_FOR_nothing if there is no such insn on the target machine. The `lib_call' slot is the name of the library function that can be used to perform the operation. A few optabs, such as move_optab and cmp_optab, are used by special code. */ struct optab GTY(()) { enum rtx_code code; struct optab_handlers { enum insn_code insn_code; rtx libfunc; } handlers [NUM_MACHINE_MODES]; }; typedef struct optab * optab;
变量的定义如下(在Optabs.c文件中):optab optab_table[OTI_MAX]; 该变量的初始化分配是在Optabs.c文件中的init_optab(...)和init_libfuncs(...)函数。 (2) insn_data在Recog.h文件中声明的,如下: struct insn_data { const char *const name; const PTR output; const insn_gen_fn genfun; const struct insn_operand_data *const operand; const char n_operands; const char n_dups; const char n_alternatives; const char output_format; }; extern const struct insn_data insn_data[]; 该变量的定义和初始化在insn-output.c文件(Generated automatically by the program `genoutput' from the machine description file `md')中,如下:const struct insn_data insn_data[] = ... 5、前面的(从2到4的分析项)都是从tree到rtl的转换过程。而后端的第二个主要工作任务是从rtl到汇编代码的产生,这个任务由Toplev.c文件中的rest_of_compilation函数来完成(源文件对这个函数的注释如下:This is called from finish_function (within langhooks.parse_file) after each top-level definition is parsed. It is supposed to compile that function or variable and output the assembler code for it. After we return, the tree storage is freed.)。所以说,rest_of_compilation函数是一个关键的分界点,在gcc编译过程中,进入到这个函数之前,它必定对源代码的某个函数(或变量)单元完成了从tree到rtl的转换;而rest_of_compilation函数内则实现了从rtl到汇编代码的输出(另外,也同时包含了其它许多重要的功能,如对rtl的优化、cfg的分析、异常的处理分析、rtl的dump等)。
6、最后,对gcc后端子系统中与平台相关的一些模块分别做一个简短的介绍。
(1) genrtx.c : rtl.def 作用:生成了一系列的gen_rtx_*函数集,这些函数是根据rtx的CODE来allocate一个rtl结构体单元 (2) insn-attrtab.c : md (由genattrtab所生成) (3) insn-conditions.c : md (由genconditions所生成) (4) insn-emit.c : md (由genemit所生成) 作用:#define GEN_FCN(CODE) (*insn_data[(int) (CODE)].genfun)所指向的目标函数,如:gen_adddi3 (5) insn-extract.c : md (由genextract所生成) (6) insn-opinit.c : md (由genopinit所生成) 作用:初始化设置optab_table表 (7) insn-output.c : md (由genoutput所生成) 作用:定义并初始化设置insn_data接口变量 (8) insn-peep.c : md (由genpeep所生成) (9) insn-recog.c : md (由genrecog所生成) (10) insn-attr.h : md (由genattr所生成) (11) insn-codes.h : md (由gencodes所生成) 作用:定义了枚举类型的insn-code (12) insn-config.h : md (由genconfig所生成) (13) insn-flags.h : md (由genflags所生成)
|
文章评论(0条评论)
登录后参与讨论