GCC's bacl-end & assemble emission (22 continue)

simplify_with_current_value_aux traverses the whole expression, and reduces the expression by eliminating unreachable parts.

 

4082 static rtx

4083 simplify_with_current_value_aux (rtx exp)                                                  in genattrtab.c

4084 {

4085   int i;

4086   rtx cond;

4087

4088   switch (GET_CODE (exp))

4089   {

4090     case EQ_ATTR:

4091       if (ATTR_EQ_ATTR_P (exp))

4092         return false_rtx ;

4093       else

4094         return true_rtx ;

4095     case CONST_STRING:

4096     case CONST_INT:

4097       return exp;

4098

4099     case IF_THEN_ELSE:

4100       cond = simplify_with_current_value_aux (XEXP (exp, 0));

4101       if (cond == true_rtx )

4102         return simplify_with_current_value_aux (XEXP (exp, 1));

4103       else if (cond == false_rtx )

4104         return simplify_with_current_value_aux (XEXP (exp, 2));

4105       else

4106         return attr_rtx (IF_THEN_ELSE, cond,

4107                     simplify_with_current_value_aux (XEXP (exp, 1)),

4108                     simplify_with_current_value_aux (XEXP (exp, 2)));

4109

4110     case IOR:

4111       cond = simplify_with_current_value_aux (XEXP (exp, 1));

4112       if (cond == true_rtx )

4113         return cond;

4114       else if (cond == false_rtx )

4115         return simplify_with_current_value_aux (XEXP (exp, 0));

4116       else

4117         return attr_rtx (IOR, cond,

4118                     simplify_with_current_value_aux (XEXP (exp, 0)));

4119

4120     case AND:

4121       cond = simplify_with_current_value_aux (XEXP (exp, 1));

4122       if (cond == true_rtx )

4123         return simplify_with_current_value_aux (XEXP (exp, 0));

4124       else if (cond == false_rtx )

4125         return cond;

4126       else

4127         return attr_rtx (AND, cond,

4128                     simplify_with_current_value_aux (XEXP (exp, 0)));

4129

4130     case NOT:

4131       cond = simplify_with_current_value_aux (XEXP (exp, 0));

4132       if (cond == true_rtx )

4133         return false_rtx ;

4134       else if (cond == false_rtx )

4135         return true_rtx ;

4136       else

4137         return attr_rtx (NOT, cond);

4138

4139     case COND:

4140       for (i = 0; i < XVECLEN (exp, 0); i += 2)

4141       {

4142         cond = simplify_with_current_value_aux (XVECEXP (exp, 0, i));

4143         if (cond == true_rtx )

4144           return simplify_with_current_value_aux (XVECEXP (exp, 0, i + 1));

4145         else if (cond == false_rtx )

4146           continue ;

4147         else

4148           abort (); /* With all EQ_ATTR's of known value, a case should

4149                    have been selected.  */

4150       }

4151       return simplify_with_current_value_aux (XEXP (exp, 1));

4152

4153     default :

4154       abort ();

4155   }

4156 }

 

From figure 51 , figure 52 , and figure 56 , expression referred by EXP(exp, 0) can first be reduced to node8 which equals to true_rtx , then we get issue_delay of op as final result.

 

4016 static int

4017 increment_current_value (struct dimension *space, int ndim)                  in genattrtab.c

4018 {

4019   int i;

4020

4021   for (i = ndim - 1; i >= 0; i--)

4022   {

4023     if ((space[i].current_value = XEXP (space[i].current_value, 1)) == 0)

4024       space[i].current_value = space[i].values;

4025     else

4026       return 1;

4027   }

4028   return 0;

4029 }

 

