[committed] amdgcn: implement vector div and mod libfuncs

Andrew Stubbs ams@codesourcery.com
Mon Jun 19 11:38:09 GMT 2023


This patch implements software divide for all integer vector modes.

It also adds divmod support for scalars. The implementation for vector 
divmod is also present, but is disabled until a solution is found 
representing pairs of vectors in the middle-end. The corresponding tests 
are xfailed.

See 
https://patchwork.sourceware.org/project/gcc/patch/77479c6f-5ce4-12fa-f429-c49ffbff3542@codesourcery.com/

The divide implementation is simply the existing scalar algorithm from 
libgcc converted to vectors. Using vector extensions, as opposed to SIMD 
clones, means that I can name the functions manually (and in any case 
the autovectorizer didn't quite work right). The macro framework is 
adapted from the one used for amdgcn in newlib libm.

Committed to mainline, and OG13 will follow shortly.

Andrew
-------------- next part --------------
amdgcn: implement vector div and mod libfuncs

Also divmod, but only for scalar modes, for now (because there are no complex
int vectors yet).

gcc/ChangeLog:

	* config/gcn/gcn.cc (gcn_expand_divmod_libfunc): New function.
	(gcn_init_libfuncs): Add div and mod functions for all modes.
	Add placeholders for divmod functions.
	(TARGET_EXPAND_DIVMOD_LIBFUNC): Define.

libgcc/ChangeLog:

	* config/gcn/lib2-divmod-di.c: Reimplement like lib2-divmod.c.
	* config/gcn/lib2-divmod.c: Likewise.
	* config/gcn/lib2-gcn.h: Add new types and prototypes for all the
	new vector libfuncs.
	* config/gcn/t-amdgcn: Add new files.
	* config/gcn/amdgcn_veclib.h: New file.
	* config/gcn/lib2-vec_divmod-di.c: New file.
	* config/gcn/lib2-vec_divmod-hi.c: New file.
	* config/gcn/lib2-vec_divmod-qi.c: New file.
	* config/gcn/lib2-vec_divmod.c: New file.

gcc/testsuite/ChangeLog:

	* gcc.dg/tree-ssa/predcom-2.c: Avoid vectors on amdgcn.
	* gcc.dg/unroll-8.c: Likewise.
	* gcc.dg/vect/slp-26.c: Change expected results on amdgdn.
	* lib/target-supports.exp
	(check_effective_target_vect_int_mod): Add amdgcn.
	(check_effective_target_divmod): Likewise.
	* gcc.target/gcn/simd-math-3-16.c: New test.
	* gcc.target/gcn/simd-math-3-2.c: New test.
	* gcc.target/gcn/simd-math-3-32.c: New test.
	* gcc.target/gcn/simd-math-3-4.c: New test.
	* gcc.target/gcn/simd-math-3-8.c: New test.
	* gcc.target/gcn/simd-math-3-char-16.c: New test.
	* gcc.target/gcn/simd-math-3-char-2.c: New test.
	* gcc.target/gcn/simd-math-3-char-32.c: New test.
	* gcc.target/gcn/simd-math-3-char-4.c: New test.
	* gcc.target/gcn/simd-math-3-char-8.c: New test.
	* gcc.target/gcn/simd-math-3-char-run-16.c: New test.
	* gcc.target/gcn/simd-math-3-char-run-2.c: New test.
	* gcc.target/gcn/simd-math-3-char-run-32.c: New test.
	* gcc.target/gcn/simd-math-3-char-run-4.c: New test.
	* gcc.target/gcn/simd-math-3-char-run-8.c: New test.
	* gcc.target/gcn/simd-math-3-char-run.c: New test.
	* gcc.target/gcn/simd-math-3-char.c: New test.
	* gcc.target/gcn/simd-math-3-long-16.c: New test.
	* gcc.target/gcn/simd-math-3-long-2.c: New test.
	* gcc.target/gcn/simd-math-3-long-32.c: New test.
	* gcc.target/gcn/simd-math-3-long-4.c: New test.
	* gcc.target/gcn/simd-math-3-long-8.c: New test.
	* gcc.target/gcn/simd-math-3-long-run-16.c: New test.
	* gcc.target/gcn/simd-math-3-long-run-2.c: New test.
	* gcc.target/gcn/simd-math-3-long-run-32.c: New test.
	* gcc.target/gcn/simd-math-3-long-run-4.c: New test.
	* gcc.target/gcn/simd-math-3-long-run-8.c: New test.
	* gcc.target/gcn/simd-math-3-long-run.c: New test.
	* gcc.target/gcn/simd-math-3-long.c: New test.
	* gcc.target/gcn/simd-math-3-run-16.c: New test.
	* gcc.target/gcn/simd-math-3-run-2.c: New test.
	* gcc.target/gcn/simd-math-3-run-32.c: New test.
	* gcc.target/gcn/simd-math-3-run-4.c: New test.
	* gcc.target/gcn/simd-math-3-run-8.c: New test.
	* gcc.target/gcn/simd-math-3-run.c: New test.
	* gcc.target/gcn/simd-math-3-short-16.c: New test.
	* gcc.target/gcn/simd-math-3-short-2.c: New test.
	* gcc.target/gcn/simd-math-3-short-32.c: New test.
	* gcc.target/gcn/simd-math-3-short-4.c: New test.
	* gcc.target/gcn/simd-math-3-short-8.c: New test.
	* gcc.target/gcn/simd-math-3-short-run-16.c: New test.
	* gcc.target/gcn/simd-math-3-short-run-2.c: New test.
	* gcc.target/gcn/simd-math-3-short-run-32.c: New test.
	* gcc.target/gcn/simd-math-3-short-run-4.c: New test.
	* gcc.target/gcn/simd-math-3-short-run-8.c: New test.
	* gcc.target/gcn/simd-math-3-short-run.c: New test.
	* gcc.target/gcn/simd-math-3-short.c: New test.
	* gcc.target/gcn/simd-math-3.c: New test.
	* gcc.target/gcn/simd-math-4-char-run.c: New test.
	* gcc.target/gcn/simd-math-4-char.c: New test.
	* gcc.target/gcn/simd-math-4-long-run.c: New test.
	* gcc.target/gcn/simd-math-4-long.c: New test.
	* gcc.target/gcn/simd-math-4-run.c: New test.
	* gcc.target/gcn/simd-math-4-short-run.c: New test.
	* gcc.target/gcn/simd-math-4-short.c: New test.
	* gcc.target/gcn/simd-math-4.c: New test.
	* gcc.target/gcn/simd-math-5-16.c: New test.
	* gcc.target/gcn/simd-math-5-32.c: New test.
	* gcc.target/gcn/simd-math-5-4.c: New test.
	* gcc.target/gcn/simd-math-5-8.c: New test.
	* gcc.target/gcn/simd-math-5-char-16.c: New test.
	* gcc.target/gcn/simd-math-5-char-32.c: New test.
	* gcc.target/gcn/simd-math-5-char-4.c: New test.
	* gcc.target/gcn/simd-math-5-char-8.c: New test.
	* gcc.target/gcn/simd-math-5-char-run-16.c: New test.
	* gcc.target/gcn/simd-math-5-char-run-32.c: New test.
	* gcc.target/gcn/simd-math-5-char-run-4.c: New test.
	* gcc.target/gcn/simd-math-5-char-run-8.c: New test.
	* gcc.target/gcn/simd-math-5-char-run.c: New test.
	* gcc.target/gcn/simd-math-5-char.c: New test.
	* gcc.target/gcn/simd-math-5-long-16.c: New test.
	* gcc.target/gcn/simd-math-5-long-32.c: New test.
	* gcc.target/gcn/simd-math-5-long-4.c: New test.
	* gcc.target/gcn/simd-math-5-long-8.c: New test.
	* gcc.target/gcn/simd-math-5-long-run-16.c: New test.
	* gcc.target/gcn/simd-math-5-long-run-32.c: New test.
	* gcc.target/gcn/simd-math-5-long-run-4.c: New test.
	* gcc.target/gcn/simd-math-5-long-run-8.c: New test.
	* gcc.target/gcn/simd-math-5-long-run.c: New test.
	* gcc.target/gcn/simd-math-5-long.c: New test.
	* gcc.target/gcn/simd-math-5-run-16.c: New test.
	* gcc.target/gcn/simd-math-5-run-32.c: New test.
	* gcc.target/gcn/simd-math-5-run-4.c: New test.
	* gcc.target/gcn/simd-math-5-run-8.c: New test.
	* gcc.target/gcn/simd-math-5-run.c: New test.
	* gcc.target/gcn/simd-math-5-short-16.c: New test.
	* gcc.target/gcn/simd-math-5-short-32.c: New test.
	* gcc.target/gcn/simd-math-5-short-4.c: New test.
	* gcc.target/gcn/simd-math-5-short-8.c: New test.
	* gcc.target/gcn/simd-math-5-short-run-16.c: New test.
	* gcc.target/gcn/simd-math-5-short-run-32.c: New test.
	* gcc.target/gcn/simd-math-5-short-run-4.c: New test.
	* gcc.target/gcn/simd-math-5-short-run-8.c: New test.
	* gcc.target/gcn/simd-math-5-short-run.c: New test.
	* gcc.target/gcn/simd-math-5-short.c: New test.
	* gcc.target/gcn/simd-math-5.c: New test.

diff --git a/gcc/config/gcn/gcn.cc b/gcc/config/gcn/gcn.cc
index ead89a9fbaf..02f4dedec42 100644
--- a/gcc/config/gcn/gcn.cc
+++ b/gcc/config/gcn/gcn.cc
@@ -3786,6 +3786,47 @@ gcn_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
 					      TRAMPOLINE_SIZE)));
 }
 
