Poplar and PopLibs
StackSizeDefs.hpp
1// Copyright (c) 2020 Graphcore Ltd. All rights reserved.
2
3#ifndef poplar_StackSizeDefs_hpp
4#define poplar_StackSizeDefs_hpp
5
6#ifdef __IPU__
7
8// Definitions needed for stack usage computation, for Assembly and C++
9// codelets.
10
11// The format for ELF stack size info used in assembly code is the same as the
12// one used by clang when the `-fstack-size-section` options is used:
13// A section named `.stack_sizes.<NAME>` is added to the ELF file, containing a
14// 'reference' to the function or section (so, the function symbol label or
15// section name), followed by the stack size encoded in ULEB128 format.
16// Note that using a 'reference' to the function/section implies that an
17// additional relocation section will be automatically added by the assembler,
18// named `.rela.stack_sizes.<NAME>`; this is needed to resolve the
19// 'reference' at link time.
20// `<NAME>` will be the name of the function or the section, as specified below.
21//
22// On top of the above clang standard format, we add an extra 'custom'
23// convention for assembly codelets:
24//
25// The 'stack size' value stored as defined above, considered as a 32 bit
26// unsigned value, will have its most significant bit used as a flag:
27//
28// 31 30 29 28 ... 1 0
29// +--+--------------------- // ---------------+
30// |TU| Stack Size Proper (30 bits) |
31// +--+--------------------- // ---------------+
32//
33// TU (Total Usage) flag: When set, this specifies that the stack size
34// defined in the rest of the value is the total
35// stack usage for this function and all its callees
36// (no need to traverse this function callgraph
37// tree to compute it). When not set, the stack size
38// is just the 'own' stack size for this function.
39//
40// The convention for the flag above is chosen to be reasonably
41// compatible with the default clang format for the .stack_sizes sections
42// (as stack sizes will always fit in less than 20 bits).
43//
44//
45// We also add some extra custom information in the ELF, also for the stack
46// usage computation:
47//
48// 1. We use bit 30 (mask 0x40000000) of the section header flag word (sh_flags)
49// to indicate that the section contains worker code. This is needed only for
50// worker code that is not part of an explicit worker vertex, so is not
51// needed for `__runCodelet_XXXXX` functions, and functions called directly
52// by them.
53//
54// 2. In case function pointers are used, the programmer should add (using a
55// macro defined here) a special section named `.func_ptrs_def.FUNCTION_NAME`
56// that contains:
57// * A reference to the caller function
58// * One or more references to the function(s) called via pointers
59// Use of function pointers is to be discouraged because use of this macro
60// offers very poor maintainability (and it is non-standard).
61//
62// 3. C/C++ functions have their ('own') stack size information added by popc.
63// But we also add a 'last resort' way to override this and specify the
64// stack "total usage" for a C++ function, by adding a section named:
65// `.stack_sizes.override.FUNCTION_NAME`
66// using the C/C++ DEF_STACK_USAGE macro below. This section has the same
67// format as described above (with the 'TU' flag set) and will be used by
68// poplar to override the `.stack_sizes` section introduced by popc.
69// This can be used for recursive functions, or function pointer use (in
70// alternative to option 2. above)
71// This involves determining 'manually' the max stack usage for the specific
72// chain of functions and all their callees.
73// Use of recursive function is discouraged because use of this macro
74// offers very poor maintainability (and it is non-standard).
75
76// Mask for the 'TU' flag defined above.
77#define TOTAL_STACK_USAGE 0x80000000
78
79// Section header flag that indicates that a section contains code that will
80// be run in a worker context.
81// This is to be used in the `.section` directive (for assembly function):
82//
83// .section .text.MyFunctionName, FUNCTION_IS_WORKER
84//
85// Note that this is not needed for explicit worker vertices entry
86// points (so, __runCodelet_XXXXX) and functions called directly by them.
87// It is required only for worker code that is run from supervisor vertices
88// but is not part of a worker vertex.
89#define FUNCTION_IS_WORKER "0x40000000"
90
91#if __ASSEMBLER__
92
93// clang-format off
94
95 // The two macros below take a parameter named `FUNC_OR_SECTION` which can be
96 // a label (the entry point of the assembly function), or the name of the
97 // section containing the code for the function.
98 // Each assembly function is required in general to be placed in a separate
99 // section with a unique name (to allow unused code elimination) so in this
100 // case there will not be ambiguity.
101 // In case a section contains multiple assembly functions, the macros can
102 // still be used, specifying the section name as the `FUNC_OR_SECTION`
103 // parameter and making sure that the value specified for the stack size is
104 // valid for the totality of the functions contained in the section.
105
106 // Note that these two assembly macros define a section themselves, so for
107 // clarity, it is better to place them OUTSIDE any other section definitions.
108
109 // See the assembly codelets in runtime/codelets for examples of use.
110
111
112 // ====================================================================
113 // Used to specify the stack size used by a function.
114 //
115 // SIZE : size in bytes of the stack used by `FUNC_OR_SECTION`
116 // *only*, so not including the stack used by any other
117 // function called by `FUNC_OR_SECTION` itself.
118 // Must be an absolute expression.
119 //
120 // FUNC_OR_SECTION : name of the function (so, its label) or section name
121 // ======================================================================
122 .macro DEF_STACK_SIZE_OWN SIZE:req FUNC_OR_SECTION:req
123 .section .stack_sizes.\FUNC_OR_SECTION, "", @progbits
124 .dc.l \FUNC_OR_SECTION
125 .uleb128 \SIZE
126 .previous
127 .endm
128
129 // ====================================================================
130 // Used to specify the *TOTAL* stack usage of a function.
131 // This includes any function that might be called by `FUNC_OR_SECTION`.
132 // See comment above for the third parameter.
133 // Used to specify the stack size used by a function.
134 //
135 // SIZE : size in bytes of the *total* stack usage of
136 // `FUNC_OR_SECTION`, which includes any function that
137 // might be called by `FUNC_OR_SECTION`.
138 // Must be an absolute expression.
139 //
140 // FUNC_OR_SECTION : name of the function (so, its label) or section name
141 // ======================================================================
142 .macro DEF_STACK_USAGE SIZE:req FUNC_OR_SECTION:req
143 .section .stack_sizes.\FUNC_OR_SECTION, "", @progbits
144 .dc.l \FUNC_OR_SECTION
145 .uleb128 \SIZE+TOTAL_STACK_USAGE
146 .previous
147 .endm
148
149 // ====================================================================
150 // Macro to declare that a function might call other functions via
151 // function pointers.
152 //
153 // CALLER_FUNC : the name (label) of the function that calls other
154 // functions via function pointers, so uses `br $mX`
155 // to call some further code (not just returning from
156 // a call).
157 //
158 // CALLED_FUNCS : a comma separated list of function names (labels)
159 // specifying which functions are called via function
160 // pointers by CALLER_FUNC.
161 // ====================================================================
162 .macro DEF_FUNC_CALL_PTRS CALLER_FUNC:req CALLED_FUNCS:vararg
163 .section .func_ptrs_def.\CALLER_FUNC, "", @progbits
164 .dc.l \CALLER_FUNC
165 .dc.l \CALLED_FUNCS
166 .previous
167 .endm
168
169// clang-format on
170#else
171
172// Used by the DEF_STACK_USAGE macro below, for stringification of the `size`
173// parameter.
174#define DEF_STACK_USAGE_HELPER(size, funcname) \
175 __asm__(".section .stack_sizes.override." #funcname ",\"\",@progbits\n" \
176 ".dc.l " #funcname "\n" \
177 ".uleb128 " #size "\n")
178
195#define DEF_STACK_USAGE(size, funcname) \
196 DEF_STACK_USAGE_HELPER((size) + 0x80000000, funcname)
197
211#define DEF_FUNC_CALL_PTRS(caller_func, called_func_list) \
212 __asm__(".section .func_ptrs_def." caller_func ",\"\",@progbits\n" \
213 ".dc.l " caller_func "\n" \
214 ".dc.l " called_func_list "\n")
215
229#define DEF_FUNCTION_AS_WORKER(funcname) \
230 __asm__(".section .text." funcname ", \"" FUNCTION_IS_WORKER "\"")
231
232#endif // #if __ASSEMBLER__
233#endif // #ifdef __IPU__
234#endif // poplar_StackSizeDefs_hpp