GCC后端及汇编发布(8)

3.4. 输出insn-recog.c

现在我们可以输出名为 insn-recog.c 的文件了。这由 write_subroutines 开始,参数 head 指向 recog_tree

 

2336 static void

2337 write_subroutines (struct decision_head *head, enum routine_type type)        in genrecog.c

2338 {

2339   struct decision *p;

2340

2341   for (p = head->first; p ; p = p->next)

2342     if (p->success.first)

2343       write_subroutines (&p->success, type);

2344

2345   if (head->first->subroutine_number > 0)

2346     write_subroutine (head, type);

2347 }

 

上面,在 2345 行,在 break_out_subroutines 1614 行设置 subroutine_number ,非 0 值表示该节点的序号是 100 SUBROUTINE_THRESHOLD )的倍数,并且要为接下来的节点构建新的例程。注意到对于第 100 200 依此类推的节点, write_subroutine 2346 行被调用,而对于其它节点,这个函数将被跳过。对于我们的例子,因为 SUBROUTINE_THRESHOLD 被假定为 4 ,调用 write_subroutine 的节点在下图中被标记成红色。

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

27 :输出 insn-recog.c ,图 1

注意到 write_subroutine 的调用是深度优先的。

 

2281 static void

2282 write_subroutine (struct decision_head *head, enum routine_type type)          in genrecog.c

