[20/25] GCN libgcc.

Message ID fb1a2303caa311e394cc267ab6fe2788cc1b1396.1536144068.git.ams@codesourcery.com
State New
Headers show
Series
  • AMD GCN Port
Related show

Commit Message

Andrew Stubbs Sept. 5, 2018, 11:52 a.m.
This patch contains the GCN port of libgcc.  I've broken it out just to keep
both parts more manageable.

We have the usual stuff, plus a "gomp_print" implementation intended to provide
a means to output text to console without using the full printf.  Originally
this was because we did not have a working Newlib port, but now it provides the
underlying mechanism for printf.  It's also much lighter than printf, and
therefore more suitable for debugging offload kernels (for which there is no
debugger, yet).

In order to work in offload kernels the same function must be present in both
host and GCN toolchains.  Therefore it needs to live in libgomp (hence the
name).  However, having found it also useful in stand alone testing I have
moved the GCN implementation to libgcc.

It was also necessary to provide a means to disable EMUTLS.

2018-09-05  Andrew Stubbs  <ams@codesourcery.com>
	    Kwok Cheung Yeung  <kcy@codesourcery.com>
	    Julian Brown  <julian@codesourcery.com>
	    Tom de Vries  <tom@codesourcery.com>

	libgcc/
	* Makefile.in: Don't add emutls.c when --enable-emutls is "no".
	* config.host: Recognize amdgcn*-*-amdhsa.
	* config/gcn/crt0.c: New file.
	* config/gcn/gomp_print.c: New file.
	* config/gcn/lib2-divmod-hi.c: New file.
	* config/gcn/lib2-divmod.c: New file.
	* config/gcn/lib2-gcn.h: New file.
	* config/gcn/reduction.c: New file.
	* config/gcn/sfp-machine.h: New file.
	* config/gcn/t-amdgcn: New file.
---
 libgcc/Makefile.in                 |   2 +
 libgcc/config.host                 |   8 +++
 libgcc/config/gcn/crt0.c           |  23 ++++++++
 libgcc/config/gcn/gomp_print.c     |  99 +++++++++++++++++++++++++++++++
 libgcc/config/gcn/lib2-divmod-hi.c | 117 +++++++++++++++++++++++++++++++++++++
 libgcc/config/gcn/lib2-divmod.c    | 117 +++++++++++++++++++++++++++++++++++++
 libgcc/config/gcn/lib2-gcn.h       |  49 ++++++++++++++++
 libgcc/config/gcn/reduction.c      |  30 ++++++++++
 libgcc/config/gcn/sfp-machine.h    |  51 ++++++++++++++++
 libgcc/config/gcn/t-amdgcn         |  25 ++++++++
 10 files changed, 521 insertions(+)
 create mode 100644 libgcc/config/gcn/crt0.c
 create mode 100644 libgcc/config/gcn/gomp_print.c
 create mode 100644 libgcc/config/gcn/lib2-divmod-hi.c
 create mode 100644 libgcc/config/gcn/lib2-divmod.c
 create mode 100644 libgcc/config/gcn/lib2-gcn.h
 create mode 100644 libgcc/config/gcn/reduction.c
 create mode 100644 libgcc/config/gcn/sfp-machine.h
 create mode 100644 libgcc/config/gcn/t-amdgcn

Comments

Joseph Myers Sept. 5, 2018, 12:32 p.m. | #1
On Wed, 5 Sep 2018, ams@codesourcery.com wrote:

> diff --git a/libgcc/config/gcn/crt0.c b/libgcc/config/gcn/crt0.c

> new file mode 100644

> index 0000000..f4f367b

> --- /dev/null

> +++ b/libgcc/config/gcn/crt0.c

> @@ -0,0 +1,23 @@

