GCC后端及汇编发布(6)

来源:互联网 发布:遥感卫星数据产品代理 编辑:程序博客网 时间:2024/05/16 06:00

3.3.构建识别树

3.3.3. 创建识别树

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

f14

14merge_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所示的树。首先,它将检查以下的节点。

f15

15merge_tree函数,图1

1438行,函数nodes_identical将检查上面的decision节点,来确定它们是否是相同的对象。而现在在1436oldhprev域,及在1418addhnext域,都是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沿着链,递归入下一个节点。我们可以看到,对于这两个链,接着的节点也是相同的,直到来到以下节点。

f16

16merge_tree函数,图2

对于这两个节点,nodes_identicalDT_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_true1249行也返回0

那么回到merge_trees,在1445行,因为maybe_both_true返回0。在1452行的代码执行在两个相等的类型上。那么在1456行,insert_before当前是null。在执行了1456行的IF块之后,我们可以得到如下的节点。两个位置是“10”的节点被链接为兄弟节点。

f17

17merge_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 }

原创粉丝点击