GCC后端及汇编发布(30)

来源:互联网 发布:信鸽邮件群发软件 编辑:程序博客网 时间:2024/05/29 19:06

9.6.输出生成文件

9.6.1. 处理属性

9.6.1.1.    统一属性

虽然我们构建了生成最小化DFA所需的数据,但收集的属性尚未处理。我们需要把它们转换为统一的形式,并如下打包有用的信息。

 

main (continued)

 

6137  printf ("#include /"config.h/"/n");

6138  printf ("#include/"system.h/"/n");

6139   printf ("#include/"coretypes.h/"/n");

6140   printf ("#include/"tm.h/"/n");

6141   printf ("#include/"rtl.h/"/n");

6142   printf ("#include/"tm_p.h/"/n");

6143   printf ("#include/"insn-config.h/"/n");

6144   printf ("#include/"recog.h/"/n");

6145   printf ("#include/"regs.h/"/n");

6146   printf ("#include/"real.h/"/n");

6147   printf ("#include/"output.h/"/n");

6148   printf ("#include/"insn-attr.h/"/n");

6149   printf ("#include/"toplev.h/"/n");

6150   printf ("#include/"flags.h/"/n");

6151   printf ("#include/"function.h/"/n");

6152   printf ("/n");

6153   printf ("#defineoperands recog_data.operand/n/n");

6154

6155   /* Make`insn_alternatives'.  */

6156   insn_alternatives = oballoc (insn_code_number* sizeof (int));

6157   for(id = defs;id; id = id->next)

6158     if (id->insn_code >=0)

6159       insn_alternatives[id->insn_code]= (1 << id->num_alternatives) - 1;

6160

6161   /* Make`insn_n_alternatives'.  */

6162   insn_n_alternatives = oballoc (insn_code_number* sizeof (int));

6163   for(id = defs;id; id = id->next)

6164     if (id->insn_code >=0)

6165       insn_n_alternatives[id->insn_code]= id->num_alternatives;

6166

6167  /* Prepare to write out attribute subroutines bychecking everything stored

6168     awayand building the attribute cases.  */

6169

6170   check_defs();

 

上面在6159行,insn_alternatives保存着,对于每个指令编码,一个位图,每个可能的替代对应其中的一个比特。而在6162行,insn_n_alternatives保存着,对于每个指令编码,约束替代的数目。在6170check_defs扫描所有的定义,检查有效性,并把所有的SET_ATTRSET_ATTR_ALTERNATIVE表达式转换为对应的SET表达式。

首先,看一下SET_ATTRSET_ATTR_ALTERNATIVE表达式,以下摘自注释

DEFINE_INSNDEFINE_PEEPHOLE最后的操作数中,这可以被用于,根据被匹配的替代,指出将被用在赋值的属性值。

以下的三个表达式是等效的:

   (set(attr "att") (cond [(eq_attrq "alternative" "1")(const_string "a1")

                   (eq_attrq "alternative""2") (const_string "a2")]

                  (const_string "a3")))

  (set_attr_alternative "att" [(const_string "a1")(const_string "a2")

                       (const_string "a3")])

  (set_attr "att" "a1,a2,a3")

check_defs将把后两个形式转换为第一个形式。

 

1313 static void

1314 check_defs (void)                                                                               ingenattrtab.c

