3.
genrecog
工具
3.1.
代码输出的准备
工具
genrecog
用于产生识别及转换
RTL
到汇编的转换引擎。在这里我们看到该工具如何从机器描述文件构建出这个引擎——我们以
i386
系统为例子,这个机器描述文件是
i386.md
。
2612
int
2613
main (int argc,
char **argv)
in
genrecog.c
2614
{
2615
rtx desc;
2616
struct
decision_head
recog_tree, split_tree, peephole2_tree,
h;
2617
2618
progname
= "genrecog";
2619
2620
memset (&recog_tree, 0, sizeof
recog_tree);
2621
memset (&split_tree, 0, sizeof
split_tree);
2622
memset (&peephole2_tree, 0, sizeof
peephole2_tree);
2623
2624
if (argc <= 1)
2625
fatal ("no input file name");
在
2616
行,结构体
decision_head
保存了转换引擎的决策树(
decision tree
)。它具有如下的定义。
73
struct
decision_head
in genrecog.c
74
{
75
struct
decision
*first;
76
struct
decision
*last;
77
};
而在上面
75
行,
decision
的定义如下。
125
struct
decision
in genrecog.c
126
{
127
struct
decision_head
success;
/*
Nodes to test on success.
*/
128
struct
decision *next;
/* Node to
test on failure.
*/
129
struct
decision *prev;
/* Node whose
failure tests us.
*/
130
struct
decision *afterward;
/* Node to test on success,
131
but failure of successor nodes.
*/
132
133
const
char *position;
/* String
denoting position in pattern.
*/
134
135
struct
decision_test
*tests;
/* The tests for this node.
*/
136
137
int number;
/* Node number, used for labels */
138
int subroutine_number;
/* Number of subroutine this node starts */
139
int need_label;
/* Label
needs to be output.
*/
140
};
在
135
行,
decision_test
保存了决策所需要的测试及其结果。
83
struct
decision_test
in genrecog.c
84
{
85
/* A linked list through the tests attached to
a node.
*/
86
struct
decision_test *next;
87
88
/* These types are roughly in the order in
which we'd like to test them.
*/
90
{
91
DT_mode, DT_code, DT_veclen,
92
DT_elt_zero_int, DT_elt_one_int, DT_elt_zero_wide,
DT_elt_zero_wide_safe,
93
DT_veclen_ge, DT_dup, DT_pred,
DT_c_test,
94
DT_accept_op, DT_accept_insn
95
} type;
96
97
union
98
{
99
enum
machine_mode mode;
/* Machine mode of node.
*/
100
RTX_CODE code;
/* Code to
test.
*/
101
102
struct
103
{
104
const
char *name;
/*
Predicate to call.
*/
105
int index;
/*
Index into `preds' or -1.
*/
106
enum
machine_mode mode;
/* Machine mode
for node.
*/
107
} pred;
108
109
const
char *c_test;
/*
Additional test to perform.
*/
110
int veclen;
/* Length of vector.
*/
111
int dup;
/*
Number of operand to compare against.
*/
112
HOST_WIDE_INT intval;
/* Value for XINT for XWINT.
*/
113
int opno;
/* Operand
number matched.
*/
114
115
struct
{
116
int code_number;
/* Insn number matched.
*/
117
int lineno;
/*
Line number of the insn.
*/
118
int num_clobbers_to_add;
/* Number of CLOBBERs to be added.
*/
119
} insn;
120
} u;
121
};
首先我们初始化
recog_tree
,
split_tree
,
peephole2_tree
及
h
的所有
decision_head
实例为
0
。然后需要初始化读入器来读入机器描述文件(
md
文件)。
main (continued, genrecog)
2627
if (init_md_reader_args (argc, argv) !=
SUCCESS_EXIT_CODE)
2628
return
(FATAL_EXIT_CODE);
2629
2630
next_insn_code
= 0;
2631
next_index
= 0;
2632
2633
write_header ();
在
2627
行,函数
init_md_reader_args
处理命令行选项。对于
genrecog
工具,它仅接受
-I
选项。这个选项显示了查找
md
文件的附加路径。然后该函数调用
init_md_reader
。这个函数我们已经在
genconditions工具
一节中看过。它从
md
文件中读入模式,构建相应的
rtx
对象并链入指定的链表。
注意到在
init_md_reader
的从
928
到
933
行,
genrecog
现在把由
genconditions
构建的
insn-conditions
放入哈希表
condition_table
中。并且记住访问的次序是:
define_attr
,
define_insn
,然后其它。
3.2.
读入
rtl
形式的定义
3.2.1.
选择合适的模式
所有的工具都有这一步,不过对于除
genconditions
以外的其它工具,可以进行一些优化,因为它们可以,通过由
genconditions
产生的
insn_conditions
,过滤出不活动的模式。
main (continued, genrecog)
2635
/* Read the machine
description.
*/
2636
2637
while
(1)
2638
{
2639
desc = read_md_rtx
(&pattern_lineno
,
&next_insn_code
);
2640
if (desc == NULL)
2641
break
;
2642
2643
if (GET_CODE (desc) == DEFINE_INSN)
2644
{
2645
h =
make_insn_sequence
(desc, RECOG);
2646
merge_trees
(&recog_tree, &h);
2647
}
2648
else if (GET_CODE (desc) == DEFINE_SPLIT)
2649
{
2650
h =
make_insn_sequence
(desc, SPLIT);
2651
merge_trees
(&split_tree, &h);
2652
}
2653
else if (GET_CODE (desc) ==
DEFINE_PEEPHOLE2)
2654
{
2655
h =
make_insn_sequence
(desc, PEEPHOLE2);
2656
merge_trees
(&peephole2_tree, &h);
2657
}
2658
2659
next_index
++;
2660
}
在
genconditions工具
一节我们已经碰到了
read_md_rtx
,现在我们仔细看一下它做什么。
965
rtx
966
read_md_rtx (int
*lineno, int *seqnr)
in
gensupport.c
967
{
968
struct
queue_elem **queue, *elem;
969
rtx desc;
970
971
discard:
972
973
/* Read all patterns from a given queue before
moving on to the next.
*/
974
if (define_attr_queue
!= NULL)
975
queue = &define_attr_queue
;
976
else if (define_insn_queue
!= NULL)
977
queue = &define_insn_queue
;
978
else if (other_queue != NULL)
979
queue = &other_queue
;
980
else
981
return
NULL_RTX;
982
983
elem = *queue;
984
*queue = elem->next;
985
desc = elem->data;
986
read_rtx_filename
= elem->filename;
987
*lineno = elem->lineno;
988
*seqnr = sequence_num
;
989
990
free (elem);
991
992
/* Discard insn patterns which we know can
never match (because
993
their C test is provably always false). If
insn_elision is
994
false, our caller needs to see all the
patterns. Note that the
995
elided patterns are never counted by the
sequence numbering; it
996
it is the caller's responsibility, when
insn_elision is false, not
997
to use elided pattern numbers for
anything.
*/
998
switch
(GET_CODE (desc))
999
{
1000
case
DEFINE_INSN:
1001
case
DEFINE_EXPAND:
1002
if (maybe_eval_c_test
(XSTR (desc, 2)) != 0)
1003
sequence_num
++;
1004
else if (insn_elision
)
1005
goto
discard;
1006
break
;
1007
1008
case
DEFINE_SPLIT:
1009
case
DEFINE_PEEPHOLE:
1010
case
DEFINE_PEEPHOLE2:
1011
if (maybe_eval_c_test
(XSTR (desc, 1)) != 0)
1012
sequence_num
++;
1013
else if (insn_elision
)
1014
goto
discard;
1015
break
;
1016
1017
default
:
1018
break
;
1019
}
1020
1021
return
desc;
1022
}
在
genrecog
中,
maybe_eval_c_test
可能为模式执行非平凡(
non-trivial
)的测试。
1067
int
1068
maybe_eval_c_test (const
char *expr)
in
gensupport.c
1069
{
1070
const
struct
c_test *test;
1071
struct
c_test
dummy;
1072
1073
if (expr[0] == 0)
1074
return
1;
1075
1076
if (insn_elision_unavailable)
1077
return
-1;
1078
1079
dummy.expr = expr;
1080
test = htab_find (condition_table
, &dummy);
1081
if (!test)
1082
abort ();
1083
1084
return
test->value;
1085
}
注意到在
1084
行,
test
从
condtion_table
获取,其内容来自由
genconditions
产生的
insn_condition
,正如我们在
init_md_reader
看到那样。
test
的
value
在
genconditions工具
一节中确定。在
write_one_condition
的
157
行,
value
由
MAYBE_EVAL(expr)
返回。
MAYBE_EVAL
也是由
genconditions
按以下方式定义:
123
puts ("/
in
genconditions.c
124
/* If we don't have
__builtin_constant_p, or it's not acceptable in/n/
125
array initializers, fall back to assuming
that all conditions/n/
126
potentially vary at run time. It works in 3.0.1
and later; 3.0/n/
127
only when not optimizing.
*/
/n/
128
#if
(GCC_VERSION >= 3001) || ((GCC_VERSION == 3000) &&
!__OPTIMIZE__)/n/
129
# define
MAYBE_EVAL(expr) (__builtin_constant_p(expr) ? (int) (expr) :
-1)/n/
130
#else
/n/
131
# define
MAYBE_EVAL(expr) -1/n/
132
#endif
/n");
__builtin_constant_p
返回整数
1
,如果该参数已知是一个编译时常量;返回
0
,如果它不能确定为编译时常量。一个
0
返回值不表示这个值不是一个常量,仅是表明
GCC
不能证明,在给定的
-O
选项(优化)值下,它是一个常量。
因此在
read_md_rtx
的
1011
行,在工具处理这个机器描述文件过程中,跳过那些条件测试部分已知为
false
的模式。这可以节省处理时间,并减小产生出来文件的大小。而那些条件测试部分已知为
true
,或那些条件测试部分不能确信为常量的模式,为
read_md_rtx
返回,并将由
make_insn_sequence
处理。
2413
static
struct
decision_head
2414
make_insn_sequence (rtx insn, enum
routine_type type)
in
genrecog.c
2415
{
2416
rtx x;
2417
const
char *c_test
= XSTR (insn, type == RECOG ? 2 : 1);
2418
int truth = maybe_eval_c_test
(c_test);
2419
struct
decision *last;
2420
struct
decision_test *test, **place;
2421
struct
decision_head head;
2422
char c_test_pos[2];
2423
2424
/* We should never
see an insn whose C test is false at compile time.
*/
2425
if (truth == 0)
2426
abort ();
2427