+/* Implement TARGET_EXPAND_DIVMOD_LIBFUNC.
+
+   There are divmod libfuncs for all modes except TImode.  They return the
+   two values packed into a larger integer/vector.  */
+
+void
+gcn_expand_divmod_libfunc (rtx libfunc, machine_mode mode, rtx op0, rtx op1,
+			   rtx *quot, rtx *rem)
+{
+  machine_mode innermode = (VECTOR_MODE_P (mode)
+			    ? GET_MODE_INNER (mode) : mode);
+  machine_mode wideinnermode = VOIDmode;
+  machine_mode widemode = VOIDmode;
+
+  switch (innermode)
+    {
+    case E_QImode:
+    case E_HImode:
+    case E_SImode:
+      wideinnermode = DImode;
+      break;
+    case E_DImode:
+      wideinnermode = TImode;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  if (VECTOR_MODE_P (mode))
+    widemode = VnMODE (GET_MODE_NUNITS (mode), wideinnermode);
+  else
+    widemode = wideinnermode;
+
+  emit_library_call_value (libfunc, gen_rtx_REG (widemode, RETURN_VALUE_REG),
+			   LCT_NORMAL, widemode, op0, mode, op1, mode);
+
+  *quot = gen_rtx_REG (mode, RETURN_VALUE_REG);
+  *rem = gen_rtx_REG (mode,
+		      RETURN_VALUE_REG + (wideinnermode == TImode ? 2 : 1));
+}
+
 /* }}}  */
 /* {{{ Miscellaneous.  */
 
@@ -4224,6 +4265,207 @@ gcn_init_libfuncs (void)
   set_optab_libfunc (popcount_optab, TImode, "__popcountti2");
   set_optab_libfunc (parity_optab, TImode, "__parityti2");
   set_optab_libfunc (bswap_optab, TImode, "__bswapti2");
+
+  set_optab_libfunc (sdivmod_optab, SImode, "__divmodsi4");
+  set_optab_libfunc (udivmod_optab, SImode, "__udivmodsi4");
+  set_optab_libfunc (sdivmod_optab, DImode, "__divmoddi4");
+  set_optab_libfunc (udivmod_optab, DImode, "__udivmoddi4");
+
+  set_optab_libfunc (sdiv_optab, V2QImode, "__divv2qi3");
+  set_optab_libfunc (udiv_optab, V2QImode, "__udivv2qi3");
+  set_optab_libfunc (smod_optab, V2QImode, "__modv2qi3");
+  set_optab_libfunc (umod_optab, V2QImode, "__umodv2qi3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V2QImode, "__divmodv2qi4");
+  set_optab_libfunc (udivmod_optab, V2QImode, "__udivmodv2qi4");
+#endif
+  set_optab_libfunc (sdiv_optab, V4QImode, "__divv4qi3");
+  set_optab_libfunc (udiv_optab, V4QImode, "__udivv4qi3");
+  set_optab_libfunc (smod_optab, V4QImode, "__modv4qi3");
+  set_optab_libfunc (umod_optab, V4QImode, "__umodv4qi3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V4QImode, "__divmodv4qi4");
+  set_optab_libfunc (udivmod_optab, V4QImode, "__udivmodv4qi4");
+#endif
+  set_optab_libfunc (sdiv_optab, V8QImode, "__divv8qi3");
+  set_optab_libfunc (udiv_optab, V8QImode, "__udivv8qi3");
+  set_optab_libfunc (smod_optab, V8QImode, "__modv8qi3");
+  set_optab_libfunc (umod_optab, V8QImode, "__umodv8qi3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V8QImode, "__divmodv8qi4");
+  set_optab_libfunc (udivmod_optab, V8QImode, "__udivmodv8qi4");
+#endif
+  set_optab_libfunc (sdiv_optab, V16QImode, "__divv16qi3");
+  set_optab_libfunc (udiv_optab, V16QImode, "__udivv16qi3");
+  set_optab_libfunc (smod_optab, V16QImode, "__modv16qi3");
+  set_optab_libfunc (umod_optab, V16QImode, "__umodv16qi3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V16QImode, "__divmodv16qi4");
+  set_optab_libfunc (udivmod_optab, V16QImode, "__udivmodv16qi4");
+#endif
+  set_optab_libfunc (sdiv_optab, V32QImode, "__divv32qi3");
+  set_optab_libfunc (udiv_optab, V32QImode, "__udivv32qi3");
+  set_optab_libfunc (smod_optab, V32QImode, "__modv32qi3");
+  set_optab_libfunc (umod_optab, V32QImode, "__umodv32qi3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V32QImode, "__divmodv32qi4");
+  set_optab_libfunc (udivmod_optab, V32QImode, "__udivmodv32qi4");
+#endif
+  set_optab_libfunc (sdiv_optab, V64QImode, "__divv64qi3");
+  set_optab_libfunc (udiv_optab, V64QImode, "__udivv64qi3");
+  set_optab_libfunc (smod_optab, V64QImode, "__modv64qi3");
+  set_optab_libfunc (umod_optab, V64QImode, "__umodv64qi3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V64QImode, "__divmodv64qi4");
+  set_optab_libfunc (udivmod_optab, V64QImode, "__udivmodv64qi4");
+#endif
+
+  set_optab_libfunc (sdiv_optab, V2HImode, "__divv2hi3");
+  set_optab_libfunc (udiv_optab, V2HImode, "__udivv2hi3");
+  set_optab_libfunc (smod_optab, V2HImode, "__modv2hi3");
+  set_optab_libfunc (umod_optab, V2HImode, "__umodv2hi3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V2HImode, "__divmodv2hi4");
+  set_optab_libfunc (udivmod_optab, V2HImode, "__udivmodv2hi4");
+#endif
+  set_optab_libfunc (sdiv_optab, V4HImode, "__divv4hi3");
+  set_optab_libfunc (udiv_optab, V4HImode, "__udivv4hi3");
+  set_optab_libfunc (smod_optab, V4HImode, "__modv4hi3");
+  set_optab_libfunc (umod_optab, V4HImode, "__umodv4hi3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V4HImode, "__divmodv4hi4");
+  set_optab_libfunc (udivmod_optab, V4HImode, "__udivmodv4hi4");
+#endif
+  set_optab_libfunc (sdiv_optab, V8HImode, "__divv8hi3");
+  set_optab_libfunc (udiv_optab, V8HImode, "__udivv8hi3");
+  set_optab_libfunc (smod_optab, V8HImode, "__modv8hi3");
+  set_optab_libfunc (umod_optab, V8HImode, "__umodv8hi3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V8HImode, "__divmodv8hi4");
+  set_optab_libfunc (udivmod_optab, V8HImode, "__udivmodv8hi4");
+#endif
+  set_optab_libfunc (sdiv_optab, V16HImode, "__divv16hi3");
+  set_optab_libfunc (udiv_optab, V16HImode, "__udivv16hi3");
+  set_optab_libfunc (smod_optab, V16HImode, "__modv16hi3");
+  set_optab_libfunc (umod_optab, V16HImode, "__umodv16hi3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V16HImode, "__divmodv16hi4");
+  set_optab_libfunc (udivmod_optab, V16HImode, "__udivmodv16hi4");
+#endif
+  set_optab_libfunc (sdiv_optab, V32HImode, "__divv32hi3");
+  set_optab_libfunc (udiv_optab, V32HImode, "__udivv32hi3");
+  set_optab_libfunc (smod_optab, V32HImode, "__modv32hi3");
+  set_optab_libfunc (umod_optab, V32HImode, "__umodv32hi3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V32HImode, "__divmodv32hi4");
+  set_optab_libfunc (udivmod_optab, V32HImode, "__udivmodv32hi4");
+#endif
+  set_optab_libfunc (sdiv_optab, V64HImode, "__divv64hi3");
+  set_optab_libfunc (udiv_optab, V64HImode, "__udivv64hi3");
+  set_optab_libfunc (smod_optab, V64HImode, "__modv64hi3");
+  set_optab_libfunc (umod_optab, V64HImode, "__umodv64hi3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V64HImode, "__divmodv64hi4");
+  set_optab_libfunc (udivmod_optab, V64HImode, "__udivmodv64hi4");
+#endif
+
+  set_optab_libfunc (sdiv_optab, V2SImode, "__divv2si3");
+  set_optab_libfunc (udiv_optab, V2SImode, "__udivv2si3");
+  set_optab_libfunc (smod_optab, V2SImode, "__modv2si3");
+  set_optab_libfunc (umod_optab, V2SImode, "__umodv2si3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V2SImode, "__divmodv2si4");
+  set_optab_libfunc (udivmod_optab, V2SImode, "__udivmodv2si4");
+#endif
+  set_optab_libfunc (sdiv_optab, V4SImode, "__divv4si3");
+  set_optab_libfunc (udiv_optab, V4SImode, "__udivv4si3");
+  set_optab_libfunc (smod_optab, V4SImode, "__modv4si3");
+  set_optab_libfunc (umod_optab, V4SImode, "__umodv4si3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V4SImode, "__divmodv4si4");
+  set_optab_libfunc (udivmod_optab, V4SImode, "__udivmodv4si4");
+#endif
+  set_optab_libfunc (sdiv_optab, V8SImode, "__divv8si3");
+  set_optab_libfunc (udiv_optab, V8SImode, "__udivv8si3");
+  set_optab_libfunc (smod_optab, V8SImode, "__modv8si3");
+  set_optab_libfunc (umod_optab, V8SImode, "__umodv8si3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V8SImode, "__divmodv8si4");
+  set_optab_libfunc (udivmod_optab, V8SImode, "__udivmodv8si4");
+#endif
+  set_optab_libfunc (sdiv_optab, V16SImode, "__divv16si3");
+  set_optab_libfunc (udiv_optab, V16SImode, "__udivv16si3");
+  set_optab_libfunc (smod_optab, V16SImode, "__modv16si3");
+  set_optab_libfunc (umod_optab, V16SImode, "__umodv16si3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V16SImode, "__divmodv16si4");
+  set_optab_libfunc (udivmod_optab, V16SImode, "__udivmodv16si4");
+#endif
+  set_optab_libfunc (sdiv_optab, V32SImode, "__divv32si3");
+  set_optab_libfunc (udiv_optab, V32SImode, "__udivv32si3");
+  set_optab_libfunc (smod_optab, V32SImode, "__modv32si3");
+  set_optab_libfunc (umod_optab, V32SImode, "__umodv32si3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V32SImode, "__divmodv32si4");
+  set_optab_libfunc (udivmod_optab, V32SImode, "__udivmodv32si4");
+#endif
+  set_optab_libfunc (sdiv_optab, V64SImode, "__divv64si3");
+  set_optab_libfunc (udiv_optab, V64SImode, "__udivv64si3");
+  set_optab_libfunc (smod_optab, V64SImode, "__modv64si3");
+  set_optab_libfunc (umod_optab, V64SImode, "__umodv64si3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V64SImode, "__divmodv64si4");
+  set_optab_libfunc (udivmod_optab, V64SImode, "__udivmodv64si4");
+#endif
+
+  set_optab_libfunc (sdiv_optab, V2DImode, "__divv2di3");
+  set_optab_libfunc (udiv_optab, V2DImode, "__udivv2di3");
+  set_optab_libfunc (smod_optab, V2DImode, "__modv2di3");
+  set_optab_libfunc (umod_optab, V2DImode, "__umodv2di3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V2DImode, "__divmodv2di4");
+  set_optab_libfunc (udivmod_optab, V2DImode, "__udivmodv2di4");
+#endif
+  set_optab_libfunc (sdiv_optab, V4DImode, "__divv4di3");
+  set_optab_libfunc (udiv_optab, V4DImode, "__udivv4di3");
+  set_optab_libfunc (smod_optab, V4DImode, "__modv4di3");
+  set_optab_libfunc (umod_optab, V4DImode, "__umodv4di3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V4DImode, "__divmodv4di4");
+  set_optab_libfunc (udivmod_optab, V4DImode, "__udivmodv4di4");
+#endif
+  set_optab_libfunc (sdiv_optab, V8DImode, "__divv8di3");
+  set_optab_libfunc (udiv_optab, V8DImode, "__udivv8di3");
+  set_optab_libfunc (smod_optab, V8DImode, "__modv8di3");
+  set_optab_libfunc (umod_optab, V8DImode, "__umodv8di3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V8DImode, "__divmodv8di4");
+  set_optab_libfunc (udivmod_optab, V8DImode, "__udivmodv8di4");
+#endif
+  set_optab_libfunc (sdiv_optab, V16DImode, "__divv16di3");
+  set_optab_libfunc (udiv_optab, V16DImode, "__udivv16di3");
+  set_optab_libfunc (smod_optab, V16DImode, "__modv16di3");
+  set_optab_libfunc (umod_optab, V16DImode, "__umodv16di3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V16DImode, "__divmodv16di4");
+  set_optab_libfunc (udivmod_optab, V16DImode, "__udivmodv16di4");
+#endif
+  set_optab_libfunc (sdiv_optab, V32DImode, "__divv32di3");
+  set_optab_libfunc (udiv_optab, V32DImode, "__udivv32di3");
+  set_optab_libfunc (smod_optab, V32DImode, "__modv32di3");
+  set_optab_libfunc (umod_optab, V32DImode, "__umodv32di3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V32DImode, "__divmodv32di4");
+  set_optab_libfunc (udivmod_optab, V32DImode, "__udivmodv32di4");
+#endif
+  set_optab_libfunc (sdiv_optab, V64DImode, "__divv64di3");
+  set_optab_libfunc (udiv_optab, V64DImode, "__udivv64di3");
+  set_optab_libfunc (smod_optab, V64DImode, "__modv64di3");
+  set_optab_libfunc (umod_optab, V64DImode, "__umodv64di3");
+#if 0
+  set_optab_libfunc (sdivmod_optab, V64DImode, "__divmodv64di4");
+  set_optab_libfunc (udivmod_optab, V64DImode, "__udivmodv64di4");
+#endif
 }
 
 /* Expand the CMP_SWAP GCN builtins.  We have our own versions that do
@@ -7495,6 +7737,8 @@ gcn_dwarf_register_span (rtx rtl)
 #define TARGET_EMUTLS_VAR_INIT gcn_emutls_var_init
 #undef  TARGET_EXPAND_BUILTIN
 #define TARGET_EXPAND_BUILTIN gcn_expand_builtin
+#undef  TARGET_EXPAND_DIVMOD_LIBFUNC
+#define TARGET_EXPAND_DIVMOD_LIBFUNC gcn_expand_divmod_libfunc
 #undef  TARGET_FRAME_POINTER_REQUIRED
 #define TARGET_FRAME_POINTER_REQUIRED gcn_frame_pointer_rqd
 #undef  TARGET_FUNCTION_ARG
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/predcom-2.c b/gcc/testsuite/gcc.dg/tree-ssa/predcom-2.c
index d8fe51c5a6c..1c54679c022 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/predcom-2.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/predcom-2.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-O2 -funroll-loops --param max-unroll-times=8 -fpredictive-commoning -fdump-tree-pcom-details -fno-tree-pre" } */
+/* { dg-additional-options "-fno-tree-vectorize" { target amdgcn-*-* } } */
 
 void abort (void);
 
diff --git a/gcc/testsuite/gcc.dg/unroll-8.c b/gcc/testsuite/gcc.dg/unroll-8.c
index dfcfe2eebf0..c4f6ac91581 100644
--- a/gcc/testsuite/gcc.dg/unroll-8.c
+++ b/gcc/testsuite/gcc.dg/unroll-8.c
@@ -1,5 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fdump-rtl-loop2_unroll -funroll-loops" } */
+/* { dg-additional-options "-fno-tree-vectorize" { target amdgcn-*-* } } */
+
 struct a {int a[7];};
 int t(struct a *a, int n)
 {
diff --git a/gcc/testsuite/gcc.dg/vect/slp-26.c b/gcc/testsuite/gcc.dg/vect/slp-26.c
index 01f4e4ee32e..f8b49ff603c 100644
--- a/gcc/testsuite/gcc.dg/vect/slp-26.c
+++ b/gcc/testsuite/gcc.dg/vect/slp-26.c
@@ -46,7 +46,7 @@ int main (void)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "vectorized 0 loops" 1 "vect" { target { ! mips_msa } } } } */
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target { mips_msa } } } } */
-/* { dg-final { scan-tree-dump-times "vectorizing stmts using SLP" 0 "vect" { target { ! mips_msa } } } } */
-/* { dg-final { scan-tree-dump-times "vectorizing stmts using SLP" 1 "vect" { target { mips_msa } } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 0 loops" 1 "vect" { target { ! { mips_msa || amdgcn-*-* } } } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target { mips_msa || amdgcn-*-* } } } } */
+/* { dg-final { scan-tree-dump-times "vectorizing stmts using SLP" 0 "vect" { target { ! { mips_msa || amdgcn-*-* } } } } } */
+/* { dg-final { scan-tree-dump-times "vectorizing stmts using SLP" 1 "vect" { target { mips_msa || amdgcn-*-* } } } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-16.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-16.c
new file mode 100644
index 00000000000..20fa12f0efc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-16.c
@@ -0,0 +1,13 @@
+#define STYPE v16si
+#define UTYPE v16usi
+#define N 16
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv16si4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv16si4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv16si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv16si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv16si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv16si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__divsi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivsi3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-2.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-2.c
new file mode 100644
index 00000000000..3baffe9ef01
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-2.c
@@ -0,0 +1,13 @@
+#define STYPE v2si
+#define UTYPE v2usi
+#define N 2
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv2si4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv2si4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv2si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv2si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv2si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv2si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__divsi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivsi3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-32.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-32.c
new file mode 100644
index 00000000000..eab48158405
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-32.c
@@ -0,0 +1,13 @@
+#define STYPE v32si
+#define UTYPE v32usi
+#define N 32
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv32si4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv32si4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv32si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv32si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv32si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv32si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__divsi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivsi3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-4.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-4.c
new file mode 100644
index 00000000000..370ca63554b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-4.c
@@ -0,0 +1,13 @@
+#define STYPE v4si
+#define UTYPE v4usi
+#define N 4
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv4si4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv4si4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv4si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv4si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv4si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv4si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__divsi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivsi3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-8.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-8.c
new file mode 100644
index 00000000000..833608eaf2a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-8.c
@@ -0,0 +1,13 @@
+#define STYPE v8si
+#define UTYPE v8usi
+#define N 8
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv8si4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv8si4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv8si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv8si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv8si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv8si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__divsi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivsi3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-char-16.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-char-16.c
new file mode 100644
index 00000000000..f156d49cd2a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-char-16.c
@@ -0,0 +1,11 @@
+#define STYPE v16qi
+#define UTYPE v16uqi
+#define N 16
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv16qi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv16qi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv16qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv16qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv16qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv16qi3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-char-2.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-char-2.c
new file mode 100644
index 00000000000..be4b9050fcd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-char-2.c
@@ -0,0 +1,11 @@
+#define STYPE v2qi
+#define UTYPE v2uqi
+#define N 2
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv2qi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv2qi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv2qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv2qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv2qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv2qi3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-char-32.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-char-32.c
new file mode 100644
index 00000000000..b0cadecb0d8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-char-32.c
@@ -0,0 +1,11 @@
+#define STYPE v32qi
+#define UTYPE v32uqi
+#define N 32
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv32qi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv32qi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv32qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv32qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv32qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv32qi3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-char-4.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-char-4.c
new file mode 100644
index 00000000000..4dc7c783d35
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-char-4.c
@@ -0,0 +1,11 @@
+#define STYPE v4qi
+#define UTYPE v4uqi
+#define N 4
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv4qi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv4qi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv4qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv4qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv4qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv4qi3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-char-8.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-char-8.c
new file mode 100644
index 00000000000..ea3753aaaf8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-char-8.c
@@ -0,0 +1,11 @@
+#define STYPE v8qi
+#define UTYPE v8uqi
+#define N 8
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv8qi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv8qi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv8qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv8qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv8qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv8qi3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-char-run-16.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-char-run-16.c
new file mode 100644
index 00000000000..159b9802b07
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-char-run-16.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3-char-16.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-char-run-2.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-char-run-2.c
new file mode 100644
index 00000000000..6e730d07a03
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-char-run-2.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3-char-2.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-char-run-32.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-char-run-32.c
new file mode 100644
index 00000000000..8e4932bf5b9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-char-run-32.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3-char-32.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-char-run-4.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-char-run-4.c
new file mode 100644
index 00000000000..d07a4318390
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-char-run-4.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3-char-4.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-char-run-8.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-char-run-8.c
new file mode 100644
index 00000000000..64f789a4528
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-char-run-8.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3-char-8.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-char-run.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-char-run.c
new file mode 100644
index 00000000000..4e2d4c0a19a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-char-run.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3-char.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-char.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-char.c
new file mode 100644
index 00000000000..478d09e2ec7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-char.c
@@ -0,0 +1,10 @@
+#define STYPE v64qi
+#define UTYPE v64uqi
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv64qi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv64qi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv64qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv64qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv64qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv64qi3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-long-16.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-long-16.c
new file mode 100644
index 00000000000..530f29e3778
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-long-16.c
@@ -0,0 +1,11 @@
+#define STYPE v16di
+#define UTYPE v16udi
+#define N 16
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv16di4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv16di4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv16di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv16di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv16di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv16di3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-long-2.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-long-2.c
new file mode 100644
index 00000000000..1c3e833c733
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-long-2.c
@@ -0,0 +1,11 @@
+#define STYPE v2di
+#define UTYPE v2udi
+#define N 2
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv2di4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv2di4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv2di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv2di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv2di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv2di3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-long-32.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-long-32.c
new file mode 100644
index 00000000000..c8556a85ffd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-long-32.c
@@ -0,0 +1,11 @@
+#define STYPE v32di
+#define UTYPE v32udi
+#define N 32
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv32di4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv32di4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv32di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv32di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv32di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv32di3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-long-4.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-long-4.c
new file mode 100644
index 00000000000..514396c565d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-long-4.c
@@ -0,0 +1,11 @@
+#define STYPE v4di
+#define UTYPE v4udi
+#define N 4
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv4di4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv4di4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv4di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv4di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv4di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv4di3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-long-8.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-long-8.c
new file mode 100644
index 00000000000..428e3a5a807
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-long-8.c
@@ -0,0 +1,11 @@
+#define STYPE v8di
+#define UTYPE v8udi
+#define N 8
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv8di4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv8di4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv8di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv8di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv8di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv8di3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-long-run-16.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-long-run-16.c
new file mode 100644
index 00000000000..7ce9c92a7a0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-long-run-16.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3-long-16.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-long-run-2.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-long-run-2.c
new file mode 100644
index 00000000000..20996a56f5c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-long-run-2.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3-long-2.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-long-run-32.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-long-run-32.c
new file mode 100644
index 00000000000..1ca25ac9b51
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-long-run-32.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3-long-32.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-long-run-4.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-long-run-4.c
new file mode 100644
index 00000000000..b31769ad0bc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-long-run-4.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3-long-4.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-long-run-8.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-long-run-8.c
new file mode 100644
index 00000000000..930256a0fc7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-long-run-8.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3-long-8.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-long-run.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-long-run.c
new file mode 100644
index 00000000000..363e42573d2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-long-run.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3-long.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-long.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-long.c
new file mode 100644
index 00000000000..321297b75ba
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-long.c
@@ -0,0 +1,10 @@
+#define STYPE v64di
+#define UTYPE v64udi
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv64di4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv64di4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv64di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv64di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv64di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv64di3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-run-16.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-run-16.c
new file mode 100644
index 00000000000..ae8cdbffa1d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-run-16.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3-16.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-run-2.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-run-2.c
new file mode 100644
index 00000000000..7d80382f23b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-run-2.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3-2.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-run-32.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-run-32.c
new file mode 100644
index 00000000000..127fd36f0f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-run-32.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3-32.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-run-4.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-run-4.c
new file mode 100644
index 00000000000..e1d5b5de5c1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-run-4.c
@@ -0,0 +1,3 @@
+/* { dg-do run } */
+#include "simd-math-3-4.c"
+
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-run-8.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-run-8.c
new file mode 100644
index 00000000000..ec98b60ae2e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-run-8.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3-8.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-run.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-run.c
new file mode 100644
index 00000000000..aca508cbc25
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-run.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-short-16.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-short-16.c
new file mode 100644
index 00000000000..80f04149035
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-short-16.c
@@ -0,0 +1,11 @@
+#define STYPE v16hi
+#define UTYPE v16uhi
+#define N 16
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv16hi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv16hi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv16hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv16hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv16hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv16hi3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-short-2.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-short-2.c
new file mode 100644
index 00000000000..37e5008a871
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-short-2.c
@@ -0,0 +1,11 @@
+#define STYPE v2hi
+#define UTYPE v2uhi
+#define N 2
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv2hi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv2hi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv2hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv2hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv2hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv2hi3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-short-32.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-short-32.c
new file mode 100644
index 00000000000..79aada0ea5b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-short-32.c
@@ -0,0 +1,11 @@
+#define STYPE v32hi
+#define UTYPE v32uhi
+#define N 32
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv32hi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv32hi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv32hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv32hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv32hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv32hi3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-short-4.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-short-4.c
new file mode 100644
index 00000000000..014acacd2ea
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-short-4.c
@@ -0,0 +1,11 @@
+#define STYPE v4hi
+#define UTYPE v4uhi
+#define N 4
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv4hi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv4hi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv4hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv4hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv4hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv4hi3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-short-8.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-short-8.c
new file mode 100644
index 00000000000..308b72b53e2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-short-8.c
@@ -0,0 +1,11 @@
+#define STYPE v8hi
+#define UTYPE v8uhi
+#define N 8
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv8hi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv8hi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv8hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv8hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv8hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv8hi3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-short-run-16.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-short-run-16.c
new file mode 100644
index 00000000000..8ca866ce21f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-short-run-16.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3-short-16.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-short-run-2.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-short-run-2.c
new file mode 100644
index 00000000000..6c6d8b68f28
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-short-run-2.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3-short-2.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-short-run-32.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-short-run-32.c
new file mode 100644
index 00000000000..8c30ebc5528
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-short-run-32.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3-short-32.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-short-run-4.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-short-run-4.c
new file mode 100644
index 00000000000..e70697e6e42
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-short-run-4.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3-short-4.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-short-run-8.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-short-run-8.c
new file mode 100644
index 00000000000..9cb9a6fe297
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-short-run-8.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3-short-8.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-short-run.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-short-run.c
new file mode 100644
index 00000000000..08f72671e96
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-short-run.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-3-short.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3-short.c b/gcc/testsuite/gcc.target/gcn/simd-math-3-short.c
new file mode 100644
index 00000000000..1ade288f389
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3-short.c
@@ -0,0 +1,10 @@
+#define STYPE v64hi
+#define UTYPE v64uhi
+#include "simd-math-3.c"
+
+/* { dg-final { scan-assembler-times {__divmodv64hi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv64hi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv64hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv64hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv64hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv64hi3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-3.c b/gcc/testsuite/gcc.target/gcn/simd-math-3.c
new file mode 100644
index 00000000000..def83852461
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-3.c
@@ -0,0 +1,186 @@
+/* Test that signed and unsigned division and modulus use the correct
+   vector routines and give the correct results.  */
+
+/* Setting it this way ensures the run tests use the same flag as the
+   compile tests.  */
+#pragma GCC optimize("O2")
+
+typedef signed char v2qi __attribute__ ((vector_size (2)));
+typedef signed char v4qi __attribute__ ((vector_size (4)));
+typedef signed char v8qi __attribute__ ((vector_size (8)));
+typedef signed char v16qi __attribute__ ((vector_size (16)));
+typedef signed char v32qi __attribute__ ((vector_size (32)));
+typedef signed char v64qi __attribute__ ((vector_size (64)));
+
+typedef unsigned char v2uqi __attribute__ ((vector_size (2)));
+typedef unsigned char v4uqi __attribute__ ((vector_size (4)));
+typedef unsigned char v8uqi __attribute__ ((vector_size (8)));
+typedef unsigned char v16uqi __attribute__ ((vector_size (16)));
+typedef unsigned char v32uqi __attribute__ ((vector_size (32)));
+typedef unsigned char v64uqi __attribute__ ((vector_size (64)));
+
+typedef short v2hi __attribute__ ((vector_size (4)));
+typedef short v4hi __attribute__ ((vector_size (8)));
+typedef short v8hi __attribute__ ((vector_size (16)));
+typedef short v16hi __attribute__ ((vector_size (32)));
+typedef short v32hi __attribute__ ((vector_size (64)));
+typedef short v64hi __attribute__ ((vector_size (128)));
+
+typedef unsigned short v2uhi __attribute__ ((vector_size (4)));
+typedef unsigned short v4uhi __attribute__ ((vector_size (8)));
+typedef unsigned short v8uhi __attribute__ ((vector_size (16)));
+typedef unsigned short v16uhi __attribute__ ((vector_size (32)));
+typedef unsigned short v32uhi __attribute__ ((vector_size (64)));
+typedef unsigned short v64uhi __attribute__ ((vector_size (128)));
+
+typedef int v2si __attribute__ ((vector_size (8)));
+typedef int v4si __attribute__ ((vector_size (16)));
+typedef int v8si __attribute__ ((vector_size (32)));
+typedef int v16si __attribute__ ((vector_size (64)));
+typedef int v32si __attribute__ ((vector_size (128)));
+typedef int v64si __attribute__ ((vector_size (256)));
+
+typedef unsigned int v2usi __attribute__ ((vector_size (8)));
+typedef unsigned int v4usi __attribute__ ((vector_size (16)));
+typedef unsigned int v8usi __attribute__ ((vector_size (32)));
+typedef unsigned int v16usi __attribute__ ((vector_size (64)));
+typedef unsigned int v32usi __attribute__ ((vector_size (128)));
+typedef unsigned int v64usi __attribute__ ((vector_size (256)));
+
+typedef long v2di __attribute__ ((vector_size (16)));
+typedef long v4di __attribute__ ((vector_size (32)));
+typedef long v8di __attribute__ ((vector_size (64)));
+typedef long v16di __attribute__ ((vector_size (128)));
+typedef long v32di __attribute__ ((vector_size (256)));
+typedef long v64di __attribute__ ((vector_size (512)));
+
+typedef unsigned long v2udi __attribute__ ((vector_size (16)));
+typedef unsigned long v4udi __attribute__ ((vector_size (32)));
+typedef unsigned long v8udi __attribute__ ((vector_size (64)));
+typedef unsigned long v16udi __attribute__ ((vector_size (128)));
+typedef unsigned long v32udi __attribute__ ((vector_size (256)));
+typedef unsigned long v64udi __attribute__ ((vector_size (512)));
+
+#ifndef STYPE
+#define STYPE v64si
+#define UTYPE v64usi
+#endif
+#ifndef N
+#define N 64
+#endif
+
+STYPE a;
+STYPE b;
+UTYPE ua;
+UTYPE ub;
+
+int main()
+{
+  int i;
+  STYPE squot, srem;
+  UTYPE usquot, usrem;
+  STYPE vquot, vrem;
+  UTYPE uvquot, uvrem;
+  STYPE vquot2, vrem2;
+  UTYPE uvquot2, uvrem2;
+  STYPE refquot, refrem;
+  UTYPE urefquot, urefrem;
+
+  for (i = 0; i < N; i++)
+    {
+      a[i] = i * (i >> 2) + (i >> 1);
+      ua[i] = a[i];
+      b[i] = i;
+      ub[i] = i;
+    }
+
+  for (i = 0; i < N; i++)
+    {
+      /* Calculate reference values using regular scalar div and mod.  */
+      refquot[i] = a[i] / b[i];
+      __asm__ ("" ::: "memory");
+      refrem[i] = a[i] % b[i];
+      urefquot[i] = ua[i] / ub[i];
+      __asm__ ("" ::: "memory");
+      urefrem[i] = ua[i] % ub[i];
+    }
+
+  __asm__ ("" ::: "memory");
+  /* Scalar with divmod.  */
+  for (i = 0; i < N; i++)
+    {
+      squot[i] = a[i] / b[i];
+      srem[i] = a[i] % b[i];
+      usquot[i] = ua[i] / ub[i];
+      usrem[i] = ua[i] % ub[i];
+    }
+
+  __asm__ ("" ::: "memory");
+  /* Vectorized with divmod.  */
+  vquot = a / b;
+  vrem = a % b;
+  uvquot = ua / ub;
+  uvrem = ua % ub;
+
+  __asm__ ("" ::: "memory");
+  /* Vectorized with separte div and mod.  */
+  vquot2 = a / b;
+  __asm__ ("" ::: "memory");
+  vrem2 = a % b;
+  uvquot2 = ua / ub;
+  __asm__ ("" ::: "memory");
+  uvrem2 = ua % ub;
+
+#ifdef DEBUG
+#define DUMP(VAR) \
+  __builtin_printf ("%8s: ", #VAR); \
+  for (i = 0; i < N; i++) \
+    __builtin_printf ("%d ", (int)VAR[i]); \
+  __builtin_printf ("\n");
+  DUMP (refquot)
+  DUMP (squot)
+  DUMP (vquot)
+  DUMP (vquot2)
+  __builtin_printf ("\n");
+  DUMP (urefquot)
+  DUMP (usquot)
+  DUMP (uvquot)
+  DUMP (uvquot2)
+  __builtin_printf ("\n");
+  DUMP (refrem)
+  DUMP (srem)
+  DUMP (vrem)
+  DUMP (vrem2)
+  __builtin_printf ("\n");
+  DUMP (urefrem)
+  DUMP (usrem)
+  DUMP (uvrem)
+  DUMP (uvrem2)
+  __builtin_printf ("\n");
+#endif
+
+  for (i = 0; i < N; i++)
+    if (squot[i] != refquot[i]
+	|| vquot[i] != refquot[i]
+	|| vquot2[i] != refquot[i]
+	|| usquot[i] != urefquot[i]
+	|| uvquot[i] != urefquot[i]
+	|| uvquot2[i] != urefquot[i]
+	|| srem[i] != refrem[i]
+	|| vrem[i] != refrem[i]
+	|| vrem2[i] != refrem[i]
+	|| usrem[i] != urefrem[i]
+	|| uvrem[i] != urefrem[i]
+	|| uvrem2[i] != urefrem[i])
+      __builtin_abort ();
+  return 0;
+}
+
+/* { dg-final { scan-assembler-times {__divmodv64si4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv64si4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv64si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv64si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__modv64si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv64si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__divsi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivsi3@rel32@lo} 1 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-4-char-run.c b/gcc/testsuite/gcc.target/gcn/simd-math-4-char-run.c
new file mode 100644
index 00000000000..b328a3eeec5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-4-char-run.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-4-char.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-4-char.c b/gcc/testsuite/gcc.target/gcn/simd-math-4-char.c
new file mode 100644
index 00000000000..df24bd4e56d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-4-char.c
@@ -0,0 +1,9 @@
+#define TYPE v64qi
+#include "simd-math-4.c"
+
+/* { dg-final { scan-assembler-times {__divmodv64qi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv64qi4@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__divv64qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv64qi3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv64qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv64qi3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-4-long-run.c b/gcc/testsuite/gcc.target/gcn/simd-math-4-long-run.c
new file mode 100644
index 00000000000..34cbc467709
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-4-long-run.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-4-long.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-4-long.c b/gcc/testsuite/gcc.target/gcn/simd-math-4-long.c
new file mode 100644
index 00000000000..768a0dfc848
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-4-long.c
@@ -0,0 +1,9 @@
+#define TYPE v64di
+#include "simd-math-4.c"
+
+/* { dg-final { scan-assembler-times {__divmodv64di4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv64di4@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__divv64di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv64di3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv64di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv64di3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-4-run.c b/gcc/testsuite/gcc.target/gcn/simd-math-4-run.c
new file mode 100644
index 00000000000..3b98c0e7738
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-4-run.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-4.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-4-short-run.c b/gcc/testsuite/gcc.target/gcn/simd-math-4-short-run.c
new file mode 100644
index 00000000000..4cbeb97432e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-4-short-run.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-4-short.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-4-short.c b/gcc/testsuite/gcc.target/gcn/simd-math-4-short.c
new file mode 100644
index 00000000000..f010942ffad
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-4-short.c
@@ -0,0 +1,9 @@
+#define TYPE v64hi
+#include "simd-math-4.c"
+
+/* { dg-final { scan-assembler-times {__divmodv64hi4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv64hi4@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__divv64hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv64hi3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv64hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv64hi3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-4.c b/gcc/testsuite/gcc.target/gcn/simd-math-4.c
new file mode 100644
index 00000000000..833dfe2a866
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-4.c
@@ -0,0 +1,99 @@
+/* Test that signed division and modulus give the correct result with
+   different variations of signedness.  */
+
+/* Setting it this way ensures the run tests use the same flag as the
+   compile tests.  */
+#pragma GCC optimize("O2")
+
+typedef char v64qi __attribute__ ((vector_size (64)));
+typedef short v64hi __attribute__ ((vector_size (128)));
+typedef int v64si __attribute__ ((vector_size (256)));
+typedef long v64di __attribute__ ((vector_size (512)));
+
+#ifndef TYPE
+#define TYPE v64si
+#endif
+#define N 64
+
+TYPE a;
+TYPE b;
+
+int main()
+{
+  int i;
+  TYPE squot, srem;
+  TYPE usquot, usrem;
+  TYPE vquot, vrem;
+  TYPE vquot2, vrem2;
+  TYPE refquot, refrem;
+
+  for (i = 0; i < 64; i++)
+    {
+      a[i] = i * (i >> 2) * (i&1 ? -1 : 1);
+      b[i] = i * (i&2 ? -1 : 1);
+    }
+
+  for (i = 0; i < N; i++)
+    {
+      /* Calculate reference values using regular scalar div and mod.  */
+      refquot[i] = a[i] / b[i];
+      __asm__ ("" ::: "memory");
+      refrem[i] = a[i] % b[i];
+    }
+
+  __asm__ ("" ::: "memory");
+  /* Scalar with divmod.  */
+  for (i = 0; i < N; i++)
+    {
+      squot[i] = a[i] / b[i];
+      srem[i] = a[i] % b[i];
+    }
+
+  __asm__ ("" ::: "memory");
+  /* Vectorized with divmod.  */
+  vquot = a / b;
+  vrem = a % b;
+
+  __asm__ ("" ::: "memory");
+  /* Vectorized with separte div and mod.  */
+  vquot2 = a / b;
+  __asm__ ("" ::: "memory");
+  vrem2 = a % b;
+
+#ifdef DEBUG
+#define DUMP(VAR) \
+  __builtin_printf ("%8s: ", #VAR); \
+  for (i = 0; i < N; i++) \
+    __builtin_printf ("%d ", (int)VAR[i]); \
+  __builtin_printf ("\n");
+  DUMP (refquot)
+  DUMP (squot)
+  DUMP (vquot)
+  DUMP (vquot2)
+  __builtin_printf ("\n");
+  DUMP (refrem)
+  DUMP (srem)
+  DUMP (vrem)
+  DUMP (vrem2)
+  __builtin_printf ("\n");
+#endif
+
+  for (i = 0; i < N; i++)
+    if (squot[i] != refquot[i]
+	|| vquot[i] != refquot[i]
+	|| vquot2[i] != refquot[i]
+	|| srem[i] != refrem[i]
+	|| vrem[i] != refrem[i]
+	|| vrem2[i] != refrem[i])
+      __builtin_abort ();
+  return 0;
+}
+
+/* { dg-final { scan-assembler-times {__divmodv64si4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv64si4@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__divv64si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv64si3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv64si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv64si3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__divsi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivsi3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-16.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-16.c
new file mode 100644
index 00000000000..41c116758b4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-16.c
@@ -0,0 +1,8 @@
+#define N 16
+#include "simd-math-5.c"
+
+/* { dg-final { scan-assembler-times {__divmodv16si4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv16si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv16si3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv16si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv16si3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-32.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-32.c
new file mode 100644
index 00000000000..3fb92b2aab2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-32.c
@@ -0,0 +1,8 @@
+#define N 32
+#include "simd-math-5.c"
+
+/* { dg-final { scan-assembler-times {__divmodv32si4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv32si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv32si3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv32si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv32si3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-4.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-4.c
new file mode 100644
index 00000000000..ffcd5120178
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-4.c
@@ -0,0 +1,8 @@
+#define N 4
+#include "simd-math-5.c"
+
+/* { dg-final { scan-assembler-times {__divmodv4si4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv4si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv4si3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv4si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv4si3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-8.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-8.c
new file mode 100644
index 00000000000..5d855b62752
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-8.c
@@ -0,0 +1,8 @@
+#define N 8
+#include "simd-math-5.c"
+
+/* { dg-final { scan-assembler-times {__divmodv8si4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv8si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv8si3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv8si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv8si3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-char-16.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-char-16.c
new file mode 100644
index 00000000000..0ebf640dc8c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-char-16.c
@@ -0,0 +1,11 @@
+#define TYPE char
+#define N 16
+#include "simd-math-5.c"
+
+/* C integer promotion means that div uses HImode and divmod doesn't match.  */
+/* { dg-final { scan-assembler-times {__divmod16.i4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv16hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__divv16qi3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__udivv16qi3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv16qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv16qi3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-char-32.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-char-32.c
new file mode 100644
index 00000000000..0905f31048c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-char-32.c
@@ -0,0 +1,11 @@
+#define TYPE char
+#define N 32
+#include "simd-math-5.c"
+
+/* C integer promotion means that div uses HImode and divmod doesn't match.  */
+/* { dg-final { scan-assembler-times {__divmod32.i4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv32hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__divv32qi3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__udivv32qi3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv32qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv32qi3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-char-4.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-char-4.c
new file mode 100644
index 00000000000..772fe37fe81
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-char-4.c
@@ -0,0 +1,11 @@
+#define TYPE char
+#define N 4
+#include "simd-math-5.c"
+
+/* C integer promotion means that div uses HImode and divmod doesn't match.  */
+/* { dg-final { scan-assembler-times {__divmod4.i4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv4hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__divv4qi3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__udivv4qi3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv4qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv4qi3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-char-8.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-char-8.c
new file mode 100644
index 00000000000..539ce9a7f91
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-char-8.c
@@ -0,0 +1,11 @@
+#define TYPE char
+#define N 8
+#include "simd-math-5.c"
+
+/* C integer promotion means that div uses HImode and divmod doesn't match.  */
+/* { dg-final { scan-assembler-times {__divmod8.i4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv8hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__divv8qi3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__udivv8qi3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv8qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv8qi3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-char-run-16.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-char-run-16.c
new file mode 100644
index 00000000000..0f1af0858ca
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-char-run-16.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-5-char-16.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-char-run-32.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-char-run-32.c
new file mode 100644
index 00000000000..a2794c84a83
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-char-run-32.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-5-char-32.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-char-run-4.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-char-run-4.c
new file mode 100644
index 00000000000..a8e418770ff
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-char-run-4.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-5-char-4.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-char-run-8.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-char-run-8.c
new file mode 100644
index 00000000000..7a6a95922cc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-char-run-8.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-5-char-8.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-char-run.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-char-run.c
new file mode 100644
index 00000000000..d3ca775f6a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-char-run.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-5-char.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-char.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-char.c
new file mode 100644
index 00000000000..2321c8390c6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-char.c
@@ -0,0 +1,10 @@
+#define TYPE char
+#include "simd-math-5.c"
+
+/* C integer promotion means that div uses HImode and divmod doesn't match.  */
+/* { dg-final { scan-assembler-times {__divmodv64si4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv64hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__divv64qi3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__udivv64qi3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv64qi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv64qi3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-long-16.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-long-16.c
new file mode 100644
index 00000000000..659907d8d52
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-long-16.c
@@ -0,0 +1,9 @@
+#define TYPE long
+#define N 16
+#include "simd-math-5.c"
+
+/* { dg-final { scan-assembler-times {__divmodv16di4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv16di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv16di3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv16di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv16di3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-long-32.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-long-32.c
new file mode 100644
index 00000000000..b03fd092470
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-long-32.c
@@ -0,0 +1,9 @@
+#define TYPE long
+#define N 32
+#include "simd-math-5.c"
+
+/* { dg-final { scan-assembler-times {__divmodv32di4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv32di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv32di3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv32di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv32di3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-long-4.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-long-4.c
new file mode 100644
index 00000000000..a8877b6c63b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-long-4.c
@@ -0,0 +1,9 @@
+#define TYPE long
+#define N 4
+#include "simd-math-5.c"
+
+/* { dg-final { scan-assembler-times {__divmodv4di4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv4di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv4di3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv4di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv4di3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-long-8.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-long-8.c
new file mode 100644
index 00000000000..5b1106c73af
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-long-8.c
@@ -0,0 +1,9 @@
+#define TYPE long
+#define N 8
+#include "simd-math-5.c"
+
+/* { dg-final { scan-assembler-times {__divmodv8di4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv8di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv8di3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv8di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv8di3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-long-run-16.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-long-run-16.c
new file mode 100644
index 00000000000..20919255404
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-long-run-16.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-5-long-16.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-long-run-32.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-long-run-32.c
new file mode 100644
index 00000000000..c7ff7ca52b9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-long-run-32.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-5-long-32.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-long-run-4.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-long-run-4.c
new file mode 100644
index 00000000000..c6cf3344ec4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-long-run-4.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-5-long-4.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-long-run-8.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-long-run-8.c
new file mode 100644
index 00000000000..85fdf6ffe1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-long-run-8.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-5-long-8.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-long-run.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-long-run.c
new file mode 100644
index 00000000000..b948fa08c7e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-long-run.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-5-long.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-long.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-long.c
new file mode 100644
index 00000000000..37b6cef691e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-long.c
@@ -0,0 +1,8 @@
+#define TYPE long
+#include "simd-math-5.c"
+
+/* { dg-final { scan-assembler-times {__divmodv64di4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv64di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv64di3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv64di3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv64di3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-run-16.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-run-16.c
new file mode 100644
index 00000000000..20919255404
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-run-16.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-5-long-16.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-run-32.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-run-32.c
new file mode 100644
index 00000000000..c7ff7ca52b9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-run-32.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-5-long-32.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-run-4.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-run-4.c
new file mode 100644
index 00000000000..c6cf3344ec4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-run-4.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-5-long-4.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-run-8.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-run-8.c
new file mode 100644
index 00000000000..85fdf6ffe1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-run-8.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-5-long-8.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-run.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-run.c
new file mode 100644
index 00000000000..de6504c737c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-run.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-5.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-short-16.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-short-16.c
new file mode 100644
index 00000000000..5d5953bc604
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-short-16.c
@@ -0,0 +1,11 @@
+#define TYPE short
+#define N 16
+#include "simd-math-5.c"
+
+/* C integer promotion means that div uses SImode and divmod doesn't match.  */
+/* { dg-final { scan-assembler-times {__divmod16.i4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv16si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__divv16hi3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__udivv16hi3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv16hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv16hi3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-short-32.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-short-32.c
new file mode 100644
index 00000000000..bf8a3addfc4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-short-32.c
@@ -0,0 +1,11 @@
+#define TYPE short
+#define N 32
+#include "simd-math-5.c"
+
+/* C integer promotion means that div uses SImode and divmod doesn't match.  */
+/* { dg-final { scan-assembler-times {__divmod32.i4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv32si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__divv32hi3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__udivv32hi3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv32hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv32hi3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-short-4.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-short-4.c
new file mode 100644
index 00000000000..a2cb46c8646
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-short-4.c
@@ -0,0 +1,11 @@
+#define TYPE short
+#define N 4
+#include "simd-math-5.c"
+
+/* C integer promotion means that div uses SImode and divmod doesn't match.  */
+/* { dg-final { scan-assembler-times {__divmod4.i4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv4si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__divv4hi3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__udivv4hi3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv4hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv4hi3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-short-8.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-short-8.c
new file mode 100644
index 00000000000..fa343e5262e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-short-8.c
@@ -0,0 +1,11 @@
+#define TYPE short
+#define N 8
+#include "simd-math-5.c"
+
+/* C integer promotion means that div uses SImode and divmod doesn't match.  */
+/* { dg-final { scan-assembler-times {__divmod8.i4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv8si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__divv8hi3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__udivv8hi3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv8hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv8hi3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-short-run-16.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-short-run-16.c
new file mode 100644
index 00000000000..3fc946e2e09
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-short-run-16.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-5-short-16.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-short-run-32.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-short-run-32.c
new file mode 100644
index 00000000000..34b1d75fa8e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-short-run-32.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-5-short-32.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-short-run-4.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-short-run-4.c
new file mode 100644
index 00000000000..09385c78bc4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-short-run-4.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-5-short-4.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-short-run-8.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-short-run-8.c
new file mode 100644
index 00000000000..1de4d2631b3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-short-run-8.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-5-short-8.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-short-run.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-short-run.c
new file mode 100644
index 00000000000..2e0c490fdd9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-short-run.c
@@ -0,0 +1,2 @@
+/* { dg-do run } */
+#include "simd-math-5-short.c"
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5-short.c b/gcc/testsuite/gcc.target/gcn/simd-math-5-short.c
new file mode 100644
index 00000000000..84cdc9b5fdd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5-short.c
@@ -0,0 +1,10 @@
+#define TYPE short
+#include "simd-math-5.c"
+
+/* C integer promotion means that div uses SImode and divmod doesn't match.  */
+/* { dg-final { scan-assembler-times {__divmodv64si4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__divv64si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__divv64hi3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__udivv64hi3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv64hi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv64hi3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/gcc.target/gcn/simd-math-5.c b/gcc/testsuite/gcc.target/gcn/simd-math-5.c
new file mode 100644
index 00000000000..bc181b45e1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/gcn/simd-math-5.c
@@ -0,0 +1,88 @@
+/* Test that the auto-vectorizer uses the libgcc vectorized division and
+   modulus functions.  */
+
+/* Setting it this way ensures the run tests use the same flag as the
+   compile tests.  */
+#pragma GCC optimize("O2")
+
+#ifndef TYPE
+#define TYPE int
+#endif
+#ifndef N
+#define N 64
+#endif
+
+TYPE a[N];
+TYPE b[N];
+
+int main()
+{
+  int i;
+  TYPE quot[N], rem[N];
+  TYPE quot2[N], rem2[N];
+  TYPE refquot[N], refrem[N];
+
+  for (i = 0; i < N; i++)
+    {
+      a[i] = i * (i >> 2) + (i >> 1);
+      b[i] = i;
+    }
+  __asm__ ("" ::: "memory");
+
+  /* Vector divmod.  */
+  for (i = 0; i < N; i++)
+    {
+      quot[i] = (TYPE)a[i] / (TYPE)b[i];
+      rem[i] = (TYPE)a[i] % (TYPE)b[i];
+    }
+  __asm__ ("" ::: "memory");
+
+  /* Vector div.  */
+  for (i = 0; i < N; i++)
+    quot2[i] = (TYPE)a[i] / (TYPE)b[i];
+  __asm__ ("" ::: "memory");
+
+  /* Vector mod.  */
+  for (i = 0; i < N; i++)
+    rem2[i] = (TYPE)a[i] % (TYPE)b[i];
+
+  /* Calculate reference values with no vectorization.  */
+  for (i = 0; i < N; i++)
+    {
+      refquot[i] = (TYPE)a[i] / (TYPE)b[i];
+      __asm__ ("" ::: "memory");
+      refrem[i] = (TYPE)a[i] % (TYPE)b[i];
+    }
+
+#ifdef DEBUG
+#define DUMP(VAR) \
+  __builtin_printf ("%8s: ", #VAR); \
+  for (i = 0; i < N; i++) \
+    __builtin_printf ("%d ", (int)VAR[i]); \
+  __builtin_printf ("\n");
+  DUMP (refquot)
+  DUMP (quot)
+  DUMP (quot2)
+  __builtin_printf ("\n");
+  DUMP (refrem)
+  DUMP (rem)
+  DUMP (rem2)
+#endif
+
+  for (i = 0; i < N; i++)
+    if (quot[i] != refquot[i]
+	|| quot2[i] != refquot[i]
+	|| rem[i] != refrem[i]
+	|| rem2[i] != refrem[i])
+      __builtin_abort ();
+  return 0;
+}
+
+/* { dg-final { scan-assembler-times {__divmodv64si4@rel32@lo} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {__udivmodv64si4@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__divv64si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivv64si3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__modv64si3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__umodv64si3@rel32@lo} 0 } } */
+/* { dg-final { scan-assembler-times {__divsi3@rel32@lo} 1 } } */
+/* { dg-final { scan-assembler-times {__udivsi3@rel32@lo} 0 } } */
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 77822499bcf..d79ad4be105 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -8493,8 +8493,9 @@ proc check_effective_target_vect_long_mult { } {
 
 proc check_effective_target_vect_int_mod { } {
     return [check_cached_effective_target_indexed vect_int_mod {
-      expr { [istarget powerpc*-*-*]
-	     && [check_effective_target_has_arch_pwr10] }}]
+      expr { ([istarget powerpc*-*-*]
+	      && [check_effective_target_has_arch_pwr10])
+             || [istarget amdgcn-*-*] }}]
 }
 
 # Return 1 if the target supports vector even/odd elements extraction, 0 otherwise.
@@ -11627,7 +11628,8 @@ proc check_effective_target_divmod { } {
     #TODO: Add checks for all targets that have either hardware divmod insn
     # or define libfunc for divmod.
     if { [istarget arm*-*-*]
-	 || [istarget i?86-*-*] || [istarget x86_64-*-*] } {
+	 || [istarget i?86-*-*] || [istarget x86_64-*-*]
+         || [istarget amdgcn-*-*] } {
 	return 1
     }
     return 0
diff --git a/libgcc/config/gcn/amdgcn_veclib.h b/libgcc/config/gcn/amdgcn_veclib.h
new file mode 100644
index 00000000000..15ea20bcd55
--- /dev/null
+++ b/libgcc/config/gcn/amdgcn_veclib.h
@@ -0,0 +1,322 @@
+/* Macro library used to help during conversion of scalar math functions to
+   vectorized SIMD equivalents on AMD GCN.
+
+   Copyright (C) 2023 Free Software Foundation, Inc.
+   Contributed by Siemens.
+  
+   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/>.  */
+
+typedef union {
+  v2sf t_v2sf;
+  v4sf t_v4sf;
+  v8sf t_v8sf;
+  v16sf t_v16sf;
+  v32sf t_v32sf;
+  v64sf t_v64sf;
+
+  v2df t_v2df;
+  v4df t_v4df;
+  v8df t_v8df;
+  v16df t_v16df;
+  v32df t_v32df;
+  v64df t_v64df;
+
+  v64qi t_v64qi;
+  v64hi t_v64hi;
+
+  v2si t_v2si;
+  v4si t_v4si;
+  v8si t_v8si;
+  v16si t_v16si;
+  v32si t_v32si;
+  v64si t_v64si;
+
+  v64usi t_v64usi;
+
+  v2di t_v2di;
+  v4di t_v4di;
+  v8di t_v8di;
+  v16di t_v16di;
+  v32di t_v32di;
+  v64di t_v64di;
+} vector_union;
+
+/* Cast between vectors with a different number of elements, or type.  */
+
+#define VGPR_CAST(to_t, from) \
+({ \
+  to_t __res; \
+  __asm__ ("" : "=v"(__res) : "0"(from)); \
+  __res; \
+})
+
+#define PACK_SI_PAIR(low, high) \
+({ \
+  v64udi __res; \
+  asm ("v_mov_b32\t%L0, %1\n\t" \
+       "v_mov_b32\t%H0, %2" \
+       : "=&v"(__res) : "v0"(low), "v"(high), "e"(-1L)); \
+  __res; \
+ })
+
+#define UNPACK_SI_LOW(to_t, pair) VGPR_CAST(to_t, pair)
+#define UNPACK_SI_HIGH(to_t, pair) \
+({ \
+  to_t __res; \
+  asm ("v_mov_b32\t%0, %H1" : "=v"(__res) : "v"(pair), "e"(-1L)); \
+  __res; \
+ })
+
+#define PACK_DI_PAIR(low, high) \
+({ \
+  v64uti __res; \
+  asm ("v_mov_b32\t%L0, %L1\n\t" \
+       "v_mov_b32\t%H0, %H1\n\t" \
+       "v_mov_b32\t%J0, %L2\n\t" \
+       "v_mov_b32\t%K0, %H2" \
+       : "=&v"(__res) : "v0"(low), "v"(high), "e"(-1L)); \
+  __res; \
+ })
+
+#define UNPACK_DI_LOW(to_t, pair) VGPR_CAST(to_t, pair)
+#define UNPACK_DI_HIGH(to_t, pair) \
+({ \
+  to_t __res; \
+  asm ("v_mov_b32\t%L0, %J1\n\t" \
+       "v_mov_b32\t%H0, %K1" : "=v"(__res) : "v"(pair), "e"(-1L)); \
+  __res; \
+ })
+
+#define NO_COND __mask
+
+/* Note - __mask is _not_ accounted for in VECTOR_MERGE!  */
+#define VECTOR_MERGE(vec1, vec2, cond) \
+({ \
+  _Static_assert (__builtin_types_compatible_p (typeof (vec1), typeof (vec2))); \
+  union { \
+    typeof (vec1) val; \
+    v64qi t_v64qi; \
+    v64hi t_v64hi; \
+    v64si t_v64si; \
+    v64di t_v64di; \
+  } __vec1, __vec2, __res; \
+  __vec1.val = (vec1); \
+  __vec2.val = (vec2); \
+  __builtin_choose_expr ( \
+        sizeof (vec1) == sizeof (v64si), \
+        ({ \
+          v64si __bitmask = __builtin_convertvector ((cond), v64si); \
+          __res.t_v64si = (__vec1.t_v64si & __bitmask) \
+                          | (__vec2.t_v64si & ~__bitmask); \
+        }), \
+	__builtin_choose_expr ( \
+	  sizeof (vec1) == sizeof (v64hi), \
+	  ({ \
+	    v64hi __bitmask = __builtin_convertvector ((cond), v64hi); \
+	    __res.t_v64hi = (__vec1.t_v64hi & __bitmask) \
+			    | (__vec2.t_v64hi & ~__bitmask); \
+	   }), \
+	   __builtin_choose_expr ( \
+	     sizeof (vec1) == sizeof (v64qi), \
+	     ({ \
+	     v64qi __bitmask = __builtin_convertvector ((cond), v64qi); \
+	     __res.t_v64qi = (__vec1.t_v64qi & __bitmask) \
+			      | (__vec2.t_v64qi & ~__bitmask); \
+	     }), \
+	     ({ \
+	      v64di __bitmask = __builtin_convertvector ((cond), v64di); \
+	      __res.t_v64di = (__vec1.t_v64di & __bitmask) \
+			      | (__vec2.t_v64di & ~__bitmask); \
+	      })))); \
+  __res.val; \
+})
+
+#define VECTOR_COND_MOVE(var, val, cond) \
+do { \
+  _Static_assert (__builtin_types_compatible_p (typeof (var), typeof (val))); \
+  __auto_type __cond = __builtin_convertvector ((cond), typeof (__mask)); \
+  var = VECTOR_MERGE ((val), var, __cond & __mask); \
+} while (0)
+
+#define VECTOR_IF(cond, cond_var) \
+{ \
+  __auto_type cond_var = (cond); \
+  __auto_type __inv_cond __attribute__((unused)) = ~cond_var; \
+  if (!ALL_ZEROES_P (cond_var)) \
+  {
+
+#define VECTOR_ELSEIF(cond, cond_var) \
+  } \
+  cond_var = __inv_cond & (cond); \
+  __inv_cond &= ~(cond); \
+  if (!ALL_ZEROES_P (cond_var)) \
+  {
+
+#define VECTOR_ELSE(cond_var) \
+  } \
+  cond_var = __inv_cond; \
+  if (!ALL_ZEROES_P (cond_var)) \
+  {
+
+#define VECTOR_IF2(cond, cond_var, prev_cond_var) \
+{ \
+  __auto_type cond_var = (cond) & __builtin_convertvector (prev_cond_var, typeof (cond)); \
+  __auto_type __inv_cond __attribute__((unused)) = ~cond_var; \
+  if (!ALL_ZEROES_P (cond_var)) \
+  {
+
+#define VECTOR_ELSEIF2(cond, cond_var, prev_cond_var) \
+  } \
+  cond_var = (cond) & __inv_cond & __builtin_convertvector (prev_cond_var, typeof (cond)); \
+  __inv_cond &= ~(cond); \
+  if (!ALL_ZEROES_P (cond_var)) \
+  {
+
+#define VECTOR_ELSE2(cond_var, prev_cond_var) \
+  } \
+  cond_var = __inv_cond & __builtin_convertvector (prev_cond_var, typeof (__inv_cond)); \
+  if (!ALL_ZEROES_P (cond_var)) \
+  {
+
+
+#define VECTOR_ENDIF \
+  } \
+}
+
+#define VECTOR_INIT_AUX(x, type) \
+({ \
+  typeof (x) __e = (x); \
+  type __tmp = { \
+    __e, __e, __e, __e, __e, __e, __e, __e, \
+    __e, __e, __e, __e, __e, __e, __e, __e, \
+    __e, __e, __e, __e, __e, __e, __e, __e, \
+    __e, __e, __e, __e, __e, __e, __e, __e, \
+    __e, __e, __e, __e, __e, __e, __e, __e, \
+    __e, __e, __e, __e, __e, __e, __e, __e, \
+    __e, __e, __e, __e, __e, __e, __e, __e, \
+    __e, __e, __e, __e, __e, __e, __e, __e }; \
+  __tmp; \
+})
+
+#define VECTOR_INIT(x) \
+  (_Generic ((x), int: VECTOR_INIT_AUX ((x), v64si), \
+                  unsigned: VECTOR_INIT_AUX ((x), v64usi), \
+                  char: VECTOR_INIT_AUX ((x), v64qi), \
+                  unsigned char: VECTOR_INIT_AUX ((x), v64uqi), \
+                  short: VECTOR_INIT_AUX ((x), v64hi), \
+                  unsigned short: VECTOR_INIT_AUX ((x), v64uhi), \
+                  long: VECTOR_INIT_AUX ((x), v64di), \
+                  unsigned long: VECTOR_INIT_AUX ((x), v64udi), \
+                  float: VECTOR_INIT_AUX ((x), v64sf), \
+                  double: VECTOR_INIT_AUX ((x), v64df)))
+
+
+#if defined (__GCN3__) || defined (__GCN5__) \
+    || defined (__CDNA1__) || defined (__CDNA2__)
+#define CDNA3_PLUS 0
+#else
+#define CDNA3_PLUS 1
+#endif
+
+#define VECTOR_INIT_MASK(COUNT) \
+({ \
+  MASKMODE __mask; \
+  int count = (COUNT); \
+  if (count == 64) \
+    { \
+      if (sizeof (MASKMODE) < 512 || CDNA3_PLUS) \
+	asm ("v_mov%B0\t%0, -1" : "=v"(__mask) : "e"(-1L)); \
+      else \
+	asm ("v_mov_b32\t%L0, -1\n\t" \
+	     "v_mov_b32\t%H0, -1" : "=v"(__mask) : "e"(-1L)); \
+    } \
+  else \
+    { \
+      long bitmask = (count == 64 ? -1 : (1<<count)-1); \
+      if (sizeof (MASKMODE) < 512 || CDNA3_PLUS) \
+        { \
+	  asm ("v_mov%B0\t%0, 0" : "=v"(__mask) : "e"(-1L)); \
+	  asm ("v_mov%B0\t%0, -1" : "+v"(__mask) : "e"(bitmask)); \
+	} \
+      else \
+        { \
+	  asm ("v_mov_b32\t%L0, 0\n\t" \
+	       "v_mov_b32\t%H0, 0" : "=v"(__mask) : "e"(-1L)); \
+	  asm ("v_mov_b32\t%L0, -1\n\t" \
+	       "v_mov_b32\t%H0, -1" : "+v"(__mask) : "e"(bitmask)); \
+	} \
+    } \
+  __mask; \
+})
+
+#define ALL_ZEROES_P(x) (COND_TO_BITMASK(x) == 0)
+
+#define COND_TO_BITMASK(x) \
+({ \
+  long __tmp = 0; \
+  __auto_type __x = __builtin_convertvector((x), typeof (__mask)) & __mask; \
+  __builtin_choose_expr (sizeof (__mask) != 512, \
+                         ({ asm ("v_cmp_ne_u32_e64 %0, %1, 0" \
+                                 : "=Sg" (__tmp) \
+                                 : "v" (__x)); }), \
+                         ({ asm ("v_cmp_ne_u64_e64 %0, %1, 0" \
+                                 : "=Sg" (__tmp) \
+                                 : "v" (__x)); })); \
+  __tmp; \
+})
+
+#define VECTOR_WHILE(cond, cond_var, prev_cond_var) \
+{ \
+  __auto_type cond_var = prev_cond_var; \
+  for (;;) { \
+    cond_var &= (cond); \
+    if (ALL_ZEROES_P (cond_var)) \
+      break;
+
+#define VECTOR_ENDWHILE \
+  } \
+}
+
+#define DEF_VARIANT(FUN, SUFFIX, OTYPE, TYPE, COUNT) \
+v##COUNT##OTYPE \
+FUN##v##COUNT##SUFFIX (v##COUNT##TYPE __arg1, v##COUNT##TYPE __arg2) \
+{ \
+  __auto_type __upsized_arg1 = VGPR_CAST (v64##TYPE, __arg1); \
+  __auto_type __upsized_arg2 = VGPR_CAST (v64##TYPE, __arg2); \
+  __auto_type __mask = VECTOR_INIT_MASK (COUNT); \
+  __auto_type __result = FUN##v64##SUFFIX##_aux (__upsized_arg1, __upsized_arg2, __mask); \
+  return VGPR_CAST (v##COUNT##OTYPE, __result); \
+}
+
+#define DEF_VARIANTS(FUN, SUFFIX, TYPE) \
+  DEF_VARIANT (FUN, SUFFIX, TYPE, TYPE, 2) \
+  DEF_VARIANT (FUN, SUFFIX, TYPE, TYPE, 4) \
+  DEF_VARIANT (FUN, SUFFIX, TYPE, TYPE, 8) \
+  DEF_VARIANT (FUN, SUFFIX, TYPE, TYPE, 16) \
+  DEF_VARIANT (FUN, SUFFIX, TYPE, TYPE, 32) \
+  DEF_VARIANT (FUN, SUFFIX, TYPE, TYPE, 64)
+
+#define DEF_VARIANTS_B(FUN, SUFFIX, OTYPE, TYPE) \
+  DEF_VARIANT (FUN, SUFFIX, OTYPE, TYPE, 2) \
+  DEF_VARIANT (FUN, SUFFIX, OTYPE, TYPE, 4) \
+  DEF_VARIANT (FUN, SUFFIX, OTYPE, TYPE, 8) \
+  DEF_VARIANT (FUN, SUFFIX, OTYPE, TYPE, 16) \
+  DEF_VARIANT (FUN, SUFFIX, OTYPE, TYPE, 32) \
+  DEF_VARIANT (FUN, SUFFIX, OTYPE, TYPE, 64)
diff --git a/libgcc/config/gcn/lib2-divmod-di.c b/libgcc/config/gcn/lib2-divmod-di.c
index a9023770c27..d0385f3b28c 100644
--- a/libgcc/config/gcn/lib2-divmod-di.c
+++ b/libgcc/config/gcn/lib2-divmod-di.c
@@ -22,14 +22,101 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 
 #include "lib2-gcn.h"
 
-/* We really want DImode here: override LIBGCC2_UNITS_PER_WORD.  */
-#define LIBGCC2_UNITS_PER_WORD 4
-#define TARGET_HAS_NO_HW_DIVIDE
+/* 64-bit SI divide and modulo as used in gcn.  */
 
-#define L_divmoddi4
-#define L_divdi3
-#define L_moddi3
-#define L_udivdi3
-#define L_umoddi3
+union pack {
+  UTItype ti;
+  struct {DItype quot, rem;} pair;
+};
+union upack {
+  UTItype ti;
+  struct {UDItype quot, rem;} pair;
+};
+
+UTItype
+__udivmoddi4 (UDItype num, UDItype den)
+{
+  UDItype bit = 1;
+  union upack res = {0};
+
+  while (den < num && bit && !(den & (1L<<63)))
+    {
+      den <<=1;
+      bit <<=1;
+    }
+  while (bit)
+    {
+      if (num >= den)
+	{
+	  num -= den;
+	  res.pair.quot |= bit;
+	}
+      bit >>=1;
+      den >>=1;
+    }
+  res.pair.rem = num;
+  return res.ti;
+}
+
+UTItype
+__divmoddi4 (DItype a, DItype b)
+{
+  word_type nega = 0, negb = 0;
+  union pack res;
+
+  if (a < 0)
+    {
+      a = -a;
+      nega = 1;
+    }
+
+  if (b < 0)
+    {
+      b = -b;
+      negb = 1;
+    }
+
+  res.ti = __udivmoddi4 (a, b);
+
+  if (nega)
+    res.pair.rem = -res.pair.rem;
+  if (nega ^ negb)
+    res.pair.quot = -res.pair.quot;
+
+  return res.ti;
+}
+
+
+DItype
+__divdi3 (DItype a, DItype b)
+{
+  union pack u;
+  u.ti = __divmoddi4 (a, b);
+  return u.pair.quot;
+}
+
+DItype
+__moddi3 (DItype a, DItype b)
+{
+  union pack u;
+  u.ti = __divmoddi4 (a, b);
+  return u.pair.rem;
+}
+
+
+UDItype
+__udivdi3 (UDItype a, UDItype b)
+{
+  union pack u;
+  u.ti = __udivmoddi4 (a, b);
+  return u.pair.quot;
+}
+
+UDItype
+__umoddi3 (UDItype a, UDItype b)
+{
+  union pack u;
+ u.ti = __udivmoddi4 (a, b);
+ return u.pair.rem;
+}
 
-#include "libgcc2.c"
diff --git a/libgcc/config/gcn/lib2-divmod.c b/libgcc/config/gcn/lib2-divmod.c
index c350f7858f1..d701d1a4f58 100644
--- a/libgcc/config/gcn/lib2-divmod.c
+++ b/libgcc/config/gcn/lib2-divmod.c
@@ -24,11 +24,20 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 
 /* 32-bit SI divide and modulo as used in gcn.  */
 
-static USItype
-udivmodsi4 (USItype num, USItype den, word_type modwanted)
+union pack {
+  UDItype di;
+  struct {SItype quot, rem;} pair;
+};
+union upack {
+  UDItype di;
+  struct {USItype quot, rem;} pair;
+};
+
+UDItype
+__udivmodsi4 (USItype num, USItype den)
 {
   USItype bit = 1;
-  USItype res = 0;
+  union upack res = {0};
 
   while (den < num && bit && !(den & (1L<<31)))
     {
@@ -40,78 +49,75 @@ udivmodsi4 (USItype num, USItype den, word_type modwanted)
       if (num >= den)
 	{
 	  num -= den;
-	  res |= bit;
+	  res.pair.quot |= bit;
 	}
       bit >>=1;
       den >>=1;
     }
-  if (modwanted)
-    return num;
-  return res;
+  res.pair.rem = num;
+  return res.di;
 }
 
-
-SItype
-__divsi3 (SItype a, SItype b)
+UDItype
+__divmodsi4 (SItype a, SItype b)
 {
-  word_type neg = 0;
-  SItype res;
+  word_type nega = 0, negb = 0;
+  union pack res;
 
   if (a < 0)
     {
       a = -a;
-      neg = !neg;
+      nega = 1;
     }
 
   if (b < 0)
     {
       b = -b;
-      neg = !neg;
+      negb = 1;
     }
 
-  res = udivmodsi4 (a, b, 0);
+  res.di = __udivmodsi4 (a, b);
 
-  if (neg)
-    res = -res;
+  if (nega)
+    res.pair.rem = -res.pair.rem;
+  if (nega ^ negb)
+    res.pair.quot = -res.pair.quot;
 
-  return res;
+  return res.di;
 }
 
 
 SItype
-__modsi3 (SItype a, SItype b)
+__divsi3 (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;
+  union pack u;
+  u.di = __divmodsi4 (a, b);
+  return u.pair.quot;
+}
 
-  return res;
+SItype
+__modsi3 (SItype a, SItype b)
+{
+  union pack u;
+  u.di = __divmodsi4 (a, b);
+  return u.pair.rem;
 }
 
 
 USItype
 __udivsi3 (USItype a, USItype b)
 {
-  return udivmodsi4 (a, b, 0);
+  union pack u;
+  u.di = __udivmodsi4 (a, b);
+  return u.pair.quot;
 }
 
 
 USItype
 __umodsi3 (USItype a, USItype b)
 {
-  return udivmodsi4 (a, b, 1);
+  union pack u;
+ u.di = __udivmodsi4 (a, b);
+ return u.pair.rem;
 }
 
diff --git a/libgcc/config/gcn/lib2-gcn.h b/libgcc/config/gcn/lib2-gcn.h
index 67ad9bafc19..dc071c0f727 100644
--- a/libgcc/config/gcn/lib2-gcn.h
+++ b/libgcc/config/gcn/lib2-gcn.h
@@ -35,15 +35,129 @@ typedef int TItype __attribute__ ((mode (TI)));
 typedef unsigned int UTItype __attribute__ ((mode (TI)));
 typedef int word_type __attribute__ ((mode (__word__)));
 
+typedef float v2sf __attribute__ ((vector_size (8)));
+typedef float v4sf __attribute__ ((vector_size (16)));
+typedef float v8sf __attribute__ ((vector_size (32)));
+typedef float v16sf __attribute__ ((vector_size (64)));
+typedef float v32sf __attribute__ ((vector_size (128)));
+typedef float v64sf __attribute__ ((vector_size (256)));
+
+typedef double v2df __attribute__ ((vector_size (16)));
+typedef double v4df __attribute__ ((vector_size (32)));
+typedef double v8df __attribute__ ((vector_size (64)));
+typedef double v16df __attribute__ ((vector_size (128)));
+typedef double v32df __attribute__ ((vector_size (256)));
+typedef double v64df __attribute__ ((vector_size (512)));
+
+typedef signed char v2qi __attribute__ ((vector_size (2)));
+typedef signed char v4qi __attribute__ ((vector_size (4)));
+typedef signed char v8qi __attribute__ ((vector_size (8)));
+typedef signed char v16qi __attribute__ ((vector_size (16)));
+typedef signed char v32qi __attribute__ ((vector_size (32)));
+typedef signed char v64qi __attribute__ ((vector_size (64)));
+
+typedef unsigned char v2uqi __attribute__ ((vector_size (2)));
+typedef unsigned char v4uqi __attribute__ ((vector_size (4)));
+typedef unsigned char v8uqi __attribute__ ((vector_size (8)));
+typedef unsigned char v16uqi __attribute__ ((vector_size (16)));
+typedef unsigned char v32uqi __attribute__ ((vector_size (32)));
+typedef unsigned char v64uqi __attribute__ ((vector_size (64)));
+
+typedef short v2hi __attribute__ ((vector_size (4)));
+typedef short v4hi __attribute__ ((vector_size (8)));
+typedef short v8hi __attribute__ ((vector_size (16)));
+typedef short v16hi __attribute__ ((vector_size (32)));
+typedef short v32hi __attribute__ ((vector_size (64)));
+typedef short v64hi __attribute__ ((vector_size (128)));
+
+typedef unsigned short v2uhi __attribute__ ((vector_size (4)));
+typedef unsigned short v4uhi __attribute__ ((vector_size (8)));
+typedef unsigned short v8uhi __attribute__ ((vector_size (16)));
+typedef unsigned short v16uhi __attribute__ ((vector_size (32)));
+typedef unsigned short v32uhi __attribute__ ((vector_size (64)));
+typedef unsigned short v64uhi __attribute__ ((vector_size (128)));
+
+typedef int v2si __attribute__ ((vector_size (8)));
+typedef int v4si __attribute__ ((vector_size (16)));
+typedef int v8si __attribute__ ((vector_size (32)));
+typedef int v16si __attribute__ ((vector_size (64)));
+typedef int v32si __attribute__ ((vector_size (128)));
+typedef int v64si __attribute__ ((vector_size (256)));
+
+typedef unsigned int v2usi __attribute__ ((vector_size (8)));
+typedef unsigned int v4usi __attribute__ ((vector_size (16)));
+typedef unsigned int v8usi __attribute__ ((vector_size (32)));
+typedef unsigned int v16usi __attribute__ ((vector_size (64)));
+typedef unsigned int v32usi __attribute__ ((vector_size (128)));
+typedef unsigned int v64usi __attribute__ ((vector_size (256)));
+
+typedef long v2di __attribute__ ((vector_size (16)));
+typedef long v4di __attribute__ ((vector_size (32)));
+typedef long v8di __attribute__ ((vector_size (64)));
+typedef long v16di __attribute__ ((vector_size (128)));
+typedef long v32di __attribute__ ((vector_size (256)));
+typedef long v64di __attribute__ ((vector_size (512)));
+
+typedef unsigned long v2udi __attribute__ ((vector_size (16)));
+typedef unsigned long v4udi __attribute__ ((vector_size (32)));
+typedef unsigned long v8udi __attribute__ ((vector_size (64)));
+typedef unsigned long v16udi __attribute__ ((vector_size (128)));
+typedef unsigned long v32udi __attribute__ ((vector_size (256)));
+typedef unsigned long v64udi __attribute__ ((vector_size (512)));
+
+typedef UTItype v2uti __attribute__ ((vector_size (32)));
+typedef UTItype v4uti __attribute__ ((vector_size (64)));
+typedef UTItype v8uti __attribute__ ((vector_size (128)));
+typedef UTItype v16uti __attribute__ ((vector_size (256)));
+typedef UTItype v32uti __attribute__ ((vector_size (512)));
+typedef UTItype v64uti __attribute__ ((vector_size (1024)));
+
 /* Exported functions.  */
 extern DItype __divdi3 (DItype, DItype);
 extern DItype __moddi3 (DItype, DItype);
+extern UTItype __divmoddi4 (DItype, DItype);
 extern UDItype __udivdi3 (UDItype, UDItype);
 extern UDItype __umoddi3 (UDItype, UDItype);
+extern UTItype __udivmoddi4 (UDItype, UDItype);
 extern SItype __divsi3 (SItype, SItype);
 extern SItype __modsi3 (SItype, SItype);
+extern UDItype __divmodsi4 (SItype, SItype);
 extern USItype __udivsi3 (USItype, USItype);
 extern USItype __umodsi3 (USItype, USItype);
+extern UDItype __udivmodsi4 (USItype, USItype);
 extern SItype __mulsi3 (SItype, SItype);
 
+#define VECTOR_PROTOTYPES(SIZE) \
+  extern v##SIZE##qi  __divv##SIZE##qi3     (v##SIZE##qi,  v##SIZE##qi);  \
+  extern v##SIZE##qi  __modv##SIZE##qi3     (v##SIZE##qi,  v##SIZE##qi);  \
+  extern v##SIZE##udi __divmodv##SIZE##qi4  (v##SIZE##qi,  v##SIZE##qi);  \
+  extern v##SIZE##uqi __udivv##SIZE##qi3    (v##SIZE##uqi, v##SIZE##uqi); \
+  extern v##SIZE##uqi __umodv##SIZE##qi3    (v##SIZE##uqi, v##SIZE##uqi); \
+  extern v##SIZE##udi __udivmodv##SIZE##qi4 (v##SIZE##uqi, v##SIZE##uqi);  \
+  extern v##SIZE##hi  __divv##SIZE##hi3     (v##SIZE##hi,  v##SIZE##hi);  \
+  extern v##SIZE##hi  __modv##SIZE##hi3     (v##SIZE##hi,  v##SIZE##hi);  \
+  extern v##SIZE##udi __divmodv##SIZE##hi4  (v##SIZE##hi,  v##SIZE##hi);  \
+  extern v##SIZE##uhi __udivv##SIZE##hi3    (v##SIZE##uhi, v##SIZE##uhi); \
+  extern v##SIZE##uhi __umodv##SIZE##hi3    (v##SIZE##uhi, v##SIZE##uhi); \
+  extern v##SIZE##udi __udivmodv##SIZE##hi4 (v##SIZE##uhi, v##SIZE##uhi); \
+  extern v##SIZE##si  __divv##SIZE##si3     (v##SIZE##si,  v##SIZE##si);  \
+  extern v##SIZE##si  __modv##SIZE##si3     (v##SIZE##si,  v##SIZE##si);  \
+  extern v##SIZE##udi __divmodv##SIZE##si4  (v##SIZE##si,  v##SIZE##si);  \
+  extern v##SIZE##usi __udivv##SIZE##si3    (v##SIZE##usi, v##SIZE##usi); \
+  extern v##SIZE##usi __umodv##SIZE##si3    (v##SIZE##usi, v##SIZE##usi); \
+  extern v##SIZE##udi __udivmodv##SIZE##si4 (v##SIZE##usi, v##SIZE##usi); \
+  extern v##SIZE##di  __divv##SIZE##di3     (v##SIZE##di,  v##SIZE##di);  \
+  extern v##SIZE##di  __modv##SIZE##di3     (v##SIZE##di,  v##SIZE##di);  \
+  extern v##SIZE##uti __divmodv##SIZE##di4  (v##SIZE##di,  v##SIZE##di);  \
+  extern v##SIZE##udi __udivv##SIZE##di3    (v##SIZE##udi, v##SIZE##udi); \
+  extern v##SIZE##udi __umodv##SIZE##di3    (v##SIZE##udi, v##SIZE##udi); \
+  extern v##SIZE##uti __udivmodv##SIZE##di4 (v##SIZE##udi, v##SIZE##udi);
+VECTOR_PROTOTYPES (2)
+VECTOR_PROTOTYPES (4)
+VECTOR_PROTOTYPES (8)
+VECTOR_PROTOTYPES (16)
+VECTOR_PROTOTYPES (32)
+VECTOR_PROTOTYPES (64)
+#undef VECTOR_PROTOTYPES
+
 #endif /* LIB2_GCN_H */
diff --git a/libgcc/config/gcn/lib2-vec_divmod-di.c b/libgcc/config/gcn/lib2-vec_divmod-di.c
new file mode 100644
index 00000000000..8f4a035f198
--- /dev/null
+++ b/libgcc/config/gcn/lib2-vec_divmod-di.c
@@ -0,0 +1,118 @@
+/* Copyright (C) 2012-2023 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"
+
+/* 64-bit V64SI divide and modulo as used in gcn.
+   This is a simple conversion from lib2-divmod.c.  */
+
+#define MASKMODE v64di
+#include "amdgcn_veclib.h"
+
+static v64uti
+__udivmodv64di4_aux (v64udi num, v64udi den, v64di __mask)
+{
+  v64udi bit = VECTOR_INIT (1UL);
+  v64udi res = VECTOR_INIT (0UL);
+
+  VECTOR_WHILE ((den < num) & (bit != 0) & ((den & (1L<<31)) == 0),
+		cond, NO_COND)
+    VECTOR_COND_MOVE (den, den << 1, cond);
+    VECTOR_COND_MOVE (bit, bit << 1, cond);
+  VECTOR_ENDWHILE
+  VECTOR_WHILE (bit != 0, loopcond, NO_COND)
+    VECTOR_IF2 (num >= den, ifcond, loopcond)
+      VECTOR_COND_MOVE (num, num - den, ifcond);
+      VECTOR_COND_MOVE (res, res | bit, ifcond);
+    VECTOR_ENDIF
+    VECTOR_COND_MOVE (bit, bit >> 1, loopcond);
+    VECTOR_COND_MOVE (den, den >> 1, loopcond);
+  VECTOR_ENDWHILE
+
+  return PACK_DI_PAIR (res, num);
+}
+
+static v64uti
+__divmodv64di4_aux (v64di a, v64di b, v64di __mask)
+{
+  v64di nega = VECTOR_INIT (0L);
+  v64di negb = VECTOR_INIT (0L);
+
+  VECTOR_IF (a < 0, cond)
+    VECTOR_COND_MOVE (a, -a, cond);
+    nega = cond;
+  VECTOR_ENDIF
+
+  VECTOR_IF (b < 0, cond)
+    VECTOR_COND_MOVE (b, -b, cond);
+    negb = cond;
+  VECTOR_ENDIF
+
+  v64udi ua = __builtin_convertvector (a, v64udi);
+  v64udi ub = __builtin_convertvector (b, v64udi);
+  v64uti pair = __udivmodv64di4_aux (ua, ub, __mask);
+
+  v64di quot = UNPACK_DI_LOW (v64di, pair);
+  v64di rem = UNPACK_DI_HIGH (v64di, pair);
+  VECTOR_COND_MOVE (quot, -quot, nega ^ negb);
+  VECTOR_COND_MOVE (rem, -rem, nega);
+  pair = PACK_DI_PAIR (quot, rem);
+
+  return pair;
+}
+
+
+static inline v64di
+__divv64di3_aux (v64di a, v64di b, v64di __mask)
+{
+  v64uti pair = __divmodv64di4_aux (a, b, __mask);
+  return UNPACK_DI_LOW (v64di, pair);
+}
+
+static inline v64di
+__modv64di3_aux (v64di a, v64di b, v64di __mask)
+{
+  v64uti pair = __divmodv64di4_aux (a, b, __mask);
+  return UNPACK_DI_HIGH (v64di, pair);
+}
+
+
+static inline v64udi
+__udivv64di3_aux (v64udi a, v64udi b, v64di __mask)
+{
+  v64uti pair = __udivmodv64di4_aux (a, b, __mask);
+  return UNPACK_DI_LOW (v64udi, pair);
+}
+
+static inline v64udi
+__umodv64di3_aux (v64udi a, v64udi b, v64di __mask)
+{
+  v64uti pair = __udivmodv64di4_aux (a, b, __mask);
+  return UNPACK_DI_HIGH (v64udi, pair);
+}
+
+DEF_VARIANTS (__div, di3, di)
+DEF_VARIANTS (__mod, di3, di)
+DEF_VARIANTS_B (__divmod, di4, uti, di)
+DEF_VARIANTS (__udiv, di3, udi)
+DEF_VARIANTS (__umod, di3, udi)
+DEF_VARIANTS_B (__udivmod, di4, uti, udi)
diff --git a/libgcc/config/gcn/lib2-vec_divmod-hi.c b/libgcc/config/gcn/lib2-vec_divmod-hi.c
new file mode 100644
index 00000000000..175ddf84bb2
--- /dev/null
+++ b/libgcc/config/gcn/lib2-vec_divmod-hi.c
@@ -0,0 +1,118 @@
+/* Copyright (C) 2012-2023 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 V64HI divide and modulo as used in gcn.
+   This is a simple conversion from lib2-divmod.c.  */
+
+#define MASKMODE v64hi
+#include "amdgcn_veclib.h"
+
+static v64udi
+__udivmodv64hi4_aux (v64uhi num, v64uhi den, v64hi __mask)
+{
+  v64uhi bit = VECTOR_INIT ((unsigned short)1U);
+  v64uhi res = VECTOR_INIT ((unsigned short)0U);
+
+  VECTOR_WHILE ((den < num) & (bit != 0) & ((den & (1L<<15)) == 0),
+		cond, NO_COND)
+    VECTOR_COND_MOVE (den, den << 1, cond);
+    VECTOR_COND_MOVE (bit, bit << 1, cond);
+  VECTOR_ENDWHILE
+  VECTOR_WHILE (bit != 0, loopcond, NO_COND)
+    VECTOR_IF2 (num >= den, ifcond, loopcond)
+      VECTOR_COND_MOVE (num, num - den, ifcond);
+      VECTOR_COND_MOVE (res, res | bit, ifcond);
+    VECTOR_ENDIF
+    VECTOR_COND_MOVE (bit, bit >> 1, loopcond);
+    VECTOR_COND_MOVE (den, den >> 1, loopcond);
+  VECTOR_ENDWHILE
+
+  return PACK_SI_PAIR (res, num);
+}
+
+static v64udi
+__divmodv64hi4_aux (v64hi a, v64hi b,  v64hi __mask)
+{
+  v64hi nega = VECTOR_INIT ((short)0);
+  v64hi negb = VECTOR_INIT ((short)0);
+
+  VECTOR_IF (a < 0, cond)
+    VECTOR_COND_MOVE (a, -a, cond);
+    nega = cond;
+  VECTOR_ENDIF
+
+  VECTOR_IF (b < 0, cond)
+    VECTOR_COND_MOVE (b, -b, cond);
+    negb = cond;
+  VECTOR_ENDIF
+
+  v64uhi ua = __builtin_convertvector (a, v64uhi);
+  v64uhi ub = __builtin_convertvector (b, v64uhi);
+  v64udi pair = __udivmodv64hi4_aux (ua, ub, __mask);
+
+  v64hi quot = UNPACK_SI_LOW (v64hi, pair);
+  v64hi rem = UNPACK_SI_HIGH (v64hi, pair);
+  VECTOR_COND_MOVE (quot, -quot, nega ^ negb);
+  VECTOR_COND_MOVE (rem, -rem, nega);
+  pair = PACK_SI_PAIR (quot, rem);
+
+  return pair;
+}
+
+
+static inline v64hi
+__divv64hi3_aux (v64hi a, v64hi b, v64hi __mask)
+{
+  v64udi pair = __divmodv64hi4_aux (a, b, __mask);
+  return UNPACK_SI_LOW (v64hi, pair);
+}
+
+static inline v64hi
+__modv64hi3_aux (v64hi a, v64hi b, v64hi __mask)
+{
+  v64udi pair = __divmodv64hi4_aux (a, b, __mask);
+  return UNPACK_SI_HIGH (v64hi, pair);
+}
+
+
+static inline v64uhi
+__udivv64hi3_aux (v64uhi a, v64uhi b, v64hi __mask)
+{
+  v64udi pair = __udivmodv64hi4_aux (a, b, __mask);
+  return UNPACK_SI_LOW (v64uhi, pair);
+}
+
+static inline v64uhi
+__umodv64hi3_aux (v64uhi a, v64uhi b, v64hi __mask)
+{
+  v64udi pair = __udivmodv64hi4_aux (a, b, __mask);
+  return UNPACK_SI_HIGH (v64uhi, pair);
+}
+
+DEF_VARIANTS (__div, hi3, hi)
+DEF_VARIANTS (__mod, hi3, hi)
+DEF_VARIANTS_B (__divmod, hi4, udi, hi)
+DEF_VARIANTS (__udiv, hi3, uhi)
+DEF_VARIANTS (__umod, hi3, uhi)
+DEF_VARIANTS_B (__udivmod, hi4, udi, uhi)
diff --git a/libgcc/config/gcn/lib2-vec_divmod-qi.c b/libgcc/config/gcn/lib2-vec_divmod-qi.c
new file mode 100644
index 00000000000..ff6b5c2e7d8
--- /dev/null
+++ b/libgcc/config/gcn/lib2-vec_divmod-qi.c
@@ -0,0 +1,118 @@
+/* Copyright (C) 2012-2023 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"
+
+/* 8-bit V64QI divide and modulo as used in gcn.
+   This is a simple conversion from lib2-divmod.c.  */
+
+#define MASKMODE v64qi
+#include "amdgcn_veclib.h"
+
+static v64udi
+__udivmodv64qi4_aux (v64uqi num, v64uqi den, v64qi __mask)
+{
+  v64uqi bit = VECTOR_INIT ((unsigned char)1U);
+  v64uqi res = VECTOR_INIT ((unsigned char)0U);
+
+  VECTOR_WHILE ((den < num) & (bit != 0) & ((den & (1<<7)) == 0),
+		cond, NO_COND)
+    VECTOR_COND_MOVE (den, den << 1, cond);
+    VECTOR_COND_MOVE (bit, bit << 1, cond);
+  VECTOR_ENDWHILE
+  VECTOR_WHILE (bit != 0, loopcond, NO_COND)
+    VECTOR_IF2 (num >= den, ifcond, loopcond)
+      VECTOR_COND_MOVE (num, num - den, ifcond);
+      VECTOR_COND_MOVE (res, res | bit, ifcond);
+    VECTOR_ENDIF
+    VECTOR_COND_MOVE (bit, bit >> 1, loopcond);
+    VECTOR_COND_MOVE (den, den >> 1, loopcond);
+  VECTOR_ENDWHILE
+
+  return PACK_SI_PAIR (res, num);
+}
+
+static v64udi
+__divmodv64qi4_aux (v64qi a, v64qi b, v64qi __mask)
+{
+  v64qi nega = VECTOR_INIT ((char)0);
+  v64qi negb = VECTOR_INIT ((char)0);
+
+  VECTOR_IF (a < 0, cond)
+    VECTOR_COND_MOVE (a, -a, cond);
+    nega = cond;
+  VECTOR_ENDIF
+
+  VECTOR_IF (b < 0, cond)
+    VECTOR_COND_MOVE (b, -b, cond);
+    negb = cond;
+  VECTOR_ENDIF
+
+  v64uqi ua = __builtin_convertvector (a, v64uqi);
+  v64uqi ub = __builtin_convertvector (b, v64uqi);
+  v64udi pair = __udivmodv64qi4_aux (ua, ub, __mask);
+
+  v64qi quot = UNPACK_SI_LOW (v64qi, pair);
+  v64qi rem = UNPACK_SI_HIGH (v64qi, pair);
+  VECTOR_COND_MOVE (quot, -quot, nega ^ negb);
+  VECTOR_COND_MOVE (rem, -rem, nega);
+  pair = PACK_SI_PAIR (quot, rem);
+
+  return pair;
+}
+
+
+static inline v64qi
+__divv64qi3_aux (v64qi a, v64qi b, v64qi __mask)
+{
+  v64udi pair = __divmodv64qi4_aux (a, b, __mask);
+  return UNPACK_SI_LOW (v64qi, pair);
+}
+
+static inline v64qi
+__modv64qi3_aux (v64qi a, v64qi b, v64qi __mask)
+{
+  v64udi pair = __divmodv64qi4_aux (a, b, __mask);
+  return UNPACK_SI_HIGH (v64qi, pair);
+}
+
+
+static inline v64uqi
+__udivv64qi3_aux (v64uqi a, v64uqi b, v64qi __mask)
+{
+  v64udi pair = __udivmodv64qi4_aux (a, b, __mask);
+  return UNPACK_SI_LOW (v64uqi, pair);
+}
+
+static inline v64uqi
+__umodv64qi3_aux (v64uqi a, v64uqi b, v64qi __mask)
+{
+  v64udi pair = __udivmodv64qi4_aux (a, b, __mask);
+  return UNPACK_SI_HIGH (v64uqi, pair);
+}
+
+DEF_VARIANTS (__div, qi3, qi)
+DEF_VARIANTS (__mod, qi3, qi)
+DEF_VARIANTS_B (__divmod, qi4, udi, qi)
+DEF_VARIANTS (__udiv, qi3, uqi)
+DEF_VARIANTS (__umod, qi3, uqi)
+DEF_VARIANTS_B (__udivmod, qi4, udi, uqi)
diff --git a/libgcc/config/gcn/lib2-vec_divmod.c b/libgcc/config/gcn/lib2-vec_divmod.c
new file mode 100644
index 00000000000..e1667668e68
--- /dev/null
+++ b/libgcc/config/gcn/lib2-vec_divmod.c
@@ -0,0 +1,118 @@
+/* Copyright (C) 2012-2023 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 V64SI divide and modulo as used in gcn.
+   This is a simple conversion from lib2-divmod.c.  */
+
+#define MASKMODE v64si
+#include "amdgcn_veclib.h"
+
+static v64udi
+__udivmodv64si4_aux (v64usi num, v64usi den, v64si __mask)
+{
+  v64usi bit = VECTOR_INIT (1U);
+  v64usi res = VECTOR_INIT (0U);
+
+  VECTOR_WHILE ((den < num) & (bit != 0) & ((den & (1L<<31)) == 0),
+		cond, NO_COND)
+    VECTOR_COND_MOVE (den, den << 1, cond);
+    VECTOR_COND_MOVE (bit, bit << 1, cond);
+  VECTOR_ENDWHILE
+  VECTOR_WHILE (bit != 0, loopcond, NO_COND)
+    VECTOR_IF2 (num >= den, ifcond, loopcond)
+      VECTOR_COND_MOVE (num, num - den, ifcond);
+      VECTOR_COND_MOVE (res, res | bit, ifcond);
+    VECTOR_ENDIF
+    VECTOR_COND_MOVE (bit, bit >> 1, loopcond);
+    VECTOR_COND_MOVE (den, den >> 1, loopcond);
+  VECTOR_ENDWHILE
+
+  return PACK_SI_PAIR (res, num);
+}
+
+static v64udi
+__divmodv64si4_aux (v64si a, v64si b, v64si __mask)
+{
+  v64si nega = VECTOR_INIT (0);
+  v64si negb = VECTOR_INIT (0);
+
+  VECTOR_IF (a < 0, cond)
+    VECTOR_COND_MOVE (a, -a, cond);
+    nega = cond;
+  VECTOR_ENDIF
+
+  VECTOR_IF (b < 0, cond)
+    VECTOR_COND_MOVE (b, -b, cond);
+    negb = cond;
+  VECTOR_ENDIF
+
+  v64usi ua = __builtin_convertvector (a, v64usi);
+  v64usi ub = __builtin_convertvector (b, v64usi);
+  v64udi pair = __udivmodv64si4_aux (ua, ub, __mask);
+
+  v64si quot = UNPACK_SI_LOW (v64si, pair);
+  v64si rem = UNPACK_SI_HIGH (v64si, pair);
+  VECTOR_COND_MOVE (quot, -quot, nega ^ negb);
+  VECTOR_COND_MOVE (rem, -rem, nega);
+  pair = PACK_SI_PAIR (quot, rem);
+
+  return pair;
+}
+
+
+static inline v64si
+__divv64si3_aux (v64si a, v64si b, v64si __mask)
+{
+  v64udi pair = __divmodv64si4_aux (a, b, __mask);
+  return UNPACK_SI_LOW (v64si, pair);
+}
+
+static inline v64si
+__modv64si3_aux (v64si a, v64si b, v64si __mask)
+{
+  v64udi pair = __divmodv64si4_aux (a, b, __mask);
+  return UNPACK_SI_HIGH (v64si, pair);
+}
+
+
+static inline v64usi
+__udivv64si3_aux (v64usi a, v64usi b, v64si __mask)
+{
+  v64udi pair = __udivmodv64si4_aux (a, b, __mask);
+  return UNPACK_SI_LOW (v64usi, pair);
+}
+
+static inline v64usi
+__umodv64si3_aux (v64usi a, v64usi b, v64si __mask)
+{
+  v64udi pair = __udivmodv64si4_aux (a, b, __mask);
+  return UNPACK_SI_HIGH (v64usi, pair);
+}
+
+DEF_VARIANTS (__div, si3, si)
+DEF_VARIANTS (__mod, si3, si)
+DEF_VARIANTS_B (__divmod, si4, udi, si)
+DEF_VARIANTS (__udiv, si3, usi)
+DEF_VARIANTS (__umod, si3, usi)
+DEF_VARIANTS_B (__udivmod, si4, udi, usi)
diff --git a/libgcc/config/gcn/t-amdgcn b/libgcc/config/gcn/t-amdgcn
index e64953e6185..d1d9a4f92b5 100644
--- a/libgcc/config/gcn/t-amdgcn
+++ b/libgcc/config/gcn/t-amdgcn
@@ -1,6 +1,10 @@
 LIB2ADD += $(srcdir)/config/gcn/atomic.c \
 	   $(srcdir)/config/gcn/lib2-divmod.c \
 	   $(srcdir)/config/gcn/lib2-divmod-di.c \
+	   $(srcdir)/config/gcn/lib2-vec_divmod.c \
+	   $(srcdir)/config/gcn/lib2-vec_divmod-qi.c \
+	   $(srcdir)/config/gcn/lib2-vec_divmod-hi.c \
+	   $(srcdir)/config/gcn/lib2-vec_divmod-di.c \
 	   $(srcdir)/config/gcn/lib2-bswapti2.c \
 	   $(srcdir)/config/gcn/unwind-gcn.c
 


More information about the Gcc-patches mailing list