You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
582 lines
17 KiB
582 lines
17 KiB
/* |
|
* Copyright (c) 2010-2014,2017 Wind River Systems, Inc. |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#ifndef ZEPHYR_INCLUDE_TOOLCHAIN_GCC_H_ |
|
#define ZEPHYR_INCLUDE_TOOLCHAIN_GCC_H_ |
|
|
|
/** |
|
* @file |
|
* @brief GCC toolchain abstraction |
|
* |
|
* Macros to abstract compiler capabilities for GCC toolchain. |
|
*/ |
|
|
|
/* |
|
* Older versions of GCC do not define __BYTE_ORDER__, so it must be manually |
|
* detected and defined using arch-specific definitions. |
|
*/ |
|
|
|
#ifndef _LINKER |
|
|
|
#ifndef __ORDER_BIG_ENDIAN__ |
|
#define __ORDER_BIG_ENDIAN__ (1) |
|
#endif |
|
|
|
#ifndef __ORDER_LITTLE_ENDIAN__ |
|
#define __ORDER_LITTLE_ENDIAN__ (2) |
|
#endif |
|
|
|
#ifndef __BYTE_ORDER__ |
|
#if defined(__BIG_ENDIAN__) || defined(__ARMEB__) || \ |
|
defined(__THUMBEB__) || defined(__AARCH64EB__) || \ |
|
defined(__MIPSEB__) || defined(__TC32EB__) |
|
|
|
#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__ |
|
|
|
#elif defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || \ |
|
defined(__THUMBEL__) || defined(__AARCH64EL__) || \ |
|
defined(__MIPSEL__) || defined(__TC32EL__) |
|
|
|
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ |
|
|
|
#else |
|
#error "__BYTE_ORDER__ is not defined and cannot be automatically resolved" |
|
#endif |
|
#endif |
|
|
|
|
|
/* C++11 has static_assert built in */ |
|
#ifdef __cplusplus |
|
#define BUILD_ASSERT(EXPR, MSG...) static_assert(EXPR, "" MSG) |
|
|
|
/* |
|
* GCC 4.6 and higher have the C11 _Static_assert built in, and its |
|
* output is easier to understand than the common BUILD_ASSERT macros. |
|
*/ |
|
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) || \ |
|
(__STDC_VERSION__) >= 201100 |
|
#define BUILD_ASSERT(EXPR, MSG...) _Static_assert(EXPR, "" MSG) |
|
#else |
|
#define BUILD_ASSERT(EXPR, MSG...) |
|
#endif |
|
|
|
#ifdef __cplusplus |
|
#define ZRESTRICT __restrict |
|
#else |
|
#define ZRESTRICT restrict |
|
#endif |
|
|
|
#include <toolchain/common.h> |
|
#include <stdbool.h> |
|
|
|
#define ALIAS_OF(of) __attribute__((alias(#of))) |
|
|
|
#define FUNC_ALIAS(real_func, new_alias, return_type) \ |
|
return_type new_alias() ALIAS_OF(real_func) |
|
|
|
#if defined(CONFIG_ARCH_POSIX) |
|
#include <arch/posix/posix_trace.h> |
|
|
|
/*let's not segfault if this were to happen for some reason*/ |
|
#define CODE_UNREACHABLE \ |
|
{\ |
|
posix_print_error_and_exit("CODE_UNREACHABLE reached from %s:%d\n",\ |
|
__FILE__, __LINE__);\ |
|
__builtin_unreachable(); \ |
|
} |
|
#else |
|
#define CODE_UNREACHABLE __builtin_unreachable() |
|
#endif |
|
#define FUNC_NORETURN __attribute__((__noreturn__)) |
|
|
|
/* The GNU assembler for Cortex-M3 uses # for immediate values, not |
|
* comments, so the @nobits# trick does not work. |
|
*/ |
|
#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) |
|
#define _NODATA_SECTION(segment) __attribute__((section(#segment))) |
|
#else |
|
#define _NODATA_SECTION(segment) \ |
|
__attribute__((section(#segment ",\"wa\",@nobits#"))) |
|
#endif |
|
|
|
/* Unaligned access */ |
|
#define UNALIGNED_GET(p) \ |
|
__extension__ ({ \ |
|
struct __attribute__((__packed__)) { \ |
|
__typeof__(*(p)) __v; \ |
|
} *__p = (__typeof__(__p)) (p); \ |
|
__p->__v; \ |
|
}) |
|
|
|
|
|
#if __GNUC__ >= 7 && (defined(CONFIG_ARM) || defined(CONFIG_ARM64)) |
|
|
|
/* Version of UNALIGNED_PUT() which issues a compiler_barrier() after |
|
* the store. It is required to workaround an apparent optimization |
|
* bug in GCC for ARM Cortex-M3 and higher targets, when multiple |
|
* byte, half-word and word stores (strb, strh, str instructions), |
|
* which support unaligned access, can be coalesced into store double |
|
* (strd) instruction, which doesn't support unaligned access (the |
|
* compilers in question do this optimization ignoring __packed__ |
|
* attribute). |
|
*/ |
|
#define UNALIGNED_PUT(v, p) \ |
|
do { \ |
|
struct __attribute__((__packed__)) { \ |
|
__typeof__(*p) __v; \ |
|
} *__p = (__typeof__(__p)) (p); \ |
|
__p->__v = (v); \ |
|
compiler_barrier(); \ |
|
} while (false) |
|
|
|
#else |
|
|
|
#define UNALIGNED_PUT(v, p) \ |
|
do { \ |
|
struct __attribute__((__packed__)) { \ |
|
__typeof__(*p) __v; \ |
|
} *__p = (__typeof__(__p)) (p); \ |
|
__p->__v = (v); \ |
|
} while (false) |
|
|
|
#endif |
|
|
|
/* Double indirection to ensure section names are expanded before |
|
* stringification |
|
*/ |
|
#define __GENERIC_SECTION(segment) __attribute__((section(STRINGIFY(segment)))) |
|
#define Z_GENERIC_SECTION(segment) __GENERIC_SECTION(segment) |
|
|
|
#define __GENERIC_DOT_SECTION(segment) \ |
|
__attribute__((section("." STRINGIFY(segment)))) |
|
#define Z_GENERIC_DOT_SECTION(segment) __GENERIC_DOT_SECTION(segment) |
|
|
|
#define ___in_section(a, b, c) \ |
|
__attribute__((section("." Z_STRINGIFY(a) \ |
|
"." Z_STRINGIFY(b) \ |
|
"." Z_STRINGIFY(c)))) |
|
#define __in_section(a, b, c) ___in_section(a, b, c) |
|
|
|
#define __in_section_unique(seg) ___in_section(seg, __FILE__, __COUNTER__) |
|
|
|
#define __in_section_unique_named(seg, name) \ |
|
___in_section(seg, __FILE__, name) |
|
|
|
/* When using XIP, using '__ramfunc' places a function into RAM instead |
|
* of FLASH. Make sure '__ramfunc' is defined only when |
|
* CONFIG_ARCH_HAS_RAMFUNC_SUPPORT is defined, so that the compiler can |
|
* report an error if '__ramfunc' is used but the architecture does not |
|
* support it. |
|
*/ |
|
#if !defined(CONFIG_XIP) |
|
#define __ramfunc |
|
#elif defined(CONFIG_ARCH_HAS_RAMFUNC_SUPPORT) |
|
#define __ramfunc __attribute__((noinline)) \ |
|
__attribute__((long_call, section(".ramfunc"))) |
|
#endif /* !CONFIG_XIP */ |
|
|
|
#ifndef __fallthrough |
|
#if __GNUC__ >= 7 |
|
#define __fallthrough __attribute__((fallthrough)) |
|
#else |
|
#define __fallthrough |
|
#endif /* __GNUC__ >= 7 */ |
|
#endif |
|
|
|
#ifndef __packed |
|
#define __packed __attribute__((__packed__)) |
|
#endif |
|
#ifndef __aligned |
|
#define __aligned(x) __attribute__((__aligned__(x))) |
|
#endif |
|
#define __may_alias __attribute__((__may_alias__)) |
|
#ifndef __printf_like |
|
#define __printf_like(f, a) __attribute__((format (printf, f, a))) |
|
#endif |
|
#define __used __attribute__((__used__)) |
|
#ifndef __deprecated |
|
#define __deprecated __attribute__((deprecated)) |
|
#endif |
|
#ifndef __attribute_const__ |
|
#define __attribute_const__ __attribute__((__const__)) |
|
#endif |
|
#ifndef __must_check |
|
#define __must_check __attribute__((warn_unused_result)) |
|
#endif |
|
#define ARG_UNUSED(x) (void)(x) |
|
|
|
#define likely(x) __builtin_expect((bool)!!(x), true) |
|
#define unlikely(x) __builtin_expect((bool)!!(x), false) |
|
|
|
#define popcount(x) __builtin_popcount(x) |
|
|
|
#ifndef __no_optimization |
|
#define __no_optimization __attribute__((optimize("-O0"))) |
|
#endif |
|
|
|
#ifndef __weak |
|
#define __weak __attribute__((__weak__)) |
|
#endif |
|
#define __unused __attribute__((__unused__)) |
|
|
|
/* Builtins with availability that depend on the compiler version. */ |
|
#if __GNUC__ >= 5 |
|
#define HAS_BUILTIN___builtin_add_overflow 1 |
|
#define HAS_BUILTIN___builtin_sub_overflow 1 |
|
#define HAS_BUILTIN___builtin_mul_overflow 1 |
|
#define HAS_BUILTIN___builtin_div_overflow 1 |
|
#endif |
|
#if __GNUC__ >= 4 |
|
#define HAS_BUILTIN___builtin_clz 1 |
|
#define HAS_BUILTIN___builtin_clzl 1 |
|
#define HAS_BUILTIN___builtin_clzll 1 |
|
#define HAS_BUILTIN___builtin_ctz 1 |
|
#define HAS_BUILTIN___builtin_ctzl 1 |
|
#define HAS_BUILTIN___builtin_ctzll 1 |
|
#endif |
|
|
|
/* |
|
* Be *very* careful with these. You cannot filter out __DEPRECATED_MACRO with |
|
* -wno-deprecated, which has implications for -Werror. |
|
*/ |
|
|
|
/* |
|
* Expands to nothing and generates a warning. Used like |
|
* |
|
* #define FOO __WARN("Please use BAR instead") ... |
|
* |
|
* The warning points to the location where the macro is expanded. |
|
*/ |
|
#define __WARN(msg) __WARN1(GCC warning msg) |
|
#define __WARN1(s) _Pragma(#s) |
|
|
|
/* Generic message */ |
|
#ifndef __DEPRECATED_MACRO |
|
#define __DEPRECATED_MACRO __WARN("Macro is deprecated") |
|
#endif |
|
|
|
/* These macros allow having ARM asm functions callable from thumb */ |
|
|
|
#if defined(_ASMLANGUAGE) |
|
|
|
#if defined(CONFIG_ARM) |
|
|
|
#if defined(CONFIG_ASSEMBLER_ISA_THUMB2) |
|
|
|
#define FUNC_CODE() .thumb; |
|
#define FUNC_INSTR(a) |
|
|
|
#else |
|
|
|
#define FUNC_CODE() .code 32 |
|
#define FUNC_INSTR(a) |
|
|
|
#endif /* CONFIG_ASSEMBLER_ISA_THUMB2 */ |
|
|
|
#else |
|
|
|
#define FUNC_CODE() |
|
#define FUNC_INSTR(a) |
|
|
|
#endif /* CONFIG_ARM */ |
|
|
|
#endif /* _ASMLANGUAGE */ |
|
|
|
/* |
|
* These macros are used to declare assembly language symbols that need |
|
* to be typed properly(func or data) to be visible to the OMF tool. |
|
* So that the build tool could mark them as an entry point to be linked |
|
* correctly. This is an elfism. Use #if 0 for a.out. |
|
*/ |
|
|
|
#if defined(_ASMLANGUAGE) |
|
|
|
#if defined(CONFIG_ARM) || defined(CONFIG_NIOS2) || defined(CONFIG_RISCV) \ |
|
|| defined(CONFIG_XTENSA) || defined(CONFIG_ARM64) |
|
#define GTEXT(sym) .global sym; .type sym, %function |
|
#define GDATA(sym) .global sym; .type sym, %object |
|
#define WTEXT(sym) .weak sym; .type sym, %function |
|
#define WDATA(sym) .weak sym; .type sym, %object |
|
#elif defined(CONFIG_ARC) |
|
/* |
|
* Need to use assembly macros because ';' is interpreted as the start of |
|
* a single line comment in the ARC assembler. |
|
*/ |
|
|
|
.macro glbl_text symbol |
|
.globl \symbol |
|
.type \symbol, %function |
|
.endm |
|
|
|
.macro glbl_data symbol |
|
.globl \symbol |
|
.type \symbol, %object |
|
.endm |
|
|
|
.macro weak_data symbol |
|
.weak \symbol |
|
.type \symbol, %object |
|
.endm |
|
|
|
#define GTEXT(sym) glbl_text sym |
|
#define GDATA(sym) glbl_data sym |
|
#define WDATA(sym) weak_data sym |
|
|
|
#else /* !CONFIG_ARM && !CONFIG_ARC */ |
|
#define GTEXT(sym) .globl sym; .type sym, @function |
|
#define GDATA(sym) .globl sym; .type sym, @object |
|
#endif |
|
|
|
/* |
|
* These macros specify the section in which a given function or variable |
|
* resides. |
|
* |
|
* - SECTION_FUNC allows only one function to reside in a sub-section |
|
* - SECTION_SUBSEC_FUNC allows multiple functions to reside in a sub-section |
|
* This ensures that garbage collection only discards the section |
|
* if all functions in the sub-section are not referenced. |
|
*/ |
|
|
|
#if defined(CONFIG_ARC) |
|
/* |
|
* Need to use assembly macros because ';' is interpreted as the start of |
|
* a single line comment in the ARC assembler. |
|
* |
|
* Also, '\()' is needed in the .section directive of these macros for |
|
* correct substitution of the 'section' variable. |
|
*/ |
|
|
|
.macro section_var section, symbol |
|
.section .\section\().\symbol |
|
\symbol : |
|
.endm |
|
|
|
.macro section_func section, symbol |
|
.section .\section\().\symbol, "ax" |
|
FUNC_CODE() |
|
PERFOPT_ALIGN |
|
\symbol : |
|
FUNC_INSTR(\symbol) |
|
.endm |
|
|
|
.macro section_subsec_func section, subsection, symbol |
|
.section .\section\().\subsection, "ax" |
|
PERFOPT_ALIGN |
|
\symbol : |
|
.endm |
|
|
|
#define SECTION_VAR(sect, sym) section_var sect, sym |
|
#define SECTION_FUNC(sect, sym) section_func sect, sym |
|
#define SECTION_SUBSEC_FUNC(sect, subsec, sym) \ |
|
section_subsec_func sect, subsec, sym |
|
#else /* !CONFIG_ARC */ |
|
|
|
#define SECTION_VAR(sect, sym) .section .sect.sym; sym: |
|
#define SECTION_FUNC(sect, sym) \ |
|
.section .sect.sym, "ax"; \ |
|
FUNC_CODE() \ |
|
PERFOPT_ALIGN; sym : \ |
|
FUNC_INSTR(sym) |
|
#define SECTION_SUBSEC_FUNC(sect, subsec, sym) \ |
|
.section .sect.subsec, "ax"; PERFOPT_ALIGN; sym : |
|
|
|
#endif /* CONFIG_ARC */ |
|
|
|
#endif /* _ASMLANGUAGE */ |
|
|
|
#if defined(_ASMLANGUAGE) |
|
#if defined(CONFIG_ARM) |
|
#if defined(CONFIG_ASSEMBLER_ISA_THUMB2) |
|
/* '.syntax unified' is a gcc-ism used in thumb-2 asm files */ |
|
#define _ASM_FILE_PROLOGUE .text; .syntax unified; .thumb |
|
#else |
|
#define _ASM_FILE_PROLOGUE .text; .code 32 |
|
#endif /* CONFIG_ASSEMBLER_ISA_THUMB2 */ |
|
#elif defined(CONFIG_ARM64) |
|
#define _ASM_FILE_PROLOGUE .text |
|
#endif /* CONFIG_ARM64 || CONFIG_ARM */ |
|
#endif /* _ASMLANGUAGE */ |
|
|
|
/* |
|
* These macros generate absolute symbols for GCC |
|
*/ |
|
|
|
/* create an extern reference to the absolute symbol */ |
|
|
|
#define GEN_OFFSET_EXTERN(name) extern const char name[] |
|
|
|
#define GEN_ABS_SYM_BEGIN(name) \ |
|
EXTERN_C void name(void); \ |
|
void name(void) \ |
|
{ |
|
|
|
#define GEN_ABS_SYM_END } |
|
|
|
/* |
|
* Note that GEN_ABSOLUTE_SYM(), depending on the architecture |
|
* and toolchain, may restrict the range of values permitted |
|
* for assignment to the named symbol. |
|
* |
|
* For example, on x86, "value" is interpreated as signed |
|
* 32-bit integer. Passing in an unsigned 32-bit integer |
|
* with MSB set would result in a negative integer. |
|
* Moreover, GCC would error out if an integer larger |
|
* than 2^32-1 is passed as "value". |
|
*/ |
|
|
|
/* |
|
* GEN_ABSOLUTE_SYM_KCONFIG() is outputted by the build system |
|
* to generate named symbol/value pairs for kconfigs. |
|
*/ |
|
|
|
#if defined(CONFIG_ARM) |
|
|
|
/* |
|
* GNU/ARM backend does not have a proper operand modifier which does not |
|
* produces prefix # followed by value, such as %0 for PowerPC, Intel, and |
|
* MIPS. The workaround performed here is using %B0 which converts |
|
* the value to ~(value). Thus "n"(~(value)) is set in operand constraint |
|
* to output (value) in the ARM specific GEN_OFFSET macro. |
|
*/ |
|
|
|
#define GEN_ABSOLUTE_SYM(name, value) \ |
|
__asm__(".globl\t" #name "\n\t.equ\t" #name \ |
|
",%B0" \ |
|
"\n\t.type\t" #name ",%%object" : : "n"(~(value))) |
|
|
|
#define GEN_ABSOLUTE_SYM_KCONFIG(name, value) \ |
|
__asm__(".globl\t" #name \ |
|
"\n\t.equ\t" #name "," #value \ |
|
"\n\t.type\t" #name ",%object") |
|
|
|
#elif defined(CONFIG_X86) |
|
|
|
#define GEN_ABSOLUTE_SYM(name, value) \ |
|
__asm__(".globl\t" #name "\n\t.equ\t" #name \ |
|
",%c0" \ |
|
"\n\t.type\t" #name ",@object" : : "n"(value)) |
|
|
|
#define GEN_ABSOLUTE_SYM_KCONFIG(name, value) \ |
|
__asm__(".globl\t" #name \ |
|
"\n\t.equ\t" #name "," #value \ |
|
"\n\t.type\t" #name ",@object") |
|
|
|
#elif defined(CONFIG_ARC) || defined(CONFIG_ARM64) |
|
|
|
#define GEN_ABSOLUTE_SYM(name, value) \ |
|
__asm__(".globl\t" #name "\n\t.equ\t" #name \ |
|
",%c0" \ |
|
"\n\t.type\t" #name ",@object" : : "n"(value)) |
|
|
|
#define GEN_ABSOLUTE_SYM_KCONFIG(name, value) \ |
|
__asm__(".globl\t" #name \ |
|
"\n\t.equ\t" #name "," #value \ |
|
"\n\t.type\t" #name ",@object") |
|
|
|
#elif defined(CONFIG_NIOS2) || defined(CONFIG_RISCV) || defined(CONFIG_XTENSA) |
|
|
|
/* No special prefixes necessary for constants in this arch AFAICT */ |
|
#define GEN_ABSOLUTE_SYM(name, value) \ |
|
__asm__(".globl\t" #name "\n\t.equ\t" #name \ |
|
",%0" \ |
|
"\n\t.type\t" #name ",%%object" : : "n"(value)) |
|
|
|
#define GEN_ABSOLUTE_SYM_KCONFIG(name, value) \ |
|
__asm__(".globl\t" #name \ |
|
"\n\t.equ\t" #name "," #value \ |
|
"\n\t.type\t" #name ",%object") |
|
|
|
#elif defined(CONFIG_ARCH_POSIX) |
|
#define GEN_ABSOLUTE_SYM(name, value) \ |
|
__asm__(".globl\t" #name "\n\t.equ\t" #name \ |
|
",%c0" \ |
|
"\n\t.type\t" #name ",@object" : : "n"(value)) |
|
|
|
#define GEN_ABSOLUTE_SYM_KCONFIG(name, value) \ |
|
__asm__(".globl\t" #name \ |
|
"\n\t.equ\t" #name "," #value \ |
|
"\n\t.type\t" #name ",@object") |
|
|
|
#elif defined(CONFIG_SPARC) |
|
#define GEN_ABSOLUTE_SYM(name, value) \ |
|
__asm__(".global\t" #name "\n\t.equ\t" #name \ |
|
",%0" \ |
|
"\n\t.type\t" #name ",#object" : : "n"(value)) |
|
|
|
#define GEN_ABSOLUTE_SYM_KCONFIG(name, value) \ |
|
__asm__(".globl\t" #name \ |
|
"\n\t.equ\t" #name "," #value \ |
|
"\n\t.type\t" #name ",#object") |
|
|
|
#else |
|
#error processor architecture not supported |
|
#endif |
|
|
|
#define compiler_barrier() do { \ |
|
__asm__ __volatile__ ("" ::: "memory"); \ |
|
} while (false) |
|
|
|
/** @brief Return larger value of two provided expressions. |
|
* |
|
* Macro ensures that expressions are evaluated only once. |
|
* |
|
* @note Macro has limited usage compared to the standard macro as it cannot be |
|
* used: |
|
* - to generate constant integer, e.g. __aligned(Z_MAX(4,5)) |
|
* - static variable, e.g. array like static uint8_t array[Z_MAX(...)]; |
|
*/ |
|
#define Z_MAX(a, b) ({ \ |
|
/* random suffix to avoid naming conflict */ \ |
|
__typeof__(a) _value_a_ = (a); \ |
|
__typeof__(b) _value_b_ = (b); \ |
|
_value_a_ > _value_b_ ? _value_a_ : _value_b_; \ |
|
}) |
|
|
|
/** @brief Return smaller value of two provided expressions. |
|
* |
|
* Macro ensures that expressions are evaluated only once. See @ref Z_MAX for |
|
* macro limitations. |
|
*/ |
|
#define Z_MIN(a, b) ({ \ |
|
/* random suffix to avoid naming conflict */ \ |
|
__typeof__(a) _value_a_ = (a); \ |
|
__typeof__(b) _value_b_ = (b); \ |
|
_value_a_ < _value_b_ ? _value_a_ : _value_b_; \ |
|
}) |
|
|
|
/** @brief Return a value clamped to a given range. |
|
* |
|
* Macro ensures that expressions are evaluated only once. See @ref Z_MAX for |
|
* macro limitations. |
|
*/ |
|
#define Z_CLAMP(val, low, high) ({ \ |
|
/* random suffix to avoid naming conflict */ \ |
|
__typeof__(val) _value_val_ = (val); \ |
|
__typeof__(low) _value_low_ = (low); \ |
|
__typeof__(high) _value_high_ = (high); \ |
|
(_value_val_ < _value_low_) ? _value_low_ : \ |
|
(_value_val_ > _value_high_) ? _value_high_ : \ |
|
_value_val_; \ |
|
}) |
|
|
|
/** |
|
* @brief Calculate power of two ceiling for some nonzero value |
|
* |
|
* @param x Nonzero unsigned long value |
|
* @return X rounded up to the next power of two |
|
*/ |
|
#ifdef CONFIG_64BIT |
|
#define Z_POW2_CEIL(x) ((1UL << (63U - __builtin_clzl(x))) < x ? \ |
|
1UL << (63U - __builtin_clzl(x) + 1U) : \ |
|
1UL << (63U - __builtin_clzl(x))) |
|
#else |
|
#define Z_POW2_CEIL(x) ((1UL << (31U - __builtin_clzl(x))) < x ? \ |
|
1UL << (31U - __builtin_clzl(x) + 1U) : \ |
|
1UL << (31U - __builtin_clzl(x))) |
|
#endif |
|
|
|
#endif /* !_LINKER */ |
|
#endif /* ZEPHYR_INCLUDE_TOOLCHAIN_GCC_H_ */
|
|
|