2283 {

2284   int subfunction = head->first ? head->first->subroutine_number : 0;

2285   const char *s_or_e;

2286   char extension[32];

2287   int i;

2288

2289   s_or_e = subfunction ? "static " : "";

2290

2291   if (subfunction)

2292     sprintf (extension, "_%d", subfunction);

2293   else if (type == RECOG)

2294     extension[0] = '/0';

2295   else

2296     strcpy (extension, "_insns");

2297

2298   switch (type)

2299   {

2300     case RECOG:

2301       printf ("%sint/n/

2302 recog%s (rtx x0 ATTRIBUTE_UNUSED,/n/trtx insn ATTRIBUTE_UNUSED,/n/tint *pnum_clobbers ATTRIBUTE_UNUSED)/n", s_or_e, extension);

2303       break ;

2304     case SPLIT:

2305       printf ("%srtx/n/

2306          split%s (rtx x0 ATTRIBUTE_UNUSED, rtx insn ATTRIBUTE_UNUSED)/n",

2307          s_or_e, extension);

2308       break ;

2309     case PEEPHOLE2:

2310       printf ("%srtx/n/

2311          peephole2%s (rtx x0 ATTRIBUTE_UNUSED,/n/trtx insn ATTRIBUTE_UNUSED,

2312          /n/tint *_pmatch_len ATTRIBUTE_UNUSED)/n", s_or_e, extension);

2313       break ;

2314   }

2315

2316   printf ("{/n  rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];/n");

2317   for (i = 1; i <= max_depth ; i++)

2318     printf ("  rtx x%d ATTRIBUTE_UNUSED;/n", i);

2319

2320   printf ("  %s tem ATTRIBUTE_UNUSED;/n", IS_SPLIT (type) ? "rtx" : "int");

2321

2322   if (!subfunction)

2323     printf ("  recog_data.insn = NULL_RTX;/n");

2324

2325   if (head->first)

2326     write_tree (head, "", type, 1);

2327   else

2328     printf ("  goto ret0;/n");

2329

2330   printf (" ret0:/n  return %d;/n}/n/n", IS_SPLIT (type) ? 0 : -1);

2331 }

 

write_subroutine 只是创建了该输出函数的公共部分。对于我们的例子,下面的语句被写入这个文件。注意到 max_depth 记录了 position 的最大长度 , ,这里是 3

 

int

recog_1 (rtx x0 ATTRIBUTE_UNUSED,

     rtx insn ATTRIBUTE_UNUSED,

     int *pnum_clobbers ATTRIBUTE_UNUSED)

{

   rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];

    rtx x1 ATTRIBUTE_UNUSED;

   rtx x2 ATTRIBUTE_UNUSED;

rtx x3 ATTRIBUTE_UNUSED;

int tem ATTRIBUTE_UNUSED;

 

在上面产生的源代码中, recog_data 被定义在 recog.h 里,并由函数 extract-insn 来初始化,该函数分析指令的 rtx 对象,并填入 recog_data 。输出输出函数的主体是 write_tree 的钩子。注意到对于最上层的调用,参数 initial 1

 

2224 static void

2225 write_tree (struct decision_head *head, const char *prevpos,                          in genrecog.c

2226            enum routine_type type, int initial)

2227 {

2228   struct decision *p = head->first;

2229

2230   putchar ('/n');

2231   if (p->need_label)

2232     OUTPUT_LABEL (" ", p->number);

2233

2234   if (! initial && p->subroutine_number > 0)

2235   {

2236     static const char * const name_prefix [] = {

2237         "recog", "split", "peephole2"

2238     };

2239

2240     static const char * const call_suffix [] = {

2241         ", pnum_clobbers", "", ", _pmatch_len"

2242     };

2243

2244     /* This node has been broken out into a separate subroutine.

2245       Call it, test the result, and branch accordingly.  */

2246

2247     if (p->afterward)

2248     {

2249        printf ("  tem = %s_%d (x0, insn%s);/n",

2250            name_prefix [type], p->subroutine_number, call_suffix [type]);

2251       if (IS_SPLIT (type))

2252           printf ("  if (tem != 0)/n    return tem;/n");

2253         else

2254          printf ("  if (tem >= 0)/n    return tem;/n");

2255

2256       change_state (p->position, p->afterward->position, NULL, "  ");

2257       printf ("  goto L%d;/n", p->afterward->number);

2258     }

2259     else

2260     {

2261       printf ("  return %s_%d (x0, insn%s);/n",

2262            name_prefix [type], p->subroutine_number, call_suffix [type]);

2263     }

2264   }

2265   else

2266   {

2267     int depth = strlen (p->position);

2268

2269     change_state (prevpos, p->position, head->last->afterward, "  ");

2270     write_tree_1 (head, depth, type);

2271

2272     for (p = head->first; p; p = p->next)

2273       if (p->success.first)

2274         write_tree (&p->success, p->position, type, 0);

2275   }

2276 }

 

因为在最上层的调用中,参数 initial 1 ,在 2265 行开始的代码首先运行。然后调用 change_state ,注意到对于这次调用,该函数的第一个参数是 null

 

1670 static void

1671 change_state (const char *oldpos, const char *newpos,                                  in genrecog.c

1672              struct decision *afterward, const char *indent)

1673 {

1674   int odepth = strlen (oldpos);

1675   int ndepth = strlen (newpos);

1676   int depth;

1677   int old_has_insn, new_has_insn;

1678

1679   /* Pop up as many levels as necessary.  */

1680   for (depth = odepth; strncmp (oldpos, newpos, depth) != 0; --depth)

1681     continue ;

1682

1683   /* Hunt for the last [A-Z] in both strings.  */

1684   for (old_has_insn = odepth - 1; old_has_insn >= 0; --old_has_insn)

1685     if (ISUPPER (oldpos[old_has_insn]))

1686       break ;

1687   for (new_has_insn = ndepth - 1; new_has_insn >= 0; --new_has_insn)

1688     if (ISUPPER (newpos[new_has_insn]))

1689       break ;

1690

1691   /* Go down to desired level.  */

1692   while (depth < ndepth)

1693   {

1694      /* It's a different insn from the first one.  */

1695     if (ISUPPER (newpos[depth]))

1696     {

1697        /* We can only fail if we're moving down the tree.  */

1698       if (old_has_insn >= 0 && oldpos[old_has_insn] >= newpos[depth])

1699       {

1700         printf ("%stem = peep2_next_insn (%d);/n",

1701              indent, newpos[depth] - 'A');

1702       }

1703        else

1704       {

1705         printf ("%stem = peep2_next_insn (%d);/n",

1706              indent, newpos[depth] - 'A');

1707         printf ("%sif (tem == NULL_RTX)/n", indent);

1708          if (afterward)

1709           printf ("%s  goto L%d;/n", indent, afterward->number);

1710         else

1711           printf ("%s  goto ret0;/n", indent);

1712       }

1713       printf ("%sx%d = PATTERN (tem);/n", indent, depth + 1);

1714     }

1715     else if (ISLOWER (newpos[depth]))

1716       printf ("%sx%d = XVECEXP (x%d, 0, %d);/n",

1717            indent, depth + 1, depth, newpos[depth] - 'a');

1718     else

1719       printf ("%sx%d = XEXP (x%d, %c);/n",

1720            indent, depth + 1, depth, newpos[depth]);

1721     ++depth;

1722   }

1723 }

 

从上面,我们知道 decision 节点的 position 域记录了节点在树中的深度。 Position 的长度越长,它埋藏得越深。对于 position 的内容而言,数字用作普通指令匹配的序列号,而小写字母用作并行( parallel )指令匹配的序列号(并行指令表示使用的指令同时起作用,而不是依次),而大写字母用作窥孔( peephole )匹配的序列号(窥孔代表一个优化机会——特定的指令序列被另一个指令序列所代替)。

在这个函数中,从 1680 1689 行,只是检查从 oldpos newpos 所需要下降的深度。如果我们不能移到新的状态,就转入由 afterward 指向的分支,如果它不是 null 。转移到新状态失败,仅发生在,如果我们正在尝试匹配多个指令,并且我们尝试越过这个流的末尾。对于我们的例子,在调整到正确的位置之后,我们可以得到以下的代码片断。

 

int

recog_1 (rtx x0 ATTRIBUTE_UNUSED,

      rtx insn ATTRIBUTE_UNUSED,

      int *pnum_clobbers ATTRIBUTE_UNUSED)

{

   rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];

   rtx x1 ATTRIBUTE_UNUSED;

   rtx x2 ATTRIBUTE_UNUSED;

rtx x3 ATTRIBUTE_UNUSED;

int tem ATTRIBUTE_UNUSED;

 

x1 = XEXP(x0, 1);

x2 = XEXP(x1, 1);

 

然后 write_tree_1 被调用来输出 recog_1 的主体部分。

 

2190 static void

2191 write_tree_1 (struct decision_head *head, int depth,                                      in genrecog.c

2192              enum routine_type subroutine_type)

2193 {

2194   struct decision *p, *next;

2195   int uncond = 0;

2196

2197   for (p = head->first; p ; p = next)

2198   {

2199     /* The label for the first element was printed in write_tree.  */

2200     if (p != head->first && p->need_label)

2201       OUTPUT_LABEL (" ", p->number);

2202

2203     /* Attempt to write a switch statement for a whole sequence.  */

2204     next = write_switch (p, depth);

2205     if (p != next)

2206       uncond = 0;

2207     else

2208     {

2209       /* Failed -- fall back and write one node.  */

2210       uncond = write_node (p, depth, subroutine_type);

2211       next = p->next;

2212     }

2213   }

2214

2215   /* Finished with this chain. Close a fallthru path by branching

2216     to the afterward node.  */

2217   if (! uncond)

2218      write_afterward (head->last, head->last->afterward, "  ");

2219 }

 

2204 行,对于我们当前的节点, write_switch 不做任何事。它仅是返回 p 。因此在 2210 行的 write_node 被调用。

 

2153 static int

2154 write_node (struct decision *p, int depth,                                                     in genrecog.c

2155            enum routine_type subroutine_type)

2156 {

2157   struct decision_test *test, *last_test;

2158   int uncond;

2159

2160   last_test = test = p->tests;

2161   uncond = is_unconditional (test, subroutine_type);

2162   if (uncond == 0)

2163   {

2164     printf ("  if (");

2165     write_cond (test, depth, subroutine_type);

2166

2167     while ((test = test->next) != NULL)

2168     {

2169       int uncond2;

2170

2171       last_test = test;

2172       uncond2 = is_unconditional (test, subroutine_type);

2173       if (uncond2 != 0)

2174         break ;

2175

2176       printf ("/n      && ");

2177       write_cond (test, depth, subroutine_type);

2178     }

2179

2180     printf (")/n");

2181   }

2182

2183   write_action (p, last_test, depth, uncond, p->success.first, subroutine_type);

2184

2185   return uncond > 0;

2186 }

 

属于我们当前节点的第一个 decision_test 节点是 DT_code ,因此对 is_unconditional 的第一次调用返回 0 ,因为它不是期望的节点。

 

2126 static int

2127 is_unconditional (struct decision_test *t, enum routine_type subroutine_type) in genrecog.c

2128 {

2129   if (t->type == DT_accept_op)

2130     return 1;

2131

2132   if (t->type == DT_accept_insn)

2133   {

2134     switch (subroutine_type)

2135     {

2136       case RECOG:

2137         return (t->u.insn.num_clobbers_to_add == 0);

2138       case SPLIT:

2139         return 1;

2140       case PEEPHOLE2:

2141         return -1;

2142       default :

2143         abort ();

2144     }

2145   }

2146

2147   return 0;

2148 }

 

那么回到 write_node ,在 2165 行, write_cond 协助填入 IF 语句的测试部分。

 

1965 static void

1966 write_cond (struct decision_test *p, int depth,                                              in genrecog.c

1967            enum routine_type subroutine_type)

1968 {

1969   switch (p->type)

1970   {

1971     case DT_mode:

1972       printf ("GET_MODE (x%d) == %smode", depth, GET_MODE_NAME (p->u.mode));

1973       break ;

1974

1975     case DT_code:

1976       printf ("GET_CODE (x%d) == ", depth);

1977       print_code (p->u.code);

1978       break ;

1979

1980     case DT_veclen:

1981       printf ("XVECLEN (x%d, 0) == %d", depth, p->u.veclen);

1982       break ;

1983

1984     case DT_elt_zero_int:

1985       printf ("XINT (x%d, 0) == %d", depth, (int) p->u.intval);

1986       break ;

1987

1988     case DT_elt_one_int:

1989       printf ("XINT (x%d, 1) == %d", depth, (int) p->u.intval);

1990       break ;

1991

1992     case DT_elt_zero_wide:

1993     case DT_elt_zero_wide_safe:

1994       printf ("XWINT (x%d, 0) == ", depth);

1995       print_host_wide_int (p->u.intval);

1996       break ;

1997

1998     case DT_veclen_ge:

1999       printf ("XVECLEN (x%d, 0) >= %d", depth, p->u.veclen);

2000       break ;

2001

2002     case DT_dup:

2003       printf ("rtx_equal_p (x%d, operands[%d])", depth, p->u.dup);

2004       break ;

2005

2006     case DT_pred:

2007       printf ("%s (x%d, %smode)", p->u.pred.name, depth,

2008            GET_MODE_NAME (p->u.pred.mode));

2009       break ;

2010

2011     case DT_c_test:

2012       printf ("(%s)", p->u.c_test);

2013       break ;

2014

2015     case DT_accept_insn:

2016       switch (subroutine_type)

2017       {

2018         case RECOG:

2019            if (p->u.insn.num_clobbers_to_add == 0)

2020              abort ();

2021            printf ("pnum_clobbers != NULL");

2022            break ;

2023

2024         default :

2025            abort ();

2026       }

2027       break ;

2028

2029       default :

2030       abort ();

2031   }

2032 }

 

继续属于我们当前节点的 decision_test 节点,当完成 DT_c_test 节点的处理,我们可以得到下面的代码片段。

 

int

recog_1 (rtx x0 ATTRIBUTE_UNUSED,

      rtx insn ATTRIBUTE_UNUSED,

      int *pnum_clobbers ATTRIBUTE_UNUSED)

{

   rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];

   rtx x1 ATTRIBUTE_UNUSED;

   rtx x2 ATTRIBUTE_UNUSED;

rtx x3 ATTRIBUTE_UNUSED;

int tem ATTRIBUTE_UNUSED;

x1 = XEXP (x0, 1);

x2 = XEXP(x1, 0);

 

if (GET_CODE (x2) == CONST

&& XWINT(x2, 0) == 0

&& (TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode)))

 

对于第三个类型为 DT_accept_insn 的节点,在 write_node 2172 行, is_unconditional 返回 1 ,接着 write_action 找出需要执行的行动( action )。注意到对于此次调用,参数 success 指向位置为“ 11 ”的节点, uncond 1 depth 2 test 指向第四个 decision_test 节点——是 DT_accept_insn ,而 subroutine_type RECOG

 

2038 static void

2039 write_action (struct decision *p, struct decision_test *test,                                    in genrecog.c

2040              int depth, int uncond, struct decision *success,

2041              enum routine_type subroutine_type)

2042 {

2043   const char *indent;

2044   int want_close = 0;

2045

2046   if (uncond)

2047     indent = "  ";

2048   else if (test->type == DT_accept_op || test->type == DT_accept_insn)

2049   {

2050     fputs ("    {/n", stdout);

2051     indent = "      ";

2052     want_close = 1;

2053   }

2054   else

2055     indent = "    ";

2056

2057   if (test->type == DT_accept_op)

2058   {

2059     printf("%soperands[%d] = x%d;/n", indent, test->u.opno, depth);

2060

2061     /* Only allow DT_accept_insn to follow.  */

2062     if (test->next)

2063     {

2064        test = test->next;

2065        if (test->type != DT_accept_insn)

2066          abort ();

2067     }

2068   }

2069

2070   /* Sanity check that we're now at the end of the list of tests.  */

2071   if (test->next)

2072     abort ();

2073

2074   if (test->type == DT_accept_insn)

2075   {

2076     switch (subroutine_type)

2077     {

2078       case RECOG:

2079          if (test->u.insn.num_clobbers_to_add != 0)

2080            printf ("%s*pnum_clobbers = %d;/n",

2081                  indent, test->u.insn.num_clobbers_to_add);

2082         printf ("%sreturn %d;/n", indent, test->u.insn.code_number);

2083          break ;

2084

2085       case SPLIT:

2086          printf ("%sreturn gen_split_%d (operands);/n",

2087               indent, test->u.insn.code_number);

2088          break ;

2089

2090       case PEEPHOLE2:

2091        {

2092          int match_len = 0, i;

2093

2094          for (i = strlen (p->position) - 1; i >= 0; --i)

2095            if (ISUPPER (p->position[i]))

2096           {

2097              match_len = p->position[i] - 'A';

2098              break ;

2099           }

2100          printf ("%s*_pmatch_len = %d;/n", indent, match_len);

2101          printf ("%stem = gen_peephole2_%d (insn, operands);/n",

2102               indent, test->u.insn.code_number);

2103          printf ("%sif (tem != 0)/n%s  return tem;/n", indent, indent);

2104         }

2105        break ;

2106

2107       default :

2108          abort ();

2109     }

2110   }

2111   else

2112   {

2113     printf("%sgoto L%d;/n", indent, success->number);

2114     success->need_label = 1;

2115   }

2116

2117   if (want_close)

2118     fputs ("    }/n", stdout);

2119 }

 

对于我们的例子,现在我们得到以下代码片段。

 

int

recog_1 (rtx x0 ATTRIBUTE_UNUSED,

      rtx insn ATTRIBUTE_UNUSED,

      int *pnum_clobbers ATTRIBUTE_UNUSED)

{

   rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];

   rtx x1 ATTRIBUTE_UNUSED;

   rtx x2 ATTRIBUTE_UNUSED;

rtx x3 ATTRIBUTE_UNUSED;

int tem ATTRIBUTE_UNUSED;

 

x1 = XEXP(x0, 1);

x2 = XEXP(x1, 1);

 

if (GET_CODE (x2) == CONST

&& XWINT(x2, 0) == 0

&& (TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode)))

