GCC's bacl-end & assemble emission (30)

9.6. Output generation file

9.6.1. Handle attributes

9.6.1.1.    Attributes unification

Though we created the data needed to generate minimized DFA, the attributes collected are still unhandled. We need put them in uniform style and pack useful information up following.

 

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 ();

 

Above at line 6159, insn_alternatives stores, for each insn code, a bitmap that has bits on for each possible alternative. And at line 6162, insn_n_alternatives stores, for each insn code, the number of constraint alternatives. At line 6170 check_defs scans all definitions, checking for validity, and converts any SET_ATTR and SET_ATTR_ALTERNATIVE expressions to the corresponding SET expressions.

First, have a glance at SET_ATTR and SET_ATTR_ALTERNATIVE expressions, following is extracting from comment

In the last operand of DEFINE_INSN and DEFINE_PEEPHOLE, this can be used to specify that attribute values are to be assigned according to the alternative matched.

The following three expressions are equivalent:

 

   (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 will converts the later 2 forms into the first form.

 

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 }

 

Above at line 1323, def points to the rtx object the insn_def belongs to, vec_idx indicates the position of attribute vector in the def , which value is hard-coded. For define_insn, it is 4. For define_peephole, it is 3. For define_asm_attribute, it is 0. The part of attribute in pattern is optional, if absent, means default value of the attribute is applied.

The RTL format of SET_ATTR_ALTERNATIVE is “sE”. Uses following example,

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

                        (const_string "a3")])

In it “att” is the “s” of the format, and “[…]” is the “E” which is vector having 3 elements. And as we have known, “s” format will correspond to rtl object of CONST_STRING, and “E” format will correspond to rtl object of RTVEC.

 

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 }

 

The RTL format of SET_ATTR is “ss”. Uses following example, (set_attr "att" "a1,a2,a3"). In it, the “ss” corresponds to “att” and “a1, a2, a3”. It first converts this SET_ATTR object to corresponding SET_ATTR_ALTERNATIVE ones. Then by above convert_set_attr_alternatives , the SET_ATTR_ALTERNATIVE object further is converted to SET object.

 

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 }

 

As now, some attributes have been modified by handling SET_ATTR_ALTERNATIVE and SET_ATTR objects, so needs check_attr_value at line 6175 below to validate attributes again.

 

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.    Complete attributes
For numeric attribute, it must have empty LIST-OF-VALUE part in its pattern definition (for detail of define_attr, can refer to section 9.3.3 Read in DEFINE_ATTR pattern).
For these numeric attributes, fill_attr aims to collect the values from the patterns. Besides, for all attributes, this function will build a list which links instructions using the same attribute value tegother.

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    }

In fill_attr, at line 2274, attribute is constant if its value is of SYMBOL_REF or CONST_INT. At line 2277, defs already links all define_insn, define_peephole, and define_asm_attributes (see gen_insn). So FOR loop at line 2283, iterates the attribute part of all patterns, and invokes get_attr_value to add any new found value into the list of value for the attribute (Notice that for attributes with name starting with star (*) which are produced by system will be added for every instruction with the same value. This because, first no instruction will contain attribute value with matching name, the last, all these attributes are created by make_internal_attr and only have single value). At line 2296, in insert_insn_ent which defined below, instructions using same attribute value are linked tegother.

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 forms the list to link instructions having the same attribute value(s), it has below definition.

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    };

Conitnue with main, to better understand make_length_attr at line 6185, first have a look at following paragraphes extracted from gccint.
For many machines, multiple types of branch instructions are provided, each for different length branch displacements. In most cases, the assembler will choose the correct instruction to use. However, when the assembler cannot do so, GCC can when a special attribute, the `length' attribute, is defined. This attribute must be defined to have numeric values by specifying a null string in its `define_attr'.
In the case of the `length' attribute, two additional forms of arithmetic terms are allowed in test expressions:
(match_dup N)
This refers to the address of operand N of the current insn, which must be a `label_ref'.
(pc)
This refers to the address of the current insn. It might have been more consistent with other usage to make this the address of the _next_ insn but this would be confusing because the length of the current insn is to be computed.
For normal insns, the length will be determined by value of the `length' attribute. In the case of `addr_vec' and `addr_diff_vec' insn patterns, the length is computed as the number of vectors multiplied by the size of each vector.
Lengths are measured in addressable storage units (bytes).
The following macros can be used to refine the length computation:
ADJUST_INSN_LENGTH (INSN, LENGTH)
If defined, modifies the length assigned to instruction INSN as a function of the context in which it is used. LENGTH is an lvalue that contains the initially computed length of the insn and should be updated with the correct length of the insn.
This macro will normally not be required. A case in which it is required is the ROMP. On this machine, the size of an `addr_vec' insn must be increased by two to compensate for the fact that alignment may be required.
The routine that returns `get_attr_length' (the value of the `length' attribute) can be used by the output routine to determine the form of the branch instruction to be written, as the example below illustrates.
As an example of the specification of variable-length branches, consider the IBM 360. If we adopt the convention that a register will be set to the starting address of a function, we can jump to labels within 4k of the start using a four-byte instruction. Otherwise, we need a six-byte sequence to load the address from memory and then branch to it.
On such a machine, a pattern for a branch instruction might be specified as follows:
     (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)))])
In fact, for every define_insn, define_peephole and define_asm_attribute pattern, if it doesn’t set an attribute explicitly, it uses the default value of that attribute. make_length here creates 3 extra attributes for every pattern according to its “length” attribute. They are:
*insn_default_length
This is the length of the instruction to be returned by get_attr_length before shorten_branches has been called. In each case where the length depends on relative address, the largest possible is used.
*insn_variable_length_p
This returns 1 if the instruction’s length depends on relative addresses, zero otherwise.
*insn_current_length
This is only called when it is known that the    instruction has a variable length and returns the current length, based on relative addresses.

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    }

Above at line 2411, substitute_address, given an expression exp, sees if it is a COND or IF_THEN_ELSE that has a test that checks relative positions of instructions (uses MATCH_DUP or PC). If so, replace it with what is obtained by passing the expression to address_fn. If not but it is a COND or IF_THEN_ELSE, call this routine recursively on each value (including the default value). Otherwise, returns the value returned by no_address_fn applied to exp.

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 scans attribute value, possibly a conditional (an exception is ATTR_FLAG at line 4979 below), and records what actions will be required to do any conditional tests in it.

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    }

At line 4952, must_extract indicates if we need to extract the instruction operands, must_constrain indicates if we must compute compiler variable which_alternative. At line 4967, length_used indicates if an (eq_attr "length" ...) was used, and at line 4972, address_used indicates if an address expression was used.
In the end, the result is shown in below for both types of instructions.
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"
table 1 : attributes created for other instruction
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"
table 2: attributes created for relative positions instruction

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值