3.
Tool
of genrecog
3.1.
Preparation for Code Emission
The tool genrecog is used to generate the translate engine to
recognize and transform RTL to asm. Here we see how the tool creates the engine
from the machine description file – we take i386 system as example, the machine
description file is 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");
At line 2616, structure decision_head holds the decision trees for
the translate engine. It has defintion as following.
73
struct
decision_head
in genrecog.c
74
{
75
struct
decision
*first;
76
struct
decision
*last;
77
};
And at line 75 above, the definition of decision
is as following.
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
};
At line 135, decision_test
holds the detail and result about
the test taken to do the decision.
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
};
We first just initialize all decision_head instances of recog_tree
,
split_tree
,
peephole2_tree
,
and h
with all 0s. Then we need initialize the reader to read in the machine
description file (md file).
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 ();
At line 2627, function init_md_reader_args
handles the command
options. For genrecog tool, only -I option is accepted, which indicates
additional directory to search for the md file. Then the function invokes init_md_reader
.
This function we have seen in Tool of
genconditions
. It just reads patterns from md file and creates
corresponding rtx object and links them into the specified list.
Note that from line 928 to 933 in init_md_reader
,
genrecog now puts insn-conditions
created by genconditions into hash table condition_table
.
And remember that the order of the accessment is define_attr, define_insn, and
others.
3.2.
Read in Rtl Definitions
3.2.1.
Select Right Patterns
All tools have this step, but for other tools except genconditions
can have some optimization as they can filter out inactive patterns by insn_conditions
generated by genconditions.
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
}
We have met read_md_rtx
in Tool
of genconditions
, now we see what it does in detail.
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
}
In genrecog, maybe_eval_c_test
may
do non-trivial test for the pattern.
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
}
Notice that at line 1084, test
is fetched from condtion_table
which content comes
from insn_condition
generated by genconditions as we have seen in init_md_reader
. The value
of
test
is
determined in Appendix A: Tool of genconditions
.
In write_one_condition
at line 157, value
is returned by MAYBE_EVAL(expr). MAYBE_EVAL is also defined in genconditions as
following:
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
returns the integer 1 if the argument is known to be a compile-time
constant and 0 if it is not known to be a compile-time constant. A return of 0
does not indicate that the value is not a constant, but merely that GCC cannot
prove it is a constant with the specified value of the `-O' option
(optimization).
So at line 1011 in
read_md_rtx
,
it will skip those patterns having conditional test part known as false during
the tool handling the machine decription files. It can save the process time
and reduce the size of file generated. And those having conditional test part
known as true, or those conidtional test part are not ensured as constant are
returned by read_md_rtx
and will be handled by 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
2428
record_insn_name
(next_insn_code
,
(type == RECOG? XSTR (insn, 0): NULL));
For define_insn pattern, the name of the pattern is recorded by
funcion record_insn_name
.
While for other nameless patterns, for which the function will create a name in
form of insn+`codeno`. All these names are saved in global array insn_name_ptr
.
2685
static
void
2686
record_insn_name (int code, const
char *name)
in
genrecog.c
2687
{
2688
static
const
char *last_real_name = "insn";
2689
static
int
last_real_code = 0;
2690
char *new;
2691
2692
if (insn_name_ptr_size
<= code)
2693
{
2694
int new_size;
2695
new_size = (insn_name_ptr_size
? insn_name_ptr_size
* 2 : 512);
2696
insn_name_ptr
= xrealloc (insn_name_ptr
, sizeof
(char *) * new_size);
2697
memset (insn_name_ptr
+ insn_name_ptr_size
, 0,
2698
sizeof
(char *) * (new_size - insn_name_ptr_size
));