{

  return `code-number` ;

}

 

那么回到 write_tree 2270 行。对于接下来的 decision 节点, write_tree 被递归调用。因为对于感兴趣的节点,它没有跟随的节点,我们进一步返回到 write_subroutine ,并得到如下输出。

 

int

recog_1 (rtx x0 ATTRIBUTE_UNUSED,

      rtx insn ATTRIBUTE_UNUSED,

      int *pnum_clobbers ATTRIBUTE_UNUSED)

{

   rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];

   rtx x1 ATTRIBUTE_UNUSED;

   rtx x2 ATTRIBUTE_UNUSED;

rtx x3 ATTRIBUTE_UNUSED;

int tem ATTRIBUTE_UNUSED;

 

x1 = XEXP(x0, 1);

x2 = XEXP(x1, 1);

 

if (GET_CODE (x2) == CONST

&& XWINT(x2, 0) == 0

&& (TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode)))

{

  return `code-number` ;

}

goto ret0;

 

ret0:

   return -1;

}

 

那么回到 write_tree ,接着输出如下的 recog_2 (我们把 position 用作编码的号码,对于 position 重复的情形,在 position 的末尾加上数字 size 来构成唯一的编码号码)。

 

int

recog_2 (rtx x0 ATTRIBUTE_UNUSED,

      rtx insn ATTRIBUTE_UNUSED,

      int *pnum_clobbers ATTRIBUTE_UNUSED)

