aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mn10300
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>2011-03-23 13:42:49 -0400
committerDavid Howells <dhowells@redhat.com>2011-03-23 13:42:49 -0400
commit5a4b65ab506398ba5a35c37e06edddd387cc0add (patch)
tree419fb3b0468f69922bf1a0c6023468ba53c4f608 /arch/mn10300
parent1a8d59e529d07f7888f9c6c86a9f59ea4ef077aa (diff)
MN10300: gcc 4.6 vs am33 inline assembly
GCC 4.6 explicitly represents the MDR register. It may be accessed via the "z" constraint. Perhaps more importantly, it tracks when the MDR register is clobbered and uses the RETF instruction if the incoming value is still valid. Thus it is important to (at least) clobber the MDR register in relevant inline assembly fragments, lest RETF be used incorrectly. The only instances I could find are here. There are reads of the MDR register in kernel/gdb-stub.c, but that's harmless. Although, frankly, __builtin_return_address(0) might be a better thing in those cases. Certainly MDR isn't going to contain anything else that might be useful... Signed-off-by: Richard Henderson <rth@redhat.com> Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'arch/mn10300')
-rw-r--r--arch/mn10300/include/asm/div64.h21
1 files changed, 17 insertions, 4 deletions
diff --git a/arch/mn10300/include/asm/div64.h b/arch/mn10300/include/asm/div64.h
index 34dcb8e68309..503efab2a516 100644
--- a/arch/mn10300/include/asm/div64.h
+++ b/arch/mn10300/include/asm/div64.h
@@ -16,6 +16,19 @@
16extern void ____unhandled_size_in_do_div___(void); 16extern void ____unhandled_size_in_do_div___(void);
17 17
18/* 18/*
19 * Beginning with gcc 4.6, the MDR register is represented explicitly. We
20 * must, therefore, at least explicitly clobber the register when we make
21 * changes to it. The following assembly fragments *could* be rearranged in
22 * order to leave the moves to/from the MDR register to the compiler, but the
23 * gains would be minimal at best.
24 */
25#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
26# define CLOBBER_MDR_CC "mdr", "cc"
27#else
28# define CLOBBER_MDR_CC "cc"
29#endif
30
31/*
19 * divide n by base, leaving the result in n and returning the remainder 32 * divide n by base, leaving the result in n and returning the remainder
20 * - we can do this quite efficiently on the MN10300 by cascading the divides 33 * - we can do this quite efficiently on the MN10300 by cascading the divides
21 * through the MDR register 34 * through the MDR register
@@ -29,7 +42,7 @@ extern void ____unhandled_size_in_do_div___(void);
29 "mov mdr,%1 \n" \ 42 "mov mdr,%1 \n" \
30 : "+r"(n), "=d"(__rem) \ 43 : "+r"(n), "=d"(__rem) \
31 : "r"(base), "1"(__rem) \ 44 : "r"(base), "1"(__rem) \
32 : "cc" \ 45 : CLOBBER_MDR_CC \
33 ); \ 46 ); \
34 } else if (sizeof(n) <= 8) { \ 47 } else if (sizeof(n) <= 8) { \
35 union { \ 48 union { \
@@ -48,7 +61,7 @@ extern void ____unhandled_size_in_do_div___(void);
48 : "=d"(__rem), "=r"(__quot.w[1]), "=r"(__quot.w[0]) \ 61 : "=d"(__rem), "=r"(__quot.w[1]), "=r"(__quot.w[0]) \
49 : "r"(base), "0"(__rem), "1"(__quot.w[1]), \ 62 : "r"(base), "0"(__rem), "1"(__quot.w[1]), \
50 "2"(__quot.w[0]) \ 63 "2"(__quot.w[0]) \
51 : "cc" \ 64 : CLOBBER_MDR_CC \
52 ); \ 65 ); \
53 n = __quot.l; \ 66 n = __quot.l; \
54 } else { \ 67 } else { \
@@ -72,7 +85,7 @@ unsigned __muldiv64u(unsigned val, unsigned mult, unsigned div)
72 * MDR = MDR:val%div */ 85 * MDR = MDR:val%div */
73 : "=r"(result) 86 : "=r"(result)
74 : "0"(val), "ir"(mult), "r"(div) 87 : "0"(val), "ir"(mult), "r"(div)
75 : "cc" 88 : CLOBBER_MDR_CC
76 ); 89 );
77 90
78 return result; 91 return result;
@@ -93,7 +106,7 @@ signed __muldiv64s(signed val, signed mult, signed div)
93 * MDR = MDR:val%div */ 106 * MDR = MDR:val%div */
94 : "=r"(result) 107 : "=r"(result)
95 : "0"(val), "ir"(mult), "r"(div) 108 : "0"(val), "ir"(mult), "r"(div)
96 : "cc" 109 : CLOBBER_MDR_CC
97 ); 110 );
98 111
99 return result; 112 return result;