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

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

2013年12月19日 ⁄ 综合 ⁄ 共 9837字 ⁄ 字号 评论关闭

4.       



Tool
of genemit

4.1.



Preparation for Code Generation

This tool outputs insn-emit.c file from machine description file.
Insn-emit.c defines function sto generate a body for patterns, given operands
as arguments.

 

775 


int

776 


main (int argc, char **argv)                                                                       
in
genemit.c

777 


{

778 


 

rtx desc;

779 

780 


 

progname = "genemit";

781 

782 


 

if (argc <= 1)

783 


   

fatal ("no input file name");

784 

785 


 

if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)

786 


   

return
(FATAL_EXIT_CODE);

787 

788 


 
/* Assign sequential codes to all entries in
the machine description

789 


   
i

n parallel with the tables in
insn-output.c. 
*/

790 

791 


 

insn_code_number = 0;

792 


 

insn_index_number = 0;

793 

794 


 

printf ("/* Generated automatically by the program `genemit'/n/

795 


       

from the machine description file `md'. 

*//n/n");

796 

797 


 
printf ("#include
/"config.h/"/n");

798 


 

printf
("#include /"system.h/"/n");

799 


 

printf ("#include /"coretypes.h/"/n");

800 


 

printf ("#include /"tm.h/"/n");

801 


 

printf ("#include /"rtl.h/"/n");

802 


 

printf ("#include /"tm_p.h/"/n");

803 


 

printf ("#include /"function.h/"/n");

804 


 

printf ("#include /"expr.h/"/n");

805 


 
printf ("#include
/"optabs.h/"/n");

806 


 

printf
("#include /"real.h/"/n");

807 


 

printf ("#include /"flags.h/"/n");

808 


 

printf ("#include /"output.h/"/n");

809 


 

printf ("#include /"insn-config.h/"/n");

810 


 

printf ("#include /"hard-reg-set.h/"/n");

811 


 

printf ("#include /"recog.h/"/n");

812 


 

printf ("#include /"resource.h/"/n");

813 


 

printf ("#include /"reload.h/"/n");

814 


 

printf ("#include /"toplev.h/"/n");

815 


 


printf
("#include /"ggc.h/"/n/n");

816 


 

printf ("#define
FAIL return (end_sequence (), _val)/n");

817 


 

printf ("#define DONE return (_val = get_insns (), end_sequence (),
_val)/n/n");

 

The beginning all looks alike. At line 785, init_md_reader_args


reads in
the machine description file and creates corresponding rtx objects. We just
takes the define_insn_and_split example in Tool of
genconditions

, which will be splited into two rtx objects.

 

4225


(define_insn_and_split
"*fix_truncsi_1"                                                      
in
i386.md

4226


 
[(set (match_operand:SI 0
"nonimmediate_operand" "=m,?r")

4227


      
(fix:SI (match_operand 1
"register_operand" "f,f")))]

4228


 
"TARGET_80387 && FLOAT_MODE_P
(GET_MODE (operands[1]))

4229


  
&& !reload_completed &&
!reload_in_progress

4230


  
&& !SSE_FLOAT_MODE_P (GET_MODE
(operands[1]))"

4231


 
"#"

4232


 
"&& 1"

4233


 
[(const_int 0)]

4234


{

4235


 
ix86_optimize_mode_switching = 1;

4236


 
operands[2] = assign_386_stack_local (HImode,
1);

4237


 
operands[3] = assign_386_stack_local (HImode,
2);

4238


 
if (memory_operand (operands[0], VOIDmode))

4239


   
emit_insn (gen_fix_truncsi_memory
(operands[0], operands[1],

4240


                           
      
operands[2], operands[3]));

4241


 
else

4242


   
{

4243


     
operands[4] = assign_386_stack_local
(SImode, 0);

4244


     
emit_insn (gen_fix_truncsi_nomemory
(operands[0], operands[1],

4245


                                  
  
operands[2], operands[3],

4246


                                  
  
operands[4]));

4247


   
}

4248


 
DONE;

4249


}

4250


 
[(set_attr "type"
"fistp")

4251


  
(set_attr "mode" "SI")])

 

Then in following, in main


we will handle the rtx object instead.

 

main (continued)

 

819 


 

/* Read the machine description. 
*/

820 

821 


 

while
(1)

822 


 

{

823 


   

int line_no;

824 

825 


   
desc = read_md_rtx
(&line_no, &insn_code_number);

826 


   

if (desc == NULL)

827 


     

break
;

828 

829 


   

switch
(GET_CODE (desc))

830 


   

{

831 


     

case
DEFINE_INSN:

832 


      

 
gen_insn
(desc,
line_no);

833 


     

  
break
;

834 

835 


     

case
DEFINE_EXPAND:

836 


       

printf ("/* %s:%d *//n", read_rtx_filename, line_no);

837 


     

  
gen_expand (desc);

838 


       

break
;

839 

840 


     

case
DEFINE_SPLIT:

841 


       

printf ("/* %s:%d *//n", read_rtx_filename, line_no);

842 


     

  

gen_split



(desc);

843 


       

break
;

844 

845 


     

case
DEFINE_PEEPHOLE2:

846 


       

printf ("/* %s:%d *//n", read_rtx_filename, line_no);

847 


     

  

gen_split



(desc);

848 


       

break
;

849 

850 


     

default
:

851 


       

break
;

852 


   

}

853 


   

++insn_index_number;

854 


 

}

855 

856 


 

/* Write out the routines to add CLOBBERs to a
pattern and say whether they

857 


   
clobber a hard reg. 
*/

858 


 

output_add_clobbers ();

859 


 

output_added_clobbers_hard_reg_p ();

860 

861 


 

fflush (stdout);

862 


 

return
(ferror (stdout) !=

0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);

863 


}

4.2.



Generate Code for define_insn

For our example define_insn_and_split pattern, after read in, the
define_insn part is as following.

t29

figure
29


 : genemit - example of define_insn_and_split pattern – insn
part

It is a define_insn rtx object, so gen_insn

will be invoked.

 

287 


static
void

288 


gen_ins

n (rtx insn, int lineno)                                                                     
      
in genemit.c

289 


{

290 


 

int operands;

291 


 

int i;

292 

293 


 

/* See if the pattern for this insn ends with
a group of CLOBBERs of (hard)

294 


   
registers or MATCH_SCRATCHes. If so, store
away the information for

295 


   
later. 

*/

296 

297 


 

if (XVEC (insn, 1))

298 


 

{

299 


   

int has_hard_reg = 0;

300 

301 


   
for
(i = XVECLEN (insn, 1) - 1; i > 0; i--)

302 


   

{

303 


     

if (GET_CODE (XVECEXP (insn, 1, i)) != CLOBBER)

304 


       

break
;

305 

306 


     

if (GET_CODE (XEXP
(XVECEXP (insn, 1, i), 0)) ==
REG)

307 


       

has_hard_reg = 1;

308 


     

else if (GET_CODE (XEXP
(XVECEXP (insn, 1, i), 0))
!= MATCH_SCRATCH)

309 


       

break
;

310 


   

}

 

For our example above, it breaks out the loop at line 304, as the
pattern doesn’t clobber any register.

 

gen_insn (continued)

 

312 


   

if (i != XVECLEN (insn, 1) - 1)

313 


   

{

314 


     

struct
clobber_pat
*p;

315 


     

struct
clobber_ent
*link = xmalloc (sizeof
(struct
clobber_ent));

316 


     

int j;

317 

318 


     

link->code_number = insn_code_number

;

319 

320 


     

/* See if any previous CLOBBER_LIST entry is
the same as this

321 


       
one. 

*/

322 

323 


     

for
(p = clobber_list

; p; p = p->next)

324 


     

{

325 


       

if (p->first_clobber != i + 1

326 


          
|| XVECLEN (p->pattern, 1) !=
XVECLEN (insn, 1))

327 


         
continue
;

328 

329 


       

for
(j = i + 1; j < XVECLEN (insn,
1); j++)

330 


       

{

331 


         
rtx old = XEXP
(XVECEXP (p->pattern, 1, j), 0);

332 


         
rtx new = XEXP
(XVECEXP (insn, 1, j), 0);

333 

334 


        

 
/* OLD
and NEW are the same if both are to be a SCRATCH

335 


           
of the same mode,

336 


           
or if both are registers of the
same mode and number. 
*/

337 


         
if (! (GET_MODE (old) == GET_MODE
(new)

338 


           
&& ((GET_CODE (old) ==
MATCH_SCRATCH

339 


           
&& GET_CODE (new) ==
MATCH_SCRATCH)

340 


           
|| (GET_CODE (old) == REG
&& GET_CODE (new) == REG

341 


              
&& REGNO (old) == REGNO
(new)))))

342 


           
break
;

343 


       

}

344 

345 


       

if (j == XVECLEN (insn, 1))

346 


         
break
;

347 


     

}

348 

349 


     

if (p == 0)

350 


     

{

351 


       

p = xmalloc (sizeof
(struct
clobber_pat));

352 

353 


       

p->insns = 0;

354 


       

p->pattern = insn;

355 


       

p->first_clobber = i + 1;

356 


       

p->next = clobber_list

;

357 


       

p->has_hard_reg = has_hard_reg;

358 


       

clobber_list

= p;

359 


     

}

360 

361 


     

link->next = p->insns;

362 


     

p->insns = link;

363 


   

}

364 


 

}

 

Above, for pattern will clobber register, the relative information
must be saved in clobber_list. It has following definition:

 


42   


struct
clobber_pat                                                                                      
in
genemit.c

43   


{

44   


 

struct
clobber_ent
*insns;

45   


 

rtx pattern;

46   


 

int first_clobber;

47   


 

struct
clobber_pat *next;

48   


 

int has_hard_reg;

49   


} *clobber_list;

50   

51   


/* Records one
insn that uses the clobber list. 
*/

52   


53   


struct
clobber_ent

54   


{

55   


 

int code_number;             
/* Counts only insns. 

*/

56   


 

struct
clobber_ent *next;

57   


};

 

clobber_pat keeps the record of clobber information for the patterns
having the same form, 
in other words, for
two patterns have different form, they will belong to different clobber_pat
instances. So has_hard_reg

,
first_clobber

are meaningful for all members in clobber_ent

, in which first_clobber

means at which step
the specified register will be clobbered and has_hard_reg

indicates if real
register is involved.

code_number

in clobber_ent distincts the patterns, as it comes from insn_code_number

,
which is unique and invariable for specified pattern. Obviously, clobber_ent is
per pattern. And for our example, no clobber information is collected.

 

gen_insn (continued)

 

366 


 

/* Don't mention instructions whose names are
the null string

367 


   
or begin with '*'. They are in the machine
description just

368 


   
to be recognized. 
*/

369 


 

if (XSTR (insn, 0)[0] == 0 || XSTR (insn, 0)[0] == '*')

370 


   

return
;

371 

372 


 

printf ("/* %s:%d *//n", read_rtx_filename

, lineno);

373 

374 


 

/* Find out how many operands this function
has. 
*/

375 


 

operands = max_operand_vec
(insn, 1);

376 


 

if (max_dup_opno

>= operands)

377 


   

fatal ("match_dup operand number has no match_operand");

378 


 

/* Output the function name and argument
declarations. 
*/

379 


 

printf ("rtx/ngen_%s (", XSTR (insn, 0));

380 


 

if (operands)

381 


   

for
(i = 0; i < operands; i++)

382 


     

if (i)

383 


       

printf (",/n/trtx operand%d ATTRIBUTE_UNUSED", i);

384 


     

else

385 


       

printf ("rtx operand%d ATTRIBUTE_UNUSED", i);

386 


 

else

387 


   

printf ("void");

388 


 

printf (")/n");

389 


 

printf ("{/n");

 

Unfortunatly, our example has ‘*’ at the beginning of its name,
which means the instruction pattern is never used for generating RTL code and
such a name is used only for identifying the instruction in RTL dumps. So in
real world, it will return at line 370 without doing something meaningful.

Now, we assuem that the ‘*’ is not appeared all long. At line 372,
it gives information where we are from. At line 375, max_operand_vec

finds out the number
of operands in the pattern. This function is quite simple. For our example, max_opno

will be 2.

 

108 


static
int


109 


max_operand_vec
(rtx insn, int arg)                                                           
in
genemit.c

110 


{

111 


 
int len = XVECLEN (insn, arg);

112 


 
int i;

113 

114 


 
max_opno

= -1;

115 


 

max_dup_opno

= -1;

116 


 

max_scratch_opno

= -1;

117 

118 


 
for
(i = 0; i < len; i++)

119 


   

max_operand_1


(XVECEXP (insn, arg, i));

120 

121 


 

return
max_opno

+ 1;

122 


}

 

72   


static
void


73   


max_operand_1
(rtx x)                                                                
      
      
in
genemit.c

74   


{

75   


 
RTX_CODE code;

76   


 
int i;

77   


 
int len;

78   


 
const
char *fmt;

79   

80   


 

if (x == 0)

81   


   

return
;

82   

83   


 

code = GET_CODE (x);

84   

85   


 

if (code == MATCH_OPERAND || code == MATCH_OPERATOR

86   


     

|| code == MATCH_PARALLEL)

87   


   

max_opno

= MAX (max_opno

,
XINT (x, 0));

88   


 
if (code == MATCH_DUP ||
code == MATCH_OP_DUP || code == MATCH_PAR_DUP)

89   


   

max_dup_opno

= MAX (max_dup_opno

,
XINT (x, 0));

90   


 

if (code == MATCH_SCRATCH)

91   


   

max_scratch_opno

= MAX (max_scratch_opno

,
XINT (x, 0));

92   

93   


 

fmt = GET_RTX_FORMAT (code);

94   


 

len = GET_RTX_LENGTH (code);

95   


 
for
(i = 0; i < len; i++)

抱歉!评论已关闭.