[PATCH] x86: Introduce ASM flags to bitops

From: Uros Bizjak
Date: Sat Jul 25 2015 - 20:16:13 EST


From: Uros Bizjak <ubizjak@xxxxxxxxx>

This patch introduces GCC ASM flags to bitops. Instead of e.g.

136d7: 48 0f a3 3d 00 00 00 bt %rdi,0x0(%rip)
136de: 00
136df: 19 ff sbb %edi,%edi
136e1: 85 ff test %edi,%edi
136e3: 0f 95 c0 setne %al

following code is generated:

13767: 48 0f a3 3d 00 00 00 bt %rdi,0x0(%rip)
1376e: 00
1376f: 0f 92 c0 setb %al

Similar improvement can be seen in following code:

7a6c: 48 0f a3 11 bt %rdx,(%rcx)
7a70: 19 d2 sbb %edx,%edx
7a72: 85 d2 test %edx,%edx
7a74: 74 eb je 7a61

which becomes:

7a8c: 48 0f a3 11 bt %rdx,(%rcx)
7a90: 73 ef jae 7a81

Signed-off-by: Uros Bizjak <ubizjak@xxxxxxxxx>
---
arch/x86/include/asm/bitops.h | 26 ++++++++++++++++++++++++--
arch/x86/include/asm/percpu.h | 18 +++++++++++++++++-
arch/x86/include/asm/signal.h | 6 ++++++
arch/x86/include/asm/sync_bitops.h | 18 ++++++++++++++++++
4 files changed, 65 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h
index cfe3b95..fb64933 100644
--- a/arch/x86/include/asm/bitops.h
+++ b/arch/x86/include/asm/bitops.h
@@ -232,10 +232,16 @@ static inline int __test_and_set_bit(long nr, volatile unsigned long *addr)
{
int oldbit;

+#ifdef __GCC_ASM_FLAG_OUTPUTS__
+ asm("bts %2,%1"
+ : "=@ccc" (oldbit), ADDR
+ : "Ir" (nr));
+#else
asm("bts %2,%1\n\t"
"sbb %0,%0"
: "=r" (oldbit), ADDR
: "Ir" (nr));
+#endif
return oldbit;
}

@@ -272,10 +278,16 @@ static inline int __test_and_clear_bit(long nr, volatile unsigned long *addr)
{
int oldbit;

+#ifdef __GCC_ASM_FLAG_OUTPUTS__
+ asm volatile("btr %2,%1"
+ : "=@ccc" (oldbit), ADDR
+ : "Ir" (nr));
+#else
asm volatile("btr %2,%1\n\t"
"sbb %0,%0"
: "=r" (oldbit), ADDR
: "Ir" (nr));
+#endif
return oldbit;
}

@@ -284,11 +296,16 @@ static inline int __test_and_change_bit(long nr, volatile unsigned long *addr)
{
int oldbit;

+#ifdef __GCC_ASM_FLAG_OUTPUTS__
+ asm volatile("btc %2,%1"
+ : "=@ccc" (oldbit), ADDR
+ : "Ir" (nr) : "memory");
+#else
asm volatile("btc %2,%1\n\t"
"sbb %0,%0"
: "=r" (oldbit), ADDR
: "Ir" (nr) : "memory");
-
+#endif
return oldbit;
}

@@ -315,11 +332,16 @@ static inline int variable_test_bit(long nr, volatile const unsigned long *addr)
{
int oldbit;

+#ifdef __GCC_ASM_FLAG_OUTPUTS__
+ asm volatile("bt %2,%1"
+ : "=@ccc" (oldbit)
+ : "m" (*(unsigned long *)addr), "Ir" (nr));
+#else
asm volatile("bt %2,%1\n\t"
"sbb %0,%0"
: "=r" (oldbit)
: "m" (*(unsigned long *)addr), "Ir" (nr));
-
+#endif
return oldbit;
}

diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h
index e0ba66c..0f8302c 100644
--- a/arch/x86/include/asm/percpu.h
+++ b/arch/x86/include/asm/percpu.h
@@ -508,6 +508,16 @@ do { \
#endif

/* This is not atomic against other CPUs -- CPU preemption needs to be off */
+#ifdef __GCC_ASM_FLAG_OUTPUTS__
+#define x86_test_and_clear_bit_percpu(bit, var) \
+({ \
+ int old__; \
+ asm volatile("btr %2,"__percpu_arg(1) \
+ : "=@ccc" (old__), "+m" (var) \
+ : "dIr" (bit)); \
+ old__; \
+})
+#else
#define x86_test_and_clear_bit_percpu(bit, var) \
({ \
int old__; \
@@ -516,6 +526,7 @@ do { \
: "dIr" (bit)); \
old__; \
})
+#endif

static __always_inline int x86_this_cpu_constant_test_bit(unsigned int nr,
const unsigned long __percpu *addr)
@@ -534,11 +545,16 @@ static inline int x86_this_cpu_variable_test_bit(int nr,
{
int oldbit;

+#ifdef __GCC_ASM_FLAG_OUTPUTS__
+ asm volatile("bt "__percpu_arg(2)",%1"
+ : "=@ccc" (oldbit)
+ : "m" (*(unsigned long *)addr), "Ir" (nr));
+#else
asm volatile("bt "__percpu_arg(2)",%1\n\t"
"sbb %0,%0"
: "=r" (oldbit)
: "m" (*(unsigned long *)addr), "Ir" (nr));
-
+#endif
return oldbit;
}

diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h
index 31eab86..0e35376 100644
--- a/arch/x86/include/asm/signal.h
+++ b/arch/x86/include/asm/signal.h
@@ -82,8 +82,14 @@ static inline int __const_sigismember(sigset_t *set, int _sig)
static inline int __gen_sigismember(sigset_t *set, int _sig)
{
int ret;
+
+#ifdef __GCC_ASM_FLAG_OUTPUTS__
+ asm("btl %2,%1"
+ : "=@ccc"(ret) : "m"(*set), "Ir"(_sig-1));
+#else
asm("btl %2,%1\n\tsbbl %0,%0"
: "=r"(ret) : "m"(*set), "Ir"(_sig-1) : "cc");
+#endif
return ret;
}

diff --git a/arch/x86/include/asm/sync_bitops.h b/arch/x86/include/asm/sync_bitops.h
index f28a24b..b690992 100644
--- a/arch/x86/include/asm/sync_bitops.h
+++ b/arch/x86/include/asm/sync_bitops.h
@@ -81,9 +81,15 @@ static inline int sync_test_and_set_bit(long nr, volatile unsigned long *addr)
{
int oldbit;

+#ifdef __GCC_ASM_FLAG_OUTPUTS__
+ asm volatile("lock; bts %2,%1"
+ : "=@ccc" (oldbit), "+m" (ADDR)
+ : "Ir" (nr) : "memory");
+#else
asm volatile("lock; bts %2,%1\n\tsbbl %0,%0"
: "=r" (oldbit), "+m" (ADDR)
: "Ir" (nr) : "memory");
+#endif
return oldbit;
}

@@ -99,9 +105,15 @@ static inline int sync_test_and_clear_bit(long nr, volatile unsigned long *addr)
{
int oldbit;

+#ifdef __GCC_ASM_FLAG_OUTPUTS__
+ asm volatile("lock; btr %2,%1"
+ : "=@ccc" (oldbit), "+m" (ADDR)
+ : "Ir" (nr) : "memory");
+#else
asm volatile("lock; btr %2,%1\n\tsbbl %0,%0"
: "=r" (oldbit), "+m" (ADDR)
: "Ir" (nr) : "memory");
+#endif
return oldbit;
}

@@ -117,9 +129,15 @@ static inline int sync_test_and_change_bit(long nr, volatile unsigned long *addr
{
int oldbit;

+#ifdef __GCC_ASM_FLAG_OUTPUTS__
+ asm volatile("lock; btc %2,%1"
+ : "=@ccc" (oldbit), "+m" (ADDR)
+ : "Ir" (nr) : "memory");
+#else
asm volatile("lock; btc %2,%1\n\tsbbl %0,%0"
: "=r" (oldbit), "+m" (ADDR)
: "Ir" (nr) : "memory");
+#endif
return oldbit;
}

--
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/