天天看點

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)

圖 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    

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  

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

1681     continue ;

1682

1683  

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  

1692   while (depth < ndepth)

1693   {

1694     

1695     if (ISUPPER (newpos[depth]))

1696     {

1697       

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    

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

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

2202

2203    

2204     next = write_switch (p, depth);

2205     if (p != next)

2206       uncond = 0;

2207     else

2208     {

2209      

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

2211       next = p->next;

2212     }

2213   }

2214

2215  

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    

2062     if (test->next)

2063     {

2064        test = test->next;

2065        if (test->type != DT_accept_insn)

2066          abort ();

2067     }

2068   }

2069

2070  

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  

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  

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    

2242

2243    

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    

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     

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        

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      

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    

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)

圖 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 ,整個産生的過程非常類似。而且它們也以相似的方式工作。

繼續閱讀