]>
Commit | Line | Data |
---|---|---|
c63539ff ML |
1 | .. |
2 | Copyright 1988-2022 Free Software Foundation, Inc. | |
3 | This is part of the GCC manual. | |
4 | For copying conditions, see the copyright.rst file. | |
5 | ||
6 | Guidelines for using poly_int | |
7 | ***************************** | |
8 | ||
9 | One of the main design goals of ``poly_int`` was to make it easy | |
10 | to write target-independent code that handles variable-sized registers | |
11 | even when the current target has fixed-sized registers. There are two | |
12 | aspects to this: | |
13 | ||
14 | * The set of ``poly_int`` operations should be complete enough that | |
15 | the question in most cases becomes 'Can we do this operation on these | |
16 | particular ``poly_int`` values? If not, bail out' rather than | |
17 | 'Are these ``poly_int`` values constant? If so, do the operation, | |
18 | otherwise bail out'. | |
19 | ||
20 | * If target-independent code compiles and runs correctly on a target | |
21 | with one value of ``NUM_POLY_INT_COEFFS``, and if the code does not | |
22 | use asserting functions like ``to_constant``, it is reasonable to | |
23 | assume that the code also works on targets with other values of | |
24 | ``NUM_POLY_INT_COEFFS``. There is no need to check this during | |
25 | everyday development. | |
26 | ||
27 | So the general principle is: if target-independent code is dealing | |
28 | with a ``poly_int`` value, it is better to operate on it as a | |
29 | ``poly_int`` if at all possible, choosing conservatively-correct | |
30 | behavior if a particular operation fails. For example, the following | |
31 | code handles an index ``pos`` into a sequence of vectors that each | |
32 | have ``nunits`` elements: | |
33 | ||
34 | .. code-block:: c++ | |
35 | ||
36 | /* Calculate which vector contains the result, and which lane of | |
37 | that vector we need. */ | |
38 | if (!can_div_trunc_p (pos, nunits, &vec_entry, &vec_index)) | |
39 | { | |
40 | if (dump_enabled_p ()) | |
41 | dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, | |
42 | "Cannot determine which vector holds the" | |
43 | " final result.\n"); | |
44 | return false; | |
45 | } | |
46 | ||
47 | However, there are some contexts in which operating on a | |
48 | ``poly_int`` is not possible or does not make sense. One example | |
49 | is when handling static initializers, since no current target supports | |
50 | the concept of a variable-length static initializer. In these | |
51 | situations, a reasonable fallback is: | |
52 | ||
53 | .. code-block:: c++ | |
54 | ||
55 | if (poly_value.is_constant (&const_value)) | |
56 | { | |
57 | ... | |
58 | /* Operate on const_value. */ | |
59 | ... | |
60 | } | |
61 | else | |
62 | { | |
63 | ... | |
64 | /* Conservatively correct fallback. */ | |
65 | ... | |
66 | } | |
67 | ||
68 | ``poly_int`` also provides some asserting functions like | |
69 | ``to_constant``. Please only use these functions if there is a | |
70 | good theoretical reason to believe that the assertion cannot fire. | |
71 | For example, if some work is divided into an analysis phase and an | |
72 | implementation phase, the analysis phase might reject inputs that are | |
73 | not ``is_constant``, in which case the implementation phase can | |
74 | reasonably use ``to_constant`` on the remaining inputs. The assertions | |
75 | should not be used to discover whether a condition ever occurs 'in the | |
76 | field'; in other words, they should not be used to restrict code to | |
77 | constants at first, with the intention of only implementing a | |
78 | ``poly_int`` version if a user hits the assertion. | |
79 | ||
80 | If a particular asserting function like ``to_constant`` is needed | |
81 | more than once for the same reason, it is probably worth adding a | |
82 | helper function or macro for that situation, so that the justification | |
83 | only needs to be given once. For example: | |
84 | ||
85 | .. code-block:: c++ | |
86 | ||
87 | /* Return the size of an element in a vector of size SIZE, given that | |
88 | the vector has NELTS elements. The return value is in the same units | |
89 | as SIZE (either bits or bytes). | |
90 | ||
91 | to_constant () is safe in this situation because vector elements are | |
92 | always constant-sized scalars. */ | |
93 | #define vector_element_size(SIZE, NELTS) \ | |
94 | (exact_div (SIZE, NELTS).to_constant ()) | |
95 | ||
96 | Target-specific code in :samp:`config/{cpu}` only needs to handle | |
97 | non-constant ``poly_int`` s if ``NUM_POLY_INT_COEFFS`` is greater | |
98 | than one. For other targets, ``poly_int`` degenerates to a compile-time | |
99 | constant and is often interchangable with a normal scalar integer. | |
100 | There are two main exceptions: | |
101 | ||
102 | * Sometimes an explicit cast to an integer type might be needed, such as to | |
103 | resolve ambiguities in a ``?:`` expression, or when passing values | |
104 | through ``...`` to things like print functions. | |
105 | ||
106 | * Target macros are included in target-independent code and so do not | |
107 | have access to the implicit conversion to a scalar integer. | |
108 | If this becomes a problem for a particular target macro, the | |
109 | possible solutions, in order of preference, are: | |
110 | ||
111 | * Convert the target macro to a target hook (for all targets). | |
112 | ||
113 | * Put the target's implementation of the target macro in its | |
114 | :samp:`{cpu}.c` file and call it from the target macro in the | |
115 | :samp:`{cpu}.h` file. | |
116 | ||
117 | * Add ``to_constant ()`` calls where necessary. The previous option | |
118 | is preferable because it will help with any future conversion of the | |
3ed1b4ce | 119 | macro to a hook. |