[RISC-V] Use C version of multi3 for RVE support.

Message ID 20171213062736.30061-1-jimw@sifive.com
State New
Headers show
Series
  • [RISC-V] Use C version of multi3 for RVE support.
Related show

Commit Message

Jim Wilson Dec. 13, 2017, 6:27 a.m.
This replaces the assembly language version of multi3/muldi3 with a C version,
as the assembly version does not work on RVE targets.  The C code is using the
same basic algorithm as the assembly code.  The RVE spec is not finalized yet,
so we haven't added the RVE option support yet, but this is one of the patches
needed to prepare for the eventual RVE support.

This was tested with a gcc testsuite run, there were no regressions.

It was also hand tested with some small testcases doing long long (32-bit
target) and int128_t (64-bit target) multiplies running on the gdb simulator
with --trace-insn to get instruction counts.  The new code is little faster
for most inputs, partly because of compiler optimization, but a little slower
when one of the inputs has a lot of leading ones.  We will worry about that
later if it turns out to be a problem.  Meanwhile, this helps with the RVE
support and gets another patch merged into FSF gcc from the github riscv
repository.

Committed.

	libgcc/
	* config/riscv/t-elf: Use multi3.c instead of multi3.S.
	* config/riscv/multi3.c: New file.
	* config/riscv/multi3.S: Remove.
---
 libgcc/ChangeLog             |  6 ++++
 libgcc/config/riscv/multi3.S | 81 -----------------------------------------
 libgcc/config/riscv/multi3.c | 86 ++++++++++++++++++++++++++++++++++++++++++++
 libgcc/config/riscv/t-elf    |  2 +-
 4 files changed, 93 insertions(+), 82 deletions(-)
 delete mode 100644 libgcc/config/riscv/multi3.S
 create mode 100644 libgcc/config/riscv/multi3.c

-- 
2.14.1

Patch

diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog
index 3d8b73e1c4a..6726a79d5b2 100644
--- a/libgcc/ChangeLog
+++ b/libgcc/ChangeLog
@@ -1,3 +1,9 @@ 
+2017-12-06  Kito Cheng <kito.cheng@gmail.com>
+
+	* config/riscv/t-elf: Use multi3.c instead of multi3.S.
+	* config/riscv/multi3.c: New file.
+	* config/riscv/multi3.S: Remove.
+
 2017-11-30  Michael Meissner  <meissner@linux.vnet.ibm.com>
 
 	* config/rs6000/_mulkc3.c (__mulkc3): Add forward declaration.
