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