GCC后端及汇编发布(30)

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 ("#define operands 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 by checking everything stored

6168     away and building the attribute cases.  */

6169

6170   check_defs ();

 

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

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

DEFINE_INSN DEFINE_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)                                                                               in genattrtab.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, "bad attribute 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_ALTERNATIVE RTL 格式是 sE 。使用以下的例子,

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

                        (const_string "a3")])

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

 

1244 static rtx

1245 convert_set_attr_alternative (rtx exp, struct insn_def *id)                        in genattrtab.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 in SET_ATTR_ALTERNATIVE");

1255     have_error = 1;

1256     return NULL_RTX;

1257   }

1258

1259   /* Make a COND with all 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_ATTR RTL 格式是“ 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)                                        in genattrtab.c

1283 {

1284   rtx newexp;

1285   const char *name_ptr;

1286   char *p;

1287   int n;

1288

1289   /* See how many alternative 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 each comma-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_ALTERNATIVE SET_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     return FATAL_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 extra attributes for `length'.  */

6185   make_length_attrs ();

6186

6187   /* Perform any possible optimizations to speed up compilation.  */

6188   optimize_attrs ();

 

9.6.1.2.    完成属性

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

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

 

2263 static void

2264 fill_attr (struct attr_desc *attr)                                                             in genattrtab.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 fill constant 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 is specified 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_attr 2274 属性视为常量 如果其值是 SYMBOL_REF CONST_INT 。在 2277 行, defs 已经链接了所有的 define_insn define_peephole define_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 in chain.  */

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_dup N)

这指向当前指令操作数 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_insn define_peephole define_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)                                                                    in genattrtab.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 length attribute is defined. If so, it must be numeric. Make

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

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 be numeric");

2403

2404   length_attr->is_const = 0;

2405   length_attr->is_special = 1;

2406

2407   /* Make each new attribute, 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_DUP PC )测试的 COND IF_THEN_ELSE 。如果是,使用通过把该表达式传递给 address_fn 所得到的结果来替代之。如果不是,但它是一个 COND IF_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 any tests 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 new copy 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     return newexp;

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     case SYMBOL_REF:

4948       if (! ATTR_IND_SIMPLIFIED_P (exp))

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

4950           However, constant expressions do not depend on any particular

4951           insn.  */

4952         must_extract = must_constrain = 1;

4953       return ;

4954

4955     case MATCH_OPERAND:

4956        must_extract = 1;

4957       return ;

4958

4959     case EQ_ATTR_ALT:

4960       must_extract = must_constrain = 1;

4961       break ;

4962

4963     case EQ_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     case MATCH_DUP:

4971       must_extract = 1;

4972       address_used = 1;

4973       return ;

4974

4975     case PC:

4976       address_used = 1;

4977       return ;

4978

4979     case ATTR_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                                rtx object of 0                             "*insn_variable_length_p"

zero_fn                                rtx object of 0                             "*insn_current_length"

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

address_fn                           result of fn on exp                            attribute attached

max_fn                                rtx object of max value in exp             "*insn_default_length"

one_fn                                 rtx object of 1                             "*insn_variable_length_p"

identify_fn                           exp                                            "*insn_current_length"

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

 

你可能感兴趣的:(GCC后端及汇编发布(30))