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 的節點在下圖中被标記成紅色。
圖 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 來一個個處理。
圖 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 ,整個産生的過程非常類似。而且它們也以相似的方式工作。