> +/* Copyright (C) 2017 Free Software Foundation, Inc.


Copyright ranges on all new files should include 2018.

-- 
Joseph S. Myers
joseph@codesourcery.com
Jeff Law Nov. 9, 2018, 6:48 p.m. | #2
On 9/5/18 5:52 AM, ams@codesourcery.com wrote:
> This patch contains the GCN port of libgcc.  I've broken it out just to keep

> both parts more manageable.

> 

> We have the usual stuff, plus a "gomp_print" implementation intended to provide

> a means to output text to console without using the full printf.  Originally

> this was because we did not have a working Newlib port, but now it provides the

> underlying mechanism for printf.  It's also much lighter than printf, and

> therefore more suitable for debugging offload kernels (for which there is no

> debugger, yet).

> 

> In order to work in offload kernels the same function must be present in both

> host and GCN toolchains.  Therefore it needs to live in libgomp (hence the

> name).  However, having found it also useful in stand alone testing I have

> moved the GCN implementation to libgcc.

> 

> It was also necessary to provide a means to disable EMUTLS.

> 

> 2018-09-05  Andrew Stubbs  <ams@codesourcery.com>

> 	    Kwok Cheung Yeung  <kcy@codesourcery.com>

> 	    Julian Brown  <julian@codesourcery.com>

> 	    Tom de Vries  <tom@codesourcery.com>

> 

> 	libgcc/

> 	* Makefile.in: Don't add emutls.c when --enable-emutls is "no".

> 	* config.host: Recognize amdgcn*-*-amdhsa.

> 	* config/gcn/crt0.c: New file.

> 	* config/gcn/gomp_print.c: New file.

> 	* config/gcn/lib2-divmod-hi.c: New file.

> 	* config/gcn/lib2-divmod.c: New file.

> 	* config/gcn/lib2-gcn.h: New file.

> 	* config/gcn/reduction.c: New file.

> 	* config/gcn/sfp-machine.h: New file.

> 	* config/gcn/t-amdgcn: New file.

> ---

> 

> 

> 0020-GCN-libgcc.patch

> 

> diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in

> index 0c5b264..6f68257 100644

> --- a/libgcc/Makefile.in

> +++ b/libgcc/Makefile.in

> @@ -429,9 +429,11 @@ LIB2ADD += enable-execute-stack.c

>  # While emutls.c has nothing to do with EH, it is in LIB2ADDEH*

>  # instead of LIB2ADD because that's the way to be sure on some targets

>  # (e.g. *-*-darwin*) only one copy of it is linked.

> +ifneq ($(enable_emutls),no)

>  LIB2ADDEH += $(srcdir)/emutls.c

>  LIB2ADDEHSTATIC += $(srcdir)/emutls.c

>  LIB2ADDEHSHARED += $(srcdir)/emutls.c

> +endif

Why is this needed? Are you just trying to cut out stuff you don't need
in the quest for smaller code or does this cause a more direct problem?


> diff --git a/libgcc/config/gcn/crt0.c b/libgcc/config/gcn/crt0.c

> new file mode 100644

> index 0000000..f4f367b

> --- /dev/null

> +++ b/libgcc/config/gcn/crt0.c

> @@ -0,0 +1,23 @@

> +/* Copyright (C) 2017 Free Software Foundation, Inc.

> +

> +   This file is free software; you can redistribute it and/or modify it

> +   under the terms of the GNU General Public License as published by the

> +   Free Software Foundation; either version 3, or (at your option) any

> +   later version.

> +

> +   This file is distributed in the hope that it will be useful, but

> +   WITHOUT ANY WARRANTY; without even the implied warranty of

> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU

> +   General Public License for more details.

> +

> +   Under Section 7 of GPL version 3, you are granted additional

> +   permissions described in the GCC Runtime Library Exception, version

> +   3.1, as published by the Free Software Foundation.

> +

> +   You should have received a copy of the GNU General Public License and

> +   a copy of the GCC Runtime Library Exception along with this program;

> +   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see

> +   <http://www.gnu.org/licenses/>.  */

> +

> +/* Provide an entry point symbol to silence a linker warning.  */

> +void _start() {}

This seems wrong.   I realize you're trying to quiet a linker warning
here, but for the case where you're creating GCN executables (testing?)
this should probably be handled by the C-runtime or linker script.


> diff --git a/libgcc/config/gcn/gomp_print.c b/libgcc/config/gcn/gomp_print.c

> new file mode 100644

> index 0000000..41f50c3

> --- /dev/null

> +++ b/libgcc/config/gcn/gomp_print.c

[ ... ]
Would this be better in libgomp?  Oh, you addressed that in the
prologue.  Feels like libgomp would be better to me, but I can
understand the rationale behind wanting it in libgcc.


I won't comment on the static sizes since this apparently has to match
something already in existence.



