xref: /aosp_15_r20/external/libopus/celt/stack_alloc.h (revision a58d3d2adb790c104798cd88c8a3aff4fa8b82cc)
1*a58d3d2aSXin Li /* Copyright (C) 2002-2003 Jean-Marc Valin
2*a58d3d2aSXin Li    Copyright (C) 2007-2009 Xiph.Org Foundation */
3*a58d3d2aSXin Li /**
4*a58d3d2aSXin Li    @file stack_alloc.h
5*a58d3d2aSXin Li    @brief Temporary memory allocation on stack
6*a58d3d2aSXin Li */
7*a58d3d2aSXin Li /*
8*a58d3d2aSXin Li    Redistribution and use in source and binary forms, with or without
9*a58d3d2aSXin Li    modification, are permitted provided that the following conditions
10*a58d3d2aSXin Li    are met:
11*a58d3d2aSXin Li 
12*a58d3d2aSXin Li    - Redistributions of source code must retain the above copyright
13*a58d3d2aSXin Li    notice, this list of conditions and the following disclaimer.
14*a58d3d2aSXin Li 
15*a58d3d2aSXin Li    - Redistributions in binary form must reproduce the above copyright
16*a58d3d2aSXin Li    notice, this list of conditions and the following disclaimer in the
17*a58d3d2aSXin Li    documentation and/or other materials provided with the distribution.
18*a58d3d2aSXin Li 
19*a58d3d2aSXin Li    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20*a58d3d2aSXin Li    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21*a58d3d2aSXin Li    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22*a58d3d2aSXin Li    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
23*a58d3d2aSXin Li    OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24*a58d3d2aSXin Li    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25*a58d3d2aSXin Li    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26*a58d3d2aSXin Li    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27*a58d3d2aSXin Li    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28*a58d3d2aSXin Li    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29*a58d3d2aSXin Li    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30*a58d3d2aSXin Li */
31*a58d3d2aSXin Li 
32*a58d3d2aSXin Li #ifndef STACK_ALLOC_H
33*a58d3d2aSXin Li #define STACK_ALLOC_H
34*a58d3d2aSXin Li 
35*a58d3d2aSXin Li #include "opus_types.h"
36*a58d3d2aSXin Li #include "opus_defines.h"
37*a58d3d2aSXin Li 
38*a58d3d2aSXin Li #if (!defined (VAR_ARRAYS) && !defined (USE_ALLOCA) && !defined (NONTHREADSAFE_PSEUDOSTACK))
39*a58d3d2aSXin Li #error "Opus requires one of VAR_ARRAYS, USE_ALLOCA, or NONTHREADSAFE_PSEUDOSTACK be defined to select the temporary allocation mode."
40*a58d3d2aSXin Li #endif
41*a58d3d2aSXin Li 
42*a58d3d2aSXin Li #ifdef USE_ALLOCA
43*a58d3d2aSXin Li # ifdef _WIN32
44*a58d3d2aSXin Li #  include <malloc.h>
45*a58d3d2aSXin Li # else
46*a58d3d2aSXin Li #  ifdef HAVE_ALLOCA_H
47*a58d3d2aSXin Li #   include <alloca.h>
48*a58d3d2aSXin Li #  else
49*a58d3d2aSXin Li #   include <stdlib.h>
50*a58d3d2aSXin Li #  endif
51*a58d3d2aSXin Li # endif
52*a58d3d2aSXin Li #endif
53*a58d3d2aSXin Li 
54*a58d3d2aSXin Li /**
55*a58d3d2aSXin Li  * @def ALIGN(stack, size)
56*a58d3d2aSXin Li  *
57*a58d3d2aSXin Li  * Aligns the stack to a 'size' boundary
58*a58d3d2aSXin Li  *
59*a58d3d2aSXin Li  * @param stack Stack
60*a58d3d2aSXin Li  * @param size  New size boundary
61*a58d3d2aSXin Li  */
62*a58d3d2aSXin Li 
63*a58d3d2aSXin Li /**
64*a58d3d2aSXin Li  * @def PUSH(stack, size, type)
65*a58d3d2aSXin Li  *
66*a58d3d2aSXin Li  * Allocates 'size' elements of type 'type' on the stack
67*a58d3d2aSXin Li  *
68*a58d3d2aSXin Li  * @param stack Stack
69*a58d3d2aSXin Li  * @param size  Number of elements
70*a58d3d2aSXin Li  * @param type  Type of element
71*a58d3d2aSXin Li  */
72*a58d3d2aSXin Li 
73*a58d3d2aSXin Li /**
74*a58d3d2aSXin Li  * @def VARDECL(var)
75*a58d3d2aSXin Li  *
76*a58d3d2aSXin Li  * Declare variable on stack
77*a58d3d2aSXin Li  *
78*a58d3d2aSXin Li  * @param var Variable to declare
79*a58d3d2aSXin Li  */
80*a58d3d2aSXin Li 
81*a58d3d2aSXin Li /**
82*a58d3d2aSXin Li  * @def ALLOC(var, size, type)
83*a58d3d2aSXin Li  *
84*a58d3d2aSXin Li  * Allocate 'size' elements of 'type' on stack
85*a58d3d2aSXin Li  *
86*a58d3d2aSXin Li  * @param var  Name of variable to allocate
87*a58d3d2aSXin Li  * @param size Number of elements
88*a58d3d2aSXin Li  * @param type Type of element
89*a58d3d2aSXin Li  */
90*a58d3d2aSXin Li 
91*a58d3d2aSXin Li #ifndef SIMD_EXTRA_ALLOC_BYTES
92*a58d3d2aSXin Li #error define SIMD_EXTRA_ALLOC_BYTES appropriately in your makefile
93*a58d3d2aSXin Li /*
94*a58d3d2aSXin Li  * Useful values:
95*a58d3d2aSXin Li  * 0  for an all-scalar processor, which should never over-read the arrays
96*a58d3d2aSXin Li  * 16 for an implementation using ARM Neon or X86 SSE4 instructions, which work
97*a58d3d2aSXin Li  *    with blocks of 16 bytes (128 bits)
98*a58d3d2aSXin Li  */
99*a58d3d2aSXin Li #endif
100*a58d3d2aSXin Li 
101*a58d3d2aSXin Li #if defined(VAR_ARRAYS)
102*a58d3d2aSXin Li 
103*a58d3d2aSXin Li #define VARDECL(type, var)
104*a58d3d2aSXin Li // include a full SIMD width afterwards;
105*a58d3d2aSXin Li #define ALLOC(var, size, type) type var[(size) + ((SIMD_EXTRA_ALLOC_BYTES)/sizeof(type))]
106*a58d3d2aSXin Li 
107*a58d3d2aSXin Li #define SAVE_STACK
108*a58d3d2aSXin Li #define RESTORE_STACK
109*a58d3d2aSXin Li #define ALLOC_STACK
110*a58d3d2aSXin Li /* C99 does not allow VLAs of size zero */
111*a58d3d2aSXin Li #define ALLOC_NONE 1
112*a58d3d2aSXin Li 
113*a58d3d2aSXin Li #elif defined(USE_ALLOCA)
114*a58d3d2aSXin Li 
115*a58d3d2aSXin Li #define VARDECL(type, var) type *var
116*a58d3d2aSXin Li 
117*a58d3d2aSXin Li # ifdef _WIN32
118*a58d3d2aSXin Li #  define ALLOC(var, size, type) var = \
119*a58d3d2aSXin Li                                  ((type*)_alloca(sizeof(type)*(size) + SIMD_EXTRA_ALLOC_BYTES))
120*a58d3d2aSXin Li # else
121*a58d3d2aSXin Li #  define ALLOC(var, size, type) var = \
122*a58d3d2aSXin Li                                  ((type*)alloca(sizeof(type)*(size) + SIMD_EXTRA_ALLOC_BYTES))
123*a58d3d2aSXin Li # endif
124*a58d3d2aSXin Li 
125*a58d3d2aSXin Li #define SAVE_STACK
126*a58d3d2aSXin Li #define RESTORE_STACK
127*a58d3d2aSXin Li #define ALLOC_STACK
128*a58d3d2aSXin Li #define ALLOC_NONE 0
129*a58d3d2aSXin Li 
130*a58d3d2aSXin Li #else
131*a58d3d2aSXin Li 
132*a58d3d2aSXin Li #ifdef CELT_C
133*a58d3d2aSXin Li char *scratch_ptr=0;
134*a58d3d2aSXin Li char *global_stack=0;
135*a58d3d2aSXin Li #else
136*a58d3d2aSXin Li extern char *global_stack;
137*a58d3d2aSXin Li extern char *scratch_ptr;
138*a58d3d2aSXin Li #endif /* CELT_C */
139*a58d3d2aSXin Li 
140*a58d3d2aSXin Li #ifdef ENABLE_VALGRIND
141*a58d3d2aSXin Li 
142*a58d3d2aSXin Li #include <valgrind/memcheck.h>
143*a58d3d2aSXin Li 
144*a58d3d2aSXin Li #ifdef CELT_C
145*a58d3d2aSXin Li char *global_stack_top=0;
146*a58d3d2aSXin Li #else
147*a58d3d2aSXin Li extern char *global_stack_top;
148*a58d3d2aSXin Li #endif /* CELT_C */
149*a58d3d2aSXin Li 
150*a58d3d2aSXin Li #define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
151*a58d3d2aSXin Li #define PUSH(stack, size, type) (VALGRIND_MAKE_MEM_NOACCESS(stack, global_stack_top-stack),ALIGN((stack),sizeof(type)/sizeof(char)),VALGRIND_MAKE_MEM_UNDEFINED(stack, ((size)*sizeof(type)/sizeof(char))),(stack)+=(2*(size)*sizeof(type)/sizeof(char)),(type*)((stack)-(2*(size)*sizeof(type)/sizeof(char))))
152*a58d3d2aSXin Li #define RESTORE_STACK ((global_stack = _saved_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack))
153*a58d3d2aSXin Li #define ALLOC_STACK char *_saved_stack; ((global_stack = (global_stack==0) ? ((global_stack_top=opus_alloc_scratch(GLOBAL_STACK_SIZE*2)+(GLOBAL_STACK_SIZE*2))-(GLOBAL_STACK_SIZE*2)) : global_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack)); _saved_stack = global_stack;
154*a58d3d2aSXin Li 
155*a58d3d2aSXin Li #else
156*a58d3d2aSXin Li 
157*a58d3d2aSXin Li #define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
158*a58d3d2aSXin Li #define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)/(sizeof(char))),(stack)+=(size)*(sizeof(type)/(sizeof(char))),(type*)((stack)-(size)*(sizeof(type)/(sizeof(char)))))
159*a58d3d2aSXin Li #if 0 /* Set this to 1 to instrument pseudostack usage */
160*a58d3d2aSXin Li #define RESTORE_STACK (printf("%ld %s:%d\n", global_stack-scratch_ptr, __FILE__, __LINE__),global_stack = _saved_stack)
161*a58d3d2aSXin Li #else
162*a58d3d2aSXin Li #define RESTORE_STACK (global_stack = _saved_stack)
163*a58d3d2aSXin Li #endif
164*a58d3d2aSXin Li #define ALLOC_STACK char *_saved_stack; (global_stack = (global_stack==0) ? (scratch_ptr=opus_alloc_scratch(GLOBAL_STACK_SIZE)) : global_stack); _saved_stack = global_stack;
165*a58d3d2aSXin Li 
166*a58d3d2aSXin Li #endif /* ENABLE_VALGRIND */
167*a58d3d2aSXin Li 
168*a58d3d2aSXin Li // this path has NOT been modified to be safe in the face of SIMD over-reads
169*a58d3d2aSXin Li #if SIMD_EXTRA_ALLOC_BYTES != 0
170*a58d3d2aSXin Li #error  "ALLOC() is not updated in this configuration to provide for SIMD over-reads"
171*a58d3d2aSXin Li #endif
172*a58d3d2aSXin Li 
173*a58d3d2aSXin Li #include "os_support.h"
174*a58d3d2aSXin Li #define VARDECL(type, var) type *var
175*a58d3d2aSXin Li #define ALLOC(var, size, type) var = PUSH(global_stack, size, type)
176*a58d3d2aSXin Li #define SAVE_STACK char *_saved_stack = global_stack;
177*a58d3d2aSXin Li #define ALLOC_NONE 0
178*a58d3d2aSXin Li 
179*a58d3d2aSXin Li #endif /* VAR_ARRAYS */
180*a58d3d2aSXin Li 
181*a58d3d2aSXin Li 
182*a58d3d2aSXin Li #ifdef ENABLE_VALGRIND
183*a58d3d2aSXin Li 
184*a58d3d2aSXin Li #include <valgrind/memcheck.h>
185*a58d3d2aSXin Li #define OPUS_CHECK_ARRAY(ptr, len) VALGRIND_CHECK_MEM_IS_DEFINED(ptr, len*sizeof(*ptr))
186*a58d3d2aSXin Li #define OPUS_CHECK_VALUE(value) VALGRIND_CHECK_VALUE_IS_DEFINED(value)
187*a58d3d2aSXin Li #define OPUS_CHECK_ARRAY_COND(ptr, len) VALGRIND_CHECK_MEM_IS_DEFINED(ptr, len*sizeof(*ptr))
188*a58d3d2aSXin Li #define OPUS_CHECK_VALUE_COND(value) VALGRIND_CHECK_VALUE_IS_DEFINED(value)
189*a58d3d2aSXin Li #define OPUS_PRINT_INT(value) do {fprintf(stderr, #value " = %d at %s:%d\n", value, __FILE__, __LINE__);}while(0)
190*a58d3d2aSXin Li #define OPUS_FPRINTF fprintf
191*a58d3d2aSXin Li 
192*a58d3d2aSXin Li #else
193*a58d3d2aSXin Li 
_opus_false(void)194*a58d3d2aSXin Li static OPUS_INLINE int _opus_false(void) {return 0;}
195*a58d3d2aSXin Li #define OPUS_CHECK_ARRAY(ptr, len) _opus_false()
196*a58d3d2aSXin Li #define OPUS_CHECK_VALUE(value) _opus_false()
197*a58d3d2aSXin Li #define OPUS_PRINT_INT(value) do{}while(0)
198*a58d3d2aSXin Li #define OPUS_FPRINTF (void)
199*a58d3d2aSXin Li 
200*a58d3d2aSXin Li #endif
201*a58d3d2aSXin Li 
202*a58d3d2aSXin Li 
203*a58d3d2aSXin Li #endif /* STACK_ALLOC_H */
204