1315 {

1316   struct insn_def *id;

1317   struct attr_desc *attr;

1318   int i;

1319   rtx value;

1320

1321   for (id = defs;id; id = id->next)

1322   {

1323     if (XVEC (id->def, id->vec_idx) ==NULL)

1324       continue;

1325

1326     for (i = 0;i < XVECLEN (id->def, id->vec_idx); i++)

1327     {

1328       value = XVECEXP (id->def, id->vec_idx,i);

1329       switch (GET_CODE (value))

1330       {

1331         case SET:

1332           if (GET_CODE (XEXP(value, 0)) != ATTR)

1333           {

1334             message_with_line (id->lineno, "badattribute set");

1335             have_error = 1;

1336             value = NULL_RTX;

1337           }

1338           break;

1339

1340         case SET_ATTR_ALTERNATIVE:

1341           value = convert_set_attr_alternative (value,id);

1342           break;

1343

1344         case SET_ATTR:

1345           value = convert_set_attr(value, id);

1346           break;

1347

1348         default:

1349           message_with_line (id->lineno,"invalid attribute code %s",

1350                 GET_RTX_NAME (GET_CODE (value)));

1351           have_error = 1;

1352           value = NULL_RTX;

1353      }

1354       if(value == NULL_RTX)

1355         continue;

1356

1357       if((attr = find_attr (&XSTR (XEXP(value, 0), 0), 0)) == NULL)

1358       {

1359         message_with_line (id->lineno,"unknown attribute %s",

1360                    XSTR (XEXP (value, 0),0));

1361         have_error= 1;

1362         continue;

1363       }

1364

1365       XVECEXP (id->def, id->vec_idx, i) =value;

1366       XEXP (value, 1) = check_attr_value(XEXP (value, 1), attr);

1367     }

1368   }

1369 }

 

上面在1323行,def指向这个insn_def所属的rtx对象,vec_idx显示属性向量在这个def中的位置,这个值是硬编码的。对于define_insn,它是4。对于define_peephole,它是3。对于define_asm_attribute,它是0。模式中的属性部分是可选的,如果不存在,意味着使用该属性的缺省值。

SET_ATTR_ALTERNATIVERTL格式是sE。使用以下的例子,

(set_attr_alternative"att" [(const_string "a1") (const_string "a2")

                       (const_string "a3")])

其中“att”是格式的“s”部分,而“[…]”是“E”部分,它是应该含有3个元素的向量。正如我们已知的,格式“s”对应CONST_STRINGrtx对象,而格式“E”对应RTVECrtx对象。

 

1244 static rtx

1245 convert_set_attr_alternative (rtx exp, struct insn_def*id)                        ingenattrtab.c

1246 {

1247  int num_alt = id->num_alternatives;

1248   rtx condexp;

1249   int i;

1250

1251   if (XVECLEN (exp, 1) != num_alt)

1252   {

1253     message_with_line (id->lineno,

1254              "bad number of entries inSET_ATTR_ALTERNATIVE");

1255     have_error = 1;

1256     returnNULL_RTX;

1257   }

1258

1259  /* Make a COND withall tests but the last. Select the last value via the

1260     default. */

1261   condexp = rtx_alloc (COND);

1262   XVEC (condexp, 0) = rtvec_alloc ((num_alt -1) * 2);

1263

1264   for (i = 0; i< num_alt - 1; i++)

1265   {

1266     const char*p;

1267     p = attr_numeral (i);

1268

1269     XVECEXP (condexp, 0, 2 * i) = attr_eq (alternative_name,p);

1270     XVECEXP (condexp, 0, 2 * i + 1) = XVECEXP(exp, 1, i);

1271   }

1272

1273   XEXP (condexp, 1) = XVECEXP (exp, 1, i);

1274

1275   return attr_rtx(SET, attr_rtx (ATTR, XSTR (exp, 0)), condexp);

1276 }

 

SET_ATTRRTL格式是“ss”。所有以下的例子,(set_attr "att" "a1,a2,a3")。其中,“ss”对应“att”,及“a1, a2, a3。首先把这个SET_ATTR对象转换到对应的SET_ATTR_ALTERNATIVE对象。然后通过上面的convert_set_attr_alternatives,这个SET_ATTR_ALTERNATIVE对象进一步转换到SET对象。

 

1281 static rtx

1282 convert_set_attr (rtx exp, struct insn_def *id)                                        ingenattrtab.c

