GCC后端及汇编发布(6)

3.3. 构建识别树

3.3.3. 创建识别树

对于每个指令描述模式(正如我们看到有 3 个类型的模式在使用—— define_insn define_split define_peephole2 。但是它们被分别处理,因此有 3 种树对应这 3 个类型的模式),将构建形如 13 的树。为了从这些树,以高效、方便的方式,产生 insn-recog.c ,我们需要把这些树合并成一棵大的树。这正是 merge_trees . 的目的。对于所有的描述, merge_trees 应该构建一棵如下的树。

GCC后端及汇编发布(6)_第1张图片

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 沿着链,递归入下一个节点。我们可以看到,对于这两个链,接着的节点也是相同的,直到来到以下节点。

GCC后端及汇编发布(6)_第2张图片

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 }

你可能感兴趣的:(汇编,struct,gcc,tree,insert,merge)