summaryrefslogtreecommitdiff
path: root/src/commonlib
diff options
context:
space:
mode:
Diffstat (limited to 'src/commonlib')
-rw-r--r--src/commonlib/include/commonlib/compiler.h15
-rw-r--r--src/commonlib/include/commonlib/helpers.h77
2 files changed, 72 insertions, 20 deletions
diff --git a/src/commonlib/include/commonlib/compiler.h b/src/commonlib/include/commonlib/compiler.h
index 2e0c454fc9..5078759360 100644
--- a/src/commonlib/include/commonlib/compiler.h
+++ b/src/commonlib/include/commonlib/compiler.h
@@ -48,4 +48,19 @@
#define __always_inline inline __attribute__((always_inline))
#endif
+/* 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/src/commonlib/include/commonlib/helpers.h b/src/commonlib/include/commonlib/helpers.h
index adc43ca98b..4429ea41c3 100644
--- a/src/commonlib/include/commonlib/helpers.h
+++ b/src/commonlib/include/commonlib/helpers.h
@@ -16,6 +16,7 @@
/* This file is for helpers for both coreboot firmware and its utilities. */
#ifndef __ASSEMBLER__
+#include <commonlib/compiler.h>
#include <stddef.h>
#endif
@@ -29,35 +30,71 @@
#define ALIGN_DOWN(x, a) ((x) & ~((__typeof__(x))(a)-1UL))
#define IS_ALIGNED(x, a) (((x) & ((__typeof__(x))(a)-1UL)) == 0)
+/* 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; \
+})
+
+#ifdef __ROMCC__ /* romcc doesn't support __builtin_choose_expr() */
+#define __CMP(a, b, op) __CMP_UNSAFE(a, b, op)
+#else
+#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))
+#endif
+
#ifndef MIN
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MIN(a, b) __CMP(a, b, <)
#endif
#ifndef MAX
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MAX(a, b) __CMP(a, b, >)
#endif
-#define ABS(a) (((a) < 0) ? (-(a)) : (a))
-#define IS_POWER_OF_2(x) (((x) & ((x) - 1)) == 0)
-#define DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y))
-#define SWAP(a, b) do { \
- typeof(a) tmp = a; \
- a = (typeof(a)) b; \
- b = (typeof(b)) tmp; \
- } while (0)
+
+#ifndef ABS
+#define ABS(a) ({ \
+ __typeof__(a) _abs_local_a = (a); \
+ (_abs_local_a < 0) ? (-_abs_local_a) : _abs_local_a; \
+})
+#endif
+
+#define IS_POWER_OF_2(x) ({ \
+ __typeof__(x) _power_local_x = (x); \
+ (_power_local_x & (_power_local_x - 1)) == 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; \
+})
+
+#define SWAP(a, b) do { \
+ __typeof__(&(a)) _swap_local_a = &(a); \
+ __typeof__(&(b)) _swap_local_b = &(b); \
+ __typeof__(a) _swap_local_tmp = *_swap_local_a; \
+ *_swap_local_a = *_swap_local_b; \
+ *_swap_local_b = _swap_local_tmp; \
+} while (0)
+
/*
* Divide positive or negative dividend by positive divisor and round
* to closest integer. Result is undefined for negative divisors and
* for negative dividends if the divisor variable type is unsigned.
*/
-#define DIV_ROUND_CLOSEST(x, divisor)( \
-{ \
- typeof(x) __x = x; \
- typeof(divisor) __d = divisor; \
- (((typeof(x))-1) > 0 || \
- ((typeof(divisor))-1) > 0 || (__x) > 0) ? \
- (((__x) + ((__d) / 2)) / (__d)) : \
- (((__x) - ((__d) / 2)) / (__d)); \
-} \
-)
+#define DIV_ROUND_CLOSEST(x, divisor)({ \
+ __typeof__(x) _div_local_x = (x); \
+ __typeof__(divisor) _div_local_d = (divisor); \
+ (((__typeof__(x))-1) > 0 || \
+ ((__typeof__(divisor))-1) > 0 || (_div_local_x) > 0) ? \
+ ((_div_local_x + (_div_local_d / 2)) / _div_local_d) : \
+ ((_div_local_x - (_div_local_d / 2)) / _div_local_d); \
+})
/* Standard units. */
#define KiB (1<<10)