{

   rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];

   rtx x1 ATTRIBUTE_UNUSED;

   rtx x2 ATTRIBUTE_UNUSED;

rtx x3 ATTRIBUTE_UNUSED;

int tem ATTRIBUTE_UNUSED;

 

x1 = XEXP(x0, 1);

x2 = XEXP(x1, 0);

 

if (GET_MODE (x2) == DI_mode)

  goto L104;

goto ret0;

 

对于跟在具有 subroutine_number 2 的节点后的节点, write_switch 不是无关紧要的。让我们仔细看一下 write_switch

 

2190 static struct decision *

2191 write_switch (struct decision *start, int depth)                                               in genrecog.c

2192 {

2193   struct decision *p = start;

2194   enum decision_type type = p->tests->type;

2195   struct decision *needs_label = NULL;

2196

2197   /* If we have two or more nodes in sequence that test the same one

2198     thing, we may be able to use a switch statement.  */

2199

2200   if (!p->next

2201       || p->tests->next

2202       || p->next->tests->type != type

2203       || p->next->tests->next

2204       || nodes_identical_1 (p->tests, p->next->tests))

2205     return p;

2206

2207   /* DT_code is special in that we can do interesting things with

2208     known predicates at the same time.  */

2209   if (type == DT_code)

2210   {

2211     char codemap[NUM_RTX_CODE];

2212     struct decision *ret;

2213     RTX_CODE code;

2214

2215     memset (codemap, 0, sizeof (codemap));

2216

2217     printf ("  switch (GET_CODE (x%d))/n    {/n", depth);

2218     code = p->tests->u.code;

2219     do

2220     {

2221       if (p != start && p->need_label && needs_label == NULL)

2222         needs_label = p;

2223

2224       printf ("    case ");

2225       print_code (code);

2226       printf (":/n      goto L%d;/n", p->success.first->number);

2227       p->success.first->need_label = 1;

2228

2229       codemap[code] = 1;

2230       p = p->next;

2231     }

2232     while (p

2233          && ! p->tests->next

2234          && p->tests->type == DT_code

2235          && ! codemap[code = p->tests->u.code]);

2236

2237     /* If P is testing a predicate that we know about and we haven't

2238       seen any of the codes that are valid for the predicate, we can

2239       write a series of "case" statement, one for each possible code.

2240       Since we are already in a switch, these redundant tests are very

2241       cheap and will reduce the number of predicates called.  */

2242

2243     /* Note that while we write out cases for these predicates here,

2244       we don't actually write the test here, as it gets kinda messy.

2245       It is trivial to leave this to later by telling our caller that

2246       we only processed the CODE tests.  */

2247     if (needs_label != NULL)

2248       ret = needs_label;

2249     else

2250        ret = p;

2251

2252     while (p && p->tests->type == DT_pred

2253           && p->tests->u.pred.index >= 0)

2254     {

2255       const RTX_CODE *c;

2256

2257       for (c = &preds [p->tests->u.pred.index].codes[0]; *c ; ++c)

2258         if (codemap[(int) *c] != 0)

2259           goto pred_done;

2260

2261       for (c = &preds [p->tests->u.pred.index].codes[0]; *c ; ++c)

2262       {

2263         printf ("    case ");

2264         print_code (*c);

2265         printf (":/n");

2266         codemap[(int) *c] = 1;

2267       }

2268

2269       printf ("      goto L%d;/n", p->number);

2270       p->need_label = 1;

2271       p = p->next;

2272     }

2273

2274   pred_done:

2275     /* Make the default case skip the predicates we managed to match.  */

2276

2277     printf ("    default:/n");

2278     if (p != ret)

2279     {

2280       if (p)

2281       {

2282         printf ("      goto L%d;/n", p->number);

2283         p->need_label = 1;

2284       }

2285       else

2286         write_afterward (start, start->afterward, "      ");

2287     }

2288     else

2289       printf ("     break;/n");

2290     printf ("   }/n");

2291

2292     return ret;

2293   }

2294   else if (type == DT_mode

2295           || type == DT_veclen

2296           || type == DT_elt_zero_int

2297           || type == DT_elt_one_int

2298           || type == DT_elt_zero_wide_safe)

2299   {

2300     const char *indent = "";

2301

2302      /* We cast switch parameter to integer, so we must ensure that the value

2303       fits.   */

2304     if (type == DT_elt_zero_wide_safe)

2305     {

2306       indent = "  ";

2307       printf("  if ((int) XWINT (x%d, 0) == XWINT (x%d, 0))/n", depth, depth);

2308     }

2309     printf ("%s  switch (", indent);

2310     switch (type)

2311     {

2312       case DT_mode:

2313         printf ("GET_MODE (x%d)", depth);

2314         break ;

2315       case DT_veclen:

2316         printf ("XVECLEN (x%d, 0)", depth);

2317         break ;

2318       case DT_elt_zero_int:

2319         printf ("XINT (x%d, 0)", depth);

2320         break ;

2321       case DT_elt_one_int:

2322         printf ("XINT (x%d, 1)", depth);

2323         break ;

2324       case DT_elt_zero_wide_safe:

2325         /* Convert result of XWINT to int for portability since some C

2326            compilers won't do it and some will.  */

2327         printf ("(int) XWINT (x%d, 0)", depth);

2328         break ;

2329       default :

2330         abort ();

2331     }

2332     printf (")/n%s    {/n", indent);

2333

2334     do

2335     {

2336       /* Merge trees will not unify identical nodes if their

2337         sub-nodes are at different levels. Thus we must check

2338         for duplicate cases.  */

2339       struct decision *q;

2340       for (q = start; q != p; q = q->next)

2341         if (nodes_identical_1 (p->tests, q->tests))

2342           goto case_done;

2343

2344       if (p != start && p->need_label && needs_label == NULL)

2345         needs_label = p;

2346

2347       printf ("%s    case ", indent);

2348       switch (type)

2349       {

2350         case DT_mode:

2351           printf ("%smode", GET_MODE_NAME (p->tests->u.mode));

2352           break ;

2353         case DT_veclen:

2354           printf ("%d", p->tests->u.veclen);

2355           break ;

2356         case DT_elt_zero_int:

2357         case DT_elt_one_int:

2358         case DT_elt_zero_wide:

2359         case DT_elt_zero_wide_safe:

2360           print_host_wide_int (p->tests->u.intval);

2361           break ;

2362         default :

2363           abort ();

2364       }

2365       printf (":/n%s      goto L%d;/n", indent, p->success.first->number);

2366       p->success.first->need_label = 1;

2367

2368       p = p->next;

2369     }

2370     while (p && p->tests->type == type && !p->tests->next);

2371

2372   case_done:

2373     printf ("%s    default:/n%s      break;/n%s    }/n",

2374              indent, indent, indent);

2375

2376     return needs_label != NULL ? needs_label : p;

2377   }

2378   else

2379   {

2380     /* None of the other tests are amenable.  */

2381     return p;

2382   }

2383 }

 

