Make common macros double-evaluation safe

I just got hit by a double-evaluation bug again, it's time to attempt
to fix this once more. Unfortunately there are several issues that don't
make this easy:

 - bitfield variables don't support typeof()
 - local macro variables that shadow others trigger -Werror=shadow
 - sign warnings with integer literal and unsigned var in typeof-MIN()
 - ({ statement expressions }) can not be used outside functions
 - romcc doesn't support any of the fancy GCC/clang extensions

This patch tries to address all of them as far as possible with macro
magic. We don't have the technology to solve the bitfield and
non-function context issues yet (__builtin_choose_expr() still throws a
"no statement expression outside a function" error if it's only in the
branch that's not chosen, unfortunately), so we'll have to provide
alternative macros for use in those cases (and we'll avoid making
__ALIGN_MASK() double-evaluation safe for now, since it would be
annoying to do that there and having an alignment mask with side
effects seems very unlikely). romcc can continue using unsafe versions
since we're hopefully not writing a lot of new code for it. Sign
warnings can be avoided in literal/variable comparisons by always using
the type of the variable there. Shadowing is avoided by picking very
explicit local variable names and using a special __COUNTER__ solution
for MIN() and MAX() (the only ones of these you're likely to nest).

Also add DIV_ROUND_UP() to libpayload since it's a generally quite
useful thing to have.

Change-Id: Iea35156c9aa9f6f2c7b8f00991418b746f44315d
Signed-off-by: Julius Werner <jwerner@chromium.org>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/32027
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
This commit is contained in:
Julius Werner 2015-05-22 18:09:48 -07:00 committed by Patrick Georgi
parent bac21f5b13
commit d371cf3336
10 changed files with 141 additions and 46 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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))
#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) tmp = a; \
a = (typeof(a)) b; \
b = (typeof(b)) tmp; \
} while (0)
__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)

View File

