diff mbox series

[committed] d: Implement core.bitop.rol() and core.bitop.ror() as intrinsics.

Message ID 20200730111130.1241389-1-ibuclaw@gdcproject.org
State New
Headers show
Series [committed] d: Implement core.bitop.rol() and core.bitop.ror() as intrinsics. | expand

Commit Message

Iain Buclaw July 30, 2020, 11:11 a.m. UTC
Hi,

Following on from the last patch, this implements rol() and ror() in the
core.bitop module as D intrinsics.

Bootstrapped and regression tested on x86_64-linux-gnu and committed to
mainline.

Regards
Iain

---
gcc/d/ChangeLog:

	* intrinsics.cc (expand_intrinsic_rotate): Add function.
	(maybe_expand_intrinsic): Handle rol and ror intrinsics.
	* intrinsics.def (ROL): Add intrinsic.
	(ROL_TIARG): Add intrinsic.
	(ROR): Add intrinsic.
	(ROR_TIARG): Add intrinsic.

gcc/testsuite/ChangeLog:

	* gdc.dg/intrinsics.d: Add ror and rol tests.
---
 gcc/d/intrinsics.cc               | 56 +++++++++++++++++++++++++++++++
 gcc/d/intrinsics.def              |  5 +++
 gcc/testsuite/gdc.dg/intrinsics.d |  6 ++++
 3 files changed, 67 insertions(+)
diff mbox series

Patch

diff --git a/gcc/d/intrinsics.cc b/gcc/d/intrinsics.cc
index 7ef1ec5ea20..28667c63e17 100644
--- a/gcc/d/intrinsics.cc
+++ b/gcc/d/intrinsics.cc
@@ -390,6 +390,56 @@  expand_intrinsic_popcnt (tree callexp)
   return call_builtin_fn (callexp, code, 1, arg);
 }
 
+/* Expand a front-end intrinsic call to INTRINSIC, which is either a call to
+   rol() or ror().  These intrinsics expect to take one or two arguments,
+   the signature to which can be either:
+
+	T rol(T) (const T value, const uint count);
+	T rol(uint count, T) (const T value);
+	T ror(T) (const T value, const uint count);
+	T ror(uint count, T) (const T value);
+
+   This bitwise rotates VALUE left or right by COUNT bit positions.  */
+
+static tree
+expand_intrinsic_rotate (intrinsic_code intrinsic, tree callexp)
+{
+  tree type = TREE_TYPE (callexp);
+  tree value = CALL_EXPR_ARG (callexp, 0);
+  tree count;
+  tree_code code;
+
+  /* Get the equivalent tree code for the intrinsic.  */
+  if (intrinsic == INTRINSIC_ROL || intrinsic == INTRINSIC_ROL_TIARG)
+    code = LROTATE_EXPR;
+  else if (intrinsic == INTRINSIC_ROR || intrinsic == INTRINSIC_ROR_TIARG)
+    code = RROTATE_EXPR;
+  else
+    gcc_unreachable ();
+
+  /* Get the COUNT parameter.  Either from the call expression arguments or the
+     template instantiation arguments.  */
+  if (intrinsic == INTRINSIC_ROL || intrinsic == INTRINSIC_ROR)
+    count = CALL_EXPR_ARG (callexp, 1);
+  else
+    {
+      tree callee = CALL_EXPR_FN (callexp);
+
+      if (TREE_CODE (callee) == ADDR_EXPR)
+	callee = TREE_OPERAND (callee, 0);
+
+      /* Retrieve from the encoded template instantation.  */
+      TemplateInstance *ti = DECL_LANG_FRONTEND (callee)->isInstantiated ();
+      gcc_assert (ti && ti->tiargs && ti->tiargs->length == 2);
+
+      Expression *e = isExpression ((*ti->tiargs)[0]);
+      gcc_assert (e && e->op == TOKint64);
+      count = build_expr (e, true);
+    }
+
+  return fold_build2 (code, type, value, count);
+}
+
 /* Expand a front-end intrinsic call to copysign().  This takes two arguments,
    the signature to which can be either:
 
@@ -737,6 +787,12 @@  maybe_expand_intrinsic (tree callexp)
     case INTRINSIC_POPCNT64:
       return expand_intrinsic_popcnt (callexp);
 
+    case INTRINSIC_ROL:
+    case INTRINSIC_ROL_TIARG:
+    case INTRINSIC_ROR:
+    case INTRINSIC_ROR_TIARG:
+      return expand_intrinsic_rotate (intrinsic, callexp);
+
     case INTRINSIC_BSWAP32:
     case INTRINSIC_BSWAP64:
     case INTRINSIC_CEIL:
diff --git a/gcc/d/intrinsics.def b/gcc/d/intrinsics.def
index 0c32126b1fa..5b8cb712264 100644
--- a/gcc/d/intrinsics.def
+++ b/gcc/d/intrinsics.def
@@ -59,6 +59,11 @@  DEF_D_BUILTIN (BSWAP64, BSWAP64, "bswap", "core.bitop", "FNaNbNiNfmZm")
 DEF_D_BUILTIN (POPCNT32, NONE, "popcnt", "core.bitop", "FNaNbNiNfkZi")
 DEF_D_BUILTIN (POPCNT64, NONE, "popcnt", "core.bitop", "FNaNbNiNfmZi")
 
+DEF_D_BUILTIN (ROL, NONE, "rol", "core.bitop", "FNaI1TkZI1T")
+DEF_D_BUILTIN (ROL_TIARG, NONE, "rol", "core.bitop", "FNaI1TZI1T")
+DEF_D_BUILTIN (ROR, NONE, "ror", "core.bitop", "FNaI1TkZI1T")
+DEF_D_BUILTIN (ROR_TIARG, NONE, "ror", "core.bitop", "FNaI1TZI1T")
+
 DEF_D_BUILTIN (VLOAD8, NONE, "volatileLoad", "core.bitop", "FNbNiNfPhZh")
 DEF_D_BUILTIN (VLOAD16, NONE, "volatileLoad", "core.bitop", "FNbNiNfPtZt")
 DEF_D_BUILTIN (VLOAD32, NONE, "volatileLoad", "core.bitop", "FNbNiNfPkZk")
diff --git a/gcc/testsuite/gdc.dg/intrinsics.d b/gcc/testsuite/gdc.dg/intrinsics.d
index e10c06dd41a..5888361a438 100644
--- a/gcc/testsuite/gdc.dg/intrinsics.d
+++ b/gcc/testsuite/gdc.dg/intrinsics.d
@@ -38,6 +38,12 @@  void test_volatileStore(ubyte *a, ubyte b) { return volatileStore(a, b); }
 void test_volatileStore(ushort *a, ushort b) { return volatileStore(a, b); }
 void test_volatileStore(uint *a, uint b) { return volatileStore(a, b); }
 void test_volatileStore(ulong *a, ulong b) { return volatileStore(a, b); }
+// { dg-final { scan-tree-dump-not " rol " "original" } }
+ubyte test_rol(ubyte a, uint b) { return rol!ubyte(a, b); }
+uint test_rol(uint a) { return rol!(1, uint)(a); }
+// { dg-final { scan-tree-dump-not " ror " "original" } }
+ushort test_ror(ushort a, uint b) { return ror!ushort(a, b); }
+ulong test_ror(ulong a) { return ror!(1, ulong)(a); }
 
 //////////////////////////////////////////////////////
 // core.checkedint