1 /*
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #ifndef _PICO_PLATFORM_COMPILER_H
8 #define _PICO_PLATFORM_COMPILER_H
9
10 /** \file platform_compiler.h
11 * \defgroup pico_platform pico_platform
12 *
13 * \brief Macros and definitions (and functions when included by non assembly code) to adapt for different compilers
14 *
15 * This header may be included by assembly code
16 */
17
18 #include "hardware/platform_defs.h"
19
20 #ifndef __ASSEMBLER__
21
22 #if defined __GNUC__
23 #include <sys/cdefs.h>
24 // note LLVM defines __GNUC__
25 #ifdef __clang__
26 #define PICO_C_COMPILER_IS_CLANG 1
27 #else
28 #define PICO_C_COMPILER_IS_GNU 1
29 #endif
30 #elif defined __ICCARM__
31 #ifndef __aligned
32 #define __aligned(x) __attribute__((__aligned__(x)))
33 #endif
34 #ifndef __always_inline
35 #define __always_inline __attribute__((__always_inline__))
36 #endif
37 #ifndef __noinline
38 #define __noinline __attribute__((__noinline__))
39 #endif
40 #ifndef __packed
41 #define __packed __attribute__((__packed__))
42 #endif
43 #ifndef __printflike
44 #define __printflike(a, b)
45 #endif
46 #ifndef __unused
47 #define __unused __attribute__((__unused__))
48 #endif
49 #ifndef __used
50 #define __used __attribute__((__used__))
51 #endif
52 #ifndef __CONCAT1
53 #define __CONCAT1(a, b) a ## b
54 #endif
55 #ifndef __CONCAT
56 #define __CONCAT(a, b) __CONCAT1(a, b)
57 #endif
58 #ifndef __STRING
59 #define __STRING(a) #a
60 #endif
61 /* Compatible definitions of GCC builtins */
62
__builtin_ctz(uint x)63 static inline uint __builtin_ctz(uint x) {
64 extern uint32_t __ctzsi2(uint32_t);
65 return __ctzsi2(x);
66 }
67 #define __builtin_expect(x, y) (x)
68 #define __builtin_isnan(x) __iar_isnan(x)
69 #else
70 #error Unsupported toolchain
71 #endif
72
73 #ifndef __weak
74 #define __weak __attribute__((weak))
75 #endif
76
77 #include "pico/types.h"
78
79 // GCC_Like_Pragma(x) is a pragma on GNUC compatible compilers
80 #ifdef __GNUC__
81 #define GCC_Like_Pragma _Pragma
82 #else
83 #define GCC_Like_Pragma(x)
84 #endif
85
86 // Clang_Pragma(x) is a pragma on Clang only
87 #ifdef __clang__
88 #define Clang_Pragma _Pragma
89 #else
90 #define Clang_Pragma(x)
91 #endif
92
93 // GCC_Pragma(x) is a pragma on GCC only
94 #if PICO_C_COMPILER_IS_GNU
95 #define GCC_Pragma _Pragma
96 #else
97 #define GCC_Pragma(x)
98 #endif
99
100 #ifdef __cplusplus
101 extern "C" {
102 #endif
103
104 /*! \brief Marker for an interrupt handler
105 * \ingroup pico_platform
106 *
107 * For example an IRQ handler function called my_interrupt_handler:
108 *
109 * void __isr my_interrupt_handler(void) {
110 */
111 #define __isr
112
113 #define __packed_aligned __packed __aligned(4)
114
115 /*! \brief Attribute to force inlining of a function regardless of optimization level
116 * \ingroup pico_platform
117 *
118 * For example my_function here will always be inlined:
119 *
120 * int __force_inline my_function(int x) {
121 *
122 */
123
124 #if PICO_C_COMPILER_IS_GNU && (__GNUC__ <= 6 || (__GNUC__ == 7 && (__GNUC_MINOR__ < 3 || !defined(__cplusplus))))
125 #define __force_inline inline __always_inline
126 #else
127 #define __force_inline __always_inline
128 #endif
129
130 /*! \brief Macro to determine the number of elements in an array
131 * \ingroup pico_platform
132 */
133 #ifndef count_of
134 #define count_of(a) (sizeof(a)/sizeof((a)[0]))
135 #endif
136
137 /*! \brief Macro to return the maximum of two comparable values
138 * \ingroup pico_platform
139 */
140 #ifndef MAX
141 #define MAX(a, b) ((a)>(b)?(a):(b))
142 #endif
143
144 /*! \brief Macro to return the minimum of two comparable values
145 * \ingroup pico_platform
146 */
147 #ifndef MIN
148 #define MIN(a, b) ((b)>(a)?(a):(b))
149 #endif
150
151 #ifdef __ARM_ARCH_ISA_THUMB
152 #define pico_default_asm(...) __asm (".syntax unified\n" __VA_ARGS__)
153 #define pico_default_asm_volatile(...) __asm volatile (".syntax unified\n" __VA_ARGS__)
154 #define pico_default_asm_goto(...) __asm goto (".syntax unified\n" __VA_ARGS__)
155 #define pico_default_asm_volatile_goto(...) __asm volatile goto (".syntax unified\n" __VA_ARGS__)
156 #else
157 #define pico_default_asm(...) __asm (__VA_ARGS__)
158 #define pico_default_asm_volatile(...) __asm volatile (__VA_ARGS__)
159 #define pico_default_asm_goto(...) __asm goto (__VA_ARGS__)
160 #define pico_default_asm_volatile_goto(...) __asm volatile goto (__VA_ARGS__)
161 #endif
162
163 /*! \brief Ensure that the compiler does not move memory access across this method call
164 * \ingroup pico_platform
165 *
166 * For example in the following code:
167 *
168 * *some_memory_location = var_a;
169 * __compiler_memory_barrier();
170 * uint32_t var_b = *some_other_memory_location
171 *
172 * The compiler will not move the load from `some_other_memory_location` above the memory barrier (which it otherwise
173 * might - even above the memory store!)
174 */
__compiler_memory_barrier(void)175 __force_inline static void __compiler_memory_barrier(void) {
176 pico_default_asm_volatile ("" : : : "memory");
177 }
178
179 /*! \brief Utility macro to assert two types are equivalent.
180 * \ingroup pico_platform
181 *
182 * This macro can be useful in other macros along with `typeof` to assert that two parameters are of equivalent type
183 * (or that a single parameter is of an expected type)
184 */
185 #define __check_type_compatible(type_a, type_b) static_assert(__builtin_types_compatible_p(type_a, type_b), __STRING(type_a) " is not compatible with " __STRING(type_b));
186
187 #define WRAPPER_FUNC(x) __wrap_ ## x
188 #define REAL_FUNC(x) __real_ ## x
189
190 #ifdef __cplusplus
191 }
192 #endif
193
194 #else // __ASSEMBLER__
195
196 #if defined __GNUC__
197 // note LLVM defines __GNUC__
198 #ifdef __clang__
199 #define PICO_ASSEMBLER_IS_CLANG 1
200 #else
201 #define PICO_ASSEMBLER_IS_GNU 1
202 #endif
203 #elif defined __ICCARM__
204 #else
205 #error Unsupported toolchain
206 #endif
207
208 #define WRAPPER_FUNC_NAME(x) __wrap_##x
209
210 #endif // !__ASSEMBLER__
211
212 #endif
213