> +

> +void

> +gomp_print_string (const char *msg, const char *value)

> +{

> +  struct printf_data *output = reserve_print_slot ();

> +  output->type = 2; /* String.  */

> +

> +  strncpy (output->msg, msg, 127);

> +  output->msg[127] = '\0';

> +  strncpy (output->text, value, 127);

> +  output->text[127] = '\0';

> +

> +  asm ("" ::: "memory");

> +  output->written = 1;

> +}

I'm not familiar with the GCN memory model, but your asm is really just
a barrier for the compiler.  Do you need any kind of hardware fencing
here?  Similarly for other instances.

All these functions probably need a little comment on their purpose and
arguments.

Note some of the divmod stuff recently changed.  You may need minor
updates as a result of those patches.  See:

2018-10-18  Paul Koning  <ni1d@arrl.net>

        * udivmodsi4.c (__udivmodsi4): Rename to conform to coding
        standard.
        * divmod.c: Update references to __udivmodsi4.
        * udivmod.c: Ditto.
        * udivhi3.c: New file.
        * udivmodhi4.c: New file.
        * config/pdp11/t-pdp11 (LIB2ADD): Add the new files.


Jeff
Andrew Stubbs Nov. 12, 2018, noon | #3
On 09/11/2018 18:48, Jeff Law wrote:
>> diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in

>> index 0c5b264..6f68257 100644

>> --- a/libgcc/Makefile.in

>> +++ b/libgcc/Makefile.in

>> @@ -429,9 +429,11 @@ LIB2ADD += enable-execute-stack.c

>>   # While emutls.c has nothing to do with EH, it is in LIB2ADDEH*

>>   # instead of LIB2ADD because that's the way to be sure on some targets

>>   # (e.g. *-*-darwin*) only one copy of it is linked.

>> +ifneq ($(enable_emutls),no)

>>   LIB2ADDEH += $(srcdir)/emutls.c

>>   LIB2ADDEHSTATIC += $(srcdir)/emutls.c

>>   LIB2ADDEHSHARED += $(srcdir)/emutls.c

>> +endif

> Why is this needed? Are you just trying to cut out stuff you don't need

> in the quest for smaller code or does this cause a more direct problem?


This dates back to when that code wouldn't compile. It also surprised me 
that --disable-emutls didn't do it (but this stuff is long ago now, so I 
don't recall the details of that).

Anyway, the code compiles now, so I can remove this hunk.

>> +/* Provide an entry point symbol to silence a linker warning.  */

>> +void _start() {}

> This seems wrong.   I realize you're trying to quiet a linker warning

> here, but for the case where you're creating GCN executables (testing?)

> this should probably be handled by the C-runtime or linker script.


We're using an LLVM linker, so I'd rather fix things here than there.

Anyway, I plan to make this a proper kernel and use it to run static 
constructors, one day. Possibly it should be in Newlib, but then the 
"ctors" code is found in crtstuff and libgcc2, so I don't know?

>> diff --git a/libgcc/config/gcn/gomp_print.c b/libgcc/config/gcn/gomp_print.c

>> new file mode 100644

>> index 0000000..41f50c3

>> --- /dev/null

>> +++ b/libgcc/config/gcn/gomp_print.c

> [ ... ]

> Would this be better in libgomp?  Oh, you addressed that in the

> prologue.  Feels like libgomp would be better to me, but I can

> understand the rationale behind wanting it in libgcc.


Now that printf works, possibly it should be moved back. There's no 
debugger for this target, so these routines are my usual means for 
debugging stuff, and libgomp isn't built in the config used to run the 
testsuite.

> I won't comment on the static sizes since this apparently has to match

> something already in existence.


Yeah, this is basically a shared memory interface. I plan to implement a 
proper circular buffer, etc., etc., etc., but there's a lot to do.

>> +

>> +void

>> +gomp_print_string (const char *msg, const char *value)

>> +{

>> +  struct printf_data *output = reserve_print_slot ();

>> +  output->type = 2; /* String.  */

>> +

>> +  strncpy (output->msg, msg, 127);

>> +  output->msg[127] = '\0';

>> +  strncpy (output->text, value, 127);

>> +  output->text[127] = '\0';

>> +

>> +  asm ("" ::: "memory");

>> +  output->written = 1;

>> +}

