至于 define_insn 模式,我们使用在前一节中的如下例子:
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")])
我们已经知道,这个模式被分为这些部分:可选的名字, RTL 模板,条件,输出模板,及可选的属性向量。在经过 init_md_reader_args 的处理后,上面的模式将被以如下的 rtx 对象,载入内存。
图 38 : DEFINE_INSN 模式的例子
因为在这个模式中仅有一部分信息是对于自动机构建有用, gen_insn 只提取它感兴趣的数据。
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 }
上面在 4386 行,结构体 insn_def 具有如下定义。它是应该链表。在 4389 行, defs 是一个 insn_def 的静态实例,它是该链表的表头。
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 用于查找在操作数分配中约束的数目。它仅返回第一个找到的数字。在我们的例子中,第一个找到的约束字符串是“ r, ?mr ”。可用替代的数目是 2 ,因为约束是由‘,’分隔的。
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 }
至于 define_attr 模式的目的,从 gccinfo 我们获取了以下的段落。
define_attr 表达式用于定义每个模板机器所要求的属性。它看起来就像:
(define_attr NAME LIST-OF-VALUES DEFAULT)
NAME 是一个指定将被定义属性名的字符串。
LIST-OF-VALUES 或者是一个指定了一串由逗号分隔的,可被赋予该属性的值的字符串;或者是一个表示该属性接受数值的空字符串。
DEFAULT 是一个属性表达式,它给出了那些匹配不包含在该属性显式值里模式的指令的值。
对于每个已定义的属性,许多定义被写入 insn-attr.h 文件。至于对一个属性指定一组显式的值的情形,则定义了以下:
* 一个 #define 被写作符号 HAVE_ATTR_NAM ' 。
* 为 attr_NAME 定义了一个枚举的类, attr_NAME 具有 UPPER-NAME_UPPER-VALU 形式的成员,其中属性名及值第一次被转换为大写。
* 一个函数 get_attr_NAME 被定义,向它传入一个指令,并返回该指令的属性值。
例如,如果以下出现在 md 文件中:
(define_attr "type" "branch,fp,load,store,arith" ...)
以下的代码行将被写入 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 ();
如果该属性接受数值,将不会定义枚举类型,并且获取该属性值的函数将返回 int 。
至于 define_attr 模式,我们使用前一节中的以下的例子:
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")))
在经过 init_md_reader_args 的处理后,上面的模式将被作为以下的 rtx 对象载入内存。
图 39 : DEFINE_ATTR 模式的例子
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 }
属性的数据被保存入全局数组 attrs 。在这里 find_attr 的参数 name_p 指向字符串“ pent_prefix ”的地址。而 find_attr 的第二个参数是 1 ,它将使得该函数构建一个新的对象,如果找不到它的话。我们必须防止重复定义,通过检查 find_attr 返回的 attr 的 default_val 。
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 }
在 5808 行的结构体 attr_desc 有以下的定义,而 5818 行的 attrs 是一个 attr_desc 的数组,大小为 256 。它实际上是一个哈希表。不过,在 5817 行的哈希函数不是非常好,因为仅对应于‘ a-zA-Z0-9 ’的索引会被使用。
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 };
在这个定义里,某些属性可以有多个值,以及如果该模式没有被另外指定,而被应用的一个默认值。 attr_value 被设计来保存这些值。
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 };
继续 gen_attr ,在分配了 attr_desc 对象来保存新的属性之后, attr_value 的对象被构建来保存属性的值。然后在 4245 行, attr_rtx 被调用来填充这些 attr_value 对象。注意到第一个参数被写死为 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 }
前面我们看到 rtx 对象可以按类别分组,已经定义了以下的 rtx 组别。
Ø “ o ”用于代表一个对象(即 REG , MEM )的 rtx 编码
Ø “ < ”用于一个比较(即 EQ , NE , LT )的 rtx 编码
Ø “ 1 ”用于一元算术表达式(即 NEG , NOT )的 rtx 编码
Ø “ c ”用于可交换二元表达式(即 PLUS , MULT )的 rtx 编码
Ø “ 3 ”用于非位域三元操作( IF_THEN_ELSE )的 rtx 编码
Ø “ 2 ”用于非可交换二元表达式(即 MINUS , DIV )的 rtx 编码
Ø “ b ”用于一个位域操作( ZERO_EXTRACT , SIGN_EXTRACT )的 rtx 编码
Ø “ i ”用于一个机器指令( INSN , JUMP_INSN , CALL_INSN )的 rtx 编码
Ø “ m ”用于匹配指令(即 MATCH_DUP )的 rtx 编码
Ø “ g ”用于组合指令(即 GROUP_PARALLEL )的 rtx 编码
Ø “ a ”用于自增地址模式(即 POST_DEC )的 rtx 编码
Ø “ x ” 其余
Rtx 编码 CONST_STRING 的类别是‘ o ’,而其格式是 and the format is ‘ s ’(定义在 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 }
对于我们的情形,在 626 行的 ELSE IF 分支被执行(参考 图 39 )。回到 gen_attr ,在 4267 行 check_attr_value 被调用来处理这个模式的第三个孩子(默认值)。这个函数,给定一个表达式,确保它是有效的形式,并且所有具名的属性值对于这个给定的属性是有效的。如果不是,发布一个致命错误。如果没有指定一个属性,它假定一个数值的属性。
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 }
对于我们的例子, check_attr_value 只是检查这个 attr_desc 是否被正确地构建,它还尝试尽可能地简化条件代码。这个函数为这个值返回一个可能被修改过的替代的表达式。参考 图 39 中 rtx 对象的第三个孩子。
在 gen_attr 的最后, get_attr_value 被用于获取该属性的默认值。注意在这里第一个参数是 define_attr 模式的第三个孩子,而第三个参数是 -2 ,它意味着不要处理一个指令,并且该指令不应该包含属性“ 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 }
get_attr_value 的参数 value 是模式的条件模板部分,为了便于查看,我们拷贝了 图 39 的这一部分,并显示如下。它由 make_canonical 改造,它为一个属性值给出了一个有效的表达式,并通过转换成一个 COND 来移除 IF_THEN_ELSE 的 rtx 对象。另外,它把一个属性值“ * ”,替换为默认属性值。
图 40 : 改造下的 exp
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 }
对于我们的情形, exp 具有编码 IF_THEN_ELSE 。它首先被转换到 COND 。在 1429 行, make_canonical 递归入新构建的 COND 对象,进入初始的第三个孩子 IF_THEN_ELSE 对象,它是 CONST_STRING (“false”) 。那么在 1396 行, DEF_ATTR_STRING 更新 attr_hash_table 。
在 1433 行, copy_boolean ,通过与 attr_hash_table 中为永久缓存的条件的比较,更新 rtx 对象的字符串。注意 copy_boolean 返回的 rtx 对象中的字符串,为 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 }
在 make_canonical 的 1436 行, XVECEXP (exp, 0, i + 1) 包含“ true ”,而 defval 包含“ false ”, rtx_equal_p 返回 0 。 exp 将被返回。
继续 get_attr_value ,由 make_canoncial 返回的 exp 接着被 compares_alternatives_p 检查 define_attr 是否包含形如 eq_attr(“alternative”, “1”) 的表达式,它们在 define_attr 模式中的这些格式下不被支持。
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 }
由 get_attr_value 返回的 rtx 对象被赋予该属性 attr_desc 的 default_val 域。记住这个 attr_desc 被保存在 attrs 里。