diff options
Diffstat (limited to 'payloads')
-rw-r--r-- | payloads/libpayload/include/compiler.h | 15 | ||||
-rw-r--r-- | payloads/libpayload/include/libpayload.h | 26 |
2 files changed, 39 insertions, 2 deletions
diff --git a/payloads/libpayload/include/compiler.h b/payloads/libpayload/include/compiler.h index a830239009..fa9c78bd36 100644 --- a/payloads/libpayload/include/compiler.h +++ b/payloads/libpayload/include/compiler.h @@ -26,4 +26,19 @@ #define __always_unused __attribute__((unused)) #define __must_check __attribute__((warn_unused_result)) +/* This evaluates to the type of the first expression, unless that is constant + in which case it evalutates to the type of the second. This is useful when + assigning macro parameters to temporary variables, because that would + normally circumvent the special loosened type promotion rules for integer + literals. By using this macro, the promotion can happen at the time the + literal is assigned to the temporary variable. If the literal doesn't fit in + the chosen type, -Werror=overflow will catch it, so this should be safe. */ +#define __TYPEOF_UNLESS_CONST(expr, fallback_expr) typeof( \ + __builtin_choose_expr(__builtin_constant_p(expr), fallback_expr, expr)) + +/* This creates a unique local variable name for use in macros. */ +#define __TMPNAME_3(i) __tmpname_##i +#define __TMPNAME_2(i) __TMPNAME_3(i) +#define __TMPNAME __TMPNAME_2(__COUNTER__) + #endif diff --git a/payloads/libpayload/include/libpayload.h b/payloads/libpayload/include/libpayload.h index 0b9ab0dcd5..3a84b3b038 100644 --- a/payloads/libpayload/include/libpayload.h +++ b/payloads/libpayload/include/libpayload.h @@ -66,10 +66,32 @@ #include <pci.h> #include <archive.h> -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#define MAX(a,b) ((a) > (b) ? (a) : (b)) +/* Double-evaluation unsafe min/max, for bitfields and outside of functions */ +#define __CMP_UNSAFE(a, b, op) ((a) op (b) ? (a) : (b)) +#define MIN_UNSAFE(a, b) __CMP_UNSAFE(a, b, <) +#define MAX_UNSAFE(a, b) __CMP_UNSAFE(a, b, >) + +#define __CMP_SAFE(a, b, op, var_a, var_b) ({ \ + __TYPEOF_UNLESS_CONST(a, b) var_a = (a); \ + __TYPEOF_UNLESS_CONST(b, a) var_b = (b); \ + var_a op var_b ? var_a : var_b; \ +}) + +#define __CMP(a, b, op) __builtin_choose_expr( \ + __builtin_constant_p(a) && __builtin_constant_p(b), \ + __CMP_UNSAFE(a, b, op), __CMP_SAFE(a, b, op, __TMPNAME, __TMPNAME)) + +#define MIN(a, b) __CMP(a, b, <) +#define MAX(a, b) __CMP(a, b, >) + #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#define DIV_ROUND_UP(x, y) ({ \ + typeof(x) _div_local_x = (x); \ + typeof(y) _div_local_y = (y); \ + (_div_local_x + _div_local_y - 1) / _div_local_y; \ +}) + static inline u32 div_round_up(u32 n, u32 d) { return (n + d - 1) / d; } #define LITTLE_ENDIAN 1234 |