Still in simplify_by_exploding , increment_current_value tegother with test_for_current_value and simplify_with_current_value are enclosed in FOR loop at line 3810. increment_current_value updates current_value as the next part of the test. Notice that in space[1] the “OTH EPR” node is a single node of NOT(EQ_ATTR(“cpu, k6”). In the second run of simplify_with_current_value_aux , the nodes are updated as below.

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

figure 57 : example of define_function_unit handling, figure 5

See that NOT(EQ_ATTR(“cpu, k6”) can’t be accessed following link headed by XEXP(exp, 0) (via dotted pointers). In figure 57 node 8 is assumed as FALSE instead as TRUE. Here, we can see one of purpose of add_values_to_cover : with extra nodes appended, we can evaluate the expression with all possible set of values.

increment_current_value will return 0 when all space s arrives their end, to make the alogrithm correct, we need sort the space s with size in decreasing order. That is why we do sorting above at line 3790.

So in the third run of simplify_with_current_value_aux , the nodes to be visited are updated as following.

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

figure 58 : example of define_function_unit handling, figure 6

This time, XEXP(exp, 0) list can be reduced to true_rtx and issue_delay of op is returned. And so on, all possible situations can be encounted and recorded. After that we go back to simplify_exploding .

 

simpilfy_by_exploding (continued)

 

3820   /* We are now finished with the original expression.  */

3821   unmark_used_attributes (0, space, ndim);

3822   free (space);

3823

3824   /* Find the most used constant value and make that the default.  */

3825   most_tests = -1;

3826   for (i = num_marks = 0; i < total; i++)

3827     if (GET_CODE (condval[i]) == CONST_STRING

3828        && ! ATTR_EQ_ATTR_P (condval[i]))

3829     {

3830       /* Mark the unmarked constant value and count how many are marked.  */

3831       ATTR_EQ_ATTR_P (condval[i]) = 1;

3832       for (j = new_marks = 0; j < total; j++)

3833         if (GET_CODE (condval[j]) == CONST_STRING

3834            && ATTR_EQ_ATTR_P (condval[j]))

3835           new_marks++;

3836       if (new_marks - num_marks > most_tests)

3837       {

3838         most_tests = new_marks - num_marks;

3839         defval = condval[i];

3840       }

3841       num_marks = new_marks;

3842     }

3843   /* Clear all the marks.  */

3844   for (i = 0; i < total; i++)

3845     ATTR_EQ_ATTR_P (condval[i]) = 0;

3846

3847   /* Give up if nothing is constant.  */

3848   if (num_marks == 0)

3849     ret = exp;

3850

3851   /* If all values are the default, use that.  */

3852   else if (total == most_tests)

3853     ret = defval;

3854

3855   /* Make a COND with the most common constant value the default. (A more

3856     complex method where tests with the same value were combined didn't

3857     seem to improve things.)  */

3858   else

3859   {

3860     condexp = rtx_alloc (COND);

3861     XVEC (condexp, 0) = rtvec_alloc ((total - most_tests) * 2);

3862     XEXP (condexp, 1) = defval;

3863     for (i = j = 0; i < total; i++)

3864       if (condval[i] != defval)

3865       {

3866         XVECEXP (condexp, 0, 2 * j) = condtest[i];

3867         XVECEXP (condexp, 0, 2 * j + 1) = condval[i];

3868         j++;

3869       }

3870     ret = condexp;

3871   }

3872   free (condtest);

3873   free (condval);

3874   return ret;

3875 }

 

unmark_used_attributes resets the ATTR_EQ_ATTR_P flag in all EQ_ATTR expressions. At line 3866 and line 3867, condtest[i] records the all possible sets of values of attributes, and condval[i] records issue_delay corresponding to condtest[i] .

 

3932 static void

3933 unmark_used_attributes (rtx list, struct dimension *space, int ndim)       in genattrtab.c

3934 {

3935   rtx link, exp;

3936   int i;

3937

3938   for (i = 0; i < ndim; i++)

3939     unmark_used_attributes (space[i].values, 0, 0);

3940

3941   for (link = list; link; link = XEXP (link, 1))

3942   {

3943     exp = XEXP (link, 0);

3944     if (GET_CODE (exp) == EQ_ATTR)

3945       ATTR_EQ_ATTR_P (exp) = 0;

3946   }

3947 }

 

For the last part of simplify_by_exploding , we have seen that condval s share rtx objects created by find_and_mark_used_attributes from the rtx objects which are originally created from machine description file – that is every rtx object in condval s is unique. So it is possible to count how many time certain rtx object encountered during tranversing condval s. However currently only rtx object of CONST_STRING is considered, as it is a simple node. If default value can be found out, we can reform condexp into a more efficient form with most used values appear first.

 

expand_units (continued)

 

1864   /* Compute the mask of function units used. Initially, the unitsmask is

1865      zero. Set up a conditional to compute each unit's contribution.  */

1866   unitsmask = make_numeric_value (0);

1867   newexp = rtx_alloc (IF_THEN_ELSE);

1868   XEXP (newexp, 2) = make_numeric_value (0);

1869

1870   /* If we have just a few units, we may be all right expanding the whole

1871     thing. But the expansion is 2**N in space on the number of opclasses,

1872     so we can't do this for very long -- Alpha and MIPS in particular have

1873     problems with this. So in that situation, we fall back on an alternate

1874     implementation method.  */

1875 #define NUM_UNITOP_CUTOFF 20

1876

1877   if (num_unit_opclasses < NUM_UNITOP_CUTOFF)

1878   {

1879     /* Merge each function unit into the unit mask attributes.  */

1880     for (unit = units ; unit; unit = unit->next)

1881     {

1882        XEXP (newexp, 0) = unit->condexp;

1883        XEXP (newexp, 1) = make_numeric_value (1 << unit->num);

1884        unitsmask = operate_exp (OR_OP, unitsmask, newexp);

1885     }

1886   }

1887   else

1888   {

1889     /* Merge each function unit into the unit mask attributes.  */

1890     for (unit = units ; unit; unit = unit->next)

1891     {

1892        XEXP (newexp, 0) = unit->condexp;

1893        XEXP (newexp, 1) = make_numeric_value (1 << unit->num);

1894        unitsmask = operate_exp (ORX_OP, unitsmask, attr_copy_rtx (newexp));

1895     }

1896   }

1897

1898   /* Simplify the unit mask expression, encode it, and make an attribute

1899     for the function_units_used function.  */

1900   unitsmask = simplify_by_exploding (unitsmask);

1901

1902   if (num_unit_opclasses < NUM_UNITOP_CUTOFF)

1903     unitsmask = encode_units_mask (unitsmask);

1904   else

1905   {

1906     /* We can no longer encode unitsmask at compile time, so emit code to

1907       calculate it at runtime. Rather, put a marker for where we'd do

1908        the code, and actually output it in write_attr_get().  */

1909     unitsmask = attr_rtx (FFS, unitsmask);

1910   }

1911

1912   make_internal_attr ("*function_units_used", unitsmask,

1913                    (ATTR_NEGATIVE_OK | ATTR_FUNC_UNITS));

 

As we know that the num field of function_unit is unique and it is sequence number, here operate_exp tries to link all unit description into a expression. For example, we have 4 units in all (number from 0 to 3). In first iteration, we get following from operate_exp :

if (condexp of unit3)

  0x10

else

  0

With second iteration, we get:

if (condexp of unit3)

   if(condexp 0f unit2) 

0x18

      else

         0x10

else

  if (condexp of unit2)

     0x8

else

     0

With third iteration, we get:

if (condexp of unit3)

   if (condexp 0f unit2) 

      if (condexp of unit1)

0x1b

          else

            0x18

      else

         if (condexp of unit1)

            0x14

         else

             0x10

else

  if (condexp of unit2)

     if (condexp of unit1)

        0xb

     else

        0x8

else

   if (condexp of uint1)

      0x4

   else

        0

Obvioulsy, here the function gives out bit masks for all possible units association.

 

1618 static rtx

1619 operate_exp (enum operator op, rtx left, rtx right)                                 in genattrtab.c

1620 {

1621   int left_value, right_value;

1622   rtx newexp;

1623   int i;

1624

1625   /* If left is a string, apply operator to it and the right side.  */

1626   if (GET_CODE (left) == CONST_STRING)

1627   {

1628     /* If right is also a string, just perform the operation.  */

1629     if (GET_CODE (right) == CONST_STRING)

1630     {

1631       left_value = atoi (XSTR (left, 0));

1632       right_value = atoi (XSTR (right, 0));

1633       switch (op)

1634       {

1635         case PLUS_OP:

1636           i = left_value + right_value;

1637           break ;

1638

1639         case MINUS_OP:

1640           i = left_value - right_value;

1641           break ;

1642

1643          case POS_MINUS_OP:  /* The positive part of LEFT - RIGHT.  */

1644           if (left_value > right_value)

1645             i = left_value - right_value;

1646           else

1647             i = 0;

1648           break ;

1649

1650         case OR_OP:

1651         case ORX_OP:

1652           i = left_value | right_value;

1653           break ;

1654

1655         case EQ_OP:

1656           i = left_value == right_value;

1657           break ;

1658

1659         case RANGE_OP:

1660           i = (left_value << (HOST_BITS_PER_INT / 2)) | right_value;

1661           break ;

1662

1663         case MAX_OP:

1664           if (left_value > right_value)

1665             i = left_value;

1666           else

1667             i = right_value;

1668           break ;

1669

1670         case MIN_OP:

1671           if (left_value < right_value)

1672             i = left_value;

1673           else

1674             i = right_value;

1675           break ;

1676

1677         default :

1678           abort ();

1679           }

1680

1681           if (i == left_value)

1682         return left;

1683           if (i == right_value)

1684         return right;

1685           return make_numeric_value (i);

1686     }

1687     else if (GET_CODE (right) == IF_THEN_ELSE)

1688     {

1689       /* Apply recursively to all values within.  */

1690       rtx newleft = operate_exp (op, left, XEXP (right, 1));

1691       rtx newright = operate_exp (op, left, XEXP (right, 2));

1692       if (rtx_equal_p (newleft, newright))

1693         return newleft;

1694       return attr_rtx (IF_THEN_ELSE, XEXP (right, 0), newleft, newright);

1695     }

1696     else if (GET_CODE (right) == COND)

1697     {

1698       int allsame = 1;

1699       rtx defval;

1700

1701       newexp = rtx_alloc (COND);

1702       XVEC (newexp, 0) = rtvec_alloc (XVECLEN (right, 0));

1703       defval = XEXP (newexp, 1) = operate_exp (op, left, XEXP (right, 1));

1704

1705       for (i = 0; i < XVECLEN (right, 0); i += 2)

1706       {

1707         XVECEXP (newexp, 0, i) = XVECEXP (right, 0, i);

1708         XVECEXP (newexp, 0, i + 1)

1709               = operate_exp (op, left, XVECEXP (right, 0, i + 1));

1710         if (! rtx_equal_p (XVECEXP (newexp, 0, i + 1),

1711                        defval))

1712           allsame = 0;

1713       }

1714

1715       /* If the resulting cond is trivial (all alternatives

1716         give the same value), optimize it away.  */

1717       if (allsame)

1718         return operate_exp (op, left, XEXP (right, 1));

1719

1720       return newexp;

1721     }

1722     else

1723       fatal ("badly formed attribute value");

1724   }

1725

1726   /* A hack to prevent expand_units from completely blowing up: ORX_OP does

1727     not associate through IF_THEN_ELSE.  */

1728   else if (op == ORX_OP && GET_CODE (right) == IF_THEN_ELSE)

1729   {

1730     return attr_rtx (IOR, left, right);

1731   }

1732

1733   /* Otherwise, do recursion the other way.  */

1734   else if (GET_CODE (left) == IF_THEN_ELSE)

1735   {

1736     rtx newleft = operate_exp (op, XEXP (left, 1), right);

1737     rtx newright = operate_exp (op, XEXP (left, 2), right);

1738     if (rtx_equal_p (newleft, newright))

1739       return newleft;

1740     return attr_rtx (IF_THEN_ELSE, XEXP (left, 0), newleft, newright);

1741   }

1742   else if (GET_CODE (left) == COND)

1743   {

1744     int allsame = 1;

1745     rtx defval;

1746

1747     newexp = rtx_alloc (COND);

1748     XVEC (newexp, 0) = rtvec_alloc (XVECLEN (left, 0));

1749     defval = XEXP (newexp, 1) = operate_exp (op, XEXP (left, 1), right);

1750

1751     for (i = 0; i < XVECLEN (left, 0); i += 2)

1752     {

1753       XVECEXP (newexp, 0, i) = XVECEXP (left, 0, i);

1754        XVECEXP (newexp, 0, i + 1)

1755             = operate_exp (op, XVECEXP (left, 0, i + 1), right);

1756        if (! rtx_equal_p (XVECEXP (newexp, 0, i + 1),

1757                      defval))

1758          allsame = 0;

1759     }

1760

1761     /* If the cond is trivial (all alternatives give the same value),

1762       optimize it away.  */

1763     if (allsame)

1764       return operate_exp (op, XEXP (left, 1), right);

1765

1766     /* If the result is the same as the LEFT operand,

1767       just use that.  */

1768     if (rtx_equal_p (newexp, left))

1769       return left;

1770

1771     return newexp;

1772   }

1773

1774   else

1775     fatal ("badly formed attribute value");

1776   /* NOTREACHED */

1777   return NULL;

1778 }

 

Above, rtx_equal_p just returns true if two parameters are of same address. Then at line 1900 in expand_units , simplify_by_exploding tries to reform this unitsmask expression with most used value appears first. Then records these bit masks as attribute in encode_units_mask .

 

2195 static rtx

2196 encode_units_mask (rtx x)                                                                  in genattrtab.c

2197 {

2198   int i;

2199   int j;

2200   enum rtx_code code;

2201   const char *fmt;

2202

2203   code = GET_CODE (x);

2204

2205   switch (code)

2206   {

2207     case CONST_STRING:

2208       i = atoi (XSTR (x, 0));

2209       if (i < 0)

2210          /* The sign bit encodes a one's complement mask.  */

2211         abort ();

2212       else if (i != 0 && i == (i & -i))

2213         /* Only one bit is set, so yield that unit number.  */

2214         for (j = 0; (i >>= 1) != 0; j++)

2215            ;

2216       else

2217          j = ~i;

2218       return attr_rtx (CONST_STRING, attr_printf (MAX_DIGITS, "%d", j));

2219

2220     case REG:

2221     case QUEUED:

2222     case CONST_INT:

2223     case CONST_DOUBLE:

2224     case CONST_VECTOR:

2225      case SYMBOL_REF:

2226     case CODE_LABEL:

2227     case PC:

2228     case CC0:

2229     case EQ_ATTR:

2230     case EQ_ATTR_ALT:

2231       return x;

2232

2233     default :

2234       break ;

2235   }

2236

2237   /* Compare the elements. If any pair of corresponding elements

2238     fail to match, return 0 for the whole things.  */

2239

2240   fmt = GET_RTX_FORMAT (code);

2241   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)

2242   {

2243     switch (fmt[i])

2244     {

2245       case 'V':

2246        case 'E':

2247            for (j = 0; j < XVECLEN (x, i); j++)

2248            XVECEXP (x, i, j) = encode_units_mask (XVECEXP (x, i, j));

2249          break ;

2250

2251       case 'e':

2252          XEXP (x, i) = encode_units_mask (XEXP (x, i));

2253        break ;

2254     }

2255   }

2256   return x;

2257 }

 

