* [Qemu-devel] [PATCH v2] osdep: Make MIN/MAX evaluate arguments only once
@ 2019-01-06 1:38 Eric Blake
2019-01-06 8:32 ` Richard Henderson
2019-01-07 9:49 ` Dr. David Alan Gilbert
0 siblings, 2 replies; 8+ messages in thread
From: Eric Blake @ 2019-01-06 1:38 UTC (permalink / raw)
To: qemu-devel
Cc: dirty.ice.hu, f4bug, Gerd Hoffmann, Peter Crosthwaite,
Richard Henderson, Paolo Bonzini, Juan Quintela,
Dr. David Alan Gilbert
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())
+#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
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH v2] osdep: Make MIN/MAX evaluate arguments only once
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
1 sibling, 1 reply; 8+ messages in thread
From: Richard Henderson @ 2019-01-06 8:32 UTC (permalink / raw)
To: Eric Blake, qemu-devel
Cc: dirty.ice.hu, f4bug, Gerd Hoffmann, Peter Crosthwaite,
Paolo Bonzini, Juan Quintela, Dr. David Alan Gilbert
On 1/6/19 11:38 AM, Eric Blake wrote:
> +/*
> + * 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
What's wrong with always using typeof? This seems like it leaves potential odd
bugs affecting gcc-4.8.
> +#undef MIN
> +#define MIN(a, b) \
> + ({ \
> + QEMU_TYPEOF((a) + 0) _a = (a) + 0; \
> + QEMU_TYPEOF((b) + 0) _b = (b) + 0; \
If you're promoting the type, why don't you want to promote to the common type
between A and B? E.g.
__typeof((a) + (b)) _a = (a), _b = (b);
After all, that's what the result type of (p ? _a : _b) will be.
r~
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH v2] osdep: Make MIN/MAX evaluate arguments only once
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 9:49 ` Dr. David Alan Gilbert
2019-01-07 14:24 ` Eric Blake
1 sibling, 1 reply; 8+ messages in thread
From: Dr. David Alan Gilbert @ 2019-01-07 9:49 UTC (permalink / raw)
To: Eric Blake
Cc: qemu-devel, dirty.ice.hu, f4bug, Gerd Hoffmann,
Peter Crosthwaite, Richard Henderson, Paolo Bonzini,
Juan Quintela
* 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
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH v2] osdep: Make MIN/MAX evaluate arguments only once
2019-01-06 8:32 ` Richard Henderson
@ 2019-01-07 14:22 ` Eric Blake
0 siblings, 0 replies; 8+ messages in thread
From: Eric Blake @ 2019-01-07 14:22 UTC (permalink / raw)
To: Richard Henderson, qemu-devel
Cc: dirty.ice.hu, f4bug, Gerd Hoffmann, Peter Crosthwaite,
Paolo Bonzini, Juan Quintela, Dr. David Alan Gilbert
[-- Attachment #1: Type: text/plain, Size: 1985 bytes --]
On 1/6/19 2:32 AM, Richard Henderson wrote:
> On 1/6/19 11:38 AM, Eric Blake wrote:
>> +/*
>> + * 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
>
> What's wrong with always using typeof? This seems like it leaves potential odd
> bugs affecting gcc-4.8.
Always using typeof is an option, but gcc documents that __auto_type is
nicer than typeof:
> Using '__auto_type' instead of 'typeof' has two advantages:
>
> * Each argument to the macro appears only once in the expansion of
> the macro. This prevents the size of the macro expansion growing
> exponentially when calls to such macros are nested inside arguments
> of such macros.
>
> * If the argument to the macro has variably modified type, it is
> evaluated only once when using '__auto_type', but twice if 'typeof'
> is used.
We don't use variably modified types (at least, I don't think we do), so
the latter is moot (but WOULD be the spot where we are most likely to be
bitten on 4.8 compilers lacking __auto_type); the former point is a
minor speed win in favor of __auto_type.
>
>> +#undef MIN
>> +#define MIN(a, b) \
>> + ({ \
>> + QEMU_TYPEOF((a) + 0) _a = (a) + 0; \
>> + QEMU_TYPEOF((b) + 0) _b = (b) + 0; \
>
> If you're promoting the type, why don't you want to promote to the common type
> between A and B? E.g.
>
> __typeof((a) + (b)) _a = (a), _b = (b);
>
> After all, that's what the result type of (p ? _a : _b) will be.
That formulation should work as well, if anyone likes it better (but it
does NOT work with __auto_type).
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3226
Virtualization: qemu.org | libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH v2] osdep: Make MIN/MAX evaluate arguments only once
2019-01-07 9:49 ` Dr. David Alan Gilbert
@ 2019-01-07 14:24 ` Eric Blake
2019-01-07 15:07 ` Dr. David Alan Gilbert
0 siblings, 1 reply; 8+ messages in thread
From: Eric Blake @ 2019-01-07 14:24 UTC (permalink / raw)
To: Dr. David Alan Gilbert
Cc: qemu-devel, dirty.ice.hu, f4bug, Gerd Hoffmann,
Peter Crosthwaite, Richard Henderson, Paolo Bonzini,
Juan Quintela
[-- Attachment #1: Type: text/plain, Size: 2370 bytes --]
On 1/7/19 3:49 AM, Dr. David Alan Gilbert wrote:
> * 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(),
>> +#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; \
> }))
Because it doesn't work - gcc treats ({}) as a syntax error inside
constant expressions, even in dead code (although 'info gcc' said that
might change in the future, we can't wait for that change). I also
tried it as documented here:
https://lists.gnu.org/archive/html/qemu-devel/2019-01/msg00715.html
hence my mention in the commit message.
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3226
Virtualization: qemu.org | libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH v2] osdep: Make MIN/MAX evaluate arguments only once
2019-01-07 14:24 ` Eric Blake
@ 2019-01-07 15:07 ` Dr. David Alan Gilbert
2019-01-07 16:16 ` Eric Blake
0 siblings, 1 reply; 8+ messages in thread
From: Dr. David Alan Gilbert @ 2019-01-07 15:07 UTC (permalink / raw)
To: Eric Blake
Cc: qemu-devel, dirty.ice.hu, f4bug, Gerd Hoffmann,
Peter Crosthwaite, Richard Henderson, Paolo Bonzini,
Juan Quintela
* Eric Blake (eblake@redhat.com) wrote:
> On 1/7/19 3:49 AM, Dr. David Alan Gilbert wrote:
> > * 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(),
>
>
> >> +#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; \
> > }))
>
> Because it doesn't work - gcc treats ({}) as a syntax error inside
> constant expressions, even in dead code (although 'info gcc' said that
> might change in the future, we can't wait for that change). I also
> tried it as documented here:
> https://lists.gnu.org/archive/html/qemu-devel/2019-01/msg00715.html
> hence my mention in the commit message.
Ah, I didn't understand the context in your message; you say 'even in
the dead branch of a __builtin_choose_expr()' but the following works
for me (on f29 and rhel7):
#include <stdio.h>
# define QEMU_TYPEOF(a) typeof(a)
#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; \
}))
int main(int argc, char *argv[])
{
int anarray[DMIN(5, 10)];
int a=5;
int b=6;
fprintf(stderr, "sizeof(anarray)=%zd DMIN(a,b)=%d\n", sizeof(anarray), DMIN(a++,b++));
fprintf(stderr, "a=%d b=%d\n", a,b);
}
Dave
> --
> Eric Blake, Principal Software Engineer
> Red Hat, Inc. +1-919-301-3226
> Virtualization: qemu.org | libvirt.org
>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH v2] osdep: Make MIN/MAX evaluate arguments only once
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
0 siblings, 1 reply; 8+ messages in thread
From: Eric Blake @ 2019-01-07 16:16 UTC (permalink / raw)
To: Dr. David Alan Gilbert
Cc: qemu-devel, dirty.ice.hu, f4bug, Gerd Hoffmann,
Peter Crosthwaite, Richard Henderson, Paolo Bonzini,
Juan Quintela
[-- Attachment #1: Type: text/plain, Size: 2066 bytes --]
On 1/7/19 9:07 AM, Dr. David Alan Gilbert wrote:
>>>> 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(),
>> Because it doesn't work - gcc treats ({}) as a syntax error inside
>> constant expressions, even in dead code (although 'info gcc' said that
>> might change in the future, we can't wait for that change). I also
>> tried it as documented here:
>> https://lists.gnu.org/archive/html/qemu-devel/2019-01/msg00715.html
>> hence my mention in the commit message.
>
> Ah, I didn't understand the context in your message; you say 'even in
> the dead branch of a __builtin_choose_expr()' but the following works
> for me (on f29 and rhel7):
>
> #include <stdio.h>
>
> # define QEMU_TYPEOF(a) typeof(a)
>
> #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; \
> }))
>
>
> int main(int argc, char *argv[])
> {
> int anarray[DMIN(5, 10)];
Not a constant context. As written, you have declared a variable-length
array, determined at runtime (even if the array is not actually
variable-length because you always provide the same length). Hoist the
declaration anarray outside of main() to see the difference. Or try:
struct foo {
int bar : DMIN(5, 10);
};
for another example of a constant context (again, outside of a function).
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3226
Virtualization: qemu.org | libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH v2] osdep: Make MIN/MAX evaluate arguments only once
2019-01-07 16:16 ` Eric Blake
@ 2019-01-07 16:24 ` Dr. David Alan Gilbert
0 siblings, 0 replies; 8+ messages in thread
From: Dr. David Alan Gilbert @ 2019-01-07 16:24 UTC (permalink / raw)
To: Eric Blake
Cc: qemu-devel, dirty.ice.hu, f4bug, Gerd Hoffmann,
Peter Crosthwaite, Richard Henderson, Paolo Bonzini,
Juan Quintela
* Eric Blake (eblake@redhat.com) wrote:
> On 1/7/19 9:07 AM, Dr. David Alan Gilbert wrote:
>
> >>>> 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(),
>
> >> Because it doesn't work - gcc treats ({}) as a syntax error inside
> >> constant expressions, even in dead code (although 'info gcc' said that
> >> might change in the future, we can't wait for that change). I also
> >> tried it as documented here:
> >> https://lists.gnu.org/archive/html/qemu-devel/2019-01/msg00715.html
> >> hence my mention in the commit message.
> >
> > Ah, I didn't understand the context in your message; you say 'even in
> > the dead branch of a __builtin_choose_expr()' but the following works
> > for me (on f29 and rhel7):
> >
> > #include <stdio.h>
> >
> > # define QEMU_TYPEOF(a) typeof(a)
> >
> > #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; \
> > }))
> >
> >
> > int main(int argc, char *argv[])
> > {
> > int anarray[DMIN(5, 10)];
>
> Not a constant context. As written, you have declared a variable-length
> array, determined at runtime (even if the array is not actually
> variable-length because you always provide the same length). Hoist the
> declaration anarray outside of main() to see the difference. Or try:
>
> struct foo {
> int bar : DMIN(5, 10);
> };
>
> for another example of a constant context (again, outside of a function).
Ah OK, yes that does fail as you say. Fair enough.
Dave
> --
> Eric Blake, Principal Software Engineer
> Red Hat, Inc. +1-919-301-3226
> Virtualization: qemu.org | libvirt.org
>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2019-01-07 16:24 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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
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
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.