From: Rusty Russell Date: Sun, 26 Sep 2010 06:01:38 +0000 (+0930) Subject: compiler: header for compiler-specific wrappers. X-Git-Url: https://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=89f1301ed2b65cdb4730bb28c42428873a69faec compiler: header for compiler-specific wrappers. Currently they sit in each module. --- diff --git a/ccan/compiler/LICENCE b/ccan/compiler/LICENCE new file mode 120000 index 00000000..d19533a5 --- /dev/null +++ b/ccan/compiler/LICENCE @@ -0,0 +1 @@ +../../licences/LGPL-3 \ No newline at end of file diff --git a/ccan/compiler/_info b/ccan/compiler/_info new file mode 100644 index 00000000..ea4fe702 --- /dev/null +++ b/ccan/compiler/_info @@ -0,0 +1,62 @@ +#include +#include +#include "config.h" + +/** + * compiler - macros for common compiler extensions + * + * Abstracts away some compiler hints. Currently these include: + * - UNLIKELY_FUNCTION_ATTRIBUTE + * For functions not called in fast paths (aka. cold functions) + * - PRINTF_ATTRIBUTE + * For functions which take printf-style parameters. + * - IDEMPOTENT_ATTRIBUTE + * For functions which return the same value for same parameters. + * - NEEDED_ATTRIBUTE + * For functions and variables which must be emitted even if unused. + * - UNNEEDED_ATTRIBUTE + * For functions and variables which need not be emitted if unused. + * - IS_COMPILE_CONSTANT + * For using different tradeoffs for compiletime vs runtime evaluation. + * + * Licence: LGPL (3 or any later version) + * Author: Rusty Russell + * + * Example: + * #include + * #include + * #include + * + * // Example of a (slow-path) logging function. + * static int log_threshold = 2; + * static void UNLIKELY_FUNCTION_ATTRIBUTE PRINTF_ATTRIBUTE(2,3) + * logger(int level, const char *fmt, ...) + * { + * va_list ap; + * va_start(ap, fmt); + * if (level >= log_threshold) + * vfprintf(stderr, fmt, ap); + * va_end(ap); + * } + * + * int main(int argc, char *argv[]) + * { + * if (argc != 1) { + * logger(3, "Don't want %i arguments!\n", argc-1); + * return 1; + * } + * return 0; + * } + */ +int main(int argc, char *argv[]) +{ + /* Expect exactly one argument */ + if (argc != 2) + return 1; + + if (strcmp(argv[1], "depends") == 0) { + return 0; + } + + return 1; +} diff --git a/ccan/compiler/compiler.h b/ccan/compiler/compiler.h new file mode 100644 index 00000000..36017490 --- /dev/null +++ b/ccan/compiler/compiler.h @@ -0,0 +1,142 @@ +#ifndef CCAN_COMPILER_H +#define CCAN_COMPILER_H +#include "config.h" + +#if HAVE_ATTRIBUTE_COLD +/** + * UNLIKELY_FUNCTION_ATTRIBUTE - a function is unlikely to be called. + * + * Used to mark an unlikely code path and optimize appropriately. + * It is usually used on logging or error routines. + * + * Example: + * void UNLIKELY_FUNCTION_ATTRIBUTE moan(const char *reason) + * { + * fprintf(stderr, "Error: %s (%s)\n", reason, strerror(errno)); + * } + */ +#define UNLIKELY_FUNCTION_ATTRIBUTE __attribute__((cold)) +#else +#define UNLIKELY_FUNCTION_ATTRIBUTE +#endif + +#if HAVE_ATTRIBUTE_PRINTF +/** + * PRINTF_ATTRIBUTE - a function takes printf-style arguments + * nfmt: the 1-based number of the function's format argument. + * narg: the 1-based number of the function's first variable argument. + * + * This allows the compiler to check your parameters as it does for printf(). + * + * Example: + * void PRINTF_ATTRIBUTE(2,3) my_printf(char *prefix, char *format, ...); + */ +#define PRINTF_ATTRIBUTE(nfmt, narg) \ + __attribute__((format(__printf__, nfmt, narg))) +#else +#define PRINTF_ATTRIBUTE(nfmt, narg) +#endif + +#if HAVE_ATTRIBUTE_CONST +/** + * IDEMPOTENT_ATTRIBUTE - a function's return depends only on its argument + * + * This allows the compiler to assume that the function will return the exact + * same value for the exact same arguments. This implies that the function + * must not use global variables, or dereference pointer arguments. + */ +#define IDEMPOTENT_ATTRIBUTE __attribute__((const)) +#else +#define IDEMPOTENT_ATTRIBUTE +#endif + +#if HAVE_ATTRIBUTE_UNUSED +/** + * UNNEEDED_ATTRIBUTE - a parameter/variable/function may not be needed + * + * This suppresses warnings about unused variables or parameters, but tells + * the compiler that if it is unused it need not emit it into the source code. + * + * Example: + * // With some config options, this is unnecessary. + * static UNNEEDED_ATTRIBUTE int counter; + * ... + * #ifdef DEBUG + * counter++; + * #endif + * ... + * // With some config options, this is unnecessary. + * static UNNEEDED_ATTRIBUTE int add_to_counter(int add) + * { + * counter += add; + * } + */ +#define UNNEEDED_ATTRIBUTE __attribute__((unused)) + +#if HAVE_ATTRIBUTE_USED +/** + * NEEDED_ATTRIBUTE - a parameter/variable/function is needed + * + * This suppresses warnings about unused variables or parameters, but tells + * the compiler that it must exist even if it (seems) unused. + * + * Example: + * // Even if this is unused, these are vital for debugging. + * static UNNEEDED_ATTRIBUTE int counter; + * static UNNEEDED_ATTRIBUTE void dump_counter(void) + * { + * printf("Counter is %i\n", counter); + * } + */ +#define NEEDED_ATTRIBUTE __attribute__((used)) +#else +/* Before used, unused functions and vars were always emitted. */ +#define NEEDED_ATTRIBUTE __attribute__((unused)) +#endif +#else +#define UNNEEDED_ATTRIBUTE +#define NEEDED_ATTRIBUTE +#endif + +#if HAVE_BUILTIN_CONSTANT_P +/** + * IS_COMPILE_CONSTANT - does the compiler know the value of this expression? + * @expr: the expression to evaluate + * + * When an expression manipulation is complicated, it is usually better to + * implement it in a function. However, if the expression being manipulated is + * known at compile time, it is better to have the compiler see the entire + * expression so it can simply substitute the result. + * + * This can be done using the IS_COMPILE_CONSTANT() macro. + * + * Example: + * enum greek { ALPHA, BETA, GAMMA, DELTA, EPSILON }; + * + * // Out-of-line version. + * const char *greek_name(enum greek greek); + * + * // Inline version. + * static inline _greek_name(enum greek greek) + * { + * switch (greek) { + * case ALPHA: return "alpha"; + * case BETA: return "beta"; + * case GAMMA: return "gamma"; + * case DELTA: return "delta"; + * case EPSILON: return "epsilon"; + * default: return "**INVALID**"; + * } + * } + * + * // Use inline if compiler knows answer. Otherwise call function + * // to avoid copies of the same code everywhere. + * #define greek_name(g) \ + * (IS_COMPILE_CONSTANT(greek) ? _greek_name(g) : greek_name(g)) + */ +#define IS_COMPILE_CONSTANT(expr) __builtin_constant_p(expr) +#else +/* If we don't know, assume it's not. */ +#define IS_COMPILE_CONSTANT(expr) 0 +#endif +#endif /* CCAN_COMPILER_H */ diff --git a/ccan/compiler/test/compile_fail-printf.c b/ccan/compiler/test/compile_fail-printf.c new file mode 100644 index 00000000..670126bb --- /dev/null +++ b/ccan/compiler/test/compile_fail-printf.c @@ -0,0 +1,22 @@ +#include + +static void PRINTF_ATTRIBUTE(2,3) my_printf(int x, const char *fmt, ...) +{ +} + +int main(int argc, char *argv[]) +{ + unsigned int i = 0; + + my_printf(1, "Not a pointer " +#ifdef FAIL + "%p", +#if !HAVE_ATTRIBUTE_PRINTF +#error "Unfortunately we don't fail if !HAVE_ATTRIBUTE_PRINTF." +#endif +#else + "%i", +#endif + i); + return 0; +} diff --git a/ccan/compiler/test/run-is_compile_constant.c b/ccan/compiler/test/run-is_compile_constant.c new file mode 100644 index 00000000..0a15280b --- /dev/null +++ b/ccan/compiler/test/run-is_compile_constant.c @@ -0,0 +1,15 @@ +#include +#include + +int main(int argc, char *argv[]) +{ + plan_tests(2); + + ok1(!IS_COMPILE_CONSTANT(argc)); +#ifdef HAVE_BUILTIN_CONSTANT_P + ok1(IS_COMPILE_CONSTANT(7)); +#else + pass("If !HAVE_BUILTIN_CONSTANT_P, IS_COMPILE_CONSTANT always false"); +#endif + return exit_status(); +}