Continue with expand_units , other data also will be filled into attributes.

 

expand_units (continued)

 

1915   /* Create an array of ops for each unit. Add an extra unit for the

1916     result_ready_cost function that has the ops of all other units.  */

1917   unit_ops = xmalloc ((num_units + 1) * sizeof (struct function_unit_op **));

1918   unit_num = xmalloc ((num_units + 1) * sizeof (struct function_unit *));

1919

1920   unit_num[num_units ] = unit = xmalloc (sizeof (struct function_unit));

1921   unit->num = num_units ;

1922   unit->num_opclasses = 0;

1923

1924   for (unit = units ; unit; unit = unit->next)

1925   {

1926     unit_num[num_units ]->num_opclasses += unit->num_opclasses;

1927     unit_num[unit->num] = unit;

1928     unit_ops[unit->num] = op_array =

1929        xmalloc (unit->num_opclasses * sizeof (struct function_unit_op *));

1930

1931     for (op = unit->ops; op; op = op->next)

1932       op_array[op->num] = op;

1933   }

1934

1935   /* Compose the array of ops for the extra unit.  */

1936   unit_ops[num_units ] = op_array =

1937       xmalloc (unit_num[num_units ]->num_opclasses

1938          * sizeof (struct function_unit_op *));

1939

1940   for (unit = units , i = 0; unit; i += unit->num_opclasses, unit = unit->next)

