From: Iain Buclaw Date: Wed, 15 Jul 2020 21:00:11 +0000 (+0200) Subject: d: Implement core.bitop.rol() and core.bitop.ror() as intrinsics. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=7d4ee8bc5843997cdc4408848ab2d9ec82f085b2;p=gcc.git d: Implement core.bitop.rol() and core.bitop.ror() as intrinsics. 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. --- 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