GCC后端及汇编发布(9)
2011-04-30 08:59
375 查看
4.
genemit
工具
4.1.
代码输出的准备
这个工具从机器描述文件生成文件insn-emit.c
。
Insn-emit.c
定义了,从机器描述文件中的模式定义生成的,以给定操作数作为参数的模式匹配函数。
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");
开始看起来都是类似的。在
785
行,
init_md_reader_args
读入机器描述文件,并构建对应的
rtx
对象。我们以
genconditions工具
中的
define_insn_and_split
为例,它将被分裂成两个
rtx
对象。
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")])
那么在下面,在
main
中我们将处理这个
rtx
对象。
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.1.
为
define_insn
产生代码
对于我们define_insn_and_split
模式的例子,其
define_insn
部分如下。
图
29
:
genemit - define_insn_and_split
模式
– insn
部分
这是一个
define_insn
的
rtx
对象,因此
gen_insn
将被调用。
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
}
对于我们上面的例子,它在
304
行跳出循环,因为这个模式不破坏任何寄存器。
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
}
上面。对于将破坏寄存器的模式,这个相关的信息必须被保存在
clobber_list
中。它具有如下的定义:
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
为具有相同形式的模式保存
clobber
信息的记录,换而言之,对于两个具有不同形式的模式,它们将属于不同的
clobber_pat
实例。因此
has_hard_reg
,
first_clobber
对于
clobber_ent
中的所有成员都是有意义的,其中
first_clobber
表示在哪一步这个指定的寄存器将被破坏,而
has_hard_reg
指出是否涉及真实的寄存器。
在
clobber_ent
中的
code_number
区分模式,因为它来自
insn_code_number
,对于指定的模式它是唯一且不变的。显然,
clobber_ent
是与模式对应的。对于我们的例子,没有收集
clobber
信息。
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");
不过,我们的例子在其名字的开头有“
*
”,这意味着这个指令模式不用于产生
RTL
代码,并且这样的一个名字仅用于在
RTL
转储(
dump
)中识别该指令。因此在真实世界里,它将在
370
行返回,而不做任何事。
现在,我们假定这个‘
*
’
压根没有出现过。在
372
行,给出我们来自那里的信息。在
375
行,
max_operand_vec
找出在该模式中操作数的个数。这个函数相当简单。对于我们的例子,
max_opno
将是
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++)
96
{
97
if (fmt[i] == 'e' || fmt[i] ==
'u')
98
max_operand_1
(XEXP
(x,
i));
99
else if (fmt[i] == 'E')
100
{
101
int j;
102
for
(j = 0; j < XVECLEN (x, i); j++)
103
max_operand_1
(XVECEXP (x, i, j));
104
}
105
}
106
}
那么,从上面的代码片段,我们将得到如下函数的定义(假定模式名字是
fix_truncsi_1
,而不是
*fix_truncsi_1
)。
rtx
gen_fix_truncsi_1(rtx operand0
ATTRIBUTE_UNUSED,
rtx
operand1 ATTRIBUTE_UNUSED,
rtx
operand2 ATTRIBUTE_UNUSED)
{
gen_insn (continued)
392
/* Output code to construct and return the rtl
for the instruction body.
*/
393
394
if (XVECLEN (insn, 1) == 1)
395
{
396
printf ("
return ");
397
gen_exp
(XVECEXP (insn, 1, 0), DEFINE_INSN,
NULL);
398
printf (";/n}/n/n");
399
}
400
else
401
{
402
printf ("
return gen_rtx_PARALLEL (VOIDmode, gen_rtvec
(%d",
403
XVECLEN (insn, 1));
404
405
for
(i = 0; i < XVECLEN (insn, 1); i++)
406
{
407
printf (",/n/t/t");
408
gen_exp
(XVECEXP (insn, 1, i), DEFINE_INSN,
NULL);
409
}
410
printf ("));/n}/n/n");
411
}
412
}
在
define_pattern
的
rtx
格式中,
RTL
模板具有格式‘
E
’——
rtx
对象的向量。在上面
394
行的
XVECLEN
给出了这个向量的大小,而在
408
行
XVECEXP
给出该向量中的元素。对于
gen_exp
的参数
x
,它指向以下的
RTL
模板。
4225
[(set (match_operand:SI 0
"nonimmediate_operand" "=m,?r")
4226
(fix:SI (match_operand 1
"register_operand" "f,f")))]
148
static
void
149
gen_exp (rtx x, enum
rtx_code subroutine_type, char *used)
in genemit.c
150
{
151
RTX_CODE code;
152
int i;
153
int len;
154
const
char *fmt;
155
156
if (x == 0)
157
{
158
printf ("NULL_RTX");
159
return
;
160
}
161
162
code = GET_CODE (x);
163
164
switch
(code)
165
{
166
case
MATCH_OPERAND:
167
case
MATCH_DUP:
168
if (used)
169
{
170
if (used[XINT (x, 0)])
171
{
172
printf ("copy_rtx
(operand%d)", XINT (x, 0));
173
return
;
174
}
175
used[XINT (x, 0)] = 1;
176
}
177
printf ("operand%d", XINT (x, 0));
178
return
;
179
180
case
MATCH_OP_DUP:
181
printf ("gen_rtx (GET_CODE (operand%d), ", XINT (x, 0));
182
if (GET_MODE (x) == VOIDmode)
183
printf ("GET_MODE (operand%d)", XINT (x, 0));
184
else
185
printf ("%smode", GET_MODE_NAME (GET_MODE (x)));
186
for
(i = 0; i < XVECLEN (x, 1); i++)
187
{
188
printf (",/n/t/t");
189
gen_exp
(XVECEXP (x, 1, i), subroutine_type,
used);
190
}
191
printf (")");
192
return
;
193
194
case
MATCH_OPERATOR:
195
printf ("gen_rtx (GET_CODE (operand%d)", XINT (x, 0));
196
printf (", %smode", GET_MODE_NAME (GET_MODE (x)));
197
for
(i = 0; i < XVECLEN (x, 2); i++)
198
{
199
printf (",/n/t/t");
200
gen_exp
(XVECEXP (x, 2, i), subroutine_type,
used);
201
}
202
printf (")");
203
return
;
204
205
case
MATCH_PARALLEL:
206
case
MATCH_PAR_DUP:
207
printf ("operand%d", XINT (x, 0));
208
return
;
209
210
case
MATCH_SCRATCH:
211
gen_rtx_scratch (x, subroutine_type);
212
return
;
213
214
case
ADDRESS:
215
fatal ("ADDRESS expression code used in named instruction
pattern");
216
217
case
PC:
218
printf ("pc_rtx");
219
return
;
220
221
case
CC0:
222
printf ("cc0_rtx");
223
return
;
224
225
case
CONST_INT:
226
if (INTVAL (x) == 0)
227
printf ("const0_rtx");
228
else if (INTVAL (x) == 1)
229
printf ("const1_rtx");
230
else if (INTVAL (x) == -1)
231
printf ("constm1_rtx");
232
else if (INTVAL (x) == STORE_FLAG_VALUE)
233
printf ("const_true_rtx");
234
else
235
{
236
printf ("GEN_INT (");
237
printf (HOST_WIDE_INT_PRINT_DEC_C, INTVAL (x));
238
printf (")");
239
}
240
return
;
241
242
case
CONST_DOUBLE:
243
/* These shouldn't be written in MD files. Instead,
the appropriate
244
routines in varasm.c should be called.
*/
245
abort ();
246
247
default
:
248
break
;
249
}
250
251
printf ("gen_rtx_");
252
print_code (code);
253
printf (" (%smode", GET_MODE_NAME (GET_MODE (x)));
对于我们这里的例子,编码是
SET
,因此我们直接跑到
251
行。因为这个
set
模式没有带
mode
信息,这个
mode
默认的是
VIODmode
。现在我们得到:
rtx
gen_fix_truncsi_1(rtx operand0
ATTRIBUTE_UNUSED,
rtx
operand1 ATTRIBUTE_UNUSED,
rtx
operand2 ATTRIBUTE_UNUSED)
{
return gen_rtx_set (VOIDmode,
对于
set
模式,其
rtl
格式是“
ee
”,因此在
263
行
gen_exp
递归入其孩子。
gen_exp (continued)
255
fmt = GET_RTX_FORMAT (code);
256
len = GET_RTX_LENGTH (code);
257
for
(i = 0; i < len; i++)
258
{
259
if (fmt[i] == '0')
260
break
;
261
printf (",/n/t");
262
if (fmt[i] == 'e' || fmt[i] == 'u')
263
gen_exp
(XEXP
(x, i),
subroutine_type, used);
264
else if (fmt[i] == 'i')
265
printf ("%u", XINT (x, i));
266
else if (fmt[i] == 's')
267
printf ("/"%s/"", XSTR (x, i));
268
else if (fmt[i] == 'E')
269
{
270
int j;
271
printf ("gen_rtvec
(%d", XVECLEN (x, i));
272
for
(j = 0; j < XVECLEN (x, i); j++)
273
{
274
printf (",/n/t/t");
275
gen_exp
(XVECEXP (x, i, j), subroutine_type,
used);
276
}
277
printf (")");
278
}
279
else
280
abort ();
281
}
282
printf (")");
283
}
这个
set
模式的第一个孩子是
match_operand
,我们将进入
166
行。注意到
gen_exp
的参数
used
是
null
,因此我们得到:
rtx
gen_fix_truncsi_1(rtx operand0
ATTRIBUTE_UNUSED,
rtx
operand1 ATTRIBUTE_UNUSED,
rtx
operand2 ATTRIBUTE_UNUSED)
{
return
gen_rtx_set (VOIDmode,
operand0
模式
set
的第二个孩子是
fix
,其
rtl
格式是‘
e
’。再次,我们直接跳到
251
行。并且也将使用
gen_exp
递归其第一个孩子
match_operand
。因此,对于这个
set
模式,我们得到以下代码片段。
rtx
gen_fix_truncsi_1(rtx operand0
ATTRIBUTE_UNUSED,
rtx
operand1 ATTRIBUTE_UNUSED,
rtx
operand2 ATTRIBUTE_UNUSED)
{
return
gen_rtx_SET (VOIDmode,
operand0,
gen_rtx_FIX (SImode,
operand1));
}
相关文章推荐
- GCC后端及汇编发布(45)
- GCC后端及汇编发布(19)
- GCC后端及汇编发布(27-续)
- GCC后端及汇编发布(46)
- GCC后端及汇编发布(20)
- GCC后端及汇编发布(22)
- GCC后端及汇编发布(47)
- GCC后端及汇编发布(6)
- GCC后端及汇编发布(10)
- GCC后端及汇编发布(21)
- GCC后端及汇编发布(22 续)
- GCC后端及汇编发布(32)
- GCC后端及汇编发布(37)
- GCC后端及汇编发布(7)
- GCC后端及汇编发布 当前目录
- GCC后端及汇编发布(33)
- GCC后端及汇编发布(23)
- GCC后端及汇编发布(38)
- GCC后端及汇编发布(8)
- GCC后端及汇编发布(11)