GCC后端及汇编发布(17)

9.3.2. 读入 DEFINE_INSN 模式

至于 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 }

9.3.3. 读入 DEFINE_ATTR 模式

至于 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 对象载入内存。

GCC后端及汇编发布(17)_第1张图片

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 对象。另外,它把一个属性值“ * ”,替换为默认属性值。

GCC后端及汇编发布(17)_第2张图片

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 里。

你可能感兴趣的:(GCC后端及汇编发布(17))