GCC后端及汇编发布(30)
来源:互联网 发布:信鸽邮件群发软件 编辑:程序博客网 时间:2024/05/29 19:06
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 ("#defineoperands 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 bychecking everything stored
6168 awayand 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) ingenattrtab.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, "badattribute 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) ingenattrtab.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 inSET_ATTR_ALTERNATIVE");
1255 have_error = 1;
1256 returnNULL_RTX;
1257 }
1258
1259 /* Make a COND withall 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) ingenattrtab.c
1283 {
1284 rtx newexp;
1285 const char*name_ptr;
1286 char *p;
1287 int n;
1288
1289 /* See how manyalternative 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 eachcomma-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 returnFATAL_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 extraattributes for `length'. */
6185 make_length_attrs ();
6186
6187 /* Perform any possible optimizations tospeed up compilation. */
6188 optimize_attrs ();
9.6.1.2. 完成属性
对于数值属性,在其模式定义中,它必须具有空的LIST-OF-VALUE部分(至于define_attr的细节,可以参考读入DEFINE_ATTR模式一节)。
对于这些数值属性,fill_attr用于从模式中收集这些值。除此之外,对于所有的属性,这个函数将构建一个列表,它把所有使用同一个属性的指令链接起来。
2263 static void
2264 fill_attr (structattr_desc *attr) ingenattrtab.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 fillconstant 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 isspecified 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 inchain. */
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_dupN)
这指向当前指令操作数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) ingenattrtab.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 lengthattribute is defined. If so, it must be numeric. Make
2396 it special so we don't output anything forit. */
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 benumeric");
2403
2404 length_attr->is_const = 0;
2405 length_attr->is_special = 1;
2406
2407 /* Make each newattribute, 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 anytests 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 newcopy 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 returnnewexp;
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 caseSYMBOL_REF:
4948 if (! ATTR_IND_SIMPLIFIED_P (exp))
4949 /* Since thisis an arbitrary expression, it can look at anything.
4950 However, constant expressions do notdepend on any particular
4951 insn. */
4952 must_extract = must_constrain = 1;
4953 return;
4954
4955 caseMATCH_OPERAND:
4956 must_extract= 1;
4957 return;
4958
4959 caseEQ_ATTR_ALT:
4960 must_extract = must_constrain = 1;
4961 break;
4962
4963 caseEQ_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 caseMATCH_DUP:
4971 must_extract = 1;
4972 address_used = 1;
4973 return;
4974
4975 case PC:
4976 address_used = 1;
4977 return;
4978
4979 caseATTR_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 rtxobject of 0 "*insn_variable_length_p"
zero_fn rtxobject of 0 "*insn_current_length"
表1:为其它指令构建的属性
address_fn result of fn on exp attribute attached
max_fn rtxobject of max value in exp "*insn_default_length"
one_fn rtxobject of 1 "*insn_variable_length_p"
identify_fn exp "*insn_current_length"
表2:为相对位置指令构建的属性
- GCC后端及汇编发布(30)
- GCC后端及汇编发布(1)
- GCC后端及汇编发布(2)
- GCC后端及汇编发布(3)
- GCC后端及汇编发布(4)
- GCC后端及汇编发布(5)
- GCC后端及汇编发布(6)
- GCC后端及汇编发布(7)
- GCC后端及汇编发布(8)
- GCC后端及汇编发布(9)
- GCC后端及汇编发布(10)
- GCC后端及汇编发布(11)
- GCC后端及汇编发布(12)
- GCC后端及汇编发布(13)
- GCC后端及汇编发布(14)
- GCC后端及汇编发布(15)
- GCC后端及汇编发布(16)
- GCC后端及汇编发布(17)
- solaris 添加用户
- 用户界面
- 实现梦想是唯一证明活在这个世界的理由
- GCC后端及汇编发布(29)
- GCC's bacl-end & assemble emission (29)
- GCC后端及汇编发布(30)
- GCC's bacl-end & assemble emission (30)
- solaris locale详解
- USB接口ID卡读卡器oem软件/读写卡测试程序及源代码/c++builder源代码
- 返回本机的Ip地址
- 移动鼠标到指定位置
- 显示气球提示框
- hibernate映射文件碰到的错误
- jBPM 5.0 released--Java业务流程管理5.0发布