From 8381fda6241faa911d08eada093d80f75282dfd4 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Mon, 16 May 2016 12:49:46 -0500 Subject: [PATCH 1/3] Merged compiler-polyfill into toolchain.h from https://github.com/armmbed/compiler-polyfill notes - Adopted existing mbed naming convention of all caps. This avoids conflicts with compiler declarations https://github.com/ARMmbed/compiler-polyfill/issues/7 - Dropped align attribute due to lack of support on IAR. - Currently toolchain.h lives in /hal/api, although with the addition of /util there may be a better home. --- hal/api/toolchain.h | 109 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 102 insertions(+), 7 deletions(-) diff --git a/hal/api/toolchain.h b/hal/api/toolchain.h index 7a79226941..b448fca102 100644 --- a/hal/api/toolchain.h +++ b/hal/api/toolchain.h @@ -16,6 +16,107 @@ #ifndef MBED_TOOLCHAIN_H #define MBED_TOOLCHAIN_H + +// Warning for unsupported compilers +#if !defined(__GNUC__) /* GCC */ \ + && !defined(__CC_ARM) /* ARMCC */ \ + && !defined(__clang__) /* LLVM/Clang */ \ + && !defined(__ICCARM__) /* IAR */ +#warning "This compiler is not yet supported." +#endif + + +// Attributes + +/** PACK + * Pack a structure, preventing any padding from being added between fields. + * + * @code + * #include "toolchain.h" + * + * struct foo { + * char x; + * int y; + * } PACKED; + * @endcode + */ +#ifndef PACKED +#if defined(__ICCARM__) +#define PACKED __packed +#else +#define PACKED __attribute__((packed)) +#endif +#endif + +/** UNUSED + * Declare a function argument to be unused, suppressing compiler warnings + * + * @code + * #include "toolchain.h" + * + * void foo(UNUSED int arg){ + * + * } + * @endcode + */ +#ifndef UNUSED +#if defined(__GNUC__) || defined(__CC_ARM) || defined(__clang__) +#define UNUSED __attribute__((__unused__)) +#else +#define UNUSED +#endif +#endif + +/** WEAK + * Mark a function as being weak. + * + * @note + * weak functions are not friendly to making code re-usable, as they can only + * be overridden once (and if they are multiply overridden the linker will emit + * no warning). You should not normally use weak symbols as part of the API to + * re-usable modules. + * + * @code + * #include "toolchain.h" + * + * WEAK void foo() { + * // a weak implementation of foo that can be overriden by a definition + * // without __weak + * } + * @endcode + */ +#ifndef WEAK +#if defined(__ICCARM__) +#define WEAK __weak +#else +#define WEAK __attribute__((weak)) +#endif +#endif + +/** DEPRECATED("message string") + * Mark a function declaration as deprecated, if it used then a warning will be + * issued by the compiler possibly including the provided message. Note that not + * all compilers are able to display the message. + * + * @code + * #include "toolchain.h" + * + * DEPRECATED("don't foo any more, bar instead") + * void foo(int arg); + * @endcode + */ +#ifndef DEPRECATED +#if defined(__GNUC__) || defined(__clang__) +#define DEPRECATED(M) __attribute__((deprecated(M))) +#elif defined(__CC_ARM) +#define DEPRECATED(M) __attribute__((deprecated)) +#else +#define DEPRECATED(M) +#endif +#endif + + +// FILEHANDLE declaration #if defined(TOOLCHAIN_ARM) #include #endif @@ -24,16 +125,10 @@ typedef int FILEHANDLE; #endif +// Backwards compatibility #ifndef EXTERN #define EXTERN extern #endif -#if defined (__ICCARM__) -# define WEAK __weak -# define PACKED __packed -#else -# define WEAK __attribute__((weak)) -# define PACKED __attribute__((packed)) -#endif #endif From f05240b666ed71ecfa0e2bfcb4b3d12010bdcd4c Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Mon, 16 May 2016 14:27:54 -0500 Subject: [PATCH 2/3] Added attribute tests from compiler-polyfill from https://github.com/ARMmbed/compiler-polyfill/tree/master/test/attributes --- hal/TESTS/api/toolchain/attributes.c | 61 ++++++++++++++++++++++++++++ hal/TESTS/api/toolchain/main.cpp | 43 ++++++++++++++++++++ hal/TESTS/api/toolchain/weak.c | 10 +++++ 3 files changed, 114 insertions(+) create mode 100644 hal/TESTS/api/toolchain/attributes.c create mode 100644 hal/TESTS/api/toolchain/main.cpp create mode 100644 hal/TESTS/api/toolchain/weak.c diff --git a/hal/TESTS/api/toolchain/attributes.c b/hal/TESTS/api/toolchain/attributes.c new file mode 100644 index 0000000000..e235477744 --- /dev/null +++ b/hal/TESTS/api/toolchain/attributes.c @@ -0,0 +1,61 @@ +#include "toolchain.h" + +#include +#include + + +struct TestAttrPackedStruct { + char a; + int x; +} PACKED; + +int testPacked() { + int failed = 0; + + if (sizeof(struct TestAttrPackedStruct) != sizeof(int) + sizeof(char)) { + failed++; + } + + return failed; +} + + +int testUnused1(UNUSED int arg) { + return 0; +} + +int testUnused() { + return testUnused1(0); +} + + +DEPRECATED("this message should not be displayed") +void testDeprecatedUnused(); +void testDeprecatedUnused() { } + +DEPRECATED("this message should be displayed") +int testDeprecatedUsed(); +int testDeprecatedUsed() { + return 0; +} + +int testDeprecated() { + return testDeprecatedUsed(); +} + + +int testWeak1(); +int testWeak2(); + +WEAK int testWeak1() { + return 1; +} + +int testWeak2() { + return 0; +} + +int testWeak() { + return testWeak1() | testWeak2(); +} + diff --git a/hal/TESTS/api/toolchain/main.cpp b/hal/TESTS/api/toolchain/main.cpp new file mode 100644 index 0000000000..40ccacb3cd --- /dev/null +++ b/hal/TESTS/api/toolchain/main.cpp @@ -0,0 +1,43 @@ +#include +#include + +#include "toolchain.h" +#include "test_env.h" +#include "unity.h" +#include "utest.h" + +using namespace utest::v1; + + +// Test functions declared as C functions to avoid issues with name mangling +extern "C" { + int testPacked(); + int testUnused(); + int testDeprecated(); + int testWeak(); +} + + +// Test wrapper and test cases for utest +template +void test_wrapper() { + TEST_ASSERT_UNLESS(F()); +} + +status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(40, "default_auto"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("Testing PACKED attribute", test_wrapper), + Case("Testing UNUSED attribute", test_wrapper), + Case("Testing DEPRECATED attribute", test_wrapper), + Case("Testing WEAK attribute", test_wrapper), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} diff --git a/hal/TESTS/api/toolchain/weak.c b/hal/TESTS/api/toolchain/weak.c new file mode 100644 index 0000000000..d81125573f --- /dev/null +++ b/hal/TESTS/api/toolchain/weak.c @@ -0,0 +1,10 @@ +#include "toolchain.h" + +int testWeak1() { + return 0; +} + +WEAK int testWeak2() { + return 1; +} + From 018e2571e6ee53b67e51f27435ead91decefd394 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Mon, 16 May 2016 18:39:17 -0500 Subject: [PATCH 3/3] Added other attributes on supported compilers tested on GCC, Clang, online compiler, and IAR attributes - PACK - ALIGN - UNUSED - WEAK - PURE - FORCEINLINE - NORETURN - UNREACHABLE - DEPRECATED --- hal/TESTS/api/toolchain/attributes.c | 109 ++++++++++++++++++++----- hal/TESTS/api/toolchain/main.cpp | 20 +++-- hal/api/toolchain.h | 117 +++++++++++++++++++++++++-- 3 files changed, 218 insertions(+), 28 deletions(-) diff --git a/hal/TESTS/api/toolchain/attributes.c b/hal/TESTS/api/toolchain/attributes.c index e235477744..196d968c1c 100644 --- a/hal/TESTS/api/toolchain/attributes.c +++ b/hal/TESTS/api/toolchain/attributes.c @@ -4,15 +4,44 @@ #include -struct TestAttrPackedStruct { +typedef struct { char a; int x; -} PACKED; +} PACKED TestAttrPackedStruct; int testPacked() { int failed = 0; - if (sizeof(struct TestAttrPackedStruct) != sizeof(int) + sizeof(char)) { + if (sizeof(TestAttrPackedStruct) != sizeof(int) + sizeof(char)) { + failed++; + } + + return failed; +} + + +int testAlign() { + int failed = 0; + + ALIGN(8) char a; + ALIGN(8) char b; + ALIGN(16) char c; + ALIGN(8) char d; + ALIGN(16) char e; + + if(((uintptr_t)&a) & 0x7){ + failed++; + } + if(((uintptr_t)&b) & 0x7){ + failed++; + } + if(((uintptr_t)&c) & 0xf){ + failed++; + } + if(((uintptr_t)&d) & 0x7){ + failed++; + } + if(((uintptr_t)&e) & 0xf){ failed++; } @@ -29,21 +58,6 @@ int testUnused() { } -DEPRECATED("this message should not be displayed") -void testDeprecatedUnused(); -void testDeprecatedUnused() { } - -DEPRECATED("this message should be displayed") -int testDeprecatedUsed(); -int testDeprecatedUsed() { - return 0; -} - -int testDeprecated() { - return testDeprecatedUsed(); -} - - int testWeak1(); int testWeak2(); @@ -59,3 +73,62 @@ int testWeak() { return testWeak1() | testWeak2(); } + +PURE int testPure1() { + return 0; +} + +int testPure() { + return testPure1(); +} + + +FORCEINLINE int testForceInline1() { + return 0; +} + +int testForceInline() { + return testForceInline1(); +} + + +NORETURN int testNoReturn1() { + while (1) {} +} + +int testNoReturn() { + if (0) { + testNoReturn1(); + } + return 0; +} + + +int testUnreachable1(int i) { + switch (i) { + case 0: + return 0; + } + + UNREACHABLE; +} + +int testUnreachable() { + return testUnreachable1(0); +} + + +DEPRECATED("this message should not be displayed") +void testDeprecatedUnused(); +void testDeprecatedUnused() { } + +DEPRECATED("this message should be displayed") +int testDeprecatedUsed(); +int testDeprecatedUsed() { + return 0; +} + +int testDeprecated() { + return testDeprecatedUsed(); +} + diff --git a/hal/TESTS/api/toolchain/main.cpp b/hal/TESTS/api/toolchain/main.cpp index 40ccacb3cd..4d64b2b2d4 100644 --- a/hal/TESTS/api/toolchain/main.cpp +++ b/hal/TESTS/api/toolchain/main.cpp @@ -12,9 +12,14 @@ using namespace utest::v1; // Test functions declared as C functions to avoid issues with name mangling extern "C" { int testPacked(); + int testAlign(); int testUnused(); - int testDeprecated(); int testWeak(); + int testPure(); + int testForceInline(); + int testNoReturn(); + int testUnreachable(); + int testDeprecated(); } @@ -30,10 +35,15 @@ status_t test_setup(const size_t number_of_cases) { } Case cases[] = { - Case("Testing PACKED attribute", test_wrapper), - Case("Testing UNUSED attribute", test_wrapper), - Case("Testing DEPRECATED attribute", test_wrapper), - Case("Testing WEAK attribute", test_wrapper), + Case("Testing PACKED attribute", test_wrapper), + Case("Testing ALIGN attribute", test_wrapper), + Case("Testing UNUSED attribute", test_wrapper), + Case("Testing WEAK attribute", test_wrapper), + Case("Testing PURE attribute", test_wrapper), + Case("Testing FORCEINLINE attribute", test_wrapper), + Case("Testing NORETURN attribute", test_wrapper), + Case("Testing UNREACHABLE attribute", test_wrapper), + Case("Testing DEPRECATED attribute", test_wrapper), }; Specification specification(test_setup, cases); diff --git a/hal/api/toolchain.h b/hal/api/toolchain.h index b448fca102..b8756d206c 100644 --- a/hal/api/toolchain.h +++ b/hal/api/toolchain.h @@ -28,16 +28,16 @@ // Attributes -/** PACK +/** PACKED * Pack a structure, preventing any padding from being added between fields. * * @code * #include "toolchain.h" * - * struct foo { + * typedef struct { * char x; * int y; - * } PACKED; + * } PACKED foo; * @endcode */ #ifndef PACKED @@ -48,19 +48,37 @@ #endif #endif +/** ALIGN(N) + * Declare a variable to be aligned on an N-byte boundary. + * + * @code + * #include "toolchain.h" + * + * ALIGN(16) char a; + * @endcode + */ +#ifndef ALIGN +#if defined(__ICCARM__) +#define _ALIGN(N) _Pragma(#N) +#define ALIGN(N) _ALIGN(data_alignment=N) +#else +#define ALIGN(N) __attribute__((aligned(N))) +#endif +#endif + /** UNUSED * Declare a function argument to be unused, suppressing compiler warnings * * @code * #include "toolchain.h" * - * void foo(UNUSED int arg){ + * void foo(UNUSED int arg) { * * } * @endcode */ #ifndef UNUSED -#if defined(__GNUC__) || defined(__CC_ARM) || defined(__clang__) +#if defined(__GNUC__) || defined(__clang__) || defined(__CC_ARM) #define UNUSED __attribute__((__unused__)) #else #define UNUSED @@ -93,6 +111,95 @@ #endif #endif +/** PURE + * Hint to the compiler that a function depends only on parameters + * + * @code + * #include "toolchain.h" + * + * PURE int foo(int arg){ + * // no access to global variables + * } + * @endcode + */ +#ifndef PURE +#if defined(__GNUC__) || defined(__clang__) || defined(__CC_ARM) +#define PURE __attribute__((const)) +#else +#define PURE +#endif +#endif + +/** FORCEINLINE + * Declare a function that must always be inlined. Failure to inline + * such a function will result in an error. + * + * @code + * #include "toolchain.h" + * + * FORCEINLINE void foo() { + * + * } + * @endcode + */ +#ifndef FORCEINLINE +#if defined(__GNUC__) || defined(__clang__) || defined(__CC_ARM) +#define FORCEINLINE static inline __attribute__((always_inline)) +#elif defined(__ICCARM__) +#define FORCEINLINE _Pragma("inline=force") static +#else +#define FORCEINLINE static inline +#endif +#endif + +/** NORETURN + * Declare a function that will never return. + * + * @code + * #include "toolchain.h" + * + * NORETURN void foo() { + * // must never return + * while (1) {} + * } + * @endcode + */ +#ifndef NORETURN +#if defined(__GNUC__) || defined(__clang__) || defined(__CC_ARM) +#define NORETURN __attribute__((noreturn)) +#elif defined(__ICCARM__) +#define NORETURN __noreturn +#else +#define NORETURN +#endif +#endif + +/** UNREACHABLE + * An unreachable statement. If the statement is reached, + * behaviour is undefined. Useful in situations where the compiler + * cannot deduce the unreachability of code. + * + * @code + * #include "toolchain.h" + * + * void foo(int arg) { + * switch (arg) { + * case 1: return 1; + * case 2: return 2; + * ... + * } + * UNREACHABLE; + * } + * @endcode + */ +#ifndef UNREACHABLE +#if (defined(__GNUC__) || defined(__clang__)) && !defined(__CC_ARM) +#define UNREACHABLE __builtin_unreachable() +#else +#define UNREACHABLE while (1) +#endif +#endif + /** DEPRECATED("message string") * Mark a function declaration as deprecated, if it used then a warning will be * issued by the compiler possibly including the provided message. Note that not