1283 {

1284   rtx newexp;

1285   const char*name_ptr;

1286   char *p;

1287   int n;

1288

1289  /* See how manyalternative specified.  */

1290   n = n_comma_elts (XSTR (exp, 1));

1291   if (n == 1)

1292     return attr_rtx(SET,

1293            attr_rtx(ATTR, XSTR (exp, 0)),

1294            attr_rtx(CONST_STRING, XSTR (exp, 1)));

1295

1296   newexp = rtx_alloc (SET_ATTR_ALTERNATIVE);

1297   XSTR (newexp, 0) = XSTR (exp, 0);

1298   XVEC (newexp, 1) = rtvec_alloc (n);

1299

1300  /* Process eachcomma-separated name.  */

1301   name_ptr = XSTR (exp, 1);

1302   n = 0;

1303   while ((p =next_comma_elt (&name_ptr)) != NULL)

1304     XVECEXP (newexp, 1, n++) = attr_rtx(CONST_STRING, p);

1305

1306   return convert_set_attr_alternative (newexp, id);

1307 }

 

现在,因为由于处理SET_ATTR_ALTERNATIVESET_ATTR对象,某些属性被改变了,因此需要下面6175行的check_attr_value来再一次验证属性。

 

main (continued)

 

6172   for (i = 0; i < MAX_ATTRS_INDEX; i++)

6173     for (attr =attrs[i];attr; attr = attr->next)

6174       attr->default_val->value

6175           = check_attr_value(attr->default_val->value, attr);

6176

6177   if (have_error)

6178     returnFATAL_EXIT_CODE;

6179

6180   for (i = 0; i < MAX_ATTRS_INDEX; i++)

6181     for (attr =attrs[i];attr; attr = attr->next)

6182       fill_attr (attr);

6183

6184   /* Construct extraattributes for `length'.  */

6185   make_length_attrs ();

6186

6187   /* Perform any possible optimizations tospeed up compilation.  */

6188   optimize_attrs ();

 

9.6.1.2.    完成属性

对于数值属性,在其模式定义中,它必须具有空的LIST-OF-VALUE部分(至于define_attr的细节,可以参考读入DEFINE_ATTR模式一节)。

对于这些数值属性,fill_attr用于从模式中收集这些值。除此之外,对于所有的属性,这个函数将构建一个列表,它把所有使用同一个属性的指令链接起来。

 

2263 static void

2264 fill_attr (structattr_desc *attr)                                                             ingenattrtab.c

2265 {

2266   struct attr_value*av;

2267   struct insn_ent*ie;

2268   struct insn_def*id;

2269   int i;

2270   rtx value;

2271

2272   /* Don't fillconstant attributes. The value is independent of

2273     any particular insn.  */

2274   if (attr->is_const)

2275     return;

2276

2277   for (id = defs;id; id = id->next)

2278   {

2279     /* If no value isspecified for this insn for this attribute, use the

2280       default. */

2281     value = NULL;

2282     if (XVEC (id->def, id->vec_idx))

2283      for (i = 0; i < XVECLEN (id->def,id->vec_idx); i++)

2284         if (! strcmp_check (XSTR (XEXP(XVECEXP (id->def, id->vec_idx, i), 0), 0),

2285                         attr->name))

2286           value = XEXP (XVECEXP (id->def,id->vec_idx, i), 1);

2287

2288     if (value == NULL)

2289       av = attr->default_val;

2290     else

2291       av = get_attr_value (value, attr, id->insn_code);

2292

2293     ie = oballoc (sizeof(struct insn_ent));

2294     ie->insn_code= id->insn_code;

2295    ie->insn_index = id->insn_code;

2296     insert_insn_ent (av, ie);

2297  }

2298 }

 

fill_attr2274属性视为常量如果其值是SYMBOL_REFCONST_INT。在2277行,defs已经链接了所有的define_insndefine_peepholedefine_asm_attributes(参见gen_insn)。因此在2283行的FOR循环遍历模式的属性部分,并调用get_attr_value来向属性的值列表加入新发现的值(注意对于具有以星号(*)开头,由系统产生的属性,它们将以相同的值,为每个指令所添加。这是因为,首先没有指令会包含匹配这个名字的属性,其次,所有这些属性由make_internal_attr构建,并具有单个的值)。而在2296行,insert_insn_ent的定义如下,它把使用相同属性值的指令链接起来。

 