为了使 2200 行的条件测试更清楚些,我们把它重写如下:

 

if (!(p->next

   && !p->tests->next

   && p->next->tests->type == type

   && !p->next->tests->next

   && !nodes_identical_1 (p->tests, p->next->tests)))

 

看到 write_switch 处理具有相同 decision_test 类型的兄弟节点。对于其他情形的兄弟节点,它们则由 write_node 通过 write_tree_1 来一个个处理。

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

28 :输出 insn-recog.c ,图 2

对于感兴趣的节点,通过由 28 表示的测试后, write_switch 将为这些节点输出 switch case 语句,因此我们可以得到如下的代码片段。

 

int

recog_2 (rtx x0 ATTRIBUTE_UNUSED,

      rtx insn ATTRIBUTE_UNUSED,

      int *pnum_clobbers ATTRIBUTE_UNUSED)

{

   rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];

   rtx x1 ATTRIBUTE_UNUSED;

   rtx x2 ATTRIBUTE_UNUSED;

rtx x3 ATTRIBUTE_UNUSED;

int tem ATTRIBUTE_UNUSED;

 

x1 = XEXP(x0, 1);

x2 = XEXP(x1, 0);

 

if (GET_MODE (x2) == DI_mode)

  goto L104;

goto ret0;

 

L104:

   switch (GET_CODE (x2))

   {

     case MATCH_OPERAND:

       goto L103;

     case MINUS:

       goto L100;

     default:

       break;

}

 

