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.
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
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++)