Skip to content

Commit

Permalink
compiler: header for compiler-specific wrappers.
Browse files Browse the repository at this point in the history
Currently they sit in each module.
  • Loading branch information
rustyrussell committed Sep 26, 2010
1 parent a8e0cfb commit 89f1301
Show file tree
Hide file tree
Showing 5 changed files with 242 additions and 0 deletions.
1 change: 1 addition & 0 deletions ccan/compiler/LICENCE
62 changes: 62 additions & 0 deletions ccan/compiler/_info
@@ -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;
}
142 changes: 142 additions & 0 deletions 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 */
22 changes: 22 additions & 0 deletions ccan/compiler/test/compile_fail-printf.c
@@ -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;
}
15 changes: 15 additions & 0 deletions ccan/compiler/test/run-is_compile_constant.c
@@ -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();
}

0 comments on commit 89f1301

Please sign in to comment.