那么当从 write_switch 返回 write_switch 时,对于正在处理的节点,在 2205 行, p 将不等于 next write_afterward 将在 2218 行被调用。

 

1738 static void

1739 write_afterward (struct decision *start, struct decision *afterward,                  in genrecog.c

1740               const char *indent)

1741 {

1742   if (!afterward || start->subroutine_number > 0)

1743     printf("%sgoto ret0;/n", indent);

1744   else

1745   {

1746     change_state (start->position, afterward->position, NULL, indent);

1747     printf ("%sgoto L%d;/n", indent, afterward->number);

1748   }

1749 }

 

这时, afterward null ,而 subroutine_number 不是 0 。那么我们得到下面的代码片段。

 

int

recog_2 (rtx x0 ATTRIBUTE_UNUSED,

      rtx insn ATTRIBUTE_UNUSED,

      int *pnum_clobbers ATTRIBUTE_UNUSED)

{

   rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];

   rtx x1 ATTRIBUTE_UNUSED;

   rtx x2 ATTRIBUTE_UNUSED;

rtx x3 ATTRIBUTE_UNUSED;

int tem ATTRIBUTE_UNUSED;

 

x1 = XEXP(x0, 1);

x2 = XEXP(x1, 0);

 

if (GET_MODE (x2) == DI_mode)

  goto L104;