diff --git a/libgcc/config/riscv/multi3.S b/libgcc/config/riscv/multi3.S
deleted file mode 100644
index 4d454e65013..00000000000
--- a/libgcc/config/riscv/multi3.S
+++ /dev/null
@@ -1,81 +0,0 @@ 
-/* Integer multiplication routines for RISC-V.
-
-   Copyright (C) 2016-2017 Free Software Foundation, Inc.
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 3, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-Under Section 7 of GPL version 3, you are granted additional
-permissions described in the GCC Runtime Library Exception, version
-3.1, as published by the Free Software Foundation.
-
-You should have received a copy of the GNU General Public License and
-a copy of the GCC Runtime Library Exception along with this program;
-see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
-<http://www.gnu.org/licenses/>.  */
-
-  .text
-  .align 2
-
-#if __riscv_xlen == 32
-/* Our RV64 64-bit routines are equivalent to our RV32 32-bit routines.  */
-# define __multi3 __muldi3
-#endif
-
-  .globl __multi3
-__multi3:
-
-#if __riscv_xlen == 32
-/* Our RV64 64-bit routines are equivalent to our RV32 32-bit routines.  */
-# define __muldi3 __mulsi3
-#endif
-
-/* We rely on the fact that __muldi3 doesn't clobber the t-registers.  */
-
-  mv  t0, ra
-  mv  t5, a0
-  mv  a0, a1
-  mv  t6, a3
-  mv  a1, t5
-  mv  a4, a2
-  li  a5, 0
-  li  t2, 0
-  li  t4, 0
-.L1:
-  add  a6, t2, a1
-  andi t3, a4, 1
-  slli a7, a5, 1
-  slti t1, a1, 0
-  srli a4, a4, 1
-  add  a5, t4, a5
-  beqz t3, .L2
-  sltu t3, a6, t2
-  mv   t2, a6
-  add  t4, t3, a5
-.L2:
-  slli a1, a1, 1
-  or   a5, t1, a7
-  bnez a4, .L1
-  beqz a0, .L3
-  mv   a1, a2
-  call __muldi3
-  add  t4, t4, a0
-.L3:
-  beqz t6, .L4
-  mv   a1, t6
-  mv   a0, t5
-  call  __muldi3
-  add  t4, t4, a0
-.L4:
-  mv  a0, t2
-  mv  a1, t4
-  jr  t0
diff --git a/libgcc/config/riscv/multi3.c b/libgcc/config/riscv/multi3.c
new file mode 100644
index 00000000000..3606a5f220b
--- /dev/null
+++ b/libgcc/config/riscv/multi3.c
@@ -0,0 +1,86 @@ 
+/* Multiplication two double word integers for RISC-V.
+
+   Copyright (C) 2016-2017 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+#include "tconfig.h"
+#include "tsystem.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "libgcc_tm.h"
+#define LIBGCC2_UNITS_PER_WORD (__riscv_xlen / 8)
+
+#include "libgcc2.h"
+
+#if __riscv_xlen == 32
+/* Our RV64 64-bit routines are equivalent to our RV32 32-bit routines.  */
+# define __multi3 __muldi3
+#endif
+
+DWtype
+__multi3 (DWtype u, DWtype v)
+{
+  const DWunion uu = {.ll = u};
+  const DWunion vv = {.ll = v};
+  DWunion w;
+  UWtype u_low = uu.s.low;
+  UWtype v_low = vv.s.low;
+  UWtype u_low_msb;
+  UWtype w_low = 0;
+  UWtype new_w_low;
+  UWtype w_high = 0;
+  UWtype w_high_tmp = 0;
+  UWtype w_high_tmp2x;
+  UWtype carry;
+
+  /* Calculate low half part of u and v, and get a UDWtype result just like
+     what __umulsidi3 do.  */
+  do
+    {
+      new_w_low = w_low + u_low;
+      w_high_tmp2x = w_high_tmp << 1;
+      w_high_tmp += w_high;
+      if (v_low & 1)
+	{
+	  carry = new_w_low < w_low;
+	  w_low = new_w_low;
+	  w_high = carry + w_high_tmp;
+	}
+      u_low_msb = (u_low >> ((sizeof (UWtype) * 8) - 1));
+      v_low >>= 1;
+      u_low <<= 1;
+      w_high_tmp = u_low_msb | w_high_tmp2x;
+    }
+  while (v_low);
+
+  w.s.low = w_low;
+  w.s.high = w_high;
+
+  if (uu.s.high)
+    w.s.high = w.s.high + __muluw3(vv.s.low, uu.s.high);
+
+  if (vv.s.high)
+    w.s.high += __muluw3(uu.s.low, vv.s.high);
+
+  return w.ll;
+}
diff --git a/libgcc/config/riscv/t-elf b/libgcc/config/riscv/t-elf
index 01d5ebaa417..dbc8f85dfc5 100644
--- a/libgcc/config/riscv/t-elf
+++ b/libgcc/config/riscv/t-elf
@@ -1,6 +1,6 @@ 
 LIB2ADD += $(srcdir)/config/riscv/save-restore.S \
 	   $(srcdir)/config/riscv/muldi3.S \
-	   $(srcdir)/config/riscv/multi3.S \
+	   $(srcdir)/config/riscv/multi3.c \
 	   $(srcdir)/config/riscv/div.S \
 	   $(srcdir)/config/riscv/atomic.c \