现在的位置: 首页 > 综合 > 正文

GCC’s bacl-end & assemble emission (4)

2013年07月28日 ⁄ 综合 ⁄ 共 9689字 ⁄ 字号 评论关闭

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. 
*/

89   


 


enum
decision_type

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

));

抱歉!评论已关闭.