MIPS: Get rid of branches to .subsections.
Subsystems (3)
It was a nice optimization - on paper at least. In practice it results in branches that may exceed the maximum legal range for a branch. We can fight that problem with -ffunction-sections but -ffunction-sections again is incompatible with -pg used by the function tracer.
By rewriting the loop around all simple LL/SC blocks to C we reduce reduce the amount of inline assembler and at the same time allow GCC to often fill the branch delay slots with something sensible or whever else clever optimization it may have up in its sleeve.
With this optimization gone we also no longer need -ffunction-sections, so drop it.
This optimization was originall introduced in 2.6.21, commit 5999eca25c1fd4b9b9aca7833b04d10fe4bc877d (linux-mips.org) rsp. f65e4fa8e0c6022ad58dc88d1b11b12589ed7f9f (kernel.org).
Original fix for the issues which caused me to pull this optimization by Paul Gortmaker <[email protected]>.
---
v2: a bunch of build fixes.
arch/mips/Makefile | 3 arch/mips/include/asm/atomic.h | 208 ++++++++++++++---------------- arch/mips/include/asm/bitops.h | 270 +++++++++++++++++----------------------- arch/mips/include/asm/cmpxchg.h | 7 - arch/mips/include/asm/system.h | 52 +++---- 5 files changed, 243 insertions(+), 297 deletions(-)
arch/mips/include/asm/atomic.h +96 -112
@@ -64,18 +64,16 @@ static __inline__ void atomic_add(int i, }else if (kernel_uses_llsc) {int temp; - __asm__ __volatile__( -" .set mips3 \n" -"1: ll %0, %1 # atomic_add \n" -" addu %0, %2 \n" -" sc %0, %1 \n" -" beqz %0, 2f \n" -" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" -" .set mips0 \n" - :"=&r" (temp),"=m" (v->counter) - :"Ir" (i),"m" (v->counter)); +do { + __asm__ __volatile__( +" .set mips3 \n" +" ll %0, %1 # atomic_add \n" +" addu %0, %2 \n" +" sc %0, %1 \n" +" .set mips0 \n" + :"=&r" (temp),"=m" (v->counter) + :"Ir" (i),"m" (v->counter)); + }while (unlikely (!temp)); }else {unsigned long flags;
@@ -109,18 +107,16 @@ static __inline__ void atomic_sub(int i, }else if (kernel_uses_llsc) {int temp; - __asm__ __volatile__( -" .set mips3 \n" -"1: ll %0, %1 # atomic_sub \n" -" subu %0, %2 \n" -" sc %0, %1 \n" -" beqz %0, 2f \n" -" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" -" .set mips0 \n" - :"=&r" (temp),"=m" (v->counter) - :"Ir" (i),"m" (v->counter)); +do { + __asm__ __volatile__( +" .set mips3 \n" +" ll %0, %1 # atomic_sub \n" +" subu %0, %2 \n" +" sc %0, %1 \n" +" .set mips0 \n" + :"=&r" (temp),"=m" (v->counter) + :"Ir" (i),"m" (v->counter)); + }while (unlikely (!temp)); }else {unsigned long flags;
@@ -156,20 +152,19 @@ static __inline__ int atomic_add_return( }else if (kernel_uses_llsc) {int temp; - __asm__ __volatile__( -" .set mips3 \n" -"1: ll %1, %2 # atomic_add_return \n" -" addu %0, %1, %3 \n" -" sc %0, %2 \n" -" beqz %0, 2f \n" -" addu %0, %1, %3 \n" -" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" -" .set mips0 \n" - :"=&r" (result),"=&r" (temp),"=m" (v->counter) - :"Ir" (i),"m" (v->counter) - :"memory" ); +do { + __asm__ __volatile__( +" .set mips3 \n" +" ll %1, %2 # atomic_add_return \n" +" addu %0, %1, %3 \n" +" sc %0, %2 \n" +" .set mips0 \n" + :"=&r" (result),"=&r" (temp),"=m" (v->counter) + :"Ir" (i),"m" (v->counter) + :"memory" ); + }while (unlikely (!result)); + + result = temp + i; }else {unsigned long flags;
@@ -205,23 +200,24 @@ static __inline__ int atomic_sub_return( : "=&r" (result), "=&r" (temp), "=m" (v->counter) : "Ir" (i), "m" (v->counter) : "memory"); + + result = temp - i; }else if (kernel_uses_llsc) {int temp; - __asm__ __volatile__( -" .set mips3 \n" -"1: ll %1, %2 # atomic_sub_return \n" -" subu %0, %1, %3 \n" -" sc %0, %2 \n" -" beqz %0, 2f \n" -" subu %0, %1, %3 \n" -" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" -" .set mips0 \n" - :"=&r" (result),"=&r" (temp),"=m" (v->counter) - :"Ir" (i),"m" (v->counter) - :"memory" ); +do { + __asm__ __volatile__( +" .set mips3 \n" +" ll %1, %2 # atomic_sub_return \n" +" subu %0, %1, %3 \n" +" sc %0, %2 \n" +" .set mips0 \n" + :"=&r" (result),"=&r" (temp),"=m" (v->counter) + :"Ir" (i),"m" (v->counter) + :"memory" ); + }while (unlikely (!result)); + + result = temp - i; }else {unsigned long flags;
@@ -279,12 +275,9 @@ static __inline__ int atomic_sub_if_posi" bltz %0, 1f \n" " sc %0, %2 \n" " .set noreorder \n" -" beqz %0, 2f \n" +" beqz %0, 1b \n" " subu %0, %1, %3 \n" " .set reorder \n" -" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" "1: \n" " .set mips0 \n" : "=&r" (result), "=&r" (temp), "=m" (v->counter)
@@ -443,18 +436,16 @@ static __inline__ void atomic64_add(long }else if (kernel_uses_llsc) {long temp; - __asm__ __volatile__( -" .set mips3 \n" -"1: lld %0, %1 # atomic64_add \n" -" daddu %0, %2 \n" -" scd %0, %1 \n" -" beqz %0, 2f \n" -" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" -" .set mips0 \n" - :"=&r" (temp),"=m" (v->counter) - :"Ir" (i),"m" (v->counter)); +do { + __asm__ __volatile__( +" .set mips3 \n" +"1: lld %0, %1 # atomic64_add \n" +" daddu %0, %2 \n" +" scd %0, %1 \n" +" .set mips0 \n" + :"=&r" (temp),"=m" (v->counter) + :"Ir" (i),"m" (v->counter)); + }while (unlikely (!temp)); }else {unsigned long flags;
@@ -488,18 +479,16 @@ static __inline__ void atomic64_sub(long }else if (kernel_uses_llsc) {long temp; - __asm__ __volatile__( -" .set mips3 \n" -"1: lld %0, %1 # atomic64_sub \n" -" dsubu %0, %2 \n" -" scd %0, %1 \n" -" beqz %0, 2f \n" -" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" -" .set mips0 \n" - :"=&r" (temp),"=m" (v->counter) - :"Ir" (i),"m" (v->counter)); +do { + __asm__ __volatile__( +" .set mips3 \n" +"1: lld %0, %1 # atomic64_sub \n" +" dsubu %0, %2 \n" +" scd %0, %1 \n" +" .set mips0 \n" + :"=&r" (temp),"=m" (v->counter) + :"Ir" (i),"m" (v->counter)); + }while (unlikely (!temp)); }else {unsigned long flags;
@@ -535,20 +524,19 @@ static __inline__ long atomic64_add_retu }else if (kernel_uses_llsc) {long temp; - __asm__ __volatile__( -" .set mips3 \n" -"1: lld %1, %2 # atomic64_add_return \n" -" daddu %0, %1, %3 \n" -" scd %0, %2 \n" -" beqz %0, 2f \n" -" daddu %0, %1, %3 \n" -" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" -" .set mips0 \n" - :"=&r" (result),"=&r" (temp),"=m" (v->counter) - :"Ir" (i),"m" (v->counter) - :"memory" ); +do { + __asm__ __volatile__( +" .set mips3 \n" +"1: lld %1, %2 # atomic64_add_return \n" +" daddu %0, %1, %3 \n" +" scd %0, %2 \n" +" .set mips0 \n" + :"=&r" (result),"=&r" (temp),"=m" (v->counter) + :"Ir" (i),"m" (v->counter) + :"memory" ); + }while (unlikely (!result)); + + result = temp + i; }else {unsigned long flags;
@@ -587,20 +575,19 @@ static __inline__ long atomic64_sub_retu }else if (kernel_uses_llsc) {long temp; - __asm__ __volatile__( -" .set mips3 \n" -"1: lld %1, %2 # atomic64_sub_return \n" -" dsubu %0, %1, %3 \n" -" scd %0, %2 \n" -" beqz %0, 2f \n" -" dsubu %0, %1, %3 \n" -" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" -" .set mips0 \n" - :"=&r" (result),"=&r" (temp),"=m" (v->counter) - :"Ir" (i),"m" (v->counter) - :"memory" ); +do { + __asm__ __volatile__( +" .set mips3 \n" +"1: lld %1, %2 # atomic64_sub_return \n" +" dsubu %0, %1, %3 \n" +" scd %0, %2 \n" +" .set mips0 \n" + :"=&r" (result),"=&r" (temp),"=m" (v->counter) + :"Ir" (i),"m" (v->counter) + :"memory" ); + }while (unlikely (!result)); + + result = temp - i; }else {unsigned long flags;
@@ -658,12 +645,9 @@ static __inline__ long atomic64_sub_if_p" bltz %0, 1f \n" " scd %0, %2 \n" " .set noreorder \n" -" beqz %0, 2f \n" +" beqz %0, 1b \n" " dsubu %0, %1, %3 \n" " .set reorder \n" -" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" "1: \n" " .set mips0 \n" : "=&r" (result), "=&r" (temp), "=m" (v->counter)
arch/mips/include/asm/bitops.h +121 -149
348 lines not on this page · raw message
arch/mips/include/asm/cmpxchg.h +2 -5
@@ -44,12 +44,9 @@" move $1, %z4 \n" \" .set mips3 \n" \" " st" $1, %1 \n" \ -" beqz $1, 3f \n" \ -"2: \n" \ -" .subsection 2 \n" \ -"3: b 1b \n" \ -" .previous \n" \ +" beqz $1, 1b \n" \" .set pop \n" \ +"2: \n" \ : "=&r" (__ret), "=R" (*m) \: " R " (*m), " Jr" (old), " Jr" (new) \ : " memory"); \
arch/mips/include/asm/system.h +24 -28
64 lines not on this page · raw message
arch/mips/Makefile +0 -3
@@ -48,9 +48,6 @@ ifneq ($(SUBARCH),$(ARCH)) endif endif -ifndef CONFIG_FUNCTION_TRACER -cflags-y := -ffunction-sections -endif ifdef CONFIG_FUNCTION_GRAPH_TRACER ifndef KBUILD_MCOUNT_RA_ADDRESS ifeq ($(call cc-option-yn,-mmcount-ra-address), y)
Hello.
Quoted 8 lines · Ralf Baechle
It was a nice optimization - on paper at least. In practice it results in branches that may exceed the maximum legal range for a branch. We can fight that problem with -ffunction-sections but -ffunction-sections again is incompatible with -pg used by the function tracer.
By rewriting the loop around all simple LL/SC blocks to C we reduce reduce the amount of inline assembler and at the same time allow GCC to often fill the branch delay slots with something sensible or whever else clever
^^^^^^
Whichever?
Quoted 6 lines
optimization it may have up in its sleeve.
With this optimization gone we also no longer need -ffunction-sections, so drop it.
This optimization was originall introduced in 2.6.21, commit
^^^^^^^^^
Originally.Quoted 12 lines
5999eca25c1fd4b9b9aca7833b04d10fe4bc877d(linux-mips.org) rsp.f65e4fa8e0c6022ad58dc88d1b11b12589ed7f9f(kernel.org).Original fix for the issues which caused me to pull this optimization by Paul Gortmaker <[email protected]>.
Signed-off-by Ralf Baechle <[email protected]>Index:
linux-queue/arch/mips/include/asm/atomic.h
===================================================================arch/mips/include/asm/atomic.h +0
-0
[...]
Quoted 10 lines
arch/mips/include/asm/atomic.h +0
-6@@ -443,18 +436,16 @@ static __inline__ void atomic64_add(long }else if (kernel_uses_llsc) {long temp; - __asm__ __volatile__( -" .set mips3 \n" -"1: lld %0, %1 # atomic64_add \n" -" daddu %0, %2 \n" -" scd %0, %1 \n" - " beqz %0, 2f \n"
arch/mips/include/asm/atomic.h static __inline__ void atomic64_add(long · line 442
Quoted 10 lines
arch/mips/include/asm/atomic.h +4
-6-" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" -" .set mips0 \n" - : "=&r" (temp), "=m" (v->counter) - : "Ir" (i), "m" (v->counter)); + do { + __asm__ __volatile__( + " .set mips3 \n" + "1: lld %0, %1 # atomic64_add \n"
You've kept the label here but it seems unused...
Quoted 19 lines
arch/mips/include/asm/atomic.h +6
-6+ " daddu %0, %2 \n" + " scd %0, %1 \n" + " .set mips0 \n" + : "=&r" (temp), "=m" (v->counter) + : "Ir" (i), "m" (v->counter)); + }while (unlikely (!temp)); }else {unsigned long flags;@@ -488,18 +479,16 @@ static __inline__ void atomic64_sub(long }else if (kernel_uses_llsc) {long temp; - __asm__ __volatile__( -" .set mips3 \n" -"1: lld %0, %1 # atomic64_sub \n" -" dsubu %0, %2 \n" -" scd %0, %1 \n" - " beqz %0, 2f \n"
arch/mips/include/asm/atomic.h static __inline__ void atomic64_sub(long · line 485
Quoted 10 lines
arch/mips/include/asm/atomic.h +4
-6-" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" -" .set mips0 \n" - : "=&r" (temp), "=m" (v->counter) - : "Ir" (i), "m" (v->counter)); + do { + __asm__ __volatile__( + " .set mips3 \n" + "1: lld %0, %1 # atomic64_sub \n"
Same here...
Quoted 21 lines
arch/mips/include/asm/atomic.h +6
-8+ " dsubu %0, %2 \n" + " scd %0, %1 \n" + " .set mips0 \n" + : "=&r" (temp), "=m" (v->counter) + : "Ir" (i), "m" (v->counter)); + }while (unlikely (!temp)); }else {unsigned long flags;@@ -535,20 +524,19 @@ static __inline__ long atomic64_add_retu }else if (kernel_uses_llsc) {long temp; - __asm__ __volatile__( -" .set mips3 \n" -"1: lld %1, %2 # atomic64_add_return \n" -" daddu %0, %1, %3 \n" -" scd %0, %2 \n" -" beqz %0, 2f \n" -" daddu %0, %1, %3 \n" - " .subsection 2 \n"
arch/mips/include/asm/atomic.h static __inline__ long atomic64_add_retu · line 530
Quoted 10 lines
arch/mips/include/asm/atomic.h +4
-6-"2: b 1b \n" -" .previous \n" -" .set mips0 \n" - : "=&r" (result), "=&r" (temp), "=m" (v->counter) - : "Ir" (i), "m" (v->counter) - : "memory"); + do { + __asm__ __volatile__( + " .set mips3 \n" + "1: lld %1, %2 # atomic64_add_return \n"
... and here.
Quoted 24 lines
arch/mips/include/asm/atomic.h +9
-8+" daddu %0, %1, %3 \n" +" scd %0, %2 \n" +" .set mips0 \n" + : "=&r" (result), "=&r" (temp), "=m" (v->counter) + : "Ir" (i), "m" (v->counter) + : "memory"); + } while (unlikely(!result)); + + result = temp + i; } else {unsigned long flags;@@ -587,20 +575,19 @@ static __inline__ long atomic64_sub_retu }else if (kernel_uses_llsc) {long temp; - __asm__ __volatile__( -" .set mips3 \n" -"1: lld %1, %2 # atomic64_sub_return \n" -" dsubu %0, %1, %3 \n" -" scd %0, %2 \n" -" beqz %0, 2f \n" -" dsubu %0, %1, %3 \n" - " .subsection 2 \n"
arch/mips/include/asm/atomic.h static __inline__ long atomic64_sub_retu · line 581
Quoted 10 lines
arch/mips/include/asm/atomic.h +4
-6-"2: b 1b \n" -" .previous \n" -" .set mips0 \n" - : "=&r" (result), "=&r" (temp), "=m" (v->counter) - : "Ir" (i), "m" (v->counter) - : "memory"); + do { + __asm__ __volatile__( + " .set mips3 \n" + "1: lld %1, %2 # atomic64_sub_return \n"
... and here.
Quoted 35 lines
arch/mips/include/asm/atomic.h +9
-0+" dsubu %0, %1, %3 \n" +" scd %0, %2 \n" +" .set mips0 \n" + : "=&r" (result), "=&r" (temp), "=m" (v->counter) + : "Ir" (i), "m" (v->counter) + : "memory"); + } while (unlikely(!result)); + + result = temp - i; } else {unsigned long flags;Index:
linux-queue/arch/mips/include/asm/bitops.h
===================================================================arch/mips/include/asm/bitops.h +2
-8@@ -213,24 +205,22 @@ static inline void change_bit(unsigned l" " __SC"%0, %1 \n" " beqzl %0, 1b \n" " .set mips0 \n" - : "=&r" (temp), "=m" (*m) - : "ir" (1UL << bit), "m" (*m)); + : "=&r" (temp), "+m" (*m) + : "ir" (1UL << bit)); } else if (kernel_uses_llsc) {unsigned long *m = ((unsigned long *) addr) + (nr >>SZLONG_LOG );unsigned long temp; - __asm__ __volatile__( -" .set mips3 \n" -"1: " __LL"%0, %1 # change_bit \n" -" xor %0, %2 \n" -" " __SC"%0, %1 \n" - " beqz %0, 2f \n"
arch/mips/include/asm/bitops.h static inline void change_bit(unsigned l · line 217
Quoted 10 lines
arch/mips/include/asm/bitops.h +4
-6-" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" -" .set mips0 \n" - : "=&r" (temp), "=m" (*m) - : "ir" (1UL << bit), "m" (*m)); + do { + __asm__ __volatile__( + " .set mips3 \n" + "1: " __LL "%0, %1 # change_bit \n"
... and here too.
Quoted 33 lines
arch/mips/include/asm/bitops.h +8
-13+" xor %0, %2 \n" +" " __SC"%0, %1 \n" +" .set mips0 \n" + : "=&r" (temp), "+m" (*m) + : "ir" (1UL << bit)); + } while (unlikely(!temp)); }else {volatile unsigned long *a = addr;unsigned long mask;@@ -272,30 +262,26 @@ static inline int test_and_set_bit(unsig" beqzl %2, 1b \n" " and %2, %0, %3 \n" " .set mips0 \n" - : "=&r" (temp), "=m" (*m), "=&r" (res) - : "r" (1UL << bit), "m" (*m) + : "=&r" (temp), "+m" (*m), "=&r" (res) + : "r" (1UL << bit) : "memory"); } else if (kernel_uses_llsc) { unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);unsigned long temp; - __asm__ __volatile__( -" .set push \n" -" .set noreorder \n" -" .set mips3 \n" -"1: " __LL"%0, %1 # test_and_set_bit \n" -" or %2, %0, %3 \n" -" " __SC"%2, %1 \n" -" beqz %2, 2f \n" -" and %2, %0, %3 \n" -" .subsection 2 \n" - "2: b 1b \n"
arch/mips/include/asm/bitops.h static inline int test_and_set_bit(unsig · line 275
Quoted 10 lines
arch/mips/include/asm/bitops.h +4
-6-" nop \n" -" .previous \n" -" .set pop \n" - : "=&r" (temp), "=m" (*m), "=&r" (res) - : "r" (1UL << bit), "m" (*m) - : "memory"); + do { + __asm__ __volatile__( + " .set mips3 \n" + "1: " __LL "%0, %1 # test_and_set_bit \n"
... and here as well.
Quoted 36 lines
arch/mips/include/asm/bitops.h +11
-13+" or %2, %0, %3 \n" +" " __SC"%2, %1 \n" +" .set mips0 \n" + : "=&r" (temp), "+m" (*m), "=&r" (res) + : "r" (1UL << bit) + : "memory"); + } while (unlikely(!res)); + + res = temp & (1UL << bit); } else {volatile unsigned long *a = addr;unsigned long mask;@@ -340,30 +326,26 @@ static inline int test_and_set_bit_lock(" beqzl %2, 1b \n" " and %2, %0, %3 \n" " .set mips0 \n" - : "=&r" (temp), "=m" (*m), "=&r" (res) - : "r" (1UL << bit), "m" (*m) + : "=&r" (temp), "+m" (*m), "=&r" (res) + : "r" (1UL << bit) : "memory"); } else if (kernel_uses_llsc) { unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);unsigned long temp; - __asm__ __volatile__( -" .set push \n" -" .set noreorder \n" -" .set mips3 \n" -"1: " __LL"%0, %1 # test_and_set_bit \n" -" or %2, %0, %3 \n" -" " __SC"%2, %1 \n" -" beqz %2, 2f \n" -" and %2, %0, %3 \n" -" .subsection 2 \n" - "2: b 1b \n"
arch/mips/include/asm/bitops.h static inline int test_and_set_bit_lock( · line 339
Quoted 10 lines
arch/mips/include/asm/bitops.h +4
-6-" nop \n" -" .previous \n" -" .set pop \n" - : "=&r" (temp), "=m" (*m), "=&r" (res) - : "r" (1UL << bit), "m" (*m) - : "memory"); + do { + __asm__ __volatile__( + " .set mips3 \n" + "1: " __LL "%0, %1 # test_and_set_bit \n"
... and here.
Quoted 13 lines
arch/mips/include/asm/bitops.h +9
-0+ " or %2, %0, %3 \n" + " " __SC "%2, %1 \n" + " .set mips0 \n" + : "=&r" (temp), "+m" (*m), "=&r" (res) + : "r" (1UL << bit) + : "memory"); + }while (unlikely (!res)); + + res = temp & (1UL << bit); }else {volatile unsigned long *a = addr;unsigned long mask;@@ -410,49 +392,43 @@ static inline int test_and_clear_bit(uns
[...]
Quoted 16 lines
arch/mips/include/asm/bitops.h +0
-12}else if (kernel_uses_llsc) {unsigned long *m = ((unsigned long *) addr) + (nr >>SZLONG_LOG );unsigned long temp; - __asm__ __volatile__( -" .set push \n" -" .set noreorder \n" -" .set mips3 \n" -"1: " __LL"%0, %1 # test_and_clear_bit \n" -" or %2, %0, %3 \n" -" xor %2, %3 \n" -" " __SC"%2, %1 \n" -" beqz %2, 2f \n" -" and %2, %0, %3 \n" -" .subsection 2 \n" - "2: b 1b \n"
arch/mips/include/asm/bitops.h static inline int test_and_clear_bit(uns · line 421
Quoted 10 lines
arch/mips/include/asm/bitops.h +4
-6-" nop \n" -" .previous \n" -" .set pop \n" - : "=&r" (temp), "=m" (*m), "=&r" (res) - : "r" (1UL << bit), "m" (*m) - : "memory"); + do { + __asm__ __volatile__( + " .set mips3 \n" + "1: " __LL "%0, %1 # test_and_clear_bit \n"
... and here.
arch/mips/include/asm/bitops.h static inline int test_and_clear_bit(uns · line 434
Quoted 13 lines
arch/mips/include/asm/bitops.h +10
-0+" or %2, %0, %3 \n" +" xor %2, %3 \n" +" " __SC"%2, %1 \n" +" .set mips0 \n" + : "=&r" (temp), "+m" (*m), "=&r" (res) + : "r" (1UL << bit) + : "memory"); + } while (unlikely(!res)); + + res = temp & (1UL << bit); }else {volatile unsigned long *a = addr;unsigned long mask;
WBR, Sergei
MIPS: Get rid of branches to .subsections.
It was a nice optimization - on paper at least. In practice it results in branches that may exceed the maximum legal range for a branch. We can fight that problem with -ffunction-sections but -ffunction-sections again is incompatible with -pg used by the function tracer.
By rewriting the loop around all simple LL/SC blocks to C we reduce reduce the amount of inline assembler and at the same time allow GCC to often fill the branch delay slots with something sensible or whatever else clever optimization it may have up in its sleeve.
With this optimization gone we also no longer need -ffunction-sections, so drop it.
This optimization was originally introduced in 2.6.21, commit 5999eca25c1fd4b9b9aca7833b04d10fe4bc877d (linux-mips.org) rsp. f65e4fa8e0c6022ad58dc88d1b11b12589ed7f9f (kernel.org).
Original fix for the issues which caused me to pull this optimization by Paul Gortmaker <[email protected]>.
--
v3: Spelling fixes and asm labels that became unused by the changed removed.
arch/mips/Makefile | 3 arch/mips/include/asm/atomic.h | 208 ++++++++++++++---------------- arch/mips/include/asm/bitops.h | 270 +++++++++++++++++----------------------- arch/mips/include/asm/cmpxchg.h | 7 - arch/mips/include/asm/system.h | 52 +++---- 5 files changed, 243 insertions(+), 297 deletions(-)
arch/mips/include/asm/atomic.h +96 -112
@@ -64,18 +64,16 @@ static __inline__ void atomic_add(int i, }else if (kernel_uses_llsc) {int temp; - __asm__ __volatile__( -" .set mips3 \n" -"1: ll %0, %1 # atomic_add \n" -" addu %0, %2 \n" -" sc %0, %1 \n" -" beqz %0, 2f \n" -" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" -" .set mips0 \n" - :"=&r" (temp),"=m" (v->counter) - :"Ir" (i),"m" (v->counter)); +do { + __asm__ __volatile__( +" .set mips3 \n" +" ll %0, %1 # atomic_add \n" +" addu %0, %2 \n" +" sc %0, %1 \n" +" .set mips0 \n" + :"=&r" (temp),"=m" (v->counter) + :"Ir" (i),"m" (v->counter)); + }while (unlikely (!temp)); }else {unsigned long flags;
@@ -109,18 +107,16 @@ static __inline__ void atomic_sub(int i, }else if (kernel_uses_llsc) {int temp; - __asm__ __volatile__( -" .set mips3 \n" -"1: ll %0, %1 # atomic_sub \n" -" subu %0, %2 \n" -" sc %0, %1 \n" -" beqz %0, 2f \n" -" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" -" .set mips0 \n" - :"=&r" (temp),"=m" (v->counter) - :"Ir" (i),"m" (v->counter)); +do { + __asm__ __volatile__( +" .set mips3 \n" +" ll %0, %1 # atomic_sub \n" +" subu %0, %2 \n" +" sc %0, %1 \n" +" .set mips0 \n" + :"=&r" (temp),"=m" (v->counter) + :"Ir" (i),"m" (v->counter)); + }while (unlikely (!temp)); }else {unsigned long flags;
@@ -156,20 +152,19 @@ static __inline__ int atomic_add_return( }else if (kernel_uses_llsc) {int temp; - __asm__ __volatile__( -" .set mips3 \n" -"1: ll %1, %2 # atomic_add_return \n" -" addu %0, %1, %3 \n" -" sc %0, %2 \n" -" beqz %0, 2f \n" -" addu %0, %1, %3 \n" -" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" -" .set mips0 \n" - :"=&r" (result),"=&r" (temp),"=m" (v->counter) - :"Ir" (i),"m" (v->counter) - :"memory" ); +do { + __asm__ __volatile__( +" .set mips3 \n" +" ll %1, %2 # atomic_add_return \n" +" addu %0, %1, %3 \n" +" sc %0, %2 \n" +" .set mips0 \n" + :"=&r" (result),"=&r" (temp),"=m" (v->counter) + :"Ir" (i),"m" (v->counter) + :"memory" ); + }while (unlikely (!result)); + + result = temp + i; }else {unsigned long flags;
@@ -205,23 +200,24 @@ static __inline__ int atomic_sub_return( : "=&r" (result), "=&r" (temp), "=m" (v->counter) : "Ir" (i), "m" (v->counter) : "memory"); + + result = temp - i; }else if (kernel_uses_llsc) {int temp; - __asm__ __volatile__( -" .set mips3 \n" -"1: ll %1, %2 # atomic_sub_return \n" -" subu %0, %1, %3 \n" -" sc %0, %2 \n" -" beqz %0, 2f \n" -" subu %0, %1, %3 \n" -" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" -" .set mips0 \n" - :"=&r" (result),"=&r" (temp),"=m" (v->counter) - :"Ir" (i),"m" (v->counter) - :"memory" ); +do { + __asm__ __volatile__( +" .set mips3 \n" +" ll %1, %2 # atomic_sub_return \n" +" subu %0, %1, %3 \n" +" sc %0, %2 \n" +" .set mips0 \n" + :"=&r" (result),"=&r" (temp),"=m" (v->counter) + :"Ir" (i),"m" (v->counter) + :"memory" ); + }while (unlikely (!result)); + + result = temp - i; }else {unsigned long flags;
@@ -279,12 +275,9 @@ static __inline__ int atomic_sub_if_posi" bltz %0, 1f \n" " sc %0, %2 \n" " .set noreorder \n" -" beqz %0, 2f \n" +" beqz %0, 1b \n" " subu %0, %1, %3 \n" " .set reorder \n" -" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" "1: \n" " .set mips0 \n" : "=&r" (result), "=&r" (temp), "=m" (v->counter)
@@ -443,18 +436,16 @@ static __inline__ void atomic64_add(long }else if (kernel_uses_llsc) {long temp; - __asm__ __volatile__( -" .set mips3 \n" -"1: lld %0, %1 # atomic64_add \n" -" daddu %0, %2 \n" -" scd %0, %1 \n" -" beqz %0, 2f \n" -" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" -" .set mips0 \n" - :"=&r" (temp),"=m" (v->counter) - :"Ir" (i),"m" (v->counter)); +do { + __asm__ __volatile__( +" .set mips3 \n" +" lld %0, %1 # atomic64_add \n" +" daddu %0, %2 \n" +" scd %0, %1 \n" +" .set mips0 \n" + :"=&r" (temp),"=m" (v->counter) + :"Ir" (i),"m" (v->counter)); + }while (unlikely (!temp)); }else {unsigned long flags;
@@ -488,18 +479,16 @@ static __inline__ void atomic64_sub(long }else if (kernel_uses_llsc) {long temp; - __asm__ __volatile__( -" .set mips3 \n" -"1: lld %0, %1 # atomic64_sub \n" -" dsubu %0, %2 \n" -" scd %0, %1 \n" -" beqz %0, 2f \n" -" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" -" .set mips0 \n" - :"=&r" (temp),"=m" (v->counter) - :"Ir" (i),"m" (v->counter)); +do { + __asm__ __volatile__( +" .set mips3 \n" +" lld %0, %1 # atomic64_sub \n" +" dsubu %0, %2 \n" +" scd %0, %1 \n" +" .set mips0 \n" + :"=&r" (temp),"=m" (v->counter) + :"Ir" (i),"m" (v->counter)); + }while (unlikely (!temp)); }else {unsigned long flags;
@@ -535,20 +524,19 @@ static __inline__ long atomic64_add_retu }else if (kernel_uses_llsc) {long temp; - __asm__ __volatile__( -" .set mips3 \n" -"1: lld %1, %2 # atomic64_add_return \n" -" daddu %0, %1, %3 \n" -" scd %0, %2 \n" -" beqz %0, 2f \n" -" daddu %0, %1, %3 \n" -" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" -" .set mips0 \n" - :"=&r" (result),"=&r" (temp),"=m" (v->counter) - :"Ir" (i),"m" (v->counter) - :"memory" ); +do { + __asm__ __volatile__( +" .set mips3 \n" +" lld %1, %2 # atomic64_add_return \n" +" daddu %0, %1, %3 \n" +" scd %0, %2 \n" +" .set mips0 \n" + :"=&r" (result),"=&r" (temp),"=m" (v->counter) + :"Ir" (i),"m" (v->counter) + :"memory" ); + }while (unlikely (!result)); + + result = temp + i; }else {unsigned long flags;
@@ -587,20 +575,19 @@ static __inline__ long atomic64_sub_retu }else if (kernel_uses_llsc) {long temp; - __asm__ __volatile__( -" .set mips3 \n" -"1: lld %1, %2 # atomic64_sub_return \n" -" dsubu %0, %1, %3 \n" -" scd %0, %2 \n" -" beqz %0, 2f \n" -" dsubu %0, %1, %3 \n" -" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" -" .set mips0 \n" - :"=&r" (result),"=&r" (temp),"=m" (v->counter) - :"Ir" (i),"m" (v->counter) - :"memory" ); +do { + __asm__ __volatile__( +" .set mips3 \n" +" lld %1, %2 # atomic64_sub_return \n" +" dsubu %0, %1, %3 \n" +" scd %0, %2 \n" +" .set mips0 \n" + :"=&r" (result),"=&r" (temp),"=m" (v->counter) + :"Ir" (i),"m" (v->counter) + :"memory" ); + }while (unlikely (!result)); + + result = temp - i; }else {unsigned long flags;
@@ -658,12 +645,9 @@ static __inline__ long atomic64_sub_if_p" bltz %0, 1f \n" " scd %0, %2 \n" " .set noreorder \n" -" beqz %0, 2f \n" +" beqz %0, 1b \n" " dsubu %0, %1, %3 \n" " .set reorder \n" -" .subsection 2 \n" -"2: b 1b \n" -" .previous \n" "1: \n" " .set mips0 \n" : "=&r" (result), "=&r" (temp), "=m" (v->counter)
arch/mips/include/asm/bitops.h +121 -149
348 lines not on this page · raw message
arch/mips/include/asm/cmpxchg.h +2 -5
@@ -44,12 +44,9 @@" move $1, %z4 \n" \" .set mips3 \n" \" " st" $1, %1 \n" \ -" beqz $1, 3f \n" \ -"2: \n" \ -" .subsection 2 \n" \ -"3: b 1b \n" \ -" .previous \n" \ +" beqz $1, 1b \n" \" .set pop \n" \ +"2: \n" \ : "=&r" (__ret), "=R" (*m) \: " R " (*m), " Jr" (old), " Jr" (new) \ : " memory"); \
arch/mips/include/asm/system.h +24 -28
64 lines not on this page · raw message
arch/mips/Makefile +0 -3
@@ -48,9 +48,6 @@ ifneq ($(SUBARCH),$(ARCH)) endif endif -ifndef CONFIG_FUNCTION_TRACER -cflags-y := -ffunction-sections -endif ifdef CONFIG_FUNCTION_GRAPH_TRACER ifndef KBUILD_MCOUNT_RA_ADDRESS ifeq ($(call cc-option-yn,-mmcount-ra-address), y)
Quoted 4 lines · Ralf Baechle
It was a nice optimization - on paper at least. In practice it results in branches that may exceed the maximum legal range for a branch. We can fight that problem with -ffunction-sections but -ffunction-sections again is incompatible with -pg used by the function tracer.
I'm pretty sure that this check in GCC is historic. I know it has been discussed in the past but I don't think a solution was ever reached and my google skills are failing me, I can't find the discussion in the archives.
We maintain a patch at work that removes this check because we always use -ffunction-sections and also needed to be able to profile things. We've never seen any issues.
GCC guys, is this check still needed? Does anyone know which architecture required this restriction?
Quoted 4 lines · Ralf Baechle
By rewriting the loop around all simple LL/SC blocks to C we reduce reduce the amount of inline assembler and at the same time allow GCC to often fill the branch delay slots with something sensible or whever else clever optimization it may have up in its sleeve.
Are you sure it won't reorder anything there that actually relies on the
atomic access to have succeeded? I suggest adding barrier() after the loop.
Maciej
Quoted 8 lines · Maciej W. Rozycki
Quoted 4 lines
By rewriting the loop around all simple LL/SC blocks to C we reduce reduce the amount of inline assembler and at the same time allow GCC to often fill the branch delay slots with something sensible or whever else clever optimization it may have up in its sleeve.
Are you sure it won't reorder anything there that actually relies on the
atomic access to have succeeded? I suggest addingbarrier()after the loop.
None of the things that were touched by the code had any barrier functionality Some of the functions such as atomic_add don't provide memory barriers but where needed a barrier was always provided by C code near the end of the function, for example in atomic_add_return.
Ralf
Quoted 8 lines · Ralf Baechle
Quoted 3 lines
Are you sure it won't reorder anything there that actually relies on the
atomic access to have succeeded? I suggest addingbarrier()after the loop.None of the things that were touched by the code had any barrier functionality Some of the functions such as
atomic_adddon't provide memory barriers but where needed a barrier was always provided by C code near the end of the function, for example inatomic_add_return.
OK, if you are sure this is safe, then I see no problem here.
Maciej