]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/doc/gccint/sizes-and-offsets-as-runtime-invariants/guidelines-for-using-polyint.rst
sphinx: add missing trailing newline
[thirdparty/gcc.git] / gcc / doc / gccint / sizes-and-offsets-as-runtime-invariants / guidelines-for-using-polyint.rst
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
119 macro to a hook.