1941     memcpy (&op_array[i], unit_ops[unit->num],

1942              unit->num_opclasses * sizeof (struct function_unit_op *));

1943

1944   /* Compute the ready cost function for each unit by computing the

1945     condition for each non-default value.  */

1946   for (u = 0; u <= num_units ; u++)

1947   {

1948     rtx orexp;

1949     int value;

1950

1951     unit = unit_num[u];

1952     op_array = unit_ops[unit->num];

1953     num = unit->num_opclasses;

1954

1955     /* Sort the array of ops into increasing ready cost order.  */

1956     for (i = 0; i < num; i++)

1957       for (j = num - 1; j > i; j--)

1958          if (op_array[j - 1]->ready < op_array[j]->ready)

1959          {

1960            op = op_array[j];

1961            op_array[j] = op_array[j - 1];

1962            op_array[j - 1] = op;

1963          }

 

Above, till line 2007, data structure of following is created. Elements of new created array unit_num point to function_unit of units except the last one which is a fake ones containing all function_unit_op of all function_unit (see line 1940). unit_ops holds all function_unit_op for all function_unit. Notice that at line 1956 the array pointed by unit_ops is sorted by ready cost in decreasing order. We show the relationship among these data in below figure (see that unit_num and unit_ops are separate arrays, items at the same index point to same define_function_unit pattern but to different parts).

figure 59 : example of define_function_unit handling, figure 7

 

expand_units (continued)

 

1965     /* Determine how many distinct non-default ready cost values there

1966        are. We use a default ready cost value of 1.  */

1967     nvalues = 0; value = 1;

1968     for (i = num - 1; i >= 0; i--)

1969       if (op_array[i]->ready > value)

1970        {

1971          value = op_array[i]->ready;

1972          nvalues++;

1973        }

1974

1975     if (nvalues == 0)

1976        readycost = make_numeric_value (1);

1977     else

1978     {

1979        /* Construct the ready cost expression as a COND of each value from

1980          the largest to the smallest.  */

1981        readycost = rtx_alloc (COND);

1982        XVEC (readycost, 0) = rtvec_alloc (nvalues * 2);

1983        XEXP (readycost, 1) = make_numeric_value (1);

1984

1985        nvalues = 0;

1986        orexp = false_rtx ;

1987        value = op_array[0]->ready;

1988        for (i = 0; i < num; i++)

1989        {

1990          op = op_array[i];

1991          if (op->ready <= 1)

1992           break ;

1993          else if (op->ready == value)

1994           orexp = insert_right_side (IOR, orexp, op->condexp, -2, -2);

1995          else

1996         {

1997            XVECEXP (readycost, 0, nvalues * 2) = orexp;

1998            XVECEXP (readycost, 0, nvalues * 2 + 1)

1999                      = make_numeric_value (value);

2000           nvalues++;

2001            value = op->ready;

2002            orexp = op->condexp;

2003         }

2004        }

2005        XVECEXP (readycost, 0, nvalues * 2) = orexp;

2006        XVECEXP (readycost, 0, nvalues * 2 + 1) = make_numeric_value (value);

2007     }

 

After sorted by ready cost, for every array of function_unit_op including the last fake one, line 1967 – 2007 constructs readycost expression as below, here we assume certain function_unit has 4 function_unit_ops linked by ops field, which have ready field with value 5, 5, 2, 1. As we see from gen_unit , and the comment above, function_unit_op presenting the instruction using this function unit, and the instruction is identified by condexp field of function_unit_op. Now assumes the condexp points to condexp1, condexp2, condexp3, condexp4 correspondingly.

For this example, nvalues at line 1975 will be 2. Then readycost looks like following.

GCC's bacl-end & assemble emission (22 continue)_第3张图片

figure 60 : example of define_function_unit handling, figure 8

Assuming the condexp field of the function_unit is simplified expression of IOR (condexp1 (IOR (condexp2 (IOR (condexp3 condexp4))))) . The FOR block at line 2059, as explained by the comment above it, creates attribute to record READY-COST data for all instructions using the unit.

 

expand_units (continued)

 

2009     if (u < num_units )

2010     {

2011        rtx max_blockage = 0, min_blockage = 0;

2012

2013        /* Simplify the readycost expression by only considering insns

2014          that use the unit.  */

2015        readycost = simplify_knowing (readycost, unit->condexp);

2016

2017        /* Determine the blockage cost the executing insn (E) given

2018          the candidate insn (C). This is the maximum of the issue

2019          delay, the pipeline delay, and the simultaneity constraint.

2020          Each function_unit_op represents the characteristics of the

2021          candidate insn, so in the expressions below, C is a known

2022          term and E is an unknown term.

2023

2024          We compute the blockage cost for each E for every possible C.

2025          Thus OP represents E, and READYCOST is a list of values for

2026          every possible C.

2027

2028          The issue delay function for C is op->issue_exp and is used to

2029          write the `<name>_unit_conflict_cost' function. Symbolically

2030          this is "ISSUE-DELAY (E,C)".

2031

2032          The pipeline delay results form the FIFO constraint on the

2033          function unit and is "READY-COST (E) + 1 - READY-COST (C)".

2034

2035          The simultaneity constraint is based on how long it takes to

2036          fill the unit given the minimum issue delay. FILL-TIME is the

2037          constant "MIN (ISSUE-DELAY (*,*)) * (SIMULTANEITY - 1)", and

2038          the simultaneity constraint is "READY-COST (E) - FILL-TIME"

2039          if SIMULTANEITY is nonzero and zero otherwise.

2040

2041            Thus, BLOCKAGE (E,C) when SIMULTANEITY is zero is

2042

2043             MAX (ISSUE-DELAY (E,C),

2044               READY-COST (E) - (READY-COST (C) - 1))

2045

2046            and otherwise

2047

2048             MAX (ISSUE-DELAY (E,C),

2049               READY-COST (E) - (READY-COST (C) - 1),

2050               READY-COST (E) - FILL-TIME)

2051

2052            The `<name>_unit_blockage' function is computed by determining

2053            this value for each candidate insn. As these values are

2054           computed, we also compute the upper and lower bounds for

2055           BLOCKAGE (E,*). These are combined to form the function

2056           `<name>_unit_blockage_range'. Finally, the maximum blockage

2057           cost, MAX (BLOCKAGE (*,*)), is computed.  */

2058

2059         for (op = unit->ops; op; op = op->next)

2060        {

2061          rtx blockage = op->issue_exp;

2062          blockage = simplify_knowing (blockage, unit->condexp);

2063

2064          /* Add this op's contribution to MAX (BLOCKAGE (E,*)) and

2065            MIN (BLOCKAGE (E,*)).  */

2066          if (max_blockage == 0)

2067           max_blockage = min_blockage = blockage;

2068          else

2069         {

2070            max_blockage

2071                 = simplify_knowing (operate_exp (MAX_OP, max_blockage,

2072                                            blockage),

2073                                unit->condexp);

2074             min_blockage

2075                = simplify_knowing (operate_exp (MIN_OP, min_blockage,

2076                                            blockage),

2077                                unit->condexp);

2078         }

2079

2080          /* Make an attribute for use in the blockage function.  */

2081          str = attr_printf ((strlen (unit->name) + sizeof "*_block_"

2082                        + MAX_DIGITS),

2083                        "*%s_block_%d", unit->name, op->num);

2084          make_internal_attr (str, blockage, ATTR_SPECIAL);

2085        }

2086

2087        /* Record MAX (BLOCKAGE (*,*)).  */

2088        {

2089          int unknown;

2090          unit->max_blockage = max_attr_value (max_blockage, &unknown);

2091        }

2092

2093        /* See if the upper and lower bounds of BLOCKAGE (E,*) are the

2094          same. If so, the blockage function carries no additional

2095          information and is not written.  */

2096        newexp = operate_exp (EQ_OP, max_blockage, min_blockage);

2097        newexp = simplify_knowing (newexp, unit->condexp);

2098        unit->needs_blockage_function

2099             = (GET_CODE (newexp) != CONST_STRING

2100               || atoi (XSTR (newexp, 0)) != 1);

2101

2102        /* If the all values of BLOCKAGE (E,C) have the same value,

2103          neither blockage function is written.  */

2104        unit->needs_range_function

2105             = (unit->needs_blockage_function

2106               || GET_CODE (max_blockage) != CONST_STRING);

2107

2108        if (unit->needs_range_function)

2109        {

2110          /* Compute the blockage range function and make an attribute

2111            for writing its value.  */

2112          newexp = operate_exp (RANGE_OP, min_blockage, max_blockage);

2113          newexp = simplify_knowing (newexp, unit->condexp);

2114

2115          str = attr_printf ((strlen (unit->name)

2116                        + sizeof "*_unit_blockage_range"),

2117                        "*%s_unit_blockage_range", unit->name);

2118          make_internal_attr (str, newexp, (ATTR_STATIC|ATTR_BLOCKAGE|ATTR_UNSIGNED));

2119        }

2120

2121       str = attr_printf (strlen (unit->name) + sizeof "*_unit_ready_cost",

2122                     "*%s_unit_ready_cost", unit->name);

2123        make_internal_attr (str, readycost, ATTR_STATIC);

2124     }     // end if u < nim_units

2125     else

2126     {

2127        /* Make an attribute for the ready_cost function. Simplifying

2128          further with simplify_by_exploding doesn't win.  */

2129        str = "*result_ready_cost";

2130        make_internal_attr (str, readycost, ATTR_NONE);

2131     }

2132   }

 

