For define_insn pattern, we use the example used in previous section as following:
467 (define_insn "cmpdi_ccno_1_rex64" in i386.md
468 [(set (reg 17)
469 (compare (match_operand:DI 0 "nonimmediate_operand" "r,?mr")
470 (match_operand:DI 1 "const0_operand" "n,n")))]
471 "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)"
472 "@
473 test{q}/t{%0, %0|%0, %0}
474 cmp{q}/t{%1, %0|%0, %1}"
475 [(set_attr "type" "test,icmp")
476 (set_attr "length_immediate" "0,1")
477 (set_attr "mode" "DI")])
As we have known, this pattern is divided into parts as: optinal name, RTL template, condition, output template, and optinal vector of attributes. After treated by init_md_reader_args , above pattern will be loaded into memory as rtx object as following.
figure 38 : example of DEFINE_INSN pattern
As only part of information contained in this pattern will be useful to automaton building, gen_insn extracts the data it interests.
4383 static void
4384 gen_insn (rtx exp, int lineno) in genattrtab.c
4385 {
4386 struct insn_def *id;
4387
4388 id = oballoc (sizeof (struct insn_def ));
4389 id->next = defs ;
4390 defs = id;
4391 id->def = exp;
4392 id->lineno = lineno;
4393
4394 switch (GET_CODE (exp))
4395 {
4396 case DEFINE_INSN:
4397 id->insn_code = insn_code_number ;
4398 id->insn_index = insn_index_number ;
4399 id->num_alternatives = count_alternatives (exp);
4400 if (id->num_alternatives == 0)
4401 id->num_alternatives = 1;
4402 id->vec_idx = 4;
4403 break ;
4404
4405 case DEFINE_PEEPHOLE:
4406 id->insn_code = insn_code_number ;
4407 id->insn_index = insn_index_number ;
4408 id->num_alternatives = count_alternatives (exp);
4409 if (id->num_alternatives == 0)
4410 id->num_alternatives = 1;
4411 id->vec_idx = 3;
4412 break ;
4413
4414 case DEFINE_ASM_ATTRIBUTES:
4415 id->insn_code = -1;
4416 id->insn_index = -1;
4417 id->num_alternatives = 1;
4418 id->vec_idx = 0;
4419 got_define_asm_attributes = 1;
4420 break ;
4421
4422 default :
4423 abort ();
4424 }
4425 }
Above at line 4386, struct insn_def has following definition. It is a list. At line 4389, defs is an static instance of insn_def, and it is the header of the list.
146 struct insn_def in genattrtab.c
147 {
148 struct insn_def *next; /* Next insn in chain. */
149 rtx def; /* The DEFINE_... */
150 int insn_code; /* Instruction number. */
151 int insn_index; /* Expression numer in file, for errors. */
152 int lineno; /* Line number. */
153 int num_alternatives; /* Number of alternatives. */
154 int vec_idx; /* Index of attribute vector in `def'. */
155 };
count_alternatives is used to find out the number of constraints in operand allocation. It returns only first found number. In our example the first found constraint string is "r, ?mr". And the number of alternative is 2, as constraints are separated by ‘,’.
4284 static int
4285 count_alternatives (rtx exp) in genattrtab.c
4286 {
4287 int i, j, n;
4288 const char *fmt;
4289
4290 if (GET_CODE (exp) == MATCH_OPERAND)
4291 return n_comma_elts (XSTR (exp, 2));
4292
4293 for (i = 0, fmt = GET_RTX_FORMAT (GET_CODE (exp));
4294 i < GET_RTX_LENGTH (GET_CODE (exp)); i++)
4295 switch (*fmt++)
4296 {
4297 case 'e':
4298 case 'u':
4299 n = count_alternatives (XEXP (exp, i));
4300 if (n)
4301 return n;
4302 break ;
4303
4304 case 'E':
4305 case 'V':
4306 if (XVEC (exp, i) != NULL)
4307 for (j = 0; j < XVECLEN (exp, i); j++)
4308 {
4309 n = count_alternatives (XVECEXP (exp, i, j));
4310 if (n)
4311 return n;
4312 }
4313 }
4314
4315 return 0;
4316 }
For the purpose of define_attr pattern, we can extract following paragraph from gccinfo.
The define_attr expression is used to define each attribute required by the target machine. It looks like:
(define_attr NAME LIST-OF-VALUES DEFAULT)
NAME is a string specifying the name of the attribute being defined.
LIST-OF-VALUES is either a string that specifies a comma-separated list of values that can be assigned to the attribute, or a null string to indicate that the attribute takes numeric values.
DEFAULT is an attribute expression that gives the value of this attribute for insns that match patterns whose definition does not include an explicit value for this attribute. *Note Attr Example::, for more information on the handling of defaults. *Note Constant Attributes::, for information on attributes that do not depend on any particular insn.
For each defined attribute, a number of definitions are written to the `insn-attr.h' file. For cases where an explicit set of values is specified for an attribute, the following are defined:
* A #define is written for the symbol HAVE_ATTR_NAM '.
* An enumerated class is defined for attr_NAME with elements of the form UPPER-NAME_UPPER-VALU ' where the attribute name and value are first converted to uppercase.
* A function get_attr_NAME is defined that is passed an insn and returns the attribute value for that insn.
For example, if the following is present in the md file:
(define_attr "type" "branch,fp,load,store,arith" ...)
the following lines will be written to the file insn-attr.h.
#define HAVE_ATTR_type
enum attr_type {TYPE_BRANCH, TYPE_FP, TYPE_LOAD,
TYPE_STORE, TYPE_ARITH};
extern enum attr_type get_attr_type ();
If the attribute takes numeric values, no enum type will be defined and the function to obtain the attribute's value will return `int'.
For define_attr pattern, we use the example used in previous section as following:
24 (define_attr "pent_prefix" "false,true" in pentium.md
25 (if_then_else (ior (eq_attr "prefix_0f" "1")
26 (ior (eq_attr "prefix_data16" "1")
27 (eq_attr "prefix_rep" "1")))
28 (const_string "true")
29 (const_string "false")))
After treated by init_md_reader_args , above pattern will be loaded into memory as rtx object as following.
figure 39 : example of DEFINE_ATTR pattern
4216 static void
4217 gen_attr (rtx exp, int lineno)
4218 {
4219 struct attr_desc *attr;
4220 struct attr_value *av;
4221 const char *name_ptr;
4222 char *p;
4223
4224 /* Make a new attribute structure. Check for duplicate by looking at
4225 attr->default_val, since it is initialized by this routine. */
4226 attr = find_attr (&XSTR (exp, 0), 1);
4227 if (attr->default_val)
4228 {
4229 message_with_line (lineno, "duplicate definition for attribute %s",
4230 attr->name);
4231 message_with_line (attr->lineno, "previous definition");
4232 have_error = 1;
4233 return ;
4234 }
4235 attr->lineno = lineno;
4236
4237 if (*XSTR (exp, 1) == '/0')
4238 attr->is_numeric = 1;
4239 else
4240 {
4241 name_ptr = XSTR (exp, 1);
4242 while ((p = next_comma_elt (&name_ptr)) != NULL)
4243 {
4244 av = oballoc (sizeof (struct attr_value));
4245 av->value = attr_rtx (CONST_STRING, p);
4246 av->next = attr->first_value;
4247 attr->first_value = av;
4248 av->first_insn = NULL;
4249 av->num_insns = 0;
4250 av->has_asm_insn = 0;
4251 }
4252 }
4253
4254 if (GET_CODE ( XEXP (exp, 2)) == CONST)
4255 {
4256 attr->is_const = 1;
4257 if (attr->is_numeric)
4258 {
4259 message_with_line (lineno,
4260 "constant attributes may not take numeric values");
4261 have_error = 1;
4262 }
4263
4264 /* Get rid of the CONST node. It is allowed only at top-level. */
4265 XEXP (exp, 2) = XEXP ( XEXP (exp, 2), 0);
4266 }
4267
4268 if (! strcmp_check (attr->name, length_str ) && ! attr->is_numeric)
4269 {
4270 message_with_line (lineno,
4271 "`length' attribute must take numeric values");
4272 have_error = 1;
4273 }
4274
4275 /* Set up the default value. */
4276 XEXP (exp, 2) = check_attr_value ( XEXP (exp, 2), attr);
4277 attr->default_val = get_attr_value ( XEXP (exp, 2), attr, -2);
4278 }
The data of attribute is saved in global array attrs . Here the parameter name_p of find_attr points to the address of string “pent_prefix”. And the second parameter of find_attr is 1, which will tell the function to create new object if not found. We must prevent attributes duplicate definition by checking default_val of the attr returned by find_attr .
5805 static struct attr_desc *
5806 find_attr (const char **name_p, int create) in genattrtab.c
5807 {
5808 struct attr_desc *attr;
5809 int index;
5810 const char *name = *name_p;
5811
5812 /* Before we resort to using `strcmp', see if the string address matches
5813 anywhere. In most cases, it should have been canonicalized to do so. */
5814 if (name == alternative_name )
5815 return NULL;
5816
5817 index = name[0] & (MAX_ATTRS_INDEX - 1);
5818 for (attr = attrs [index]; attr; attr = attr->next)
5819 if (name == attr->name)
5820 return attr;
5821
5822 /* Otherwise, do it the slow way. */
5823 for (attr = attrs [index]; attr; attr = attr->next)
5824 if (name[0] == attr->name[0] && ! strcmp (name, attr->name))
5825 {
5826 *name_p = attr->name;
5827 return attr;
5828 }
5829
5830 if (! create)
5831 return NULL;
5832
5833 attr = oballoc (sizeof (struct attr_desc ));
5834 attr->name = DEF_ATTR_STRING (name);
5835 attr->first_value = attr->default_val = NULL;
5836 attr->is_numeric = attr->negative_ok = attr->is_const = attr->is_special = 0;
5837 attr->unsigned_p = attr->func_units_p = attr->blockage_p = attr->static_p = 0;
5838 attr->next = attrs [index];
5839 attrs [index] = attr;
5840
5841 *name_p = attr->name;
5842
5843 return attr;
5844 }
The structure attr_desc at line 5808 has following definition, and attrs at line 5818 is an array of attr_desc, size of 256. It is a hash table indeed. However, the hash function at line 5817 above is not very good, as only indexes correspond to ‘a-zA-Z0-9’ will be occupied.
184 struct attr_desc in genattrtab.c
186 {
185 char *name; /* Name of attribute. */
187 struct attr_desc *next; /* Next attribute. */
188 struct attr_value *first_value; /* First value of this attribute. */
189 struct attr_value *default_val; /* Default value for this attribute. */
190 int lineno : 24; /* Line number. */
191 unsigned is_numeric : 1; /* Values of this attribute are numeric. */
192 unsigned negative_ok : 1; /* Allow negative numeric values. */
193 unsigned unsigned_p : 1; /* Make the output function unsigned int. */
194 unsigned is_const : 1; /* Attribute value constant for each run. */
195 unsigned is_special : 1; /* Don't call `write_attr_set'. */
196 unsigned func_units_p : 1; /* This is the function_units attribute. */
197 unsigned blockage_p : 1; /* This is the blockage range function. */
198 unsigned static_p : 1; /* Make the output function static. */
199 };
From the definition, certain attribute can have several values, and a default value which will be applied if the pattern not specified otherwise. attr_value is designed to hold these values.
173 struct attr_value in genattrtab.c
174 {
175 rtx value; /* Value of attribute. */
176 struct attr_value *next; /* Next attribute value in chain. */
177 struct insn_ent *first_insn; /* First insn with this value. */
178 int num_insns; /* Number of insns with this value. */
179 int has_asm_insn; /* True if this value used for `asm' insns */
180 };
Continue with gen_attr , after allocating object of attr_desc to hold the new attribute, objects of attr_value are created to hold attribute values. Then at line 4245, attr_rtx is invoked to fill in these objects of attr_value . Notice that the first parameter is hardcoded as CONST_STRING.
729 static rtx
730 attr_rtx (enum rtx_code code, ...) in genautomata.c
731 {
732 rtx result;
733 va_list p;
734
735 va_start (p, code);
736 result = attr_rtx_1 (code, p);
737 va_end (p);
738 return result;
739 }
We see before that rtx objects can be grouped by classes, following rtx classes have been defined.
Ø "o" an rtx code that can be used to represent an object (e.g, REG, MEM)
Ø "<" an rtx code for a comparison (e.g, EQ, NE, LT)
Ø "1" an rtx code for a unary arithmetic expression (e.g, NEG, NOT)
Ø "c" an rtx code for a commutative binary operation (e.g, PLUS, MULT)
Ø "3" an rtx code for a non-bitfield three input operation (IF_THEN_ELSE)
Ø "2" an rtx code for a non-commutative binary operation (e.g., MINUS, DIV)
Ø "b" an rtx code for a bit-field operation (ZERO_EXTRACT, SIGN_EXTRACT)
Ø "i" an rtx code for a machine insn (INSN, JUMP_INSN, CALL_INSN)
Ø "m" an rtx code for something that matches in insns (e.g, MATCH_DUP)
Ø "g" an rtx code for grouping insns together (e.g, GROUP_PARALLEL)
Ø "a" an rtx code for autoincrement addressing modes (e.g. POST_DEC)
Ø "x" everything else
The class of rtx code CONST_STRING is ‘o’, and the format is ‘s’ (defined in rtl.def).
556 static rtx
557 attr_rtx_1 (enum rtx_code code, va_list p) in genautomata.c
558 {
559 rtx rt_val = NULL_RTX;/* RTX to return to caller... */
560 int hashcode;
561 struct attr_hash *h;
562 struct obstack *old_obstack = rtl_obstack ;
563
564 /* For each of several cases, search the hash table for an existing entry.
565 Use that entry if one is found; otherwise create a new RTL and add it
566 to the table. */
567
568 if (GET_RTX_CLASS (code) == '1')
569 {
570 rtx arg0 = va_arg (p, rtx);
571
572 /* A permanent object cannot point to impermanent ones. */
573 if (! ATTR_PERMANENT_P (arg0))
574 {
575 rt_val = rtx_alloc (code);
576 XEXP (rt_val, 0) = arg0;
577 return rt_val;
578 }
579
580 hashcode = ((HOST_WIDE_INT) code + RTL_HASH (arg0));
581 for (h = attr_hash_table [hashcode % RTL_HASH_SIZE]; h; h = h->next)
582 if (h->hashcode == hashcode
583 && GET_CODE (h->u.rtl) == code
584 && XEXP (h->u.rtl, 0) == arg0)
585 return h->u.rtl;
586
587 if (h == 0)
588 {
589 rtl_obstack = hash_obstack ;
590 rt_val = rtx_alloc (code);
591 XEXP (rt_val, 0) = arg0;
592 }
593 }
594 else if (GET_RTX_CLASS (code) == 'c'
595 || GET_RTX_CLASS (code) == '2'
596 || GET_RTX_CLASS (code) == '<')
597 {
598 rtx arg0 = va_arg (p, rtx);
599 rtx arg1 = va_arg (p, rtx);
600
601 /* A permanent object cannot point to impermanent ones. */
602 if (! ATTR_PERMANENT_P (arg0) || ! ATTR_PERMANENT_P (arg1))
603 {
604 rt_val = rtx_alloc (code);
605 XEXP (rt_val, 0) = arg0;
606 XEXP (rt_val, 1) = arg1;
607 return rt_val;
608 }
609
610 hashcode = ((HOST_WIDE_INT) code + RTL_HASH (arg0) + RTL_HASH (arg1));
611 for (h = attr_hash_table [hashcode % RTL_HASH_SIZE]; h; h = h->next)
612 if (h->hashcode == hashcode
613 && GET_CODE (h->u.rtl) == code
614 && XEXP (h->u.rtl, 0) == arg0
615 && XEXP (h->u.rtl, 1) == arg1)
616 return h->u.rtl;
617
618 if (h == 0)
619 {
620 rtl_obstack = hash_obstack ;
621 rt_val = rtx_alloc (code);
622 XEXP (rt_val, 0) = arg0;
623 XEXP (rt_val, 1) = arg1;
624 }
625 }
626 else if (GET_RTX_LENGTH (code) == 1
627 && GET_RTX_FORMAT (code)[0] == 's')
628 {
629 char *arg0 = va_arg (p, char *);
630
631 arg0 = DEF_ATTR_STRING (arg0);
632
633 hashcode = ((HOST_WIDE_INT) code + RTL_HASH (arg0));
634 for (h = attr_hash_table [hashcode % RTL_HASH_SIZE]; h; h = h->next)
635 if (h->hashcode == hashcode
636 && GET_CODE (h->u.rtl) == code
637 && XSTR (h->u.rtl, 0) == arg0)
638 return h->u.rtl;
639
640 if (h == 0)
641 {
642 rtl_obstack = hash_obstack ;
643 rt_val = rtx_alloc (code);
644 XSTR (rt_val, 0) = arg0;
645 }
646 }
647 else if (GET_RTX_LENGTH (code) == 2
648 && GET_RTX_FORMAT (code)[0] == 's'
649 && GET_RTX_FORMAT (code)[1] == 's')
650 {
651 char *arg0 = va_arg (p, char *);
652 char *arg1 = va_arg (p, char *);
653
654 hashcode = ((HOST_WIDE_INT) code + RTL_HASH (arg0) + RTL_HASH (arg1));
655 for (h = attr_hash_table [hashcode % RTL_HASH_SIZE]; h; h = h->next)
656 if (h->hashcode == hashcode
657 && GET_CODE (h->u.rtl) == code
658 && XSTR (h->u.rtl, 0) == arg0
659 && XSTR (h->u.rtl, 1) == arg1)
660 return h->u.rtl;
661
662 if (h == 0)
663 {
664 rtl_obstack = hash_obstack ;
665 rt_val = rtx_alloc (code);
666 XSTR (rt_val, 0) = arg0;
667 XSTR (rt_val, 1) = arg1;
668 }
669 }
670 else if (code == CONST_INT)
671 {
672 HOST_WIDE_INT arg0 = va_arg (p, HOST_WIDE_INT);
673 if (arg0 == 0)
674 return false_rtx ;
675 else if (arg0 == 1)
676 return true_rtx ;
677 else
678 goto nohash;
679 }
680 else
681 {
682 int i; /* Array indices... */
683 const char *fmt; /* Current rtx's format... */
684 nohash:
685 rt_val = rtx_alloc (code); /* Allocate the storage space. */
686
687 fmt = GET_RTX_FORMAT (code); /* Find the right format... */
688 for (i = 0; i < GET_RTX_LENGTH (code); i++)
689 {
690 switch (*fmt++)
691 {
692 case '0': /* Unused field. */
693 break ;
694
695 case 'i': /* An integer? */
696 XINT (rt_val, i) = va_arg (p, int);
697 break ;
698
699 case 'w': /* A wide integer? */
700 XWINT (rt_val, i) = va_arg (p, HOST_WIDE_INT);
701 break ;
702
703 case 's': /* A string? */
704 XSTR (rt_val, i) = va_arg (p, char *);
705 break ;
706
707 case 'e': /* An expression? */
708 case 'u': /* An insn? Same except when printing. */
709 XEXP (rt_val, i) = va_arg (p, rtx);
710 break ;
711
712 case 'E': /* An RTX vector? */
713 XVEC (rt_val, i) = va_arg (p, rtvec);
714 break ;
715
716 default :
717 abort ();
718 }
719 }
720 return rt_val;
721 }
722
723 rtl_obstack = old_obstack;
724 attr_hash_add_rtx (hashcode, rt_val);
725 ATTR_PERMANENT_P (rt_val) = 1;
726 return rt_val;
727 }
For our case, ELSE IF branch at line 626 is executed (refer to figure 39 for clear view). Back to gen_attr , check_attr_value is invoked at line 4276 to handle the third child of the pattern (the default value). The function given an expression ensures that it is validly formed and that all named attribute values are valid for the given attribute. Issues a fatal error if not. If no attribute is specified, it assumes a numeric attribute.
1073 static rtx
1074 check_attr_value (rtx exp, struct attr_desc *attr) in genattrtab.c
1075 {
1076 struct attr_value *av;
1077 const char *p;
1078 int i;
1079
1080 switch (GET_CODE (exp))
1081 {
1082 case CONST_INT:
1083 if (attr && ! attr->is_numeric)
1084 {
1085 message_with_line (attr->lineno,
1086 "CONST_INT not valid for non-numeric attribute %s",
1087 attr->name);
1088 have_error = 1;
1089 break ;
1090 }
1091
1092 if (INTVAL (exp) < 0 && ! attr->negative_ok)
1093 {
1094 message_with_line (attr->lineno,
1095 "negative numeric value specified for attribute %s",
1096 attr->name);
1097 have_error = 1;
1098 break ;
1099 }
1100 break ;
1101
1102 case CONST_STRING:
1103 if (! strcmp (XSTR (exp, 0), "*"))
1104 break ;
1105
1106 if (attr == 0 || attr->is_numeric)
1107 {
1108 p = XSTR (exp, 0);
1109 if (attr && attr->negative_ok && *p == '-')
1110 p++;
1111 for (; *p; p++)
1112 if (! ISDIGIT (*p))
1113 {
1114 message_with_line (attr ? attr->lineno : 0,
1115 "non-numeric value for numeric attribute %s",
1116 attr ? attr->name : "internal");
1117 have_error = 1;
1118 break ;
1119 }
1120 break ;
1121 }
1122
1123 for (av = attr->first_value; av; av = av->next)
1124 if (GET_CODE (av->value) == CONST_STRING
1125 && ! strcmp (XSTR (av->value, 0), XSTR (exp, 0)))
1126 break ;
1127
1128 if (av == NULL)
1129 {
1130 message_with_line (attr->lineno,
1131 "unknown value `%s' for `%s' attribute",
1132 XSTR (exp, 0), attr ? attr->name : "internal");
1133 have_error = 1;
1134 }
1135 break ;
1136
1137 case IF_THEN_ELSE:
1138 XEXP (exp, 0) = check_attr_test (XEXP (exp, 0),
1139 attr ? attr->is_const : 0,
1140 attr ? attr->lineno : 0);
1141 XEXP (exp, 1) = check_attr_value (XEXP (exp, 1), attr);
1142 XEXP (exp, 2) = check_attr_value (XEXP (exp, 2), attr);
1143 break ;
1144
1145 case PLUS:
1146 case MINUS:
1147 case MULT:
1148 case DIV:
1149 case MOD:
1150 if (attr && !attr->is_numeric)
1151 {
1152 message_with_line (attr->lineno,
1153 "invalid operation `%s' for non-numeric attribute value",
1154 GET_RTX_NAME (GET_CODE (exp)));
1155 have_error = 1;
1156 break ;
1157 }
1158 /* Fall through. */
1159
1160 case IOR:
1161 case AND:
1162 XEXP (exp, 0) = check_attr_value (XEXP (exp, 0), attr);
1163 XEXP (exp, 1) = check_attr_value (XEXP (exp, 1), attr);
1164 break ;
1165
1166 case FFS:
1167 case CLZ:
1168 case CTZ:
1169 case POPCOUNT:
1170 case PARITY:
1171 XEXP (exp, 0) = check_attr_value (XEXP (exp, 0), attr);
1172 break ;
1173
1174 case COND:
1175 if (XVECLEN (exp, 0) % 2 != 0)
1176 {
1177 message_with_line (attr->lineno,
1178 "first operand of COND must have even length");
1179 have_error = 1;
1180 break ;
1181 }
1182
1183 for (i = 0; i < XVECLEN (exp, 0); i += 2)
1184 {
1185 XVECEXP (exp, 0, i) = check_attr_test (XVECEXP (exp, 0, i),
1186 attr ? attr->is_const : 0,
1187 attr ? attr->lineno : 0);
1188 XVECEXP (exp, 0, i + 1)
1189 = check_attr_value (XVECEXP (exp, 0, i + 1), attr);
1190 }
1191
1192 XEXP (exp, 1) = check_attr_value (XEXP (exp, 1), attr);
1193 break ;
1194
1195 case ATTR:
1196 {
1197 struct attr_desc *attr2 = find_attr (&XSTR (exp, 0), 0);
1198 if (attr2 == NULL)
1199 {
1200 message_with_line (attr ? attr->lineno : 0,
1201 "unknown attribute `%s' in ATTR",
1202 XSTR (exp, 0));
1203 have_error = 1;
1204 }
1205 else if (attr && attr->is_const && ! attr2->is_const)
1206 {
1207 message_with_line (attr->lineno,
1208 "non-constant attribute `%s' referenced from `%s'",
1209 XSTR (exp, 0), attr->name);
1210 have_error = 1;
1211 }
1212 else if (attr
1213 && (attr->is_numeric != attr2->is_numeric
1214 || (! attr->negative_ok && attr2->negative_ok)))
1215 {
1216 message_with_line (attr->lineno,
1217 "numeric attribute mismatch calling `%s' from `%s'",
1218 XSTR (exp, 0), attr->name);
1219 have_error = 1;
1220 }
1221 }
1222 break ;
1223
1224 case SYMBOL_REF:
1225 /* A constant SYMBOL_REF is valid as a constant attribute test and
1226 is expanded later by make_canonical into a COND. In a non-constant
1227 attribute test, it is left be. */
1228 return attr_rtx (SYMBOL_REF, XSTR (exp, 0));
1229
1230 default :
1231 message_with_line (attr ? attr->lineno : 0,
1232 "invalid operation `%s' for attribute value",
1233 GET_RTX_NAME (GET_CODE (exp)));
1234 have_error = 1;
1235 break ;
1236 }
1237
1238 return exp;
1239 }
For our example, check_attr_value just checks if the attr_desc is created correctly or not; it also tries to simplify condition codes as possible. The function returns a perhaps modified replacement expression for the value. Just refer to the third child of rtx object in figure 39 for better understand.
Last in gen_attr , get_attr_value is used to fetch the default value of the attribute. Note that the first parameter here is the third child of define_attr pattern, and the third parameter is -2 which means not processing an insn and which shouldn’t contain attribute of “alternative”.
1480 static struct attr_value *
1481 get_attr_value (rtx value, struct attr_desc *attr, int insn_code) in genattrtab.c
1482 {
1483 struct attr_value *av;
1484 int num_alt = 0;
1485
1486 value = make_canonical (attr, value);
1487 if (compares_alternatives_p (value))
1488 {
1489 if (insn_code < 0 || insn_alternatives == NULL)
1490 fatal ("(eq_attr /"alternatives/" ...) used in non-insn context");
1491 else
1492 num_alt = insn_alternatives [insn_code];
1493 }
1494
1495 for (av = attr->first_value; av; av = av->next)
1496 if (rtx_equal_p (value, av->value)
1497 && (num_alt == 0 || av->first_insn == NULL
1498 || insn_alternatives [av->first_insn->insn_code]))
1499 return av;
1500
1501 av = oballoc (sizeof (struct attr_value));
1502 av->value = value;
1503 av->next = attr->first_value;
1504 attr->first_value = av;
1505 av->first_insn = NULL;
1506 av->num_insns = 0;
1507 av->has_asm_insn = 0;
1508
1509 return av;
1510 }
The value parameter of get_attr_value is condition template of the pattern, for easy reference, we copy this part of figure 138 and show it below. It is reformed by make_canonical which gives a valid expression for an attribute value, removes any rtx object of IF_THEN_ELSE by converting them into a COND ones. Besides, it replaces an attribute value of "*" with the default attribute value.
figure 40 : the exp under reforming
1376 static rtx
1377 make_canonical (struct attr_desc *attr, rtx exp) in genattrtab
1378 {
1379 int i;
1380 rtx newexp;
1381
1382 switch (GET_CODE (exp))
1383 {
1384 case CONST_INT:
1385 exp = make_numeric_value (INTVAL (exp));
1386 break ;
1387
1388 case CONST_STRING:
1389 if (! strcmp (XSTR (exp, 0), "*"))
1390 {
1391 if (attr == 0 || attr->default_val == 0)
1392 fatal ("(attr_value /"*/") used in invalid context");
1393 exp = attr->default_val->value;
1394 }
1395 else
1396 XSTR (exp, 0) = DEF_ATTR_STRING (XSTR (exp, 0));
1397
1398 break ;
1399
1400 case SYMBOL_REF:
1401 if (!attr->is_const || ATTR_IND_SIMPLIFIED_P (exp))
1402 break ;
1403 /* The SYMBOL_REF is constant for a given run, so mark it as unchanging.
1404 This makes the COND something that won't be considered an arbitrary
1405 expression by walk_attr_value. */
1406 ATTR_IND_SIMPLIFIED_P (exp) = 1;
1407 exp = check_attr_value (exp, attr);
1408 break ;
1409
1410 case IF_THEN_ELSE:
1411 newexp = rtx_alloc (COND);
1412 XVEC (newexp, 0) = rtvec_alloc (2);
1413 XVECEXP (newexp, 0, 0) = XEXP (exp, 0);
1414 XVECEXP (newexp, 0, 1) = XEXP (exp, 1);
1415
1416 XEXP (newexp, 1) = XEXP (exp, 2);
1417
1418 exp = newexp;
1419 /* Fall through to COND case since this is now a COND. */
1420
1421 case COND:
1422 {
1423 int allsame = 1;
1424 rtx defval;
1425
1426 /* First, check for degenerate COND. */
1427 if (XVECLEN (exp, 0) == 0)
1428 return make_canonical (attr, XEXP (exp, 1));
1429 defval = XEXP (exp, 1) = make_canonical (attr, XEXP (exp, 1));
1430
1431 for (i = 0; i < XVECLEN (exp, 0); i += 2)
1432 {
1433 XVECEXP (exp, 0, i) = copy_boolean (XVECEXP (exp, 0, i));
1434 XVECEXP (exp, 0, i + 1)
1435 = make_canonical (attr, XVECEXP (exp, 0, i + 1));
1436 if (! rtx_equal_p (XVECEXP (exp, 0, i + 1), defval))
1437 allsame = 0;
1438 }
1439 if (allsame)
1440 return defval;
1441 }
1442 break ;
1443
1444 default :
1445 break ;
1446 }
1447
1448 return exp;
1449 }
For our case, exp has code of IF_THEN_ELSE. It is converted to COND first. At line 1429, make_canonical is recursed into the new created COND object, by the field which is original third child of IF_THEN_ELSE object which is CONST_STRING (“false”). Then at line 1396, DEF_ATTR_STRING updates attr_hash_table with it.
At line 1433, copy_boolean updates string of rtx objects out of comparison of the condition in attr_hash_table which is permanent buffer. Notice that copy_boolean returns the rtx object with strings replaced with those kept in attr_hash_table.
1451 static rtx
1452 copy_boolean (rtx exp) in genattrtab
1453 {
1454 if (GET_CODE (exp) == AND || GET_CODE (exp) == IOR)
1455 return attr_rtx (GET_CODE (exp), copy_boolean (XEXP (exp, 0)),
1456 copy_boolean (XEXP (exp, 1)));
1457 if (GET_CODE (exp) == MATCH_OPERAND)
1458 {
1459 XSTR (exp, 1) = DEF_ATTR_STRING (XSTR (exp, 1));
1460 XSTR (exp, 2) = DEF_ATTR_STRING (XSTR (exp, 2));
1461 }
1462 else if (GET_CODE (exp) == EQ_ATTR)
1463 {
1464 XSTR (exp, 0) = DEF_ATTR_STRING (XSTR (exp, 0));
1465 XSTR (exp, 1) = DEF_ATTR_STRING (XSTR (exp, 1));
1466 }
1467
1468 return exp;
1469 }
In make_canonical at line 1436, XVECEXP (exp, 0, i + 1) contains “true”, and defval contains “false”, rtx_equal_p returns 0. exp will be returned.
Continue with get_attr_value , exp returned by make_canoncial is then checked by compares_alternatives_p whether define_attr contains the expression like eq_attr(“alternative”, “1”) which is not supported in these formats in define_attr pattern.
4321 static int
4322 compares_alternatives_p (rtx exp) in genattrtab
4323 {
4324 int i, j;
4325 const char *fmt;
4326
4327 if (GET_CODE (exp) == EQ_ATTR && XSTR (exp, 0) == alternative_name )
4328 return 1;
4329
4330 for (i = 0, fmt = GET_RTX_FORMAT (GET_CODE (exp));
4331 i < GET_RTX_LENGTH (GET_CODE (exp)); i++)
4332 switch (*fmt++)
4333 {
4334 case 'e':
4335 case 'u':
4336 if (compares_alternatives_p (XEXP (exp, i)))
4337 return 1;
4338 break ;
4339
4340 case 'E':
4341 for (j = 0; j < XVECLEN (exp, i); j++)
4342 if (compares_alternatives_p (XVECEXP (exp, i, j)))
4343 return 1;
4344 break ;
4345 }
4346
4347 return 0;
4348 }
The rtx object returned by get_attr_value is assigned to default_val field of attr_desc of the attribute. Remember that this attr_desc is saved in attrs .