对于每个指令描述模式(正如我们看到有 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, struct decision_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 merge bits 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 semantics of pattern matching state that the tests are
1421 done in the order given in the MD file so that if an insn
1422 matches two patterns, the first one will be used. However,
1423 i n practice, most, if not all, patterns are unambiguous so
1424 that their order is independent. In that case, we can merge
1425 identical tests and group all similar modes and codes together.
1426
1427 Scan starting from the end of OLDH until we reach a point
1428 where we reach the head of the list or where we pass a
1429 pattern that could also be true if NEW is true. If we find
1430 an identical pattern, we can merge them. Also, record the
1431 last node that tests the same code and mode and the last one
1432 that tests just the same mode.
1433
1434 If we have no match, place NEW after the closest 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 goto merged_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) in genrecog.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 their subnodes are at the same position, as any one set
1335 of sibling decisions must be at the same position. Allowing this
1336 requires complications to find_afterward and 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) in genrecog.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 is for a normal insn and the second is for the base
1371 insn with clobbers stripped off, the second node 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 do here. */
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, in genrecog.c
1204 int toplevel)
1205 {
1206 struct decision *p1, *p2;
1207 int cmp;
1208
1209 /* Don't compare strings on the different positions in insn. Doing so
1210 is incorrect and results in false matches from 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 are recursing through the remainder
1219 of a node's success nodes (from the loop at the end of this function).
1220 Skip forward until we come to a position that matches.
1221
1222 Due to the way position strings are constructed, 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 the d2->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 return 1;
1242
1243 return 0;
1244 }
1245
1246 /* Test the current level. */
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 both be 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 are mutually exclusive. If
1254 either does not have any successors, we can'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 return 1;
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, struct decision_test *d2) in genrecog.c
1170 {
1171 struct decision_test *t1, *t2;
1172
1173 /* A match_operand with no predicate can match anything. Recognize
1174 this by the existence of alone DT_accept_op test. */
1175 if (d1->type == DT_accept_op || d2->type == DT_accept_op)
1176 return 1;
1177
1178 /* Eliminate pairs of 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, consider all 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 return 0;
1191
1192 return -1;
1193 }
maybe_both_true_2 处理测试集中的具体测试。如果两个测试是相同的,它返回 1 ;如果不同,则返回 0 ;如果不能证明它们是相同的,就返回 -1 。
1058 static int
1059 maybe_both_true_2 (struct decision_test *d1, struct decision_test *d2) in genrecog.c
1060 {
1061 if (d1->type == d2->type)
1062 {
1063 switch (d1->type)
1064 {
1065 case DT_mode:
1066 return d1->u.mode == d2->u.mode;
1067
1068 case DT_code:
1069 return d1->u.code == d2->u.code;
1070
1071 case DT_veclen:
1072 return d1->u.veclen == d2->u.veclen;
1073
1074 case DT_elt_zero_int:
1075 case DT_elt_one_int:
1076 case DT_elt_zero_wide:
1077 case DT_elt_zero_wide_safe:
1078 return d1->u.intval == d2->u.intval;
1079
1080 default :
1081 break ;
1082 }
1083 }
1084
1085 /* If either has a predicate that we know something about, set
1086 things up so that D1 is the one that always has a known
1087 predicate. Then see if they have any codes in 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 matches D1. */
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 an address_operand predicate is the
1104 mode of the memory, not the operand. 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 return 0;
1109 }
1110 /* Don't check two predicate modes here, because if both predicates
1111 accept CONST_INT, then both can still be true even if the modes
1112 are different. If they don't accept CONST_INT, there will be a
1113 separate DT_mode that will make maybe_both_true_1 return 0. */
1114 }
1115
1116 if (d1->u.pred.index >= 0)
1117 {
1118 /* If D2 tests a 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 return 0;
1131 }
1132
1133 /* Otherwise see 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 return 0;
1152 }
1153 }
1154 }
1155
1156 /* Tests vs veclen may be known when strict equality is involved. */
1157 if (d1->type == DT_veclen && d2->type == DT_veclen_ge)
1158 return d1->u.veclen >= d2->u.veclen;
1159 if (d1->type == DT_veclen_ge && d2->type == DT_veclen)
1160 return d2->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 return FATAL_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 }