@ -355,12 +355,12 @@ GfxGmcInitializeSequencerModel (
if (ActiveChannel == 2) {
// Both controllers enabled
GMMx277C.Field.ActRd = MIN (DctChannel[0].D18F2x0F4_x40.Field.Trcd, DctChannel[1].D18F2x0F4_x40.Field.Trcd) + 5;
GMMx277C.Field.RasMActRd = MIN ((DctChannel[0].D18F2x0F4_x40.Field.Trc + 11 - (DctChannel[0].D18F2x0F4_x40.Field.Trcd + 5)),
GMMx277C.Field.ActRd = MIN_UNSAFE (DctChannel[0].D18F2x0F4_x40.Field.Trcd, DctChannel[1].D18F2x0F4_x40.Field.Trcd) + 5;
GMMx277C.Field.RasMActRd = MIN_UNSAFE ((DctChannel[0].D18F2x0F4_x40.Field.Trc + 11 - (DctChannel[0].D18F2x0F4_x40.Field.Trcd + 5)),
(DctChannel[1].D18F2x0F4_x40.Field.Trc + 11 - (DctChannel[1].D18F2x0F4_x40.Field.Trcd + 5)));
GMMx2780.Field.Ras2Ras = MIN (DctChannel[0].D18F2x0F4_x40.Field.Trc, DctChannel[1].D18F2x0F4_x40.Field.Trc) + 11 - 1;
GMMx2780.Field.Rp = MIN (DctChannel[0].D18F2x0F4_x40.Field.Trp, DctChannel[1].D18F2x0F4_x40.Field.Trp) + 5 - 1;
GMMx2780.Field.WrPlusRp = MIN (
GMMx2780.Field.Ras2Ras = MIN_UNSAFE (DctChannel[0].D18F2x0F4_x40.Field.Trc, DctChannel[1].D18F2x0F4_x40.Field.Trc) + 11 - 1;
GMMx2780.Field.Rp = MIN_UNSAFE (DctChannel[0].D18F2x0F4_x40.Field.Trp, DctChannel[1].D18F2x0F4_x40.Field.Trp) + 5 - 1;
GMMx2780.Field.WrPlusRp = MIN_UNSAFE (
((DctChannel[0].D18F2x084.Field.Twr == 0) ? 16 :
((DctChannel[0].D18F2x084.Field.Twr < 4) ? (DctChannel[0].D18F2x084.Field.Twr + 4) :
(DctChannel[0].D18F2x084.Field.Twr * 2)) + DctChannel[0].D18F2x0F4_x40.Field.Trp + 5),
@ -368,7 +368,7 @@ GfxGmcInitializeSequencerModel (
((DctChannel[1].D18F2x084.Field.Twr < 4) ? (DctChannel[1].D18F2x084.Field.Twr + 4) :
(DctChannel[1].D18F2x084.Field.Twr * 2)) + DctChannel[1].D18F2x0F4_x40.Field.Trp + 5)
) - 1;
GMMx2780.Field.BusTurn = (MIN (
GMMx2780.Field.BusTurn = (MIN_UNSAFE (
DctChannel[0].D18F2x084.Field.Tcwl + 5 +
DctChannel[0].D18F2x0F4_x41.Field.Twtr + 4 +
DctChannel[0].D18F2x08C.Field.TrwtTO + 2 ,

View File

@ -361,12 +361,12 @@ GfxGmcInitializeSequencerModel (
if (ActiveChannel == 2) {
// Both controllers enabled
GMMx277C.Field.ActRd = MIN (DctChannel[0].D18F2x0F4_x40.Field.Trcd, DctChannel[1].D18F2x0F4_x40.Field.Trcd) + 5;
GMMx277C.Field.RasMActRd = MIN ((DctChannel[0].D18F2x0F4_x40.Field.Trc + 11 - (DctChannel[0].D18F2x0F4_x40.Field.Trcd + 5)),
GMMx277C.Field.ActRd = MIN_UNSAFE (DctChannel[0].D18F2x0F4_x40.Field.Trcd, DctChannel[1].D18F2x0F4_x40.Field.Trcd) + 5;
GMMx277C.Field.RasMActRd = MIN_UNSAFE ((DctChannel[0].D18F2x0F4_x40.Field.Trc + 11 - (DctChannel[0].D18F2x0F4_x40.Field.Trcd + 5)),
(DctChannel[1].D18F2x0F4_x40.Field.Trc + 11 - (DctChannel[1].D18F2x0F4_x40.Field.Trcd + 5)));
GMMx2780.Field.Ras2Ras = MIN (DctChannel[0].D18F2x0F4_x40.Field.Trc, DctChannel[1].D18F2x0F4_x40.Field.Trc) + 11 - 1;
GMMx2780.Field.Rp = MIN (DctChannel[0].D18F2x0F4_x40.Field.Trp, DctChannel[1].D18F2x0F4_x40.Field.Trp) + 5 - 1;
GMMx2780.Field.WrPlusRp = MIN (
GMMx2780.Field.Ras2Ras = MIN_UNSAFE (DctChannel[0].D18F2x0F4_x40.Field.Trc, DctChannel[1].D18F2x0F4_x40.Field.Trc) + 11 - 1;
GMMx2780.Field.Rp = MIN_UNSAFE (DctChannel[0].D18F2x0F4_x40.Field.Trp, DctChannel[1].D18F2x0F4_x40.Field.Trp) + 5 - 1;
GMMx2780.Field.WrPlusRp = MIN_UNSAFE (
((DctChannel[0].D18F2x084.Field.Twr == 0) ? 16 :
((DctChannel[0].D18F2x084.Field.Twr < 4) ? (DctChannel[0].D18F2x084.Field.Twr + 4) :
(DctChannel[0].D18F2x084.Field.Twr * 2)) + DctChannel[0].D18F2x0F4_x40.Field.Trp + 5),
@ -374,7 +374,7 @@ GfxGmcInitializeSequencerModel (
((DctChannel[1].D18F2x084.Field.Twr < 4) ? (DctChannel[1].D18F2x084.Field.Twr + 4) :
(DctChannel[1].D18F2x084.Field.Twr * 2)) + DctChannel[1].D18F2x0F4_x40.Field.Trp + 5)
) - 1;
GMMx2780.Field.BusTurn = (MIN (
GMMx2780.Field.BusTurn = (MIN_UNSAFE (
DctChannel[0].D18F2x084.Field.Tcwl + 5 +
DctChannel[0].D18F2x0F4_x41.Field.Twtr + 4 +
DctChannel[0].D18F2x08C.Field.TrwtTO + 2 ,

View File

@ -340,30 +340,30 @@ GfxGmcInitializeSequencerTN (
GnbRegisterReadTN (TYPE_GMM , 0x27fc , &ex1061.Value, 0, GnbLibGetHeader (Gfx));
if (((DramChannelPresent & GNB_GFX_DRAM_CH_0_PRESENT) != 0) && ((DramChannelPresent & GNB_GFX_DRAM_CH_1_PRESENT) != 0)) {
ex1047.Field.ex1047_0 = (MIN (DctChannel.D18F2x200_dct0_mp0.Field.Trcd, DctChannel.D18F2x200_dct1_mp0.Field.Trcd) * scale_mp0) / 100;
ex1047.Field.ex1047_0 = (MIN_UNSAFE (DctChannel.D18F2x200_dct0_mp0.Field.Trcd, DctChannel.D18F2x200_dct1_mp0.Field.Trcd) * scale_mp0) / 100;
ex1047.Field.ex1047_1 = ex1047.Field.ex1047_0;
ex1047.Field.ex1047_2 = (MIN ((DctChannel.D18F2x204_dct0_mp0.Field.Trc - DctChannel.D18F2x200_dct0_mp0.Field.Trcd),
ex1047.Field.ex1047_2 = (MIN_UNSAFE ((DctChannel.D18F2x204_dct0_mp0.Field.Trc - DctChannel.D18F2x200_dct0_mp0.Field.Trcd),
(DctChannel.D18F2x204_dct1_mp0.Field.Trc - DctChannel.D18F2x200_dct1_mp0.Field.Trcd)) * scale_mp0) / 100;
ex1047.Field.ex1047_3 = ex1047.Field.ex1047_2;
ex1048.Field.ex1048_0 = (MIN (DctChannel.D18F2x204_dct0_mp0.Field.Trc, DctChannel.D18F2x204_dct1_mp0.Field.Trc) * scale_mp0) / 100;
ex1048.Field.ex1048_1 = (MIN (DctChannel.D18F2x200_dct0_mp0.Field.Trp, DctChannel.D18F2x200_dct1_mp0.Field.Trp) * scale_mp0) / 100;
ex1048.Field.ex1048_2 = (MIN ((DctChannel.D18F2x22C_dct0_mp0.Field.Twr + DctChannel.D18F2x200_dct0_mp0.Field.Trp),
ex1048.Field.ex1048_0 = (MIN_UNSAFE (DctChannel.D18F2x204_dct0_mp0.Field.Trc, DctChannel.D18F2x204_dct1_mp0.Field.Trc) * scale_mp0) / 100;
ex1048.Field.ex1048_1 = (MIN_UNSAFE (DctChannel.D18F2x200_dct0_mp0.Field.Trp, DctChannel.D18F2x200_dct1_mp0.Field.Trp) * scale_mp0) / 100;
ex1048.Field.ex1048_2 = (MIN_UNSAFE ((DctChannel.D18F2x22C_dct0_mp0.Field.Twr + DctChannel.D18F2x200_dct0_mp0.Field.Trp),
(DctChannel.D18F2x22C_dct1_mp0.Field.Twr + DctChannel.D18F2x200_dct1_mp0.Field.Trp)) * scale_mp0) / 100;
ex1048.Field.ex1048_3 = ((MIN ((DctChannel.D18F2x20C_dct0_mp0.Field.Tcwl + 4 + DctChannel.D18F2x20C_dct0_mp0.Field.Twtr + DctChannel.D18F2x21C_dct0_mp0.Field.TrwtTO),
ex1048.Field.ex1048_3 = ((MIN_UNSAFE ((DctChannel.D18F2x20C_dct0_mp0.Field.Tcwl + 4 + DctChannel.D18F2x20C_dct0_mp0.Field.Twtr + DctChannel.D18F2x21C_dct0_mp0.Field.TrwtTO),
(DctChannel.D18F2x20C_dct1_mp0.Field.Tcwl + 4 + DctChannel.D18F2x20C_dct1_mp0.Field.Twtr + DctChannel.D18F2x21C_dct1_mp0.Field.TrwtTO)) / 2) * scale_mp0) / 100;
ex1060.Field.ex1060_0 = (MIN (DctChannel.D18F2x200_dct0_mp1.Field.Trcd, DctChannel.D18F2x200_dct1_mp1.Field.Trcd) * scale_mp1) / 100;
ex1060.Field.ex1060_0 = (MIN_UNSAFE (DctChannel.D18F2x200_dct0_mp1.Field.Trcd, DctChannel.D18F2x200_dct1_mp1.Field.Trcd) * scale_mp1) / 100;
ex1060.Field.ex1060_1 = ex1060.Field.ex1060_0;
ex1060.Field.ex1060_2 = (MIN ((DctChannel.D18F2x204_dct0_mp1.Field.Trc - DctChannel.D18F2x200_dct0_mp1.Field.Trcd),
ex1060.Field.ex1060_2 = (MIN_UNSAFE ((DctChannel.D18F2x204_dct0_mp1.Field.Trc - DctChannel.D18F2x200_dct0_mp1.Field.Trcd),
(DctChannel.D18F2x204_dct1_mp1.Field.Trc - DctChannel.D18F2x200_dct1_mp1.Field.Trcd)) * scale_mp1) / 100;
ex1060.Field.ex1060_3 = ex1060.Field.ex1060_2;
ex1061.Field.ex1061_0 = (MIN (DctChannel.D18F2x204_dct0_mp1.Field.Trc, DctChannel.D18F2x204_dct1_mp1.Field.Trc) * scale_mp1) / 100;
ex1061.Field.ex1061_1 = (MIN (DctChannel.D18F2x200_dct0_mp1.Field.Trp, DctChannel.D18F2x200_dct1_mp1.Field.Trp) * scale_mp1) / 100;
ex1061.Field.ex1061_2 = (MIN ((DctChannel.D18F2x22C_dct0_mp1.Field.Twr + DctChannel.D18F2x200_dct0_mp1.Field.Trp),
ex1061.Field.ex1061_0 = (MIN_UNSAFE (DctChannel.D18F2x204_dct0_mp1.Field.Trc, DctChannel.D18F2x204_dct1_mp1.Field.Trc) * scale_mp1) / 100;
ex1061.Field.ex1061_1 = (MIN_UNSAFE (DctChannel.D18F2x200_dct0_mp1.Field.Trp, DctChannel.D18F2x200_dct1_mp1.Field.Trp) * scale_mp1) / 100;
ex1061.Field.ex1061_2 = (MIN_UNSAFE ((DctChannel.D18F2x22C_dct0_mp1.Field.Twr + DctChannel.D18F2x200_dct0_mp1.Field.Trp),
(DctChannel.D18F2x22C_dct1_mp1.Field.Twr + DctChannel.D18F2x200_dct1_mp1.Field.Trp)) * scale_mp1) / 100;
ex1061.Field.ex1061_3 = ((MIN ((DctChannel.D18F2x20C_dct0_mp1.Field.Tcwl + 4 + DctChannel.D18F2x20C_dct0_mp1.Field.Twtr + DctChannel.D18F2x21C_dct0_mp1.Field.TrwtTO),
ex1061.Field.ex1061_3 = ((MIN_UNSAFE ((DctChannel.D18F2x20C_dct0_mp1.Field.Tcwl + 4 + DctChannel.D18F2x20C_dct0_mp1.Field.Twtr + DctChannel.D18F2x21C_dct0_mp1.Field.TrwtTO),
(DctChannel.D18F2x20C_dct1_mp1.Field.Tcwl + 4 + DctChannel.D18F2x20C_dct1_mp1.Field.Twtr + DctChannel.D18F2x21C_dct1_mp1.Field.TrwtTO)) / 2) * scale_mp1) / 100;
} else if ((DramChannelPresent & GNB_GFX_DRAM_CH_0_PRESENT) != 0) {

View File

@ -735,8 +735,10 @@ typedef UINTN *BASE_LIST;
@return The absolute value of the signed operand.
**/
#ifndef ABS
#define ABS(a) \
(((a) < 0) ? (-(a)) : (a))
#endif
//
// Status codes common to all execution phases

View File

@ -941,8 +941,10 @@ typedef UINTN *BASE_LIST;
@return The absolute value of the signed operand.
**/
#ifndef ABS
#define ABS(a) \
(((a) < 0) ? (-(a)) : (a))
#endif
//
// Status codes common to all execution phases

View File

@ -718,8 +718,10 @@ typedef UINTN *BASE_LIST;
@return The absolute value of the signed operand.
**/
#ifndef ABS
#define ABS(a) \
(((a) < 0) ? (-(a)) : (a))
#endif
//
// Status codes common to all execution phases