2632 static void

2633 insert_insn_ent (struct attr_value *av, struct insn_ent*ie)                       in genattrtab.c

2634 {

2635   ie->next = av->first_insn;

2636   av->first_insn = ie;

2637   av->num_insns++;

2638   if (ie->insn_code == -1)

2639     av->has_asm_insn = 1;

2640

2641   num_insn_ents++;

2642 }

 

insn_ent构成了具有相同属性值指令的链表,它具有如下定义。

 

161  struct insn_ent                                                                                     in genattrtab.c

162  {

163   struct insn_ent *next; /* Next inchain.  */

164   int insn_code;            /* Instruction number. */

165   int insn_index;           /* Index of definition in file */

166   int lineno;                 /* Line number.  */

167  };

 

继续main,为了更好地了解6185行的make_length_attr,首先看一下以下摘自gccint的段落。

对于许多机器而言,它们提供了多种跳转指令,每个对应不同跳转偏移。在绝大多数情形下,汇编器将选择使用正确的指令。不过,当汇编器做不到这一点时,GCC可以,当一个特殊的属性——‘length’属性被定义时。这个属性必须,通过在其‘define_attr’中指定一个空字符串,来定义为具有数字值。

length’属性而言,允许在测试表达式中使用另外两个形式的算术项:

(match_dupN)

这指向当前指令操作数N的地址,它必须是一个‘label_re.’。

(pc)

这指向当前指令的地址。其他的用法把它作为下一个指令的地址可能更符合,不过因为当前指令的长度会被计入,这可能会让人困扰。

对于普通的指令,长度将由‘length’属性的值来决定。在‘addr_vec’及‘addr_diff_vec’指令模式中,其长度通过向量的数量乘以每个向量的大小来计算。

长度以可取址储存单元(byte)为单位来计量。

下面的宏可以用于细化长度计算:

ADJUST_INSN_LENGTH(INSN, LENGTH)

如果定义了,作为一个其所被应用的上下文中的一个函数,修改赋予指令INSN的长度。LENGTH是一个左值(lvalue),它包含了该指令初始计算的长度,并将为该指令正确的长度所更新。

这个宏通常是不要求的。要求它的一个情形是ROMP。在这个机器中,一个‘addr_vec’指令的长度必须加上2,来补偿可能要求对齐的这个事实。

返回‘get_attr_length’(‘length’属性的值)的函数,可以被输出函数所使用,来确定所要写出的跳转指令的形式,如下面例子所显示的。

作为一个可变长度跳转说明的例子,考虑IBM 360。如果我们采用约定,一个寄存器将被设置为一个函数的起始地址,我们可以,使用一个4字节指令,跳转到距起始地址4k内的label。否则,我们需要一个6字节序列,来从内存载入地址,然后跳转到这个地址。

