GCC后端及汇编发布(22 续)

simplify_with_current_value_aux 遍历整个表达式,通过消除不可到达部分来约简这个表达式。

 

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 }

 

51 52 56 ,由 EXP(exp, 0) 指向的表达式,可以首先被约简到节点 8 。它等于 true_rtx ,然后我们得到 op issue_delay 作为最终的结果。

 

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 }

 

还是在 simplify_by_exploding 里, increment_current_value 连同 test_for_current_value 以及 simplify_with_current_value 都包含在 3810 行的 FOR 循环中。 increment_current_value current_value 更新为下一部分测试。注意到,对于 space[1] ,“ OTH EPR ”节点实际上是一个为“ NOT(EQ_ATTR(“cpu, k6”) ”的节点。在 simplify_with_current_value_aux 的第二次运行中,链表节点更新为如下:

t57

57 define_function_unit 处理的案例,图 5

注意 NOT(EQ_ATTR(“cpu, k6”) 不在由 XEXP(exp, 0) 开始的链表上(虚线指针的链表)。在 57 中,假定节点 8 FALSE ,而不是 TRUE 。此处,我们可以看到 add_values_to_cover 的一个目的:通过添加的额外的节点,我们可以所有可能的值来评估这个表达式。

当所有的 space 都到达末尾时, increment_current_value 将返回 0 。为了使算法正确,我们需要按 space 大小降序的次序排序。这就是为什么我们在上面 3790 行进行排序。

那么在 simplify_with_current_value_aux 的第三次运行中,将被访问的节点更新为如下图所示。

t58

58 define_function_unit 处理的案例,图 6

这一次, XEXP(exp, 0) 链表可以被化简为 true_rtx ,并返回 op issue_delay 。依此类推,所有可能的情形都可以被遇见,并加以记录。接着我们回到 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 重置了所有表达式 EQ_ATTR 中的 ATTR_EQ_ATTR_P 标记。在 3866 3867 行, condtest[i] 记录了属性所有可能的值的集合,而 condval[i] 则记录了对应于 condtest[i] issue_delay

 

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 }

 

至于 simplify_by_exploding 的余下部分 我们已经看到所有的 condval 共享由 find_and_mark_used_attributes 从起初由机器描述文件生成的 rtx 对象构建出来的 rtx 对象——即在 condval 中的每个 rtx 对象都是唯一的。因此有可能在遍历 condval 时, 计算某个 rtx 对象出现的次数。不过当前仅考虑 CONST_STRING rtx 对象,因为这是一个简单的节点。 如果能找出默认值,我们可以把 condexp 转换为更高效的形式,把最常用的值放在最前面。

 

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));

 

正如我们知道 function_unit num 域是独一无二的,并且是序列号,在这里 operate_exp 尝试把所有的单元描述链接入一个表达式。例如,我们总共有 4 个单元(号码从 0 3 )。在第一次循环中,我们从 operate_exp 获得如下的结果:

if (condexp of unit3)

  0x10

else

  0

在第二次循环中,我们得到:

if (condexp of unit3)

   if(condexp 0f unit2) 

0x18

      else

         0x10

else

  if (condexp of unit2)

     0x8

else

     0

在第三次循环中,我们得到:

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

显然,在这里这个函数给出了所有可能的单元组合的掩码。

 

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 }

 

在上面,如果两个参数的地址相同, rtx_equal_p 只是返回 true 。然后在 expand_units 1900 行, simplify_by_exploding 尝试以最常用的值放在最前面来转换这个 unitsmask 表达式。接着在 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 }

 

继续 expand_units ,其它数据也将被填入属性。

 

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          }

 

上面直到 2007 构建了如下的数据结构。新构建的数组 unit_num 的元素指向 units function_unit 除了最后的那个。它是一个包含了所有 function_unit 的全部 function_unit_op 的伪对象 参见 1940 unit_ops 为所有 function_unit 保存全部的 function_unit_op 。注意在 1956 行,被 unit_ops 指向的数组以就绪代价降序排序。我们在下图显示了这些数据间的关系(看到 unit_num unit_ops 是独立的数组,相同索引的项指向同一个 define_function_unit 模式,不过是不同的部分)。

t59

59 define_function_unit 处理的案例,图 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     }

 

在以就绪代价排序后,对于每个 function_unit_op 数组,包括最后的那个伪对象, 1967 ~ 2007 行如下构建 readycost 表达式,在这里我们假定某个具有 4 ready 域分别为 5 5 2 1 function_unit_op function_unit 链接在 ops 域。正如我们从 gen_unit 及上面的注释中看到的, function_unit_op 代表使用这个功能单元的指令,而这个指令被 function_unit_op condexp 域所识别。现在假定这个 condexp 指向 condexp1 condexp2 condexp3 condexp4

对于这个例子,在 1975 行的 nvalues 将是 2. 那么 readycost 看起来就像如下。

t60

60 define_function_unit 处理的案例,图 8

假定这个 function_unit condexp 域是简化后的表达式 IOR (condexp1 (IOR (condexp2 (IOR (condexp3 condexp4))))) 。在 2059 行的 FOR 循环,正如在它前面的注释所解释的,构建了属性,来为所有使用这个单元的指令,记录 READY-COST 数据。

 

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   }

 

2061 行的 op->issue_exp ,正如我们在 1842 ~ 1847 所见,逻辑上它等同于:

IF op->conflict_exp THEN

op->issue_delay

ELSE

op->issue_delay                                                            (1)

或者 op->issue_delay                                                                    (1’)

那么在 2062 行,首先在逻辑上在 simplify_knowing 构建如下的 blockage

IF (unit->condexp) THEN

  IF op->conflict_exp THEN

op->issue_delay

ELSE

0

ELSE

op->issue_delay                                                           (2)

或者

IF (unit->condexp) THEN

  op->issue_delay

ELSE

  op->issue_delay                                                            (2’)

然后 FOR 循环找出具有最大 issue_delay 或者最小 issue_delay 的表达式。而以下的代码则把数据记录入相应的属性。 注意它们是 blockage readycost blockage range 如果可能的话

 

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 }

 

Unit num_opclasses 域记录了在相关 function_unit ops 的数目(即共享这个单元的指令数目)。 expand_units 的余下代码则构建属性来记录类似于 switch-case 的表达式——或称之为指令号码映射表达式。

现在我们有了用于 define_function_unit 模式,记录结构化数据的属性,这些属性 在后面将被用来输出流水线危险识别器的辅助函数。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值