GCC后端及汇编发布(6)
来源:互联网 发布:遥感卫星数据产品代理 编辑:程序博客网 时间:2024/05/16 06:00
3.3.构建识别树
3.3.3. 创建识别树
对于每个指令描述模式(正如我们看到有3个类型的模式在使用——define_insn,define_split及define_peephole2。但是它们被分别处理,因此有3种树对应这3个类型的模式),将构建形如图13 的树。为了从这些树,以高效、方便的方式,产生insn-recog.c,我们需要把这些树合并成一棵大的树。这正是merge_trees.的目的。对于所有的描述, merge_trees应该构建一棵如下的树。
图14:由merge_trees创建的描述树
图14的树(目标树)从指令的第一棵描述树,通过加入其它描述树,生长起来。对于这些树,它们将与目标树,从根节点开始,进行比较。在那些目标树中的节点不同于描述树节点的位置,该描述树节点将被作为目标树节点的兄弟节点加入。而如果目标树节点被发现与描述树节点相同,就进入这两棵树的下一级节点(在这两棵树中,深度由decision节点的position域,以我们在上面看到的方式,来显示),然后重复比较,合并或深入的步骤。
显然,每个指令与目标树的某个叶子匹配,注意到叶子与指令是一一对应的。从根节点到特定的叶子,其路径代表了用于选择该指令的条件测试。
1397 static void
1398 merge_trees (struct decision_head *oldh, structdecision_head *addh) in genrecog.c
1399 {
1400 struct decision *next, *add;
1401
1402 if (addh->first == 0)
1403 return;
1404 if (oldh->first == 0)
1405 {
1406 *oldh = *addh;
1407 return;
1408 }
1409
1410 /* Trying to mergebits at different positions isn't possible. */
1411 if (strcmp (oldh->first->position,addh->first->position))
1412 abort ();
1413
1414 for (add =addh->first; add ; add = next)
1415 {
1416 struct decision *old, *insert_before = NULL;
1417
1418 next = add->next;
1419
1420 /* The semanticsof pattern matching state that the tests are
1421 done in the order given in the MD file sothat if an insn
1422 matches two patterns, the first one willbe used. However,
1423 in practice, most, if not all, patterns are unambiguous so
1424 that their order is independent. In thatcase, we can merge
1425 identical tests and group all similarmodes and codes together.
1426
1427 Scan starting from the end of OLDH untilwe reach a point
1428 where we reach the head of the list orwhere we pass a
1429 pattern that could also be true if NEW istrue. If we find
1430 an identical pattern, we can merge them.Also, record the
1431 last node that tests the same code andmode and the last one
1432 that tests just the same mode.
1433
1434 If we have no match, place NEW after theclosest match we found. */
1435
1436 for (old =oldh->last; old; old = old->prev)
1437 {
1438 if (nodes_identical(old, add))
1439 {
1440 merge_accept_insn(old, add);
1441 merge_trees(&old->success, &add->success);
1442 gotomerged_nodes;
1443 }
1444
1445 if (maybe_both_true(old, add, 0))
1446 break;
1447
1448 /* Insert the nodes in DT test type order,which is roughly
1449 how expensive/important the test is.Given that the tests
1450 are also ordered within the list,examining the first is
1451 sufficient. */
1452 if ((int) add->tests->type <(int) old->tests->type)
1453 insert_before = old;
1454 }
1455
1456 if (insert_before == NULL)
1457 {
1458 add->next = NULL;
1459 add->prev = oldh->last;
1460 oldh->last->next = add;
1461 oldh->last = add;
1462 }
1463 else
1464 {
1465 if ((add->prev =insert_before->prev) != NULL)
1466 add->prev->next = add;
1467 else
1468 oldh->first = add;
1469 add->next = insert_before;
1470 insert_before->prev = add;
1471 }
1472
1473 merged_nodes:;
1474 }
1475 }
这是一个非常复杂的过程,让我们一步一步来。在main中的调用点,我们看到该函数的第一个参数oldh指向我们例子的recog_tree,而第二个参数addh指向图13所示的树。首先,它将检查以下的节点。
图15:merge_tree函数,图1
在1438行,函数nodes_identical将检查上面的decision节点,来确定它们是否是相同的对象。而现在在1436行oldh的prev域,及在1418行addh的next域,都是null。
1317 static int
1318 nodes_identical (struct decision *d1, struct decision *d2) ingenrecog.c
1319 {
1320 struct decision_test *t1, *t2;
1321
1322 for (t1 = d1->tests, t2 = d2->tests; t1&& t2; t1 = t1->next, t2 = t2->next)
1323 {
1324 if (t1->type != t2->type)
1325 return 0;
1326 if (! nodes_identical_1 (t1, t2))
1327 return 0;
1328 }
1329
1330 /* For success,they should now both be null. */
1331 if (t1 != t2)
1332 return 0;
1333
1334 /* Check that theirsubnodes are at the same position, as any one set
1335 of sibling decisions must be at the sameposition. Allowing this
1336 requires complications to find_afterwardand when change_state is
1337 invoked. */
1338 if (d1->success.first
1339 && d2->success.first
1340 && strcmp(d1->success.first->position, d2->success.first->position))
1341 return 0;
1342
1343 return 1;
1344 }
上面,在1326行,在比较了类型之后,nodes_identical_1进一步检查内容是否匹配。接着在1338行,要完全相同,跟随它们的节点的position也必须是相同的。显然我们例子中所关注的节点是相同的。
给定两个声明完全相同的节点,在1440行的函数merge_accept_insn拷贝这两个指令的接受状态。下面的DT_accept_insn表示一旦通过这个decision_test,对应的指令被匹配。即,这个decision_test节点是匹配这个指令的最后一个测试。
1353 static void
1354 merge_accept_insn (struct decision *oldd, struct decision *addd) ingenrecog.c
1355 {
1356 struct decision_test *old, *add;
1357
1358 for (old =oldd->tests; old; old = old->next)
1359 if (old->type == DT_accept_insn)
1360 break;
1361 if (old == NULL)
1362 return;
1363
1364 for (add =addd->tests; add; add = add->next)
1365 if (add->type == DT_accept_insn)
1366 break;
1367 if (add == NULL)
1368 return;
1369
1370 /* If one node isfor a normal insn and the second is for the base
1371 insn with clobbers stripped off, the secondnode should be ignored. */
1372
1373 if (old->u.insn.num_clobbers_to_add == 0
1374 &&add->u.insn.num_clobbers_to_add > 0)
1375 {
1376 /* Nothing to dohere. */
1377 }
1378 else if (old->u.insn.num_clobbers_to_add> 0
1379 && add->u.insn.num_clobbers_to_add == 0)
1380 {
1381 /* In this case,replace OLD with ADD. */
1382 old->u.insn = add->u.insn;
1383 }
1384 else
1385 {
1386 message_with_line (add->u.insn.lineno,"`%s' matches `%s'",
1387 get_insn_name(add->u.insn.code_number),
1388 get_insn_name(old->u.insn.code_number));
1389 message_with_line (old->u.insn.lineno,"previous definition of `%s'",
1390 get_insn_name(old->u.insn.code_number));
1391 error_count++;
1392 }
1393 }
上面的num_clobbers_to_add,在make_insn_sequence中,设置为PARALLEL对象中元素数目的记录。如果它们在是否带clobber上不相同,那么这个冲突是由make_insn_sequence造成的,我们可以丢掉带有clobber的版本。如果这两个节点不能通过clobber来区分,我们在机器描述文件中找到了一个二义性错误。这个机制用于筛选更有效率的指令。
对于两个相同的节点,那样merge_trees沿着链,递归入下一个节点。我们可以看到,对于这两个链,接着的节点也是相同的,直到来到以下节点。
图16:merge_tree函数,图2
对于这两个节点,nodes_identical在DT_Code类型的decision_test的子节点处返回0。然后函数maybe_both_true将被调用。这个函数把描述树的节点与目标树的兄弟节点比较,如果任一兄弟节点匹配这个节点就返回1,如果没有找到这样的兄弟节点就返回0,不确定则返回-1。
1202 static int
1203 maybe_both_true (struct decision *d1, struct decision *d2, ingenrecog.c
1204 int toplevel)
1205 {
1206 struct decision *p1, *p2;
1207 int cmp;
1208
1209 /* Don't compare strings on the differentpositions in insn. Doing so
1210 is incorrect and results in false matchesfrom constructs like
1211
1212 [(set (subreg:HI (match_operand:SI"register_operand" "r") 0)
1213 (subreg:HI (match_operand:SI"register_operand" "r") 0))]
1214 vs
1215 [(set (match_operand:HI"register_operand" "r")
1216 (match_operand:HI "register_operand""r"))]
1217
1218 If we are presented with such, we arerecursing through the remainder
1219 of a node's success nodes (from the loop atthe end of this function).
1220 Skip forward until we come to a positionthat matches.
1221
1222 Due to the way position strings areconstructed, we know that iterating
1223 forward from the lexically lower position(e.g. "00") will run into
1224 the lexically higher position (e.g."1") and not the other way around.
1225 This saves a bit of effort. */
1226
1227 cmp = strcmp (d1->position,d2->position);
1228 if (cmp != 0)
1229 {
1230 if (toplevel)
1231 abort ();
1232
1233 /* If thed2->position was lexically lower, swap. */
1234 if (cmp > 0)
1235 p1= d1, d1 = d2, d2 = p1;
1236
1237 if (d1->success.first == 0)
1238 return 1;
1239 for (p1 =d1->success.first; p1; p1 = p1->next)
1240 if (maybe_both_true(p1, d2, 0))
1241 return1;
1242
1243 return 0;
1244 }
1245
1246 /* Test the currentlevel. */
1247 cmp = maybe_both_true_1(d1->tests, d2->tests);
1248 if (cmp >= 0)
1249 return cmp;
1250
1251 /* We can't prove that D1 and D2 cannot bothbe true. If we are only
1252 to check the top level, return 1.Otherwise, see if we can prove
1253 that all choices in both successors aremutually exclusive. If
1254 either does not have any successors, wecan't prove they can't both
1255 be true. */
1256
1257 if (toplevel || d1->success.first == 0 ||d2->success.first == 0)
1258 return 1;
1259
1260 for (p1 =d1->success.first; p1; p1 = p1->next)
1261 for (p2 =d2->success.first; p2; p2 = p2->next)
1262 if (maybe_both_true(p1, p2, 0))
1263 return1;
1264
1265 return 0;
1266 }
然后merge_trees开始处理position(‘10’)的节点。对于这些节点,在1227行的测试将可通过。它们具有相同的位置。接着函数maybe_both_true_1测试属于这两个节点的decision_test,来确保这些测试集是相同的。如果匹配,它将返回1,可能匹配则返回-1,不匹配则返回0。
1168 static int
1169 maybe_both_true_1 (struct decision_test *d1, structdecision_test *d2) in genrecog.c
1170 {
1171 struct decision_test *t1, *t2;
1172
1173 /* A match_operandwith no predicate can match anything. Recognize
1174 this by the existence of alone DT_accept_optest. */
1175 if(d1->type == DT_accept_op || d2->type == DT_accept_op)
1176 return 1;
1177
1178 /* Eliminate pairsof tests while they can exactly match. */
1179 while (d1&& d2 && d1->type == d2->type)
1180 {
1181 if (maybe_both_true_2(d1, d2) == 0)
1182 return 0;
1183 d1 = d1->next, d2 = d2->next;
1184 }
1185
1186 /* After that, considerall pairs. */
1187 for (t1 = d1; t1 ; t1 = t1->next)
1188 for (t2 = d2; t2 ; t2 = t2->next)
1189 if (maybe_both_true_2(t1, t2) == 0)
1190 return0;
1191
1192 return -1;
1193 }
maybe_both_true_2处理测试集中的具体测试。如果两个测试是相同的,它返回1;如果不同,则返回0;如果不能证明它们是相同的,就返回-1。
1058 static int
1059 maybe_both_true_2 (struct decision_test *d1, structdecision_test *d2) in genrecog.c
1060 {
1061 if (d1->type == d2->type)
1062 {
1063 switch(d1->type)
1064 {
1065 caseDT_mode:
1066 returnd1->u.mode == d2->u.mode;
1067
1068 caseDT_code:
1069 returnd1->u.code == d2->u.code;
1070
1071 caseDT_veclen:
1072 returnd1->u.veclen == d2->u.veclen;
1073
1074 caseDT_elt_zero_int:
1075 caseDT_elt_one_int:
1076 caseDT_elt_zero_wide:
1077 caseDT_elt_zero_wide_safe:
1078 returnd1->u.intval == d2->u.intval;
1079
1080 default:
1081 break;
1082 }
1083 }
1084
1085 /* If either has apredicate that we know something about, set
1086 things up so that D1 is the one that alwayshas a known
1087 predicate. Then see if they have any codesin common. */
1088
1089 if (d1->type == DT_pred || d2->type ==DT_pred)
1090 {
1091 if (d2->type == DT_pred)
1092 {
1093 struct decision_test *tmp;
1094 tmp = d1, d1 = d2, d2 = tmp;
1095 }
1096
1097 /* If D2 tests a mode, see if it matchesD1. */
1098 if (d1->u.pred.mode != VOIDmode)
1099 {
1100 if (d2->type == DT_mode)
1101 {
1102 if (d1->u.pred.mode != d2->u.mode
1103 /* The mode of anaddress_operand predicate is the
1104 mode of the memory, not theoperand. It can only
1105 be used for testing the predicate,so we must
1106 ignore it here. */
1107 && strcmp (d1->u.pred.name,"address_operand") != 0)
1108 return0;
1109 }
1110 /* Don't checktwo predicate modes here, because if both predicates
1111 accept CONST_INT, then both can stillbe true even if the modes
1112 are different. If they don't acceptCONST_INT, there will be a
1113 separate DT_mode that will makemaybe_both_true_1 return 0. */
1114 }
1115
1116 if (d1->u.pred.index >= 0)
1117 {
1118 /* If D2 testsa code, see if it is in the list of valid
1119 codes for D1's predicate. */
1120 if (d2->type == DT_code)
1121 {
1122 const RTX_CODE *c = &preds[d1->u.pred.index].codes[0];
1123 while(*c != 0)
1124 {
1125 if (*c == d2->u.code)
1126 break;
1127 ++c;
1128 }
1129 if (*c == 0)
1130 return0;
1131 }
1132
1133 /* Otherwisesee if the predicates have any codes in common. */
1134 else if (d2->type == DT_pred&& d2->u.pred.index >= 0)
1135 {
1136 const RTX_CODE *c1 = &preds[d1->u.pred.index].codes[0];
1137 int common = 0;
1138
1139 while(*c1 != 0 && !common)
1140 {
1141 const RTX_CODE *c2 = &preds[d2->u.pred.index].codes[0];
1142 while (*c2!= 0 && !common)
1143 {
1144 common = (*c1 == *c2);
1145 ++c2;
1146 }
1147 ++c1;
1148 }
1149
1150 if (!common)
1151 return0;
1152 }
1153 }
1154 }
1155
1156 /* Tests vs veclenmay be known when strict equality is involved. */
1157 if(d1->type == DT_veclen && d2->type == DT_veclen_ge)
1158 returnd1->u.veclen >= d2->u.veclen;
1159 if(d1->type == DT_veclen_ge && d2->type == DT_veclen)
1160 returnd2->u.veclen >= d1->u.veclen;
1161
1162 return -1;
1163 }
对于这里感兴趣的节点,maybe_both_true_2将对第二个子节点返回0,它进而使得在1182行的maybe_both_true_1返回0。接着函数maybe_both_true在1249行也返回0。
那么回到merge_trees,在1445行,因为maybe_both_true返回0。在1452行的代码执行在两个相等的类型上。那么在1456行,insert_before当前是null。在执行了1456行的IF块之后,我们可以得到如下的节点。两个位置是“10”的节点被链接为兄弟节点。
图17:merge_tree函数,图3
从这个图中,我们可以看到,向recog_tree加入了一个分枝。看到事实上从addh剥除了公共的部分,对recog_tree的根节点,它们不可到达。
main (continued)
2662 if (error_count)
2663 returnFATAL_EXIT_CODE;
2664
2665 puts ("/n/n");
2666
2667 process_tree(&recog_tree, RECOG);
2668 process_tree(&split_tree, SPLIT);
2669 process_tree(&peephole2_tree, PEEPHOLE2);
2670
2671 fflush (stdout);
2672 return(ferror (stdout) != 0 ?FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
2673 }
- GCC后端及汇编发布(6)
- GCC后端及汇编发布(1)
- GCC后端及汇编发布(2)
- GCC后端及汇编发布(3)
- GCC后端及汇编发布(4)
- GCC后端及汇编发布(5)
- GCC后端及汇编发布(7)
- GCC后端及汇编发布(8)
- GCC后端及汇编发布(9)
- GCC后端及汇编发布(10)
- GCC后端及汇编发布(11)
- GCC后端及汇编发布(12)
- GCC后端及汇编发布(13)
- GCC后端及汇编发布(14)
- GCC后端及汇编发布(15)
- GCC后端及汇编发布(16)
- GCC后端及汇编发布(17)
- GCC后端及汇编发布(18)
- java接口和类(六)用Class获取类
- 2011/4/23
- MyEclipse中,jsp文件输入中文,文件不能保存
- 我们的未来
- 不懂你就问嘛
- GCC后端及汇编发布(6)
- Linux shell 快捷键
- android 安全机制
- 追根究底,剖析MFC六大关键技术(第一部分)
- Eclipse快捷键大全
- 业界资讯:adobe air 2.7 和flash player10.3 放出
- GCC's bacl-end & assemble emission (6)
- 追根究底,MFC六大关键技术之剖析(第二部分)
- 使用spawn-fcgi运行php-cgi