goto ret0;

 

L104:

   switch (GET_CODE (x2))

   {

     case MATCH_OPERAND:

       goto L103;

     case MINUS:

       goto L100;

     default:

       break;

}

goto ret0;

 

随后我们回到 write_tree ,在 2272 行,对 27 中,跟在 position 10 size 4 的节点后的节点,递归调用该函数。注意到这个节点具有为 1 need_label 。我们在下面显示 write_tree 中相关的代码。

 

2224 static void

2225 write_tree (struct decision_head *head, const char *prevpos,                          in genrecog.c

2226            enum routine_type type, int initial)

2227 {

2228   struct decision *p = head->first;

2229

2230   putchar ('/n');

2231   if (p->need_label)

2232     OUTPUT_LABEL (" ", p->number);

2233

2234   if (! initial && p->subroutine_number > 0)

2235   {

   

2264   }

2265   else

2266   {

2267     int depth = strlen (p->position);

2268

2269     change_state (prevpos, p->position, head->last->afterward, "  ");

2270     write_tree_1 (head, depth, type);

2271

2272     for (p = head->first; p; p = p->next)

2273       if (p->success.first)

2274         write_tree (&p->success, p->position, type, 0);

2275   }

2276 }

 

现在对于包含这个节点的分支,我们得到如下的代码片段。

 

int

