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