> I'm not familiar with the GCN memory model, but your asm is really just

> a barrier for the compiler.  Do you need any kind of hardware fencing

> here?  Similarly for other instances.


As long as the compiler doesn't reorder the write instructions then this 
is fine, as is. The architecture does not reorder writes in hardware.

That said, actually the updated version I'm preparing has additional L1 
cache flushes to make absolutely sure the data are written to the L2 
cache memory in order. I did this when investigating a problem to make 
sure I wasn't losing debug output, and even though I found that I was 
not, I kept the patch anyway.

> All these functions probably need a little comment on their purpose and

> arguments.


Understood.

> Note some of the divmod stuff recently changed.  You may need minor

> updates as a result of those patches.  See:


OK, thanks for the heads up.

And thanks for the review. I'm planning to post a somewhat-updated V2 
patch set any week now.

Andrew

Patch

diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index 0c5b264..6f68257 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -429,9 +429,11 @@  LIB2ADD += enable-execute-stack.c
 # While emutls.c has nothing to do with EH, it is in LIB2ADDEH*
 # instead of LIB2ADD because that's the way to be sure on some targets
 # (e.g. *-*-darwin*) only one copy of it is linked.
+ifneq ($(enable_emutls),no)
 LIB2ADDEH += $(srcdir)/emutls.c
 LIB2ADDEHSTATIC += $(srcdir)/emutls.c
 LIB2ADDEHSHARED += $(srcdir)/emutls.c
+endif
 
 # Library members defined in libgcc2.c.
 lib2funcs = _muldi3 _negdi2 _lshrdi3 _ashldi3 _ashrdi3 _cmpdi2 _ucmpdi2	   \
diff --git a/libgcc/config.host b/libgcc/config.host
index 029f656..29178da 100644
--- a/libgcc/config.host
+++ b/libgcc/config.host
@@ -91,6 +91,10 @@  alpha*-*-*)
 am33_2.0-*-linux*)
 	cpu_type=mn10300
 	;;
+amdgcn*-*-*)
+	cpu_type=gcn
+	tmake_file="${tmake_file} t-softfp-sfdf t-softfp"
+	;;
 arc*-*-*)
 	cpu_type=arc
 	;;
@@ -384,6 +388,10 @@  alpha*-dec-*vms*)
 	extra_parts="$extra_parts vms-dwarf2.o vms-dwarf2eh.o"
 	md_unwind_header=alpha/vms-unwind.h
 	;;
+amdgcn*-*-amdhsa)
+	tmake_file="$tmake_file gcn/t-amdgcn"
+	extra_parts="crt0.o"
+	;;
 arc*-*-elf*)
 	tmake_file="arc/t-arc"
 	extra_parts="crti.o crtn.o crtend.o crtbegin.o crtendS.o crtbeginS.o"
