summaryrefslogtreecommitdiff
path: root/payloads/libpayload
diff options
context:
space:
mode:
Diffstat (limited to 'payloads/libpayload')
-rw-r--r--payloads/libpayload/include/compiler.h15
-rw-r--r--payloads/libpayload/include/libpayload.h26
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