From: Uros Bizjak <[email protected]>

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 <[email protected]>
---
 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 [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to