diff --git a/libgcc/config/gcn/crt0.c b/libgcc/config/gcn/crt0.c
new file mode 100644
index 0000000..f4f367b
--- /dev/null
+++ b/libgcc/config/gcn/crt0.c
@@ -0,0 +1,23 @@ 
+/* Copyright (C) 2017 Free Software Foundation, Inc.
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Provide an entry point symbol to silence a linker warning.  */
+void _start() {}
diff --git a/libgcc/config/gcn/gomp_print.c b/libgcc/config/gcn/gomp_print.c
new file mode 100644
index 0000000..41f50c3
--- /dev/null
+++ b/libgcc/config/gcn/gomp_print.c
@@ -0,0 +1,99 @@ 
+/* Newlib may not have been built yet.  */
+typedef long int64_t;
+typedef long size_t;
+extern char *strncpy (char *dst, const char *src, size_t length);
+extern void exit(int);
+
+void gomp_print_string (const char *msg, const char *value);
+void gomp_print_integer (const char *msg, int64_t value);
+void gomp_print_double (const char *msg, double value);
+
+/* This struct must match the one used by gcn-run and libgomp.
+   It holds all the data output from a kernel (besides mapping data).
+ 
+   The base address pointer can be found at kernargs+16.
+ 
+   The next_output counter must be atomically incremented for each
+   print output.  Only when the print data is fully written can the
+   "written" flag be set.  */
+struct output {
+  int return_value;
+  int next_output;
+  struct printf_data {
+    int written;
+    char msg[128];
+    int type;
+    union {
+      int64_t ivalue;
+      double dvalue;
+      char text[128];
+    };
+  } queue[1000];
+};
+
+static struct printf_data *
+reserve_print_slot (void) {
+  /* The kernargs pointer is in s[8:9].
+     This will break if the enable_sgpr_* flags are ever changed.  */
+  char *kernargs;
+  asm ("s_mov_b64 %0, s[8:9]" : "=Sg"(kernargs));
+
+  /* The output data is at kernargs[2].  */
+  struct output *data = *(struct output **)(kernargs + 16);
+
+  /* We don't have atomic operators in C yet.
+     "glc" means return original value.  */
+  int index = 0;
+  asm ("flat_atomic_add %0, %1, %2 glc\n\t"
+       "s_waitcnt 0"
+       : "=v"(index)
+       : "v"(&data->next_output), "v"(1), "e"(1l));
+
+  if (index >= 1000)
+    exit(1);
+
+  return &(data->queue[index]);
+}
+
+void
+gomp_print_string (const char *msg, const char *value)
+{
+  struct printf_data *output = reserve_print_slot ();
+  output->type = 2; /* String.  */
+
+  strncpy (output->msg, msg, 127);
+  output->msg[127] = '\0';
+  strncpy (output->text, value, 127);
+  output->text[127] = '\0';
+
+  asm ("" ::: "memory");
+  output->written = 1;
+}
+
+void
+gomp_print_integer (const char *msg, int64_t value)
+{
+  struct printf_data *output = reserve_print_slot ();
+  output->type = 0; /* Integer.  */
+
+  strncpy (output->msg, msg, 127);
+  output->msg[127] = '\0';
+  output->ivalue = value;
+
+  asm ("" ::: "memory");
+  output->written = 1;
+}
+
+void
+gomp_print_double (const char *msg, double value)
+{
+  struct printf_data *output = reserve_print_slot ();
+  output->type = 1; /* Double.  */
+
+  strncpy (output->msg, msg, 127);
+  output->msg[127] = '\0';
+  output->dvalue = value;
+
+  asm ("" ::: "memory");
+  output->written = 1;
+}
diff --git a/libgcc/config/gcn/lib2-divmod-hi.c b/libgcc/config/gcn/lib2-divmod-hi.c
new file mode 100644
index 0000000..d57e145
--- /dev/null
+++ b/libgcc/config/gcn/lib2-divmod-hi.c
@@ -0,0 +1,117 @@ 
+/* Copyright (C) 2012-2017 Free Software Foundation, Inc.
+   Contributed by Altera and Mentor Graphics, Inc.
+
+This file is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+#include "lib2-gcn.h"
+
+/* 16-bit HI divide and modulo as used in gcn.  */
+
+static UHItype
+udivmodhi4 (UHItype num, UHItype den, word_type modwanted)
+{
+  UHItype bit = 1;
+  UHItype res = 0;
+
+  while (den < num && bit && !(den & (1L<<15)))
+    {
+      den <<=1;
+      bit <<=1;
+    }
+  while (bit)
+    {
+      if (num >= den)
+	{
+	  num -= den;
+	  res |= bit;
+	}
+      bit >>=1;
+      den >>=1;
+    }
+  if (modwanted)
+    return num;
+  return res;
+}
+
+
+HItype
+__divhi3 (HItype a, HItype b)
+{
+  word_type neg = 0;
+  HItype res;
+
+  if (a < 0)
+    {
+      a = -a;
+      neg = !neg;
+    }
+
+  if (b < 0)
+    {
+      b = -b;
+      neg = !neg;
+    }
+
+  res = udivmodhi4 (a, b, 0);
+
+  if (neg)
+    res = -res;
+
+  return res;
+}
+
+
+HItype
+__modhi3 (HItype a, HItype b)
+{
+  word_type neg = 0;
+  HItype res;
+
+  if (a < 0)
+    {
+      a = -a;
+      neg = 1;
+    }
+
+  if (b < 0)
+    b = -b;
+
+  res = udivmodhi4 (a, b, 1);
+
+  if (neg)
+    res = -res;
+
+  return res;
+}
+
+
+UHItype
+__udivhi3 (UHItype a, UHItype b)
+{
+  return udivmodhi4 (a, b, 0);
+}
+
+
+UHItype
+__umodhi3 (UHItype a, UHItype b)
+{
+  return udivmodhi4 (a, b, 1);
+}
+
diff --git a/libgcc/config/gcn/lib2-divmod.c b/libgcc/config/gcn/lib2-divmod.c
new file mode 100644
index 0000000..08e7103
--- /dev/null
+++ b/libgcc/config/gcn/lib2-divmod.c
@@ -0,0 +1,117 @@ 
+/* Copyright (C) 2012-2017 Free Software Foundation, Inc.
+   Contributed by Altera and Mentor Graphics, Inc.
+
+This file is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+#include "lib2-gcn.h"
+
+/* 32-bit SI divide and modulo as used in gcn.  */
+
+static USItype
+udivmodsi4 (USItype num, USItype den, word_type modwanted)
+{
+  USItype bit = 1;
+  USItype res = 0;
+
+  while (den < num && bit && !(den & (1L<<31)))
+    {
+      den <<=1;
+      bit <<=1;
+    }
+  while (bit)
+    {
+      if (num >= den)
+	{
+	  num -= den;
+	  res |= bit;
+	}
+      bit >>=1;
+      den >>=1;
+    }
+  if (modwanted)
+    return num;
+  return res;
+}
+
+
+SItype
+__divsi3 (SItype a, SItype b)
+{
+  word_type neg = 0;
+  SItype res;
+
+  if (a < 0)
+    {
+      a = -a;
+      neg = !neg;
+    }
+
+  if (b < 0)
+    {
+      b = -b;
+      neg = !neg;
+    }
+
+  res = udivmodsi4 (a, b, 0);
+
+  if (neg)
+    res = -res;
+
+  return res;
+}
+
+
+SItype
+__modsi3 (SItype a, SItype b)
+{
+  word_type neg = 0;
+  SItype res;
+
+  if (a < 0)
+    {
+      a = -a;
+      neg = 1;
+    }
+
+  if (b < 0)
+    b = -b;
+
+  res = udivmodsi4 (a, b, 1);
+
+  if (neg)
+    res = -res;
+
+  return res;
+}
+
+
+SItype
+__udivsi3 (SItype a, SItype b)
+{
+  return udivmodsi4 (a, b, 0);
+}
+
+
+SItype
+__umodsi3 (SItype a, SItype b)
+{
+  return udivmodsi4 (a, b, 1);
+}
+
diff --git a/libgcc/config/gcn/lib2-gcn.h b/libgcc/config/gcn/lib2-gcn.h
new file mode 100644
index 0000000..aff0bd2
--- /dev/null
+++ b/libgcc/config/gcn/lib2-gcn.h
@@ -0,0 +1,49 @@ 
+/* Integer arithmetic support for gcn.
+
+   Copyright (C) 2012-2017 Free Software Foundation, Inc.
+   Contributed by Altera and Mentor Graphics, Inc.
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef LIB2_GCN_H
+#define LIB2_GCN_H
+
+/* Types.  */
+
+typedef char QItype __attribute__ ((mode (QI)));
+typedef unsigned char UQItype __attribute__ ((mode (QI)));
+typedef short HItype __attribute__ ((mode (HI)));
+typedef unsigned short UHItype __attribute__ ((mode (HI)));
+typedef int SItype __attribute__ ((mode (SI)));
+typedef unsigned int USItype __attribute__ ((mode (SI)));
+typedef int word_type __attribute__ ((mode (__word__)));
+
+/* Exported functions.  */
+extern SItype __divsi3 (SItype, SItype);
+extern SItype __modsi3 (SItype, SItype);
+extern SItype __udivsi3 (SItype, SItype);
+extern SItype __umodsi3 (SItype, SItype);
+extern HItype __divhi3 (HItype, HItype);
+extern HItype __modhi3 (HItype, HItype);
+extern UHItype __udivhi3 (UHItype, UHItype);
+extern UHItype __umodhi3 (UHItype, UHItype);
+extern SItype __mulsi3 (SItype, SItype);
+
+#endif /* LIB2_GCN_H */
diff --git a/libgcc/config/gcn/reduction.c b/libgcc/config/gcn/reduction.c
new file mode 100644
index 0000000..fbe9aaa
--- /dev/null
+++ b/libgcc/config/gcn/reduction.c
@@ -0,0 +1,30 @@ 
+/* Oversized reductions lock variable
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   Contributed by Mentor Graphics.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+/* We use a global lock variable for reductions on objects larger than
+   64 bits.  Until and unless proven that lock contention for
+   different reductions is a problem, a single lock will suffice.  */
+
+unsigned volatile __reduction_lock = 0;
diff --git a/libgcc/config/gcn/sfp-machine.h b/libgcc/config/gcn/sfp-machine.h
new file mode 100644
index 0000000..7874081
--- /dev/null
+++ b/libgcc/config/gcn/sfp-machine.h
@@ -0,0 +1,51 @@ 
+/* Use 32-bit types here to prevent longlong.h trying to use TImode.
+   Once TImode works we might be better to use 64-bit here.  */
+
+#define _FP_W_TYPE_SIZE		32
+#define _FP_W_TYPE		unsigned int
+#define _FP_WS_TYPE		signed int
+#define _FP_I_TYPE		int
+
+#define _FP_MUL_MEAT_S(R,X,Y)				\
+  _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_D(R,X,Y)				\
+  _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
+
+#define _FP_DIV_MEAT_S(R,X,Y)	_FP_DIV_MEAT_1_loop(S,R,X,Y)
+#define _FP_DIV_MEAT_D(R,X,Y)	_FP_DIV_MEAT_2_udiv(D,R,X,Y)
+
+#define _FP_NANFRAC_S		((_FP_QNANBIT_S << 1) - 1)
+#define _FP_NANFRAC_D		((_FP_QNANBIT_D << 1) - 1), -1
+#define _FP_NANSIGN_S		0
+#define _FP_NANSIGN_D		0
+
+#define _FP_KEEPNANFRACP 1
+#define _FP_QNANNEGATEDP 0
+
+/* Someone please check this.  */
+#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP)			\
+  do {								\
+    if ((_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)		\
+	&& !(_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs))	\
+      {								\
+	R##_s = Y##_s;						\
+	_FP_FRAC_COPY_##wc(R,Y);				\
+      }								\
+    else							\
+      {								\
+	R##_s = X##_s;						\
+	_FP_FRAC_COPY_##wc(R,X);				\
+      }								\
+    R##_c = FP_CLS_NAN;						\
+  } while (0)
+
+#define _FP_TININESS_AFTER_ROUNDING 0
+
+#define __LITTLE_ENDIAN 1234
+#define	__BIG_ENDIAN	4321
+#define __BYTE_ORDER __LITTLE_ENDIAN
+
+/* Define ALIASNAME as a strong alias for NAME.  */
+# define strong_alias(name, aliasname) _strong_alias(name, aliasname)
+# define _strong_alias(name, aliasname) \
+  extern __typeof (name) aliasname __attribute__ ((alias (#name)));
diff --git a/libgcc/config/gcn/t-amdgcn b/libgcc/config/gcn/t-amdgcn
new file mode 100644
index 0000000..d0c423d
--- /dev/null
+++ b/libgcc/config/gcn/t-amdgcn
@@ -0,0 +1,25 @@ 
+LIB2ADD += $(srcdir)/config/gcn/gomp_print.c
+
+LIB2ADD += $(srcdir)/config/gcn/lib2-divmod.c \
+	   $(srcdir)/config/gcn/lib2-divmod-hi.c
+
+LIB2ADD += $(srcdir)/config/gcn/reduction.c
+
+LIB2ADDEH=
+LIB2FUNCS_EXCLUDE=__main
+
+override LIB2FUNCS_ST := $(filter-out __gcc_bcmp,$(LIB2FUNCS_ST))
+
+# Debug information is not useful, and probably uses broken relocations
+LIBGCC2_DEBUG_CFLAGS = -g0
+
+crt0.o: $(srcdir)/config/gcn/crt0.c
+	$(crt_compile) -c $<
+
+# Prevent building "advanced" stuff (for example, gcov support).  We don't
+# support it, and it may cause the build to fail, because of alloca usage, for
+# example.
+INHIBIT_LIBC_CFLAGS = -Dinhibit_libc
+
+# Disable emutls.c (temporarily?)
+enable_emutls = no