From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
To: Eric Blake <eblake@redhat.com>
Cc: qemu-devel@nongnu.org, dirty.ice.hu@gmail.com, f4bug@amsat.org,
Gerd Hoffmann <kraxel@redhat.com>,
Peter Crosthwaite <crosthwaite.peter@gmail.com>,
Richard Henderson <rth@twiddle.net>,
Paolo Bonzini <pbonzini@redhat.com>,
Juan Quintela <quintela@redhat.com>
Subject: Re: [Qemu-devel] [PATCH v2] osdep: Make MIN/MAX evaluate arguments only once
Date: Mon, 7 Jan 2019 09:49:28 +0000 [thread overview]
Message-ID: <20190107094927.GA2442@work-vm> (raw)
In-Reply-To: <20190106013802.3645-1-eblake@redhat.com>
* Eric Blake (eblake@redhat.com) wrote:
> Add the macro QEMU_TYPEOF() to access __auto_type in new enough
> compilers, while falling back to typeof on older compilers (the
> fallback doesn't handle variable length arrays, but we don't use
> those; it also expands to more text).
>
> Then use that macro to make MIN/MAX only evaluate their argument
> once; this uses type promotion (by adding to 0) to work around
> the fact that typeof(bitfield) won't compile. However, we are
> unable to work around gcc refusing to compile ({}) in a constant
> context, even when only used in the dead branch of a
> __builtin_choose_expr(), so we have to provide a second macro
> pair MIN_CONST and MAX_CONST for use when both arguments are
> known to be compile-time constants and where the result must
> also be usable in constant contexts.
>
> Fix the resulting callsites that compute a compile-time constant
> min or max to use the new macros.
>
> Signed-off-by: Eric Blake <eblake@redhat.com>
>
> ---
> v2: Force use of our smart macros, and make macro handle bitfields,
> constant expressions, and older compilers [Zoltan]
> ---
> hw/usb/hcd-xhci.h | 2 +-
> include/exec/cpu-defs.h | 2 +-
> include/qemu/compiler.h | 10 +++++++++
> include/qemu/osdep.h | 46 ++++++++++++++++++++++++++++++++++-------
> migration/qemu-file.c | 2 +-
> 5 files changed, 51 insertions(+), 11 deletions(-)
>
> diff --git a/hw/usb/hcd-xhci.h b/hw/usb/hcd-xhci.h
> index fc36a4c787c..10beee9a7b1 100644
> --- a/hw/usb/hcd-xhci.h
> +++ b/hw/usb/hcd-xhci.h
> @@ -210,7 +210,7 @@ struct XHCIState {
> uint32_t dcbaap_high;
> uint32_t config;
>
> - USBPort uports[MAX(MAXPORTS_2, MAXPORTS_3)];
> + USBPort uports[MAX_CONST(MAXPORTS_2, MAXPORTS_3)];
> XHCIPort ports[MAXPORTS];
> XHCISlot slots[MAXSLOTS];
> uint32_t numports;
> diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h
> index 6a60f94a41d..5b2fd46f687 100644
> --- a/include/exec/cpu-defs.h
> +++ b/include/exec/cpu-defs.h
> @@ -90,7 +90,7 @@ typedef uint64_t target_ulong;
> * of tlb_table inside env (which is non-trivial but not huge).
> */
> #define CPU_TLB_BITS \
> - MIN(8, \
> + MIN_CONST(8, \
> TCG_TARGET_TLB_DISPLACEMENT_BITS - CPU_TLB_ENTRY_BITS - \
> (NB_MMU_MODES <= 1 ? 0 : \
> NB_MMU_MODES <= 2 ? 1 : \
> diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h
> index 261842beae2..3bf6f68a6b0 100644
> --- a/include/qemu/compiler.h
> +++ b/include/qemu/compiler.h
> @@ -191,4 +191,14 @@
> #define QEMU_GENERIC9(x, a0, ...) QEMU_GENERIC_IF(x, a0, QEMU_GENERIC8(x, __VA_ARGS__))
> #define QEMU_GENERIC10(x, a0, ...) QEMU_GENERIC_IF(x, a0, QEMU_GENERIC9(x, __VA_ARGS__))
>
> +/*
> + * Automatic type deduction, to be used as:
> + * QEMU_TYPEOF(expr) name = expr;
> + */
> +#if QEMU_GNUC_PREREQ(4, 9)
> +# define QEMU_TYPEOF(a) __auto_type
> +#else
> +# define QEMU_TYPEOF(a) typeof(a)
> +#endif
> +
> #endif /* COMPILER_H */
> diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
> index 3bf48bcdec0..821ce627f73 100644
> --- a/include/qemu/osdep.h
> +++ b/include/qemu/osdep.h
> @@ -232,18 +232,48 @@ extern int daemon(int, int);
> #define SIZE_MAX ((size_t)-1)
> #endif
>
> -#ifndef MIN
> -#define MIN(a, b) (((a) < (b)) ? (a) : (b))
> -#endif
> -#ifndef MAX
> -#define MAX(a, b) (((a) > (b)) ? (a) : (b))
> -#endif
> +/*
> + * Two variations of MIN/MAX macros. The first is for runtime use, and
> + * evaluates arguments only once (so it is safe even with side
> + * effects), but will not work in constant contexts (such as array
> + * size declarations). The second is for compile-time use, where
> + * evaluating arguments twice is safe because the result is going to
> + * be constant anyway.
> + */
> +#undef MIN
> +#define MIN(a, b) \
> + ({ \
> + QEMU_TYPEOF((a) + 0) _a = (a) + 0; \
> + QEMU_TYPEOF((b) + 0) _b = (b) + 0; \
> + _a < _b ? _a : _b; \
> + })
> +#define MIN_CONST(a, b) \
> + __builtin_choose_expr( \
> + __builtin_constant_p(a) && __builtin_constant_p(b), \
> + (a) < (b) ? (a) : (b), \
> + __builtin_unreachable())
Why do these need to be separate macros? Can't you just put the
non-constant code in what you have as the 'builtin_unreachable' side of
the choose_expr:
#define DMIN(a,b) __builtin_choose_expr( \
__builtin_constant_p(a) && __builtin_constant_p(b), \
(a) < (b) ? (a) : (b), \
({ \
QEMU_TYPEOF((a) + 0) _a = (a) + 0; \
QEMU_TYPEOF((b) + 0) _b = (b) + 0; \
_a < _b ? _a : _b; \
}))
Dave
> +#undef MAX
> +#define MAX(a, b) \
> + ({ \
> + QEMU_TYPEOF((a) + 0) _a = (a) + 0; \
> + QEMU_TYPEOF((b) + 0) _b = (b) + 0; \
> + _a > _b ? _a : _b; \
> + })
> +#define MAX_CONST(a, b) \
> + __builtin_choose_expr( \
> + __builtin_constant_p(a) && __builtin_constant_p(b), \
> + (a) > (b) ? (a) : (b), \
> + __builtin_unreachable())
>
> /* Minimum function that returns zero only iff both values are zero.
> * Intended for use with unsigned values only. */
> #ifndef MIN_NON_ZERO
> -#define MIN_NON_ZERO(a, b) ((a) == 0 ? (b) : \
> - ((b) == 0 ? (a) : (MIN(a, b))))
> +#define MIN_NON_ZERO(a, b) \
> + ({ \
> + QEMU_TYPEOF((a) + 0) _a = (a) + 0; \
> + QEMU_TYPEOF((b) + 0) _b = (b) + 0; \
> + _a == 0 ? _b : (_b == 0 || _b > _a) ? _a : _b; \
> + })
> #endif
>
> /* Round number down to multiple */
> diff --git a/migration/qemu-file.c b/migration/qemu-file.c
> index 977b9ae07c1..9746cbec0f3 100644
> --- a/migration/qemu-file.c
> +++ b/migration/qemu-file.c
> @@ -31,7 +31,7 @@
> #include "trace.h"
>
> #define IO_BUF_SIZE 32768
> -#define MAX_IOV_SIZE MIN(IOV_MAX, 64)
> +#define MAX_IOV_SIZE MIN_CONST(IOV_MAX, 64)
>
> struct QEMUFile {
> const QEMUFileOps *ops;
> --
> 2.20.1
>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
next prev parent reply other threads:[~2019-01-07 9:54 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-01-06 1:38 [Qemu-devel] [PATCH v2] osdep: Make MIN/MAX evaluate arguments only once Eric Blake
2019-01-06 8:32 ` Richard Henderson
2019-01-07 14:22 ` Eric Blake
2019-01-07 9:49 ` Dr. David Alan Gilbert [this message]
2019-01-07 14:24 ` Eric Blake
2019-01-07 15:07 ` Dr. David Alan Gilbert
2019-01-07 16:16 ` Eric Blake
2019-01-07 16:24 ` Dr. David Alan Gilbert
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190107094927.GA2442@work-vm \
--to=dgilbert@redhat.com \
--cc=crosthwaite.peter@gmail.com \
--cc=dirty.ice.hu@gmail.com \
--cc=eblake@redhat.com \
--cc=f4bug@amsat.org \
--cc=kraxel@redhat.com \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=quintela@redhat.com \
--cc=rth@twiddle.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.