diff mbox

[U-Boot] dm: mips: Import libgcc components from Linux

Message ID 1343414125-23359-1-git-send-email-marex@denx.de
State Superseded
Delegated to: Daniel Schwierzeck
Headers show

Commit Message

Marek Vasut July 27, 2012, 6:35 p.m. UTC
Import ashldr3, ashrdi3 and lshrdi3 to squash possible libgcc fp mismatch,
resulting in the following warning:

mips-linux-gnu-ld: Warning: /usr/lib/gcc/mips-linux-gnu/4.7/libgcc.a(_lshrdi3.o) uses hard float, u-boot uses soft float
mips-linux-gnu-ld: Warning: /usr/lib/gcc/mips-linux-gnu/4.7/libgcc.a(_ashldi3.o) uses hard float, u-boot uses soft float

Imported from Linux (linux-next 20120723) as of commit:

commit 72fbfb260197a52c2bc2583f3e8f15d261d0f924
Author: Ralf Baechle <ralf@linux-mips.org>
Date:   Wed Jun 7 13:25:37 2006 +0100

    [MIPS] Fix optimization for size build.

    It took a while longer than on other architectures but gcc has finally
    started to strike us as well ...

    This also fixes the damage by 6edfba1b33c701108717f4e036320fc39abe1912.

    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
---
 arch/mips/lib/Makefile  |    2 ++
 arch/mips/lib/ashldi3.c |   25 +++++++++++++++++++++++++
 arch/mips/lib/ashrdi3.c |   27 +++++++++++++++++++++++++++
 arch/mips/lib/libgcc.h  |   25 +++++++++++++++++++++++++
 arch/mips/lib/lshrdi3.c |   25 +++++++++++++++++++++++++
 5 files changed, 104 insertions(+)
 create mode 100644 arch/mips/lib/ashldi3.c
 create mode 100644 arch/mips/lib/ashrdi3.c
 create mode 100644 arch/mips/lib/libgcc.h
 create mode 100644 arch/mips/lib/lshrdi3.c

Comments

Mike Frysinger July 27, 2012, 7:06 p.m. UTC | #1
On Friday 27 July 2012 14:35:25 Marek Vasut wrote:
> --- a/arch/mips/lib/Makefile
> +++ b/arch/mips/lib/Makefile
> @@ -34,6 +34,8 @@ else
>  COBJS-y	+= bootm.o
>  endif
> 
> +COBJS-y	+= ashldi3.o ashrdi3.o lshrdi3.o

pretty sure this belongs behind USE_PRIVATE_LIBGCC
-mike
Marek Vasut July 27, 2012, 7:10 p.m. UTC | #2
Dear Mike Frysinger,

> On Friday 27 July 2012 14:35:25 Marek Vasut wrote:
> > --- a/arch/mips/lib/Makefile
> > +++ b/arch/mips/lib/Makefile
> > @@ -34,6 +34,8 @@ else
> > 
> >  COBJS-y	+= bootm.o
> >  endif
> > 
> > +COBJS-y	+= ashldi3.o ashrdi3.o lshrdi3.o
> 
> pretty sure this belongs behind USE_PRIVATE_LIBGCC

Good point ... Mike, I was always wondering what this USE_PRIVATE_LIBGCC is, can 
you elaborate please (pour some of your knowledge on me ;-) ) ?

> -mike

Best regards,
Marek Vasut
Wolfgang Denk July 27, 2012, 7:37 p.m. UTC | #3
Dear Marek Vasut,

In message <1343414125-23359-1-git-send-email-marex@denx.de> you wrote:
> Import ashldr3, ashrdi3 and lshrdi3 to squash possible libgcc fp mismatch,
> resulting in the following warning:
> 
> mips-linux-gnu-ld: Warning: /usr/lib/gcc/mips-linux-gnu/4.7/libgcc.a(_lshrdi3.o) uses hard float, u-boot uses soft float
> mips-linux-gnu-ld: Warning: /usr/lib/gcc/mips-linux-gnu/4.7/libgcc.a(_ashldi3.o) uses hard float, u-boot uses soft float

We consider this a bug in the tool chain.  We provide a workarounf for
such broken tool chains, but it has to be enabled explicitly by
setting USE_PRIVATE_LIBGCC

> diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
> index 9244f31..a469e30 100644
> --- a/arch/mips/lib/Makefile
> +++ b/arch/mips/lib/Makefile
> @@ -34,6 +34,8 @@ else
>  COBJS-y	+= bootm.o
>  endif
>  
> +COBJS-y	+= ashldi3.o ashrdi3.o lshrdi3.o
> +

Please make this dependent on USE_PRIVATE_LIBGCC being set.

Best regards,

Wolfgang Denk
Mike Frysinger July 31, 2012, 7:56 a.m. UTC | #4
On Friday 27 July 2012 15:10:00 Marek Vasut wrote:
> Dear Mike Frysinger,
> > On Friday 27 July 2012 14:35:25 Marek Vasut wrote:
> > > --- a/arch/mips/lib/Makefile
> > > +++ b/arch/mips/lib/Makefile
> > > @@ -34,6 +34,8 @@ else
> > > 
> > >  COBJS-y	+= bootm.o
> > >  endif
> > > 
> > > +COBJS-y	+= ashldi3.o ashrdi3.o lshrdi3.o
> > 
> > pretty sure this belongs behind USE_PRIVATE_LIBGCC
> 
> Good point ... Mike, I was always wondering what this USE_PRIVATE_LIBGCC
> is, can you elaborate please (pour some of your knowledge on me ;-) ) ?