At line 2061, op->issue_exp , as we see at line 1842 – 1847, it is logical the same as:

IF op->conflict_exp THEN

op->issue_delay

ELSE

op->issue_delay                                                            (1)

Or op->issue_delay                                                                (1’)

Then at line 2062, blockage first is built in logical as below in simplify_knowing .

IF (unit->condexp) THEN

  IF op->conflict_exp THEN

op->issue_delay

ELSE

0

ELSE

op->issue_delay                                                           (2)

Or

IF (unit->condexp) THEN

  op->issue_delay

ELSE

  op->issue_delay                                                            (2’)

Then the FOR block finds out the expression has max issue_delay or min issue_delay. And following code records the data into corresponding attributes. Notice that they are blockage, readycost, and blockage range (if possible).

 

expand_units (continued)

 

2134   /* For each unit that requires a conflict cost function, make an attribute

2135     that maps insns to the operation number.  */

2136   for (unit = units ; unit; unit = unit->next)

2137   {

2138     rtx caseexp;

2139

2140     if (! unit->needs_conflict_function

2141           && ! unit->needs_blockage_function)

2142       continue ;

2143

2144     caseexp = rtx_alloc (COND);

2145     XVEC (caseexp, 0) = rtvec_alloc ((unit->num_opclasses - 1) * 2);

2146

2147     for (op = unit->ops; op; op = op->next)

2148     {

2149        /* Make our adjustment to the COND being computed. If we are the

2150          last operation class, place our values into the default of the

2151          COND.  */

2152        if (op->num == unit->num_opclasses - 1)

2153        {

2154          XEXP (caseexp, 1) = make_numeric_value (op->num);

2155        }

2156        else

2157        {

2158          XVECEXP (caseexp, 0, op->num * 2) = op->condexp;

2159          XVECEXP (caseexp, 0, op->num * 2 + 1)

2160                   = make_numeric_value (op->num);

2161        }

2162     }

2163

2164     /* Simplifying caseexp with simplify_by_exploding doesn't win.  */

2165     str = attr_printf (strlen (unit->name) + sizeof "*_cases",

2166                    "*%s_cases", unit->name);

2167     make_internal_attr (str, caseexp, ATTR_SPECIAL);

2168   }

2169 }

 

num_opclasses field of unit records the number of ops in related function_unit (that is number the instructions sharing the unit). The left code of expand_units builds attributes that records switch-case alike expression – or call it instruction number mapping expression.

Now we have attributes recording structured data for define_function_unit patterns, these attributes will later be used to output helper functions for pipeline hazards recognizer.

你可能感兴趣的:(GCC's bacl-end & assemble emission (22 continue))