]> git.ozlabs.org Git - ccan/commitdiff
compiler: header for compiler-specific wrappers.
authorRusty Russell <rusty@rustcorp.com.au>
Sun, 26 Sep 2010 06:01:38 +0000 (15:31 +0930)
committerRusty Russell <rusty@rustcorp.com.au>
Sun, 26 Sep 2010 06:01:38 +0000 (15:31 +0930)
Currently they sit in each module.

ccan/compiler/LICENCE [new symlink]
ccan/compiler/_info [new file with mode: 0644]
ccan/compiler/compiler.h [new file with mode: 0644]
ccan/compiler/test/compile_fail-printf.c [new file with mode: 0644]
ccan/compiler/test/run-is_compile_constant.c [new file with mode: 0644]

diff --git a/ccan/compiler/LICENCE b/ccan/compiler/LICENCE
new file mode 120000 (symlink)
index 0000000..d19533a
--- /dev/null
@@ -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 (file)
index 0000000..ea4fe70
--- /dev/null
@@ -0,0 +1,62 @@
+#include <string.h>
+#include <stdio.h>
+#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 <rusty@rustcorp.com.au>
+ *
+ * Example:
+ *     #include <ccan/compiler/attributs.h>
+ *     #include <stdio.h>
+ *     #include <stdarg.h>
+ *
+ *     // 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 (file)
index 0000000..3601749
--- /dev/null
@@ -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 (file)
index 0000000..670126b
--- /dev/null
@@ -0,0 +1,22 @@
+#include <ccan/compiler/compiler.h>
+
+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 (file)
index 0000000..0a15280
--- /dev/null
@@ -0,0 +1,15 @@
+#include <ccan/compiler/compiler.h>
+#include <ccan/tap/tap.h>
+
+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();
+}