在这样的一个机器上,一个用于一个跳转指令的模式可能被详细说明如下:

     (define_insn"jump"

       [(set (pc)

            (label_ref (match_operand 0 "" "")))]

       ""

       {

         return (get_attr_length (insn) == 4

                ?"b %l0" : "l r15,=a(%l0); br r15");

       }

       [(set (attr"length")

             (if_then_else(lt (minus (pc) (match_dup 0) (const_int 4096))

                          (const_int 4)

                          (const_int 6)))])

事实上,对于每个define_insndefine_peepholedefine_asm_attribute模式,如果它不显式设置一个属性,它将使用该属性的缺省值。在这里make_length为每个模式,根据其“length”属性,构建了3个额外的属性。它们是:

*insn_default_length

这是在调用shorten_branches之前,由返回的get_attr_length指令的长度。在长度依赖于相对地址的情形下,使用最大可能的那个。

*insn_variable_length_p

这返回1,如果该指令的长度依赖于相对地址;否则返回0

*insn_current_length

仅当已知该指令具有一个可变长度时,这才被调用,并基于相对地址返回当前长度。

 

2379 static void

2380 make_length_attrs (void)                                                                    ingenattrtab.c

2381 {

2382   static const char *new_names[] =

2383   {

2384     "*insn_default_length",

2385     "*insn_variable_length_p",

2386     "*insn_current_length"

2387   };

2388   static rtx (*const no_address_fn[]) (rtx) = {identity_fn, zero_fn,zero_fn};

2389   static rtx (*const address_fn[]) (rtx) = {max_fn, one_fn,identity_fn};

2390   size_t i;

2391  struct attr_desc*length_attr, *new_attr;

2392   struct attr_value*av, *new_av;

2393   struct insn_ent*ie, *new_ie;

2394

2395   /* See if lengthattribute is defined. If so, it must be numeric. Make

2396     it special so we don't output anything forit.  */

2397   length_attr = find_attr(&length_str,0);

2398   if (length_attr == 0)

2399     return;

2400

2401   if (! length_attr->is_numeric)

2402     fatal ("length attribute must benumeric");

2403

2404   length_attr->is_const = 0;

2405   length_attr->is_special = 1;

2406

2407   /* Make each newattribute, in turn.  */

2408   for (i = 0; i< ARRAY_SIZE (new_names); i++)

2409   {

2410     make_internal_attr (new_names[i],

2411                     substitute_address (length_attr->default_val->value,

2412                                   no_address_fn[i], address_fn[i]),

2413                     ATTR_NONE);

2414     new_attr = find_attr(&new_names[i], 0);

2415     for (av =length_attr->first_value; av; av = av->next)

2416       for (ie =av->first_insn; ie; ie = ie->next)

2417       {

2418         new_av = get_attr_value (substitute_address (av->value,

2419                              no_address_fn[i],

2420                              address_fn[i]),

2421                              new_attr,ie->insn_code);

2422         new_ie = oballoc (sizeof (struct insn_ent));

2423        new_ie->insn_code = ie->insn_code;

2424         new_ie->insn_index =ie->insn_index;

2425         insert_insn_ent (new_av, new_ie);

2426       }

2427   }

2428 }

 

上面在2411行,substitute_address,给定一个表达式exp,查看它是否是一个具有检查指令相对位置(使用MATCH_DUPPC)测试的COND IF_THEN_ELSE。如果是,使用通过把该表达式传递给address_fn所得到的结果来替代之。如果不是,但它是一个CONDIF_THEN_ELSE,在每个值上递归调用这个函数(包括缺省值)。否则,返回由应用在exp上的no_address_fn所返回的值。

 

2307 static rtx

2308 substitute_address (rtx exp, rtx(*no_address_fn) (rtx),                          in genattrtab.c

2309                 rtx (*address_fn) (rtx))

2310 {

2311   int i;

2312   rtx newexp;

2313

2314   if (GET_CODE (exp) == COND)

2315   {

2316     /* See if anytests use addresses.  */

2317     address_used = 0;

2318     for (i = 0;i < XVECLEN (exp, 0); i += 2)

2319       walk_attr_value (XVECEXP (exp, 0, i));

2320

2321     if (address_used)

2322       return(*address_fn) (exp);

2323

2324     /* Make a newcopy of this COND, replacing each element. */

2325     newexp = rtx_alloc (COND);

2326     XVEC (newexp, 0) = rtvec_alloc (XVECLEN(exp, 0));

2327    for (i = 0; i < XVECLEN (exp, 0); i += 2)

2328     {

2329      XVECEXP (newexp, 0, i) = XVECEXP (exp, 0, i);

2330       XVECEXP (newexp, 0, i + 1)

2331                 = substitute_address (XVECEXP (exp, 0, i + 1),

2332                                  no_address_fn,address_fn);

2333     }

2334

2335     XEXP (newexp, 1) = substitute_address (XEXP (exp, 1),

2336                                      no_address_fn,address_fn);

2337

2338     returnnewexp;

2339   }

2340

2341   else if (GET_CODE (exp) == IF_THEN_ELSE)

2342   {

2343     address_used = 0;

2344     walk_attr_value (XEXP (exp, 0));

2345     if (address_used)

2346       return(*address_fn) (exp);

2347

2348     return attr_rtx(IF_THEN_ELSE,

2349                 substitute_address (XEXP (exp, 0),

2350                                 no_address_fn,address_fn),

2351                 substitute_address (XEXP (exp, 1),

2352                                 no_address_fn, address_fn),

2353                 substitute_address (XEXP (exp, 2),

2354                                 no_address_fn,address_fn));

2355   }

2356

2357   return (*no_address_fn)(exp);

2358 }

 

walk_attr_value扫描属性值,这可能是个条件值(一个例外是下面4979行的ATTR_FLAG),并记录将要求什么动作来对它进行条件测试。

 

4934 static void

4935 walk_attr_value (rtx exp)                                                                     in genattrtab.c

4936 {

4937   int i, j;

4938   const char*fmt;

4939   RTX_CODE code;

4940

4941   if (exp == NULL)

4942     return;

4943

4944   code = GET_CODE (exp);

4945   switch (code)

4946   {

4947     caseSYMBOL_REF:

4948       if (! ATTR_IND_SIMPLIFIED_P (exp))

4949         /* Since thisis an arbitrary expression, it can look at anything.

4950           However, constant expressions do notdepend on any particular

4951           insn. */

4952         must_extract = must_constrain = 1;

4953       return;

4954

4955     caseMATCH_OPERAND:

4956       must_extract= 1;

4957       return;

4958

4959     caseEQ_ATTR_ALT:

4960       must_extract = must_constrain = 1;

4961       break;

4962

4963     caseEQ_ATTR:

4964       if (XSTR (exp, 0) == alternative_name)

4965         must_extract = must_constrain = 1;

4966       else if (strcmp_check (XSTR (exp, 0), length_str)== 0)

4967         length_used = 1;

4968       return;

4969

4970     caseMATCH_DUP:

4971       must_extract = 1;

4972       address_used = 1;

4973       return;

4974

4975     case PC:

4976       address_used = 1;

4977       return;

4978

4979     caseATTR_FLAG:

4980       return;

4981

4982     default:

4983       break;

4984   }

4985

4986   for (i = 0,fmt = GET_RTX_FORMAT (code); i < GET_RTX_LENGTH (code); i++)

4987     switch (*fmt++)

4988     {

4989       case 'e':

4990       case 'u':

4991         walk_attr_value (XEXP (exp, i));

4992         break;

4993

4994       case 'E':

4995         if (XVEC (exp, i) != NULL)

4996           for(j = 0; j < XVECLEN (exp, i); j++)

4997             walk_attr_value (XVECEXP (exp, i, j));

4998         break;

4999    }

5000 }

 

4952行,must_extract表示我们是否需要提取指令的操作数,must_constrain表示我们是否必须计算编译器变量which_alternative。在4967行,length_used表示,是否使用了一个 (eq_attr"length" ...),而在4972行,address_used显示是否使用了一个地址表达式。

最后,对两种指令类型的结果显示如下。

no_address_fn                            result of fn on exp                            attribute attached

identity_fn                            exp                                            "*insn_default_length"

zero_fn                                rtxobject of 0                             "*insn_variable_length_p"

zero_fn                                rtxobject of 0                             "*insn_current_length"

1:为其它指令构建的属性

address_fn                           result of fn on exp                            attribute attached

max_fn                                rtxobject of max value in exp             "*insn_default_length"

one_fn                                 rtxobject of 1                             "*insn_variable_length_p"

identify_fn                           exp                                            "*insn_current_length"

2:为相对位置指令构建的属性

 

原创粉丝点击