recog_2 (rtx x0 ATTRIBUTE_UNUSED,

      rtx insn ATTRIBUTE_UNUSED,

      int *pnum_clobbers ATTRIBUTE_UNUSED)

{

   rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];

   rtx x1 ATTRIBUTE_UNUSED;

   rtx x2 ATTRIBUTE_UNUSED;

rtx x3 ATTRIBUTE_UNUSED;

int tem ATTRIBUTE_UNUSED;

 

x1 = XEXP(x0, 1);

x2 = XEXP(x1, 0);

 

if (GET_MODE (x2) == DI_mode)

  goto L104;

goto ret0;

 

L104:

   switch (GET_CODE (x2))

   {

     case MATCH_OPERAND:

       goto L103;

     case MINUS:

       goto L100;

     default:

       break;

}

goto ret0;

 

L103:

   if (nonimmediate_operand (x2, SUBREG))

   {

     operands[0] = x2;

     goto L112;

   }

   goto ret0;

 

L112:

   x2 = XEXP (x1, 1);

   if (const0_operand (x2, CONST_INT))

   {

     operands[1] = x2;

     goto L111;

   }

   goto ret0;

 

L111:

   if (TARGET_64BIT && ix86_match_ccmode (insn, CCNomode))

   {

     return `code-number` ;

   }

   goto ret0;

 

对于 27 中的另一个分支,则可以得到如下代码片段。

 

int

recog_2 (rtx x0 ATTRIBUTE_UNUSED,

      rtx insn ATTRIBUTE_UNUSED,

      int *pnum_clobbers ATTRIBUTE_UNUSED)

{

   rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];

   rtx x1 ATTRIBUTE_UNUSED;

   rtx x2 ATTRIBUTE_UNUSED;

rtx x3 ATTRIBUTE_UNUSED;

int tem ATTRIBUTE_UNUSED;

 

x1 = XEXP(x0, 1);

x2 = XEXP(x1, 0);

 

if (GET_MODE (x2) == DI_mode)

  goto L104;

goto ret0;

 

L104:

   switch (GET_CODE (x2))

   {

     case MATCH_OPERAND:

       goto L103;

     case MINUS:

       goto L100;

     default:

       break;

}

goto ret0;

 

L103:

   if (nonimmediate_operand (x2, SUBREG))

   {

     operands[0] = x2;

     goto L112;

   }

   goto ret0;

 

L112:

   x2 = XEXP (x1, 1);

   if (const0_operand (x2, CONST_INT))

   {

     operands[1] = x2;

     goto L111;

   }

   goto ret0;

 

L111:

   if (TARGET_64BIT && ix86_match_ccmode (insn, CCNomode))

   {

     return `code-number` ;

   }

   goto ret0;

 

L100:

   x2 = XEXP (x1, 0);

   x3 = XEXP (x2, 0);

   if (nonimmediate_operand (x3, SUBREG))

   {

     operands[0] = x3;

     goto L101:

   }

   goto ret0;

 

L101:

   x3 = XEXP (x2, 1);

   if (x86_64_general_operand (x3, CONST_INT))

   {

     operands[1] = x3;

     goto L11;

   }

   goto ret0;

 

L11:

   return recog_1 (x0, insn, pnum_clobbers);

 

ret0:

   return -1;

}

 

在完成了这两个分支之后,我们将从 write_subroutines 返回到 process_tree 。在 2607 行, write_subroutine 将为根节点所调用。注意到根节点不计入节点数目,因此没有分配 subroutine_number (保持为 0 )。因而我们将得到下面的函数。

 

static int

recog (rtx x0 ATTRIBUTE_UNUSED,

      rtx insn ATTRIBUTE_UNUSED,

      int *pnum_clobbers ATTRIBUTE_UNUSED)

{

rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];

   rtx x1 ATTRIBUTE_UNUSED;

   rtx x2 ATTRIBUTE_UNUSED;

rtx x3 ATTRIBUTE_UNUSED;

int tem ATTRIBUTE_UNUSED;

recog_data.insn = NULL_RTX;

if (GET_CODE (x0) == SET)

  goto L3;

goto ret0;

L3:

   x1 = XEXP (x0, 0);

   if (GET_CODE (x1) == REG &&

XINT (x0, 0) == 17)

   {

     goto L1:

   }

   goto ret0;

 

L1:

   x1 = XEXP (x0, 1);

   if (GET_CODE (x1) == COMPARE)

   {

     goto L101:

}

goto ret0;

 

L101:

   return recog_2 (x0, insn, pnum_clobbers);

 

ret0:

   return -1;

}

 

现在我们了解了 recog 做什么用,并且它如何起作用。对于 split peephole2 ,整个产生的过程非常类似。而且它们也以相似的方式工作。

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