GCC's bacl-end & assemble emission (17)

9.3.2. Read in DEFINE_INSN pattern

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 }

9.3.3. Read in DEFINE_ATTR pattern

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.

GCC's bacl-end & assemble emission (17)_第1张图片

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.

GCC's bacl-end & assemble emission (17)_第2张图片

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 .

你可能感兴趣的:(struct,String,object,gcc,constraints,attributes)