libgcc is a supplemental library that gcc provides that often times contains 
extended routines (usually written in assembly) for implementing math 
functions that the hardware does not provide itself in the form of dedicated 
instructions.  most commonly, this takes the form of multiplication/divide 
routines.  x86 tends to be "fat" and provide instructions like "mul" and 
"div", but embedded arches like arm/blackfin/mips/etc... tend to have simpler 
instructions so we have to implement these in software.

the problem comes in when the toolchain is built targeting an ABI/float model 
that differs from what we want in u-boot.  Linux has long avoided this problem 
by always bundling the libgcc source files directly into its arch/ tree.  it 
pulls in the bare min that it needs, and then never links with -lgcc.

u-boot has taken the opposite approach: it links against -lgcc for math 
routines rather than keeping a copy of its own.  this leads to the problem you 
noticed with mips, but many of us have hit it with arm.

for the longest time, the party line was "use a different toolchain".  but 
that's often impractical (if not almost impossible) for many users/devs, so 
the compromise has been the USE_PRIVATE_LIBGCC knob.  now the ABI of the 
libgcc that comes with your toolchain does not matter because it isn't linked 
in -- we just compile (for the right ABI) local copies of the math routines, 
and then link against those.

personally, i wouldn't mind converting everyone to USE_PRIVATE_LIBGCC (and 
match exactly what Linux has been doing for ages), but i can live with the 
USE_PRIVATE_LIBGCC trade off.
-mike
diff mbox

Patch

diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index 9244f31..a469e30 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -34,6 +34,8 @@  else
 COBJS-y	+= bootm.o
 endif
 
+COBJS-y	+= ashldi3.o ashrdi3.o lshrdi3.o
+
 SRCS	:= $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
 OBJS	:= $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
 
diff --git a/arch/mips/lib/ashldi3.c b/arch/mips/lib/ashldi3.c
new file mode 100644
index 0000000..9b50d86
--- /dev/null
+++ b/arch/mips/lib/ashldi3.c
@@ -0,0 +1,25 @@ 
+#include "libgcc.h"
+
+long long __ashldi3(long long u, word_type b)
+{
+	DWunion uu, w;
+	word_type bm;
+
+	if (b == 0)
+		return u;
+
+	uu.ll = u;
+	bm = 32 - b;
+
+	if (bm <= 0) {
+		w.s.low = 0;
+		w.s.high = (unsigned int) uu.s.low << -bm;
+	} else {
+		const unsigned int carries = (unsigned int) uu.s.low >> bm;
+
+		w.s.low = (unsigned int) uu.s.low << b;
+		w.s.high = ((unsigned int) uu.s.high << b) | carries;
+	}
+
+	return w.ll;
+}
diff --git a/arch/mips/lib/ashrdi3.c b/arch/mips/lib/ashrdi3.c
new file mode 100644
index 0000000..f30359b
--- /dev/null
+++ b/arch/mips/lib/ashrdi3.c
@@ -0,0 +1,27 @@ 
+#include "libgcc.h"
+
+long long __ashrdi3(long long u, word_type b)
+{
+	DWunion uu, w;
+	word_type bm;
+
+	if (b == 0)
+		return u;
+
+	uu.ll = u;
+	bm = 32 - b;
+
+	if (bm <= 0) {
+		/* w.s.high = 1..1 or 0..0 */
+		w.s.high =
+		    uu.s.high >> 31;
+		w.s.low = uu.s.high >> -bm;
+	} else {
+		const unsigned int carries = (unsigned int) uu.s.high << bm;
+
+		w.s.high = uu.s.high >> b;
+		w.s.low = ((unsigned int) uu.s.low >> b) | carries;
+	}
+
+	return w.ll;
+}
diff --git a/arch/mips/lib/libgcc.h b/arch/mips/lib/libgcc.h
new file mode 100644
index 0000000..05909d5
--- /dev/null
+++ b/arch/mips/lib/libgcc.h
@@ -0,0 +1,25 @@ 
+#ifndef __ASM_LIBGCC_H
+#define __ASM_LIBGCC_H
+
+#include <asm/byteorder.h>
+
+typedef int word_type __attribute__ ((mode (__word__)));
+
+#ifdef __BIG_ENDIAN
+struct DWstruct {
+	int high, low;
+};
+#elif defined(__LITTLE_ENDIAN)
+struct DWstruct {
+	int low, high;
+};
+#else
+#error I feel sick.
+#endif
+
+typedef union {
+	struct DWstruct s;
+	long long ll;
+} DWunion;
+
+#endif /* __ASM_LIBGCC_H */
diff --git a/arch/mips/lib/lshrdi3.c b/arch/mips/lib/lshrdi3.c
new file mode 100644
index 0000000..bb340ac
--- /dev/null
+++ b/arch/mips/lib/lshrdi3.c
@@ -0,0 +1,25 @@ 
+#include "libgcc.h"
+
+long long __lshrdi3(long long u, word_type b)
+{
+	DWunion uu, w;
+	word_type bm;
+
+	if (b == 0)
+		return u;
+
+	uu.ll = u;
+	bm = 32 - b;
+
+	if (bm <= 0) {
+		w.s.high = 0;
+		w.s.low = (unsigned int) uu.s.high >> -bm;
+	} else {
+		const unsigned int carries = (unsigned int) uu.s.high << bm;
+
+		w.s.high = (unsigned int) uu.s.high >> b;
+		w.s.low = ((unsigned int) uu.s.low >> b) | carries;
+	}
+
+	return w.ll;
+}