GCC后端及汇编发布(30)
2011-06-18 08:33
519 查看
9.6.
输出生成文件
9.6.1.
处理属性
9.6.1.1.
统一属性
虽然我们构建了生成最小化DFA
所需的数据,但收集的属性尚未处理。我们需要把它们转换为统一的形式,并如下打包有用的信息。
main (continued)
6137
printf ("#include /"config.h/"/n");
6138
printf ("#include
/"system.h/"/n");
6139
printf ("#include
/"coretypes.h/"/n");
6140
printf ("#include
/"tm.h/"/n");
6141
printf ("#include
/"rtl.h/"/n");
6142
printf ("#include
/"tm_p.h/"/n");
6143
printf ("#include
/"insn-config.h/"/n");
6144
printf ("#include
/"recog.h/"/n");
6145
printf ("#include
/"regs.h/"/n");
6146
printf ("#include
/"real.h/"/n");
6147
printf ("#include
/"output.h/"/n");
6148
printf ("#include
/"insn-attr.h/"/n");
6149
printf ("#include
/"toplev.h/"/n");
6150
printf ("#include
/"flags.h/"/n");
6151
printf ("#include
/"function.h/"/n");
6152
printf ("/n");
6153
printf ("#define
operands recog_data.operand/n/n");
6154
6155
/* Make
`insn_alternatives'.
*/
6156
insn_alternatives
= oballoc (insn_code_number
* sizeof
(int));
6157
for
(id = defs
;
id; id = id->next)
6158
if (id->insn_code >=
0)
6159
insn_alternatives
[id->insn_code]
= (1 << id->num_alternatives) - 1;
6160
6161
/* Make
`insn_n_alternatives'.
*/
6162
insn_n_alternatives
= oballoc (insn_code_number
* sizeof
(int));
6163
for
(id = defs
;
id; id = id->next)
6164
if (id->insn_code >=
0)
6165
insn_n_alternatives
[id->insn_code]
= id->num_alternatives;
6166
6167
/* Prepare to write out attribute subroutines by
checking everything stored
6168
away
and building the attribute cases.
*/
6169
6170
check_defs
();
上面在
6159
行,
insn_alternatives
保存着,对于每个指令编码,一个位图,每个可能的替代对应其中的一个比特。而在
6162
行,
insn_n_alternatives
保存着,对于每个指令编码,约束替代的数目。在
6170
行
check_defs
扫描所有的定义,检查有效性,并把所有的
SET_ATTR
及
SET_ATTR_ALTERNATIVE
表达式转换为对应的
SET
表达式。
首先,看一下
SET_ATTR
及
SET_ATTR_ALTERNATIVE
表达式,以下摘自注释
在
DEFINE_INSN
及
DEFINE_PEEPHOLE
最后的操作数中,这可以被用于,根据被匹配的替代,指出将被用在赋值的属性值。
以下的三个表达式是等效的:
(set
(attr "att") (cond [(eq_attrq "alternative" "1")
(const_string "a1")
(eq_attrq "alternative"
"2") (const_string "a2")]
(const_string "a3")))
(set_attr_alternative "att" [(const_string "a1")
(const_string "a2")
(const_string "a3")])
(set_attr "att" "a1,a2,a3")
check_defs
将把后两个形式转换为第一个形式。
1313
static
void
1314
check_defs
(void)
in
genattrtab.c
1315
{
1316
struct
insn_def
*id;
1317
struct
attr_desc
*attr;
1318
int i;
1319
rtx value;
1320
1321
for
(id = defs
;
id; id = id->next)
1322
{
1323
if (XVEC (id->def, id->vec_idx) ==
NULL)
1324
continue
;
1325
1326
for
(i = 0;
i < XVECLEN (id->def, id->vec_idx); i++)
1327
{
1328
value = XVECEXP (id->def, id->vec_idx,
i);
1329
switch
(GET_CODE (value))
1330
{
1331
case
SET:
1332
if (GET_CODE (XEXP
(value, 0)) != ATTR)
1333
{
1334
message_with_line (id->lineno, "bad
attribute set");
1335
have_error
= 1;
1336
value = NULL_RTX;
1337
}
1338
break
;
1339
1340
case
SET_ATTR_ALTERNATIVE:
1341
value = convert_set_attr_alternative
(value,
id);
1342
break
;
1343
1344
case
SET_ATTR:
1345
value = convert_set_attr
(value, id);
1346
break
;
1347
1348
default
:
1349
message_with_line (id->lineno,
"invalid attribute code %s",
1350
GET_RTX_NAME (GET_CODE (value)));
1351
have_error
= 1;
1352
value = NULL_RTX;
1353
}
1354
if
(value == NULL_RTX)
1355
continue
;
1356
1357
if
((attr = find_attr
(&XSTR (XEXP
(value, 0), 0), 0)) == NULL)
1358
{
1359
message_with_line (id->lineno,
"unknown attribute %s",
1360
XSTR (XEXP
(value, 0),
0));
1361
have_error
= 1;
1362
continue
;
1363
}
1364
1365
XVECEXP (id->def, id->vec_idx, i) =
value;
1366
XEXP
(value, 1) = check_attr_value
(XEXP
(value, 1), attr);
1367
}
1368
}
1369
}
上面在
1323
行,
def
指向这个
insn_def
所属的
rtx
对象,
vec_idx
显示属性向量在这个
def
中的位置,这个值是硬编码的。对于
define_insn
,它是
4
。对于
define_peephole
,它是
3
。对于
define_asm_attribute
,它是
0
。模式中的属性部分是可选的,如果不存在,意味着使用该属性的缺省值。
SET_ATTR_ALTERNATIVE
的
RTL
格式是
“
sE
”
。使用以下的例子,
(set_attr_alternative
"att" [(const_string "a1") (const_string "a2")
(const_string "a3")])
其中“
att
”是格式的“
s
”部分,而“
[…]
”是“
E
”部分,它是应该含有
3
个元素的向量。正如我们已知的,格式“
s
”对应
CONST_STRING
的
rtx
对象,而格式“
E
”对应
RTVEC
的
rtx
对象。
1244
static
rtx
1245
convert_set_attr_alternative
(rtx exp, struct
insn_def
*id)
in
genattrtab.c
1246
{
1247
int num_alt = id->num_alternatives;
1248
rtx condexp;
1249
int i;
1250
1251
if (XVECLEN (exp, 1) != num_alt)
1252
{
1253
message_with_line (id->lineno,
1254
"bad number of entries in
SET_ATTR_ALTERNATIVE");
1255
have_error
= 1;
1256
return
NULL_RTX;
1257
}
1258
1259
/* Make a COND with
all tests but the last. Select the last value via the
1260
default.
*/
1261
condexp = rtx_alloc (COND);
1262
XVEC (condexp, 0) = rtvec_alloc ((num_alt -
1) * 2);
1263
1264
for
(i = 0; i
< num_alt - 1; i++)
1265
{
1266
const
char
*p;
1267
p = attr_numeral (i);
1268
1269
XVECEXP (condexp, 0, 2 * i) =
attr_eq
(alternative_name
,
p);
1270
XVECEXP (condexp, 0, 2 * i + 1) = XVECEXP
(exp, 1, i);
1271
}
1272
1273
XEXP
(condexp, 1) = XVECEXP (exp, 1, i);
1274
1275
return
attr_rtx
(SET,
attr_rtx
(ATTR, XSTR (exp, 0)), condexp);
1276
}
SET_ATTR
的
RTL
格式是“
ss
”。所有以下的例子,
(set_attr "att" "a1,a2,a3")
。其中,“
ss
”对应“
att
”,及“
a1, a2, a3”
。首先把这个
SET_ATTR
对象转换到对应的
SET_ATTR_ALTERNATIVE
对象。然后通过上面的
convert_set_attr_alternatives
,这个
SET_ATTR_ALTERNATIVE
对象进一步转换到
SET
对象。
1281
static
rtx
1282
convert_set_attr
(rtx exp, struct
insn_def
*id)
in
genattrtab.c
1283
{
1284
rtx newexp;
1285
const
char
*name_ptr;
1286
char *p;
1287
int n;
1288
1289
/* See how many
alternative specified.
*/
1290
n = n_comma_elts (XSTR (exp, 1));
1291
if (n == 1)
1292
return
attr_rtx
(SET,
1293
attr_rtx
(ATTR, XSTR (exp, 0)),
1294
attr_rtx
(CONST_STRING, XSTR (exp, 1)));
1295
1296
newexp = rtx_alloc (SET_ATTR_ALTERNATIVE);
1297
XSTR (newexp, 0) = XSTR (exp, 0);
1298
XVEC (newexp, 1) = rtvec_alloc (n);
1299
1300
/* Process each
comma-separated name.
*/
1301
name_ptr = XSTR (exp, 1);
1302
n = 0;
1303
while
((p =
next_comma_elt (&name_ptr)) != NULL)
1304
XVECEXP (newexp, 1, n++) =
attr_rtx
(CONST_STRING, p);
1305
1306
return
convert_set_attr_alternative
(newexp, id);
1307
}
现在,因为由于处理
SET_ATTR_ALTERNATIVE
及
SET_ATTR
对象,某些属性被改变了,因此需要下面
6175
行的
check_attr_value
来再一次验证属性。
main (continued)
6172
for
(i = 0; i < MAX_ATTRS_INDEX; i++)
6173
for
(attr =
attrs
[i];
attr; attr = attr->next)
6174
attr->default_val->value
6175
= check_attr_value
(attr->default_val->value, attr);
6176
6177
if (have_error
)
6178
return
FATAL_EXIT_CODE;
6179
6180
for
(i = 0; i < MAX_ATTRS_INDEX; i++)
6181
for
(attr =
attrs
[i];
attr; attr = attr->next)
6182
fill_attr
(attr);
6183
6184
/* Construct extra
attributes for `length'.
*/
6185
make_length_attrs
();
6186
6187
/* Perform any possible optimizations to
speed up compilation.
*/
6188
optimize_attrs
();
9.6.1.2.
完成属性
对于数值属性,在其模式定义中,它必须具有空的LIST-OF-VALUE
部分(至于
define_attr
的细节,可以参考
读入
DEFINE_ATTR模式
一节)。
对于这些数值属性,
fill_attr
用于从模式中收集这些值。除此之外,对于所有的属性,这个函数将构建一个列表,它把所有使用同一个属性的指令链接起来。
2263
static
void
2264
fill_attr
(struct
attr_desc
*attr)
in
genattrtab.c
2265
{
2266
struct
attr_value
*av;
2267
struct
insn_ent
*ie;
2268
struct
insn_def
*id;
2269
int i;
2270
rtx value;
2271
2272
/* Don't fill
constant attributes. The value is independent of
2273
any particular insn.
*/
2274
if (attr->is_const)
2275
return
;
2276
2277
for
(id = defs
;
id; id = id->next)
2278
{
2279
/* If no value is
specified for this insn for this attribute, use the
2280
default.
*/
2281
value = NULL;
2282
if (XVEC (id->def, id->vec_idx))
2283
for
(i = 0; i < XVECLEN (id->def,
id->vec_idx); i++)
2284
if (! strcmp_check (XSTR (
XEXP
(XVECEXP (id->def, id->vec_idx, i), 0), 0),
2285
attr->name))
2286
value =
XEXP
(XVECEXP (id->def,
id->vec_idx, i), 1);
2287
2288
if (value == NULL)
2289
av = attr->default_val;
2290
else
2291
av =
get_attr_value
(value, attr, id->insn_code);
2292
2293
ie = oballoc (sizeof
(struct
insn_ent
));
2294
ie->insn_code
= id->insn_code;
2295
ie->insn_index = id->insn_code;
2296
insert_insn_ent
(av, ie);
2297
}
2298
}
在
fill_attr
的
2274
行
,
属性视为常量
,
如果其值是
SYMBOL_REF
或
CONST_INT
。在
2277
行,
defs
已经链接了所有的
define_insn
,
define_peephole
及
define_asm_attributes
(参见
gen_insn
)。因此在
2283
行的
FOR
循环遍历模式的属性部分,并调用
get_attr_value
来向属性的值列表加入新发现的值(注意对于具有以星号(
*
)开头,由系统产生的属性,它们将以相同的值,为每个指令所添加。这是因为,首先没有指令会包含匹配这个名字的属性,其次,所有这些属性由
make_internal_attr
构建,并具有单个的值)。而在
2296
行,
insert_insn_ent
的定义如下,它把使用相同属性值的指令链接起来。
2632
static
void
2633
insert_insn_ent
(struct
attr_value
*av, struct
insn_ent
*ie)
in genattrtab.c
2634
{
2635
ie->next = av->first_insn;
2636
av->first_insn = ie;
2637
av->num_insns++;
2638
if (ie->insn_code == -1)
2639
av->has_asm_insn = 1;
2640
2641
num_insn_ents
++;
2642
}
insn_ent
构成了具有相同属性值指令的链表,它具有如下定义。
161
struct
insn_ent
in genattrtab.c
162
{
163
struct
insn_ent *next;
/* Next in
chain.
*/
164
int insn_code;
/* Instruction number.
*/
165
int insn_index;
/* Index of definition in file */
166
int lineno;
/* Line number.
*/
167
};
继续
main
,为了更好地了解
6185
行的
make_length_attr
,首先看一下以下摘自
gccint
的段落。
对于许多机器而言,它们提供了多种跳转指令,每个对应不同跳转偏移。在绝大多数情形下,汇编器将选择使用正确的指令。不过,当汇编器做不到这一点时,
GCC
可以,当一个特殊的属性——‘
length
’属性被定义时。这个属性必须,通过在其‘
define_attr
’中指定一个空字符串,来定义为具有数字值。
就‘
length
’属性而言,允许在测试表达式中使用另外两个形式的算术项:
(match_dup
N)
这指向当前指令操作数
N
的地址,它必须是一个‘
label_re.
’。
(pc)
这指向当前指令的地址。其他的用法把它作为下一个指令的地址可能更符合,不过因为当前指令的长度会被计入,这可能会让人困扰。
对于普通的指令,长度将由‘
length
’属性的值来决定。在‘
addr_vec
’及‘
addr_diff_vec
’指令模式中,其长度通过向量的数量乘以每个向量的大小来计算。
长度以可取址储存单元(
byte
)为单位来计量。
下面的宏可以用于细化长度计算:
ADJUST_INSN_LENGTH
(INSN, LENGTH)
如果定义了,作为一个其所被应用的上下文中的一个函数,修改赋予指令
INSN
的长度。
LENGTH
是一个左值(
lvalue
),它包含了该指令初始计算的长度,并将为该指令正确的长度所更新。
这个宏通常是不要求的。要求它的一个情形是
ROMP
。在这个机器中,一个‘
addr_vec
’指令的长度必须加上
2
,来补偿可能要求对齐的这个事实。
返回‘
get_attr_length
’(‘
length
’属性的值)的函数,可以被输出函数所使用,来确定所要写出的跳转指令的形式,如下面例子所显示的。
作为一个可变长度跳转说明的例子,考虑
IBM 360
。如果我们采用约定,一个寄存器将被设置为一个函数的起始地址,我们可以,使用一个
4
字节指令,跳转到距起始地址
4k
内的
label
。否则,我们需要一个
6
字节序列,来从内存载入地址,然后跳转到这个地址。
在这样的一个机器上,一个用于一个跳转指令的模式可能被详细说明如下:
(define_insn
"jump"
[(set (pc)
(label_ref (match_operand 0 "" "")))]
""
{
return (get_attr_length (insn) == 4
?
"b %l0" : "l r15,=a(%l0); br r15");
}
[(set (attr
"length")
(if_then_else
(lt (minus (pc) (match_dup 0) (const_int 4096))
(const_int 4)
(const_int 6)))])
事实上,对于每个
define_insn
,
define_peephole
及
define_asm_attribute
模式,如果它不显式设置一个属性,它将使用该属性的缺省值。在这里
make_length
为每个模式,根据其“
length
”属性,构建了
3
个额外的属性。它们是:
*insn_default_length
这是在调用
shorten_branches
之前,由返回的
get_attr_length
指令的长度。在长度依赖于相对地址的情形下,使用最大可能的那个。
*insn_variable_length_p
这返回
1
,如果该指令的长度依赖于相对地址;否则返回
0
。
*insn_current_length
仅当已知该指令具有一个可变长度时,这才被调用,并基于相对地址返回当前长度。
2379
static
void
2380
make_length_attrs
(void)
in
genattrtab.c
2381
{
2382
static
const
char *new_names[] =
2383
{
2384
"*insn_default_length",
2385
"*insn_variable_length_p",
2386
"*insn_current_length"
2387
};
2388
static
rtx (*const
no_address_fn[]) (rtx) = {identity_fn, zero_fn,
zero_fn};
2389
static
rtx (*const
address_fn[]) (rtx) = {max_fn, one_fn,
identity_fn};
2390
size_t i;
2391
struct
attr_desc
*length_attr, *new_attr;
2392
struct
attr_value
*av, *new_av;
2393
struct
insn_ent
*ie, *new_ie;
2394
2395
/* See if length
attribute is defined. If so, it must be numeric. Make
2396
it special so we don't output anything for
it.
*/
2397
length_attr =
find_attr
(&length_str
,
0);
2398
if (length_attr == 0)
2399
return
;
2400
2401
if (! length_attr->is_numeric)
2402
fatal ("length attribute must be
numeric");
2403
2404
length_attr->is_const = 0;
2405
length_attr->is_special = 1;
2406
2407
/* Make each new
attribute, in turn.
*/
2408
for
(i = 0; i
< ARRAY_SIZE (new_names); i++)
2409
{
2410
make_internal_attr
(new_names[i],
2411
substitute_address
(length_attr->default_val->value,
2412
no_address_fn[i], address_fn[i]),
2413
ATTR_NONE);
2414
new_attr =
find_attr
(&new_names[i], 0);
2415
for
(av =
length_attr->first_value; av; av = av->next)
2416
for
(ie =
av->first_insn; ie; ie = ie->next)
2417
{
2418
new_av =
get_attr_value
(
substitute_address
(av->value,
2419
no_address_fn[i],
2420
address_fn[i]),
2421
new_attr,
ie->insn_code);
2422
new_ie = oballoc (sizeof
(struct
insn_ent
));
2423
new_ie->insn_code = ie->insn_code;
2424
new_ie->insn_index =
ie->insn_index;
2425
insert_insn_ent
(new_av, new_ie);
2426
}
2427
}
2428
}
上面在
2411
行,
substitute_address
,给定一个表达式
exp
,查看它是否是一个具有检查指令相对位置(使用
MATCH_DUP
或
PC
)测试的
COND
或
IF_THEN_ELSE
。如果是,使用通过把该表达式传递给
address_fn
所得到的结果来替代之。如果不是,但它是一个
COND
或
IF_THEN_ELSE
,在每个值上递归调用这个函数(包括缺省值)。否则,返回由应用在
exp
上的
no_address_fn
所返回的值。
2307
static
rtx
2308
substitute_address
(rtx exp, rtx
(*no_address_fn) (rtx),
in genattrtab.c
2309
rtx (*address_fn) (rtx))
2310
{
2311
int i;
2312
rtx newexp;
2313
2314
if (GET_CODE (exp) == COND)
2315
{
2316
/* See if any
tests use addresses.
*/
2317
address_used
= 0;
2318
for
(i = 0;
i < XVECLEN (exp, 0); i += 2)
2319
walk_attr_value
(XVECEXP (exp, 0, i));
2320
2321
if (address_used
)
2322
return
(*address_fn) (exp);
2323
2324
/* Make a new
copy of this COND, replacing each element.
*/
2325
newexp = rtx_alloc (COND);
2326
XVEC (newexp, 0) = rtvec_alloc (XVECLEN
(exp, 0));
2327
for
(i = 0; i < XVECLEN (exp, 0); i += 2)
2328
{
2329
XVECEXP (newexp, 0, i) = XVECEXP (exp, 0, i);
2330
XVECEXP (newexp, 0, i + 1)
2331
=
substitute_address
(XVECEXP (exp, 0, i + 1),
2332
no_address_fn,
address_fn);
2333
}
2334
2335
XEXP
(newexp, 1) =
substitute_address
(
XEXP
(exp, 1),
2336
no_address_fn,
address_fn);
2337
2338
return
newexp;
2339
}
2340
2341
else if (GET_CODE (exp) == IF_THEN_ELSE)
2342
{
2343
address_used
= 0;
2344
walk_attr_value
(
XEXP
(exp, 0));
2345
if (address_used
)
2346
return
(*address_fn) (exp);
2347
2348
return
attr_rtx
(IF_THEN_ELSE,
2349
substitute_address
(
XEXP
(exp, 0),
2350
no_address_fn,
address_fn),
2351
substitute_address
(
XEXP
(exp, 1),
2352
no_address_fn, address_fn),
2353
substitute_address
(
XEXP
(exp, 2),
2354
no_address_fn,
address_fn));
2355
}
2356
2357
return
(*no_address_fn)
(exp);
2358
}
walk_attr_value
扫描属性值,这可能是个条件值(一个例外是下面
4979
行的
ATTR_FLAG
),并记录将要求什么动作来对它进行条件测试。
4934
static
void
4935
walk_attr_value
(rtx exp)
in genattrtab.c
4936
{
4937
int i, j;
4938
const
char
*fmt;
4939
RTX_CODE code;
4940
4941
if (exp == NULL)
4942
return
;
4943
4944
code = GET_CODE (exp);
4945
switch
(code)
4946
{
4947
case
SYMBOL_REF:
4948
if (!
ATTR_IND_SIMPLIFIED_P
(exp))
4949
/* Since this
is an arbitrary expression, it can look at anything.
4950
However, constant expressions do not
depend on any particular
4951
insn.
*/
4952
must_extract
= must_constrain
= 1;
4953
return
;
4954
4955
case
MATCH_OPERAND:
4956
must_extract
= 1;
4957
return
;
4958
4959
case
EQ_ATTR_ALT:
4960
must_extract
= must_constrain
= 1;
4961
break
;
4962
4963
case
EQ_ATTR:
4964
if (XSTR (exp, 0) == alternative_name
)
4965
must_extract
= must_constrain
= 1;
4966
else if (strcmp_check (XSTR (exp, 0), length_str
)
== 0)
4967
length_used
= 1;
4968
return
;
4969
4970
case
MATCH_DUP:
4971
must_extract
= 1;
4972
address_used
= 1;
4973
return
;
4974
4975
case
PC:
4976
address_used
= 1;
4977
return
;
4978
4979
case
ATTR_FLAG:
4980
return
;
4981
4982
default
:
4983
break
;
4984
}
4985
4986
for
(i = 0,
fmt = GET_RTX_FORMAT (code); i < GET_RTX_LENGTH (code); i++)
4987
switch
(*fmt++)
4988
{
4989
case
'e':
4990
case
'u':
4991
walk_attr_value
(
XEXP
(exp, i));
4992
break
;
4993
4994
case
'E':
4995
if (XVEC (exp, i) != NULL)
4996
for
(j = 0; j < XVECLEN (exp, i); j++)
4997
walk_attr_value
(XVECEXP (exp, i, j));
4998
break
;
4999
}
5000
}
在
4952
行,
must_extract
表示我们是否需要提取指令的操作数,
must_constrain
表示我们是否必须计算编译器变量
which_alternative
。在
4967
行,
length_used
表示,是否使用了一个
(eq_attr
"length" ...)
,而在
4972
行,
address_used
显示是否使用了一个地址表达式。
最后,对两种指令类型的结果显示如下。
no_address_fn
result of fn on exp
attribute attached
identity_fn
exp
"*insn_default_length"
zero_fn
rtx
object of 0
"*insn_variable_length_p"
zero_fn
rtx
object of 0
"*insn_current_length"
表
1
:为其它指令构建的属性
address_fn
result of fn on exp
attribute attached
max_fn
rtx
object of max value in exp
"*insn_default_length"
one_fn
rtx
object of 1
"*insn_variable_length_p"
identify_fn
exp
"*insn_current_length"
表
2
:为相对位置指令构建的属性
相关文章推荐