虽然我们已经构建了属性相关的数据,为了流水线危险识别器的使用,它们需要被输出为接受指令rtx对象,并返回指令的属性值的函数。这些函数被输出到文件insn-attrtab.c中,并将作为gcc源代码的一部分,来产生执行映像。
main (continued)
6190 /* Now write outall the `gen_attr_...' routines. Do these before the
6191 special routines (specifically beforewrite_function_unit_info), so
6192 that they get defined before they areused. */
6193
6194 for (i = 0; i < MAX_ATTRS_INDEX; i++)
6195 for (attr =attrs[i];attr; attr = attr->next)
6196 {
6197 if (! attr->is_special && !attr->is_const)
6198 {
6199 int insn_alts_p;
6200
6201 insn_alts_p
6202 = (attr->name [0] == '*'
6203 && strcmp(&attr->name[1], INSN_ALTS_FUNC_NAME) == 0);
6204 if(insn_alts_p)
6205 printf ("\n#ifAUTOMATON_ALTS\n");
6206 write_attr_get (attr);
6207 if (insn_alts_p)
6208 printf ("#endif\n\n");
6209 }
6210 }
上面在6197行,is_special为需要特殊处理的属性所设置——它们将不产生普通的属性值提取器。下面是设置了is_special的属性的列表:
*delay_type(它是整个系统范围内的单件)
*delay_`delay-no`_`slot-no`(对于每个define_delay 模式,它对应每个槽(slot))
*annul_true_`delay-no`_`slot-no`(对于每个define_delay 模式,它对应每个槽(slot))
*annul_false_`delay-no`_`slot-no`(对于每个define_delay 模式,它对应每个槽(slot))
*`unit-name`_cost_`op-num`(发布指令在单元上的代价)
*`unit-name`_block_`op-num`(发布指令在单元上的延迟)
*`unit-name`_cases(单件,用于所有单元的case表达式,参见expand_units)
对于包含常量内容的属性,设置is_const。
在6203行,INSN_ATLS_FUNC_NAME被定义为“insn_alts”,其关联的属性在make_insn_alts_attr中构建,这个属性描述了define_insn_reservation中替代的数目。
write_attr_get对给定的指令写出提取属性值的函数。
5004 static void
5005 write_attr_get (structattr_desc *attr) in genattrtab.c
5006 {
5007 struct attr_value*av, *common_av;
5008
5009 /* Find the mostused attribute value. Handle that as the `default' of the
5010 switch we will generate. */
5011 common_av = find_most_used (attr);
5012
5013 /* Write out startof function, then all values with explicit `case' lines,
5014 then a `default', then the value with themost uses. */
5015 if (attr->static_p)
5016 printf ("static ");
5017 if (!attr->is_numeric)
5018 printf ("enum attr_%s\n",attr->name);
5019 else if (attr->unsigned_p)
5020 printf ("unsigned int\n");
5021 else
5022 printf ("int\n");
5023
5024 /* If the attributename starts with a star, the remainder is the name of
5025 the subroutine to use, instead of`get_attr_...'. */
5026 if (attr->name[0] == '*')
5027 printf ("%s (rtx insnATTRIBUTE_UNUSED)\n", &attr->name[1]);
5028 else if (attr->is_const == 0)
5029 printf ("get_attr_%s (rtx insnATTRIBUTE_UNUSED)\n", attr->name);
5030 else
5031 {
5032 printf ("get_attr_%s (void)\n",attr->name);
5033 printf ("{\n");
5034
5035 for (av =attr->first_value; av; av = av->next)
5036 if (av->num_insns != 0)
5037 write_attr_set (attr, 2, av->value,"return", ";",
5038 true_rtx,av->first_insn->insn_code,
5039 av->first_insn->insn_index);
5040
5041 printf ("}\n\n");
5042 return;
5043 }
5044
5045 printf ("{\n");
5046
5047 if (GET_CODE (common_av->value) == FFS)
5048 {
5049 rtx p = XEXP (common_av->value, 0);
5050
5051 /* No need toemit code to abort if the insn is unrecognized; the
5052 other get_attr_foo functions will do thatwhen we call them. */
5053
5054 write_toplevel_expr (p);
5055
5056 printf ("\n if (accum && accum == (accum &-accum))\n");
5057 printf (" {\n");
5058 printf (" int i;\n");
5059 printf (" for (i = 0; accum >>= 1; ++i)continue;\n");
5060 printf (" accum = i;\n");
5061 printf (" }\n else\n");
5062 printf (" accum = ~accum;\n");
5063 printf (" return accum;\n}\n\n");
5064 }
5065 else
5066 {
5067 printf (" switch (recog_memoized (insn))\n");
5068 printf (" {\n");
5069
5070 for (av =attr->first_value; av; av = av->next)
5071 if (av != common_av)
5072 write_attr_case (attr, av, 1, "return", ";", 4, true_rtx);
5073
5074 write_attr_case (attr, common_av, 0, "return", ";", 4, true_rtx);
5075 printf (" }\n}\n\n");
5076 }
5077 }
在5037行,注意write_attr_set为包含常量,并且其名字开头没有‘*’的属性所调用。不过在进入write_attr_get之前,这种类型的属性已经被滤掉了(参见main的6197行)。write_attr_set将不会在这里被调用。
在5047行的FFS代表“查找第一个设置比特”的操作。在这里,对于使用FFS最多的指令,我们不尝试识别它。在4版本,移走了对于FFS的特殊处理。不管怎样,对于其它指令,识别是必须的。看到在5067行输出的recog_memoized,这个函数是由genrecog(参见genrecog工具)输出的recog的一个封装。其返回值是输入指令对象的指令编码。
对于每个属性值,write_attr_case输出其计算过程。
5201 static void
5202 write_attr_case (struct attr_desc *attr, struct attr_value*av, in genattrtab.c
5203 int write_case_lines, const char *prefix, constchar *suffix,
5204 int indent, rtx known_true)
5205 {
5206 struct insn_ent*ie;
5207
5208 if (av->num_insns == 0)
5209 return;
5210
5211 if (av->has_asm_insn)
5212 {
5213 write_indent (indent);
5214 printf ("case -1:\n");
5215 write_indent (indent + 2);
5216 printf ("if (GET_CODE (PATTERN (insn))!= ASM_INPUT\n");
5217 write_indent (indent + 2);
5218 printf (" && asm_noperands (PATTERN (insn))< 0)\n");
5219 write_indent (indent + 2);
5220 printf (" fatal_insn_not_found (insn);\n");
5221 }
5222
5223 if (write_case_lines)
5224 {
5225 for (ie =av->first_insn; ie; ie = ie->next)
5226 if (ie->insn_code != -1)
5227 {
5228 write_indent (indent);
5229 printf ("case %d:\n",ie->insn_code);
5230 }
5231 }
5232 else
5233 {
5234 write_indent (indent);
5235 printf ("default:\n");
5236 }
5237
5238 /* See what we haveto do to output this value. */
5239 must_extract = must_constrain = address_used= 0;
5240 walk_attr_value (av->value);
5241
5242 if (must_constrain)
5243 {
5244 write_indent (indent + 2);
5245 printf ("extract_constrain_insn_cached(insn);\n");
5246 }
5247 else if (must_extract)
5248 {
5249 write_indent (indent + 2);
5250 printf ("extract_insn_cached(insn);\n");
5251 }
5252
5253 write_attr_set (attr, indent + 2, av->value, prefix, suffix,
5254 known_true,av->first_insn->insn_code,
5255 av->first_insn->insn_index);
5256
5257 if (strncmp (prefix, "return", 6))
5258 {
5259 write_indent (indent + 2);
5260 printf ("break;\n");
5261 }
5262 printf ("\n");
5263 }
上面在5211行,只要该属性具有在某些汇编语句中设置的值,就要设置域has_asm_insn(不管在其他多少地方,这个值被重新设置)。对于汇编语句,其指令编码为-1。
5112 static void
5113 write_attr_set (structattr_desc *attr, int indent, rtx value, ingenattrtab.c
5114 constchar *prefix, const char *suffix, rtxknown_true,
5115 intinsn_code, int insn_index)
5116 {
5117 if (GET_CODE (value) == COND)
5118 {
5119 /* Assume the default value will be thedefault of the COND unless we
5120 find an always true expression. */
5121 rtx default_val = XEXP (value, 1);
5122 rtx our_known_true = known_true;
5123 rtx newexp;
5124 int first_if = 1;
5125 int i;
5126
5127 for (i = 0; i < XVECLEN (value, 0); i += 2)
5128 {
5129 rtx testexp;
5130 rtx inner_true;
5131
5132 testexp = eliminate_known_true (our_known_true,
5133 XVECEXP(value, 0, i),
5134 insn_code,insn_index);
5135 newexp = attr_rtx(NOT, testexp);
5136 newexp = insert_right_side (AND, our_known_true, newexp,
5137 insn_code,insn_index);
5138
5139 /* If the testexpression is always true or if the next `known_true'
5140 expression is always false, this is thelast case, so break
5141 out and let this value be the `else'case. */
5142 if (testexp == true_rtx || newexp == false_rtx)
5143 {
5144 default_val = XVECEXP (value, 0, i +1);
5145 break;
5146 }
5147
5148 /* Compute theexpression to pass to our recursive call as being
5149 known true. */
5150 inner_true = insert_right_side (AND, our_known_true,
5151 testexp,insn_code, insn_index);
5152
5153 /* If this is always false, skip it. */
5154 if (inner_true == false_rtx)
5155 continue;
5156
5157 write_indent (indent);
5158 printf ("%sif ", first_if ?"" : "else ");
5159 first_if = 0;
5160 write_test_expr (testexp, 0);
5161 printf ("\n");
5162 write_indent (indent + 2);
5163 printf ("{\n");
5164
5165 write_attr_set (attr, indent + 4,
5166 XVECEXP (value, 0, i + 1),prefix, suffix,
5167 inner_true, insn_code,insn_index);
5168 write_indent (indent + 2);
5169 printf ("}\n");
5170 our_known_true = newexp;
5171 }
5172
5173 if (! first_if)
5174 {
5175 write_indent (indent);
5176 printf ("else\n");
5177 write_indent (indent + 2);
5178 printf ("{\n");
5179 }
5180
5181 write_attr_set (attr, first_if ? indent : indent + 4, default_val,
5182 prefix, suffix, our_known_true,insn_code, insn_index);
5183
5184 if (! first_if)
5185 {
5186 write_indent (indent + 2);
5187 printf ("}\n");
5188 }
5189 }
5190 else
5191 {
5192 write_indent (indent);
5193 printf ("%s ", prefix);
5194 write_attr_value (attr, value);
5195 printf ("%s\n", suffix);
5196 }
5197 }
虽然我们在上面章节中进行了简化,不过这个简化基本上是对应条件测试的。在simplify_cond中,在简化之后,我们将检查相邻的条件测试是否相同,如果相同就合并它们。考虑以下例子。
cond [ cond1
val1
cond2
val2
cond3
val1]
如果cond1能与cond3合并就再好不过了。不过这不是必然的。因此这里不尝试这样做。那么,考虑以下例子:
cond [ cond1
val1
cond2
val2
NOT (AND (cond1, cond2))
Val3 ]
第三个条件在其位置上总是true。我们应该移除这个条件,并把关联的值作为缺省值。
最后的例子,(eq_attr "att""v1")及(eq_attr"att" "v2"),在任一点上,都不可能同时为true,因而是互补的。如果这一项或其互补出现在树中,它可以为TRUE或FALSE所分别替代。
还有一个特殊的案例:如果我们看到
(and (not (eq_attr"att" "v1"))
(eq_attr "att" "v2"))
这可以为(eq_attr "att""v2")所替代。
注意5135,5136行的newexp,以及5150行的inner_true。在5136及5150行,记得insert_right_side将在simplify_test_exp_in_temp中调用来简化所构造的表达式。
同样注意在5160行,write_test_expr被用于输出测试语句,因为我们不需要考虑嵌套的COND的情形(这个测试必须是简单的判断。为了包容复杂的情形,它可以包括一个COND对象作为其值)。而在5165行,write_attr_set则用于输出关联的属性值。
5084 static rtx
5085 eliminate_known_true (rtx known_true,rtx exp, int insn_code, int insn_index) ingenattrtab.c
5086 {
5087 rtx term;
5088
5089 known_true = SIMPLIFY_TEST_EXP (known_true, insn_code, insn_index);
5090
5091 if (GET_CODE (known_true) == AND)
5092 {
5093 exp = eliminate_known_true (XEXP (known_true, 0), exp,
5094 insn_code,insn_index);
5095 exp = eliminate_known_true (XEXP (known_true, 1), exp,
5096 insn_code,insn_index);
5097 }
5098 else
5099 {
5100 term = known_true;
5101 exp = simplify_and_tree (exp, &term, insn_code, insn_index);
5102 }
5103
5104 return exp;
5105 }
注意由下面eliminate_known_true传给simplify_and_tree的pterm等于known_true,对象known_true被确信为,在当前条件下,其评估为true。如果pterm或其互补出现在这个树里,它可以分别为TRUE或FALSE所替代。
2889 static rtx
2890 simplify_and_tree (rtx exp, rtx *pterm,int insn_code, int insn_index) in genattrtab.c
2891 {
2892 rtx left, right;
2893 rtx newexp;
2894 rtx temp;
2895 int left_eliminates_term,right_eliminates_term;
2896
2897 if (GET_CODE (exp) == AND)
2898 {
2899 left = simplify_and_tree (XEXP (exp, 0), pterm, insn_code, insn_index);
2900 right = simplify_and_tree (XEXP (exp, 1), pterm, insn_code, insn_index);
2901 if (left != XEXP (exp, 0) || right != XEXP (exp,1))
2902 {
2903 newexp = attr_rtx(AND, left, right);
2904
2905 exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index);
2906 }
2907 }
2908
2909 else if (GET_CODE (exp) == IOR)
2910 {
2911 /* For the IORcase, we do the same as above, except that we can
2912 only eliminate `term' if both sides ofthe IOR would do so. */
2913 temp = *pterm;
2914 left = simplify_and_tree (XEXP (exp, 0), &temp, insn_code, insn_index);
2915 left_eliminates_term = (temp == true_rtx);
2916
2917 temp = *pterm;
2918 right = simplify_and_tree (XEXP (exp, 1), &temp, insn_code, insn_index);
2919 right_eliminates_term = (temp == true_rtx);
2920
2921 if (left_eliminates_term &&right_eliminates_term)
2922 *pterm = true_rtx;
2923
2924 if (left != XEXP (exp, 0) || right != XEXP (exp,1))
2925 {
2926 newexp = attr_rtx(IOR, left, right);
2927
2928 exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index);
2929 }
2930 }
2931
2932 /* Check forsimplifications. Do some extra checking here since this
2933 routine is called so many times. */
2934
2935 if (exp == *pterm)
2936 return true_rtx;
2937
2938 else if (GET_CODE (exp) == NOT && XEXP (exp,0) == *pterm)
2939 return false_rtx;
2940
2941 else if (GET_CODE (*pterm) == NOT &&exp == XEXP (*pterm, 0))
2942 return false_rtx;
2943
2944 else if (GET_CODE (exp) == EQ_ATTR_ALT&& GET_CODE (*pterm) == EQ_ATTR_ALT)
2945 {
2946 if (attr_alt_subset_p (*pterm, exp))
2947 return true_rtx;
2948
2949 if (attr_alt_subset_of_compl_p (*pterm,exp))
2950 return false_rtx;
2951
2952 if (attr_alt_subset_p (exp, *pterm))
2953 *pterm = true_rtx;
2954
2955 return exp;
2956 }
2957
2958 else if (GET_CODE (exp) == EQ_ATTR &&GET_CODE (*pterm) == EQ_ATTR)
2959 {
2960 if (XSTR (exp, 0) != XSTR (*pterm, 0))
2961 returnexp;
2962
2963 if (! strcmp_check (XSTR (exp, 1), XSTR(*pterm, 1)))
2964 return true_rtx;
2965 else
2966 return false_rtx;
2967 }
2968
2969 else if (GET_CODE (*pterm) == EQ_ATTR&& GET_CODE (exp) == NOT
2970 && GET_CODE (XEXP (exp, 0)) ==EQ_ATTR)
2971 {
2972 if (XSTR (*pterm, 0) != XSTR (XEXP (exp,0), 0))
2973 returnexp;
2974
2975 if (! strcmp_check (XSTR (*pterm, 1), XSTR(XEXP (exp, 0), 1)))
2976 return false_rtx;
2977 else
2978 return true_rtx;
2979 }
2980
2981 else if (GET_CODE (exp) == EQ_ATTR &&GET_CODE (*pterm) == NOT
2982 && GET_CODE (XEXP(*pterm, 0)) == EQ_ATTR)
2983 {
2984 if (XSTR (exp, 0) != XSTR (XEXP(*pterm, 0), 0))
2985 returnexp;
2986
2987 if (! strcmp_check (XSTR (exp, 1), XSTR (XEXP(*pterm, 0), 1)))
2988 return false_rtx;
2989 else
2990 *pterm = true_rtx;
2991 }
2992
2993 else if (GET_CODE (exp) == NOT &&GET_CODE (*pterm) == NOT)
2994 {
2995 if (attr_equal_p (XEXP (exp, 0), XEXP (*pterm, 0)))
2996 return true_rtx;
2997 }
2998
2999 else if (GET_CODE (exp) == NOT)
3000 {
3001 if (attr_equal_p (XEXP (exp, 0), *pterm))
3002 return false_rtx;
3003 }
3004
3005 else if (GET_CODE (*pterm) == NOT)
3006 {
3007 if (attr_equal_p (XEXP (*pterm, 0), exp))
3008 return false_rtx;
3009 }
3010
3011 else if (attr_equal_p (exp, *pterm))
3012 return true_rtx;
3013
3014 return exp;
3015 }
回到write_attr_set,在5160行,write_test_expr给定一段RTX,输出一个C表达式来测试其真假值。在这里,在write_attr_set中参数exp是textexp——消除已知真值后的测试。
4559 static void
4560 write_test_expr (rtx exp, int flags) in genattrtab.c
4561 {
4562 int comparison_operator = 0;
4563 RTX_CODE code;
4564 struct attr_desc*attr;
4565
4566 /* In order not toworry about operator precedence, surround our part of
4567 the expression with parentheses. */
4568
4569 printf ("(");
4570 code = GET_CODE (exp);
4571 switch (code)
4572 {
4573 /* Binaryoperators. */
4574 case EQ: case NE:
4575 case GE: case GT: case GEU: case GTU:
4576 case LE: case LT: case LEU: case LTU:
4577 comparison_operator = 1;
4578
4579 casePLUS: caseMINUS: caseMULT: caseDIV: caseMOD:
4580 caseAND: caseIOR: caseXOR:
4581 caseASHIFT: caseLSHIFTRT: case ASHIFTRT:
4582 write_test_expr (XEXP (exp, 0), flags | comparison_operator);
4583 switch(code)
4584 {
4585 caseEQ:
4586 printf (" == ");
4587 break;
4588 caseNE:
4589 printf (" != ");
4590 break;
4591 caseGE:
4592 printf (" >= ");
4593 break;
4594 caseGT:
4595 printf (" > ");
4596 break;
4597 caseGEU:
4598 printf (" >= (unsigned) ");
4599 break;
4600 caseGTU:
4601 printf (" > (unsigned) ");
4602 break;
4603 caseLE:
4604 printf (" <= ");
4605 break;
4606 caseLT:
4607 printf (" < ");
4608 break;
4609 caseLEU:
4610 printf (" <= (unsigned) ");
4611 break;
4612 caseLTU:
4613 printf (" < (unsigned) ");
4614 break;
4615 casePLUS:
4616 printf (" + ");
4617 break;
4618 caseMINUS:
4619 printf (" - ");
4620 break;
4621 caseMULT:
4622 printf (" * ");
4623 break;
4624 caseDIV:
4625 printf (" / ");
4626 break;
4627 caseMOD:
4628 printf (" %% ");
4629 break;
4630 caseAND:
4631 if (flags & 1)
4632 printf (" & ");
4633 else
4634 printf (" && ");
4635 break;
4636 caseIOR:
4637 if (flags & 1)
4638 printf (" | ");
4639 else
4640 printf (" || ");
4641 break;
4642 caseXOR:
4643 printf (" ^ ");
4644 break;
4645 caseASHIFT:
4646 printf (" << ");
4647 break;
4648 caseLSHIFTRT:
4649 caseASHIFTRT:
4650 printf (" >> ");
4651 break;
4652 default:
4653 abort();
4654 }
4655
4656 write_test_expr (XEXP (exp, 1), flags | comparison_operator);
4657 break;
4658
4659 case NOT:
4660 /* Special-case(not (eq_attrq "alternative" "x")) */
4661 if (! (flags & 1) && GET_CODE(XEXP (exp, 0)) == EQ_ATTR
4662 && XSTR (XEXP (exp, 0), 0) == alternative_name)
4663 {
4664 printf ("which_alternative != %s",XSTR (XEXP (exp, 0), 1));
4665 break;
4666 }
4667
4668 /* Otherwise,fall through to normal unary operator. */
4669
4670 /* Unaryoperators. */
4671 caseABS: caseNEG:
4672 switch(code)
4673 {
4674 caseNOT:
4675 if (flags & 1)
4676 printf ("~ ");
4677 else
4678 printf ("! ");
4679 break;
4680 caseABS:
4681 printf ("abs ");
4682 break;
4683 caseNEG:
4684 printf ("-");
4685 break;
4686 default:
4687 abort ();
4688 }
4689
4690 write_test_expr (XEXP (exp, 0), flags);
4691 break;
4692
4693 caseEQ_ATTR_ALT:
4694 {
4695 intset = XINT (exp, 0), bit = 0;
4696
4697 if(flags & 1)
4698 fatal ("EQ_ATTR_ALT not valid insidecomparison");
4699
4700 if(!set)
4701 fatal ("Empty EQ_ATTR_ALT should beoptimized out");
4702
4703 if(!(set & (set - 1)))
4704 {
4705 if (!(set & 0xffff))
4706 {
4707 bit += 16;
4708 set >>= 16;
4709 }
4710 if (!(set & 0xff))
4711 {
4712 bit += 8;
4713 set >>= 8;
4714 }
4715 if (!(set & 0xf))
4716 {
4717 bit += 4;
4718 set >>= 4;
4719 }
4720 if (!(set & 0x3))
4721 {
4722 bit += 2;
4723 set >>= 2;
4724 }
4725 if (!(set & 1))
4726 bit++;
4727
4728 printf ("which_alternative %s=%d",
4729 XINT (exp, 1) ? "!" : "=", bit);
4730 }
4731 else
4732 {
4733 printf ("%s((1 <<which_alternative) & 0x%x)",
4734 XINT (exp, 1) ? "!" : "", set);
4735 }
4736 }
4737 break;
4738
4739 /* Comparisontest of an attribute with a value. Most of these will
4740 have been removed by optimization. Handle"alternative"
4741 specially and give error if EQ_ATTRpresent inside a comparison. */
4742 caseEQ_ATTR:
4743 if (flags & 1)
4744 fatal ("EQ_ATTR not valid insidecomparison");
4745
4746 if (XSTR (exp, 0) == alternative_name)
4747 {
4748 printf ("which_alternative == %s",XSTR (exp, 1));
4749 break;
4750 }
4751
4752 attr = find_attr(&XSTR (exp, 0), 0);
4753 if (! attr)
4754 abort ();
4755
4756 /* Now is the time to expand the value of aconstant attribute. */
4757 if (attr->is_const)
4758 {
4759 write_test_expr (evaluate_eq_attr (exp, attr->default_val->value,
4760 -2, -2),
4761 flags);
4762 }
4763 else
4764 {
4765 if (flags & 2)
4766 printf ("attr_%s",attr->name);
4767 else
4768 printf ("get_attr_%s (insn)",attr->name);
4769 printf(" == ");
4770 write_attr_valueq (attr, XSTR (exp, 1));
4771 }
4772 break;
4773
4774 /* Comparison test of flags fordefine_delays. */
4775 case ATTR_FLAG:
4776 if (flags & 1)
4777 fatal ("ATTR_FLAG not valid insidecomparison");
4778 printf("(flags & ATTR_FLAG_%s) != 0", XSTR (exp, 0));
4779 break;
4780
4781 /* See if an operand matches a predicate. */
4782 caseMATCH_OPERAND:
4783 /* If only a mode is given, just ensure themode matches the operand.
4784 If neither a mode nor predicate isgiven, error. */
4785 if (XSTR (exp, 1) == NULL || *XSTR (exp,1) == '\0')
4786 {
4787 if (GET_MODE (exp) == VOIDmode)
4788 fatal ("null MATCH_OPERAND specifiedas test");
4789 else
4790 printf ("GET_MODE (operands[%d]) ==%smode",
4791 XINT (exp,0), GET_MODE_NAME (GET_MODE (exp)));
4792 }
4793 else
4794 printf ("%s (operands[%d],%smode)",
4795 XSTR (exp, 1), XINT (exp,0), GET_MODE_NAME (GET_MODE (exp)));
4796 break;
4797
4798 caseMATCH_INSN:
4799 printf ("%s (insn)", XSTR (exp,0));
4800 break;
4801
4802 /* Constantinteger. */
4803 caseCONST_INT:
4804 printf (HOST_WIDE_INT_PRINT_DEC, XWINT (exp,0));
4805 break;
4806
4807 /* A random Cexpression. */
4808 caseSYMBOL_REF:
4809 printf ("%s", XSTR (exp, 0));
4810 break;
4811
4812 /* The address ofthe branch target. */
4813 caseMATCH_DUP:
4814 printf ("I
4815 NSN_ADDRESSES_SET_P() ? INSN_ADDRESSES (INSN_UID (GET_CODE (operands[%d]) == LABEL_REF ? XEXP(operands[%d], 0) : operands[%d])) : 0",
4816 XINT (exp, 0), XINT (exp, 0), XINT (exp, 0));
4817 break;
4818
4819 case PC:
4820 /* The addressof the current insn. We implement this actually as the
4821 address of the current insn forbackward branches, but the last
4822 address of the next insn for forward branches,and both with
4823 adjustments that account for the worst-casepossible stretching of
4824 intervening alignments between this insn andits destination. */
4825 printf ("insn_current_reference_address(insn)");
4826 break;
4827
4828 caseCONST_STRING:
4829 printf ("%s", XSTR (exp, 0));
4830 break;
4831
4832 caseIF_THEN_ELSE:
4833 write_test_expr (XEXP (exp, 0), flags & 2);
4834 printf (" ? ");
4835 write_test_expr (XEXP (exp, 1), flags | 1);
4836 printf (" : ");
4837 write_test_expr (XEXP (exp, 2), flags | 1);
4838 break;
4839
4840 default:
4841 fatal ("bad RTX code `%s' inattribute calculation\n",
4842 GET_RTX_NAME (code));
4843 }
4844
4845 printf (")");
4846 }
我们可以看到在insn-attrtab.c中,由这个工具输出的gen_attr_*函数。通常,输出的函数将是如下的形式(绿色的内容不是输出的)。
get_attr_`attr-name`(rtx insn ATTRIBUTE_UNUSED)
{
switch(recog_memoized (insn))
{
case insn-code-n: //first attribute value expression
case insn-code-p:
… // other insn for the same attribute value
extract_constrain_insn_cached(insn); // usedaccording to attr characteristic.
extract_insn_cached(insn); // used according to attr characteristic.
if(`attr-test-1` ) // for attribute value of cond
{
returnattr-val-1;
}
else if (…) // for attribute value of cond
…
else // for attribute value of cond
…
break;
… // other insn
break;
case insn-code-s: // second attribute valueexpression
… // other insn for the same attribute value
extract_constrain_insn_cached(insn); // usedaccording to attr characteristic.
extract_insn_cached(insn); //used according to attr characteristic.
returnattr-val-q; // for simple attrinute value
break;
}
}