Allow defining variables and perform cast with a typeof which removes
the volatile and const qualifiers.
This prevents declaring a stack variable with a volatile qualifier
within a macro, which would generate sub-optimal assembler.
This is imported from the "librseq" project.
Signed-off-by: Mathieu Desnoyers <[email protected]>
---
tools/testing/selftests/rseq/compiler.h | 27 +++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/tools/testing/selftests/rseq/compiler.h b/tools/testing/selftests/rseq/compiler.h
index f47092bddeba..8dc7f881e253 100644
--- a/tools/testing/selftests/rseq/compiler.h
+++ b/tools/testing/selftests/rseq/compiler.h
@@ -33,4 +33,31 @@
#define RSEQ_COMBINE_TOKENS(_tokena, _tokenb) \
RSEQ__COMBINE_TOKENS(_tokena, _tokenb)
+#ifdef __cplusplus
+#define rseq_unqual_scalar_typeof(x) \
+ std::remove_cv<std::remove_reference<decltype(x)>::type>::type
+#else
+/*
+ * Use C11 _Generic to express unqualified type from expression. This removes
+ * volatile qualifier from expression type.
+ */
+#define rseq_unqual_scalar_typeof(x) \
+ __typeof__( \
+ _Generic((x), \
+ char: (char)0, \
+ unsigned char: (unsigned char)0, \
+ signed char: (signed char)0, \
+ unsigned short: (unsigned short)0, \
+ signed short: (signed short)0, \
+ unsigned int: (unsigned int)0, \
+ signed int: (signed int)0, \
+ unsigned long: (unsigned long)0, \
+ signed long: (signed long)0, \
+ unsigned long long: (unsigned long long)0, \
+ signed long long: (signed long long)0, \
+ default: (x) \
+ ) \
+ )
+#endif
+
#endif /* RSEQ_COMPILER_H_ */
--
2.25.1
Use rseq_unqual_scalar_typeof() rather than typeof() in macros to remove
the volatile qualifier (if there is one in the input argument), thus
generating better assembly code in those scenarios.
Also add extra brackets around the "p" parameter in RSEQ_READ_ONCE(),
RSEQ_WRITE_ONCE(), and rseq_unqual_scalar_typeof() across architectures
to preserve expectations of operator priority. Here is an example that
shows how operator priority may be an issue with missing parentheses:
#define m(p) \
do { \
__typeof__(*p) v = 0; \
} while (0)
void fct(unsigned long long *p1)
{
m(p1 + 1); /* works */
m(1 + p1); /* broken */
}
Signed-off-by: Mathieu Desnoyers <[email protected]>
Cc: Peter Zijlstra <[email protected]>
---
tools/testing/selftests/rseq/rseq-arm.h | 4 ++--
tools/testing/selftests/rseq/rseq-mips.h | 4 ++--
tools/testing/selftests/rseq/rseq-ppc.h | 4 ++--
tools/testing/selftests/rseq/rseq-riscv.h | 6 +++---
tools/testing/selftests/rseq/rseq-s390.h | 4 ++--
tools/testing/selftests/rseq/rseq-x86.h | 4 ++--
6 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/tools/testing/selftests/rseq/rseq-arm.h b/tools/testing/selftests/rseq/rseq-arm.h
index 8414fc3eac15..d887b3bbe257 100644
--- a/tools/testing/selftests/rseq/rseq-arm.h
+++ b/tools/testing/selftests/rseq/rseq-arm.h
@@ -66,7 +66,7 @@
#define rseq_smp_load_acquire(p) \
__extension__ ({ \
- __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
+ rseq_unqual_scalar_typeof(*(p)) ____p1 = RSEQ_READ_ONCE(*(p)); \
rseq_smp_mb(); \
____p1; \
})
@@ -76,7 +76,7 @@ __extension__ ({ \
#define rseq_smp_store_release(p, v) \
do { \
rseq_smp_mb(); \
- RSEQ_WRITE_ONCE(*p, v); \
+ RSEQ_WRITE_ONCE(*(p), v); \
} while (0)
#define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, start_ip, \
diff --git a/tools/testing/selftests/rseq/rseq-mips.h b/tools/testing/selftests/rseq/rseq-mips.h
index 50b950cf9585..42ef8e946693 100644
--- a/tools/testing/selftests/rseq/rseq-mips.h
+++ b/tools/testing/selftests/rseq/rseq-mips.h
@@ -45,7 +45,7 @@
#define rseq_smp_load_acquire(p) \
__extension__ ({ \
- __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
+ rseq_unqual_scalar_typeof(*(p)) ____p1 = RSEQ_READ_ONCE(*(p)); \
rseq_smp_mb(); \
____p1; \
})
@@ -55,7 +55,7 @@ __extension__ ({ \
#define rseq_smp_store_release(p, v) \
do { \
rseq_smp_mb(); \
- RSEQ_WRITE_ONCE(*p, v); \
+ RSEQ_WRITE_ONCE(*(p), v); \
} while (0)
#if _MIPS_SZLONG == 64
diff --git a/tools/testing/selftests/rseq/rseq-ppc.h b/tools/testing/selftests/rseq/rseq-ppc.h
index dc9190facee9..57b160597189 100644
--- a/tools/testing/selftests/rseq/rseq-ppc.h
+++ b/tools/testing/selftests/rseq/rseq-ppc.h
@@ -23,7 +23,7 @@
#define rseq_smp_load_acquire(p) \
__extension__ ({ \
- __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
+ rseq_unqual_scalar_typeof(*(p)) ____p1 = RSEQ_READ_ONCE(*(p)); \
rseq_smp_lwsync(); \
____p1; \
})
@@ -33,7 +33,7 @@ __extension__ ({ \
#define rseq_smp_store_release(p, v) \
do { \
rseq_smp_lwsync(); \
- RSEQ_WRITE_ONCE(*p, v); \
+ RSEQ_WRITE_ONCE(*(p), v); \
} while (0)
/*
diff --git a/tools/testing/selftests/rseq/rseq-riscv.h b/tools/testing/selftests/rseq/rseq-riscv.h
index 17932a79e066..37e598d0a365 100644
--- a/tools/testing/selftests/rseq/rseq-riscv.h
+++ b/tools/testing/selftests/rseq/rseq-riscv.h
@@ -36,8 +36,8 @@
#define rseq_smp_load_acquire(p) \
__extension__ ({ \
- __typeof(*(p)) ____p1 = RSEQ_READ_ONCE(*(p)); \
- RISCV_FENCE(r, rw) \
+ rseq_unqual_scalar_typeof(*(p)) ____p1 = RSEQ_READ_ONCE(*(p)); \
+ RISCV_FENCE(r, rw); \
____p1; \
})
@@ -46,7 +46,7 @@ __extension__ ({ \
#define rseq_smp_store_release(p, v) \
do { \
RISCV_FENCE(rw, w); \
- RSEQ_WRITE_ONCE(*(p), v); \
+ RSEQ_WRITE_ONCE(*(p), v); \
} while (0)
#define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, start_ip, \
diff --git a/tools/testing/selftests/rseq/rseq-s390.h b/tools/testing/selftests/rseq/rseq-s390.h
index 46c92598acc7..33baaa9f9997 100644
--- a/tools/testing/selftests/rseq/rseq-s390.h
+++ b/tools/testing/selftests/rseq/rseq-s390.h
@@ -15,7 +15,7 @@
#define rseq_smp_load_acquire(p) \
__extension__ ({ \
- __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
+ rseq_unqual_scalar_typeof(*(p)) ____p1 = RSEQ_READ_ONCE(*(p)); \
rseq_barrier(); \
____p1; \
})
@@ -25,7 +25,7 @@ __extension__ ({ \
#define rseq_smp_store_release(p, v) \
do { \
rseq_barrier(); \
- RSEQ_WRITE_ONCE(*p, v); \
+ RSEQ_WRITE_ONCE(*(p), v); \
} while (0)
#ifdef __s390x__
diff --git a/tools/testing/selftests/rseq/rseq-x86.h b/tools/testing/selftests/rseq/rseq-x86.h
index fb65ef54b0fb..a2aa428ba151 100644
--- a/tools/testing/selftests/rseq/rseq-x86.h
+++ b/tools/testing/selftests/rseq/rseq-x86.h
@@ -42,7 +42,7 @@
#define rseq_smp_load_acquire(p) \
__extension__ ({ \
- __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
+ rseq_unqual_scalar_typeof(*(p)) ____p1 = RSEQ_READ_ONCE(*(p)); \
rseq_barrier(); \
____p1; \
})
@@ -52,7 +52,7 @@ __extension__ ({ \
#define rseq_smp_store_release(p, v) \
do { \
rseq_barrier(); \
- RSEQ_WRITE_ONCE(*p, v); \
+ RSEQ_WRITE_ONCE(*(p), v); \
} while (0)
#define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \
--
2.25.1
On Wed, May 03, 2023 at 04:13:22PM -0400, Mathieu Desnoyers wrote:
> Allow defining variables and perform cast with a typeof which removes
> the volatile and const qualifiers.
>
> This prevents declaring a stack variable with a volatile qualifier
> within a macro, which would generate sub-optimal assembler.
>
> This is imported from the "librseq" project.
>
> Signed-off-by: Mathieu Desnoyers <[email protected]>
> ---
> tools/testing/selftests/rseq/compiler.h | 27 +++++++++++++++++++++++++
> 1 file changed, 27 insertions(+)
>
> diff --git a/tools/testing/selftests/rseq/compiler.h b/tools/testing/selftests/rseq/compiler.h
> index f47092bddeba..8dc7f881e253 100644
> --- a/tools/testing/selftests/rseq/compiler.h
> +++ b/tools/testing/selftests/rseq/compiler.h
> @@ -33,4 +33,31 @@
> #define RSEQ_COMBINE_TOKENS(_tokena, _tokenb) \
> RSEQ__COMBINE_TOKENS(_tokena, _tokenb)
>
> +#ifdef __cplusplus
> +#define rseq_unqual_scalar_typeof(x) \
> + std::remove_cv<std::remove_reference<decltype(x)>::type>::type
> +#else
> +/*
> + * Use C11 _Generic to express unqualified type from expression. This removes
> + * volatile qualifier from expression type.
> + */
> +#define rseq_unqual_scalar_typeof(x) \
> + __typeof__( \
> + _Generic((x), \
> + char: (char)0, \
> + unsigned char: (unsigned char)0, \
> + signed char: (signed char)0, \
> + unsigned short: (unsigned short)0, \
> + signed short: (signed short)0, \
> + unsigned int: (unsigned int)0, \
> + signed int: (signed int)0, \
> + unsigned long: (unsigned long)0, \
> + signed long: (signed long)0, \
> + unsigned long long: (unsigned long long)0, \
> + signed long long: (signed long long)0, \
> + default: (x) \
> + ) \
> + )
FWIW, I like how the kernel version uses a little helper for the
signed/unsigned pairs. Makes it a little more readable.
> +#endif
> +
> #endif /* RSEQ_COMPILER_H_ */
> --
> 2.25.1
>
On 2023-05-04 02:09, Peter Zijlstra wrote:
> On Wed, May 03, 2023 at 04:13:22PM -0400, Mathieu Desnoyers wrote:
>> Allow defining variables and perform cast with a typeof which removes
>> the volatile and const qualifiers.
>>
>> This prevents declaring a stack variable with a volatile qualifier
>> within a macro, which would generate sub-optimal assembler.
>>
>> This is imported from the "librseq" project.
>>
>> Signed-off-by: Mathieu Desnoyers <[email protected]>
>> ---
>> tools/testing/selftests/rseq/compiler.h | 27 +++++++++++++++++++++++++
>> 1 file changed, 27 insertions(+)
>>
>> diff --git a/tools/testing/selftests/rseq/compiler.h b/tools/testing/selftests/rseq/compiler.h
>> index f47092bddeba..8dc7f881e253 100644
>> --- a/tools/testing/selftests/rseq/compiler.h
>> +++ b/tools/testing/selftests/rseq/compiler.h
>> @@ -33,4 +33,31 @@
>> #define RSEQ_COMBINE_TOKENS(_tokena, _tokenb) \
>> RSEQ__COMBINE_TOKENS(_tokena, _tokenb)
>>
>> +#ifdef __cplusplus
>> +#define rseq_unqual_scalar_typeof(x) \
>> + std::remove_cv<std::remove_reference<decltype(x)>::type>::type
>> +#else
>> +/*
>> + * Use C11 _Generic to express unqualified type from expression. This removes
>> + * volatile qualifier from expression type.
>> + */
>> +#define rseq_unqual_scalar_typeof(x) \
>> + __typeof__( \
>> + _Generic((x), \
>> + char: (char)0, \
>> + unsigned char: (unsigned char)0, \
>> + signed char: (signed char)0, \
>> + unsigned short: (unsigned short)0, \
>> + signed short: (signed short)0, \
>> + unsigned int: (unsigned int)0, \
>> + signed int: (signed int)0, \
>> + unsigned long: (unsigned long)0, \
>> + signed long: (signed long)0, \
>> + unsigned long long: (unsigned long long)0, \
>> + signed long long: (signed long long)0, \
>> + default: (x) \
>> + ) \
>> + )
>
> FWIW, I like how the kernel version uses a little helper for the
> signed/unsigned pairs. Makes it a little more readable.
OK, will update for next round:
#define rseq_scalar_type_to_expr(type) \
unsigned type: (unsigned type)0, \
signed type: (signed type)0
/*
* Use C11 _Generic to express unqualified type from expression. This removes
* volatile qualifier from expression type.
*/
#define rseq_unqual_scalar_typeof(x) \
__typeof__( \
_Generic((x), \
char: (char)0, \
rseq_scalar_type_to_expr(char), \
rseq_scalar_type_to_expr(short), \
rseq_scalar_type_to_expr(int), \
rseq_scalar_type_to_expr(long), \
rseq_scalar_type_to_expr(long long), \
default: (x) \
) \
)
Thanks,
Mathieu
>
>> +#endif
>> +
>> #endif /* RSEQ_COMPILER_H_ */
>> --
>> 2.25.1
>>
--
Mathieu Desnoyers
EfficiOS Inc.
https://www.efficios.com