[ARC] Provide a TARGET_FOLD_BUILTIN target hook.

Message ID 00d401da0e8d$f9ea4b30$edbee190$@nextmovesoftware.com
State Accepted
Headers
Series [ARC] Provide a TARGET_FOLD_BUILTIN target hook. |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Roger Sayle Nov. 3, 2023, 7:43 p.m. UTC
  This patch implements a arc_fold_builtin target hook to allow ARC
builtins to be folded at the tree-level.  Currently this function
converts __builtin_arc_swap into a LROTATE_EXPR at the tree-level,
and evaluates __builtin_arc_norm and __builtin_arc_normw of integer
constant arguments at compile-time.  Because ARC_BUILTIIN_SWAP is
now handled at the tree-level, UNSPEC_ARC_SWAP no longer used,
allowing it and the "swap" define_insn to be removed.

An example benefit of folding things at compile-time is that
calling __builtin_arc_swap on the result of __builtin_arc_swap
now eliminates both and generates no code, and likewise calling
__builtin_arc_swap of a constant integer argument is evaluated
at compile-time.

Tested with a cross-compiler to arc-linux hosted on x86_64,
with no new (compile-only) regressions from make -k check.
Ok for mainline if this passes Claudiu's nightly testing?


2023-11-03  Roger Sayle  <roger@nextmovesoftware.com>

gcc/ChangeLog
        * config/arc/arc.cc (TARGET_FOLD_BUILTIN): Define to
        arc_fold_builtin.
        (arc_fold_builtin): New function.  Convert ARC_BUILTIN_SWAP
        into a rotate.  Evaluate ARC_BUILTIN_NORM and
        ARC_BUILTIN_NORMW of constant arguments.
        * config/arc/arc.md (UNSPEC_ARC_SWAP): Delete.
        (normw): Make output template/assembler whitespace consistent.
        (swap): Remove define_insn, only use of SWAP UNSPEC.
        * config/arc/builtins.def: Tweak indentation.
        (SWAP): Expand using rotlsi2_cnt16 instead of using swap.

gcc/testsuite/ChangeLog
        * gcc.target/arc/builtin_norm-1.c: New test case.
        * gcc.target/arc/builtin_norm-2.c: Likewise.
        * gcc.target/arc/builtin_normw-1.c: Likewise.
        * gcc.target/arc/builtin_normw-2.c: Likewise.
        * gcc.target/arc/builtin_swap-1.c: Likewise.
        * gcc.target/arc/builtin_swap-2.c: Likewise.
        * gcc.target/arc/builtin_swap-3.c: Likewise.


Thanks in advance,
Roger
--
  

Comments

Claudiu Zissulescu Nov. 13, 2023, 8:13 a.m. UTC | #1
Hi Roger,

Looks good. Please proceed with your commit.

Thank you,
Claudiu

-----Original Message-----
From: Roger Sayle <roger@nextmovesoftware.com> 
Sent: Friday, November 3, 2023 9:43 PM
To: gcc-patches@gcc.gnu.org
Cc: 'Claudiu Zissulescu' <claziss@gmail.com>
Subject: [ARC PATCH] Provide a TARGET_FOLD_BUILTIN target hook.


This patch implements a arc_fold_builtin target hook to allow ARC builtins to be folded at the tree-level.  Currently this function converts __builtin_arc_swap into a LROTATE_EXPR at the tree-level, and evaluates __builtin_arc_norm and __builtin_arc_normw of integer constant arguments at compile-time.  Because ARC_BUILTIIN_SWAP is now handled at the tree-level, UNSPEC_ARC_SWAP no longer used, allowing it and the "swap" define_insn to be removed.

An example benefit of folding things at compile-time is that calling __builtin_arc_swap on the result of __builtin_arc_swap now eliminates both and generates no code, and likewise calling __builtin_arc_swap of a constant integer argument is evaluated at compile-time.

Tested with a cross-compiler to arc-linux hosted on x86_64, with no new (compile-only) regressions from make -k check.
Ok for mainline if this passes Claudiu's nightly testing?


2023-11-03  Roger Sayle  <roger@nextmovesoftware.com>

gcc/ChangeLog
        * config/arc/arc.cc (TARGET_FOLD_BUILTIN): Define to
        arc_fold_builtin.
        (arc_fold_builtin): New function.  Convert ARC_BUILTIN_SWAP
        into a rotate.  Evaluate ARC_BUILTIN_NORM and
        ARC_BUILTIN_NORMW of constant arguments.
        * config/arc/arc.md (UNSPEC_ARC_SWAP): Delete.
        (normw): Make output template/assembler whitespace consistent.
        (swap): Remove define_insn, only use of SWAP UNSPEC.
        * config/arc/builtins.def: Tweak indentation.
        (SWAP): Expand using rotlsi2_cnt16 instead of using swap.

gcc/testsuite/ChangeLog
        * gcc.target/arc/builtin_norm-1.c: New test case.
        * gcc.target/arc/builtin_norm-2.c: Likewise.
        * gcc.target/arc/builtin_normw-1.c: Likewise.
        * gcc.target/arc/builtin_normw-2.c: Likewise.
        * gcc.target/arc/builtin_swap-1.c: Likewise.
        * gcc.target/arc/builtin_swap-2.c: Likewise.
        * gcc.target/arc/builtin_swap-3.c: Likewise.


Thanks in advance,
Roger
--
  

Patch

diff --git a/gcc/config/arc/arc.cc b/gcc/config/arc/arc.cc
index e209ad2..70ee410 100644
--- a/gcc/config/arc/arc.cc
+++ b/gcc/config/arc/arc.cc
@@ -643,6 +643,9 @@  static rtx arc_legitimize_address_0 (rtx, rtx, machine_mode mode);
 #undef  TARGET_EXPAND_BUILTIN
 #define TARGET_EXPAND_BUILTIN arc_expand_builtin
 
+#undef  TARGET_FOLD_BUILTIN
+#define TARGET_FOLD_BUILTIN arc_fold_builtin
+
 #undef  TARGET_BUILTIN_DECL
 #define TARGET_BUILTIN_DECL arc_builtin_decl
 
@@ -7048,6 +7051,46 @@  arc_expand_builtin (tree exp,
     return const0_rtx;
 }
 
+/* Implement TARGET_FOLD_BUILTIN.  */
+
+static tree
+arc_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *arg,
+                  bool ignore ATTRIBUTE_UNUSED)
+{
+  unsigned int fcode = DECL_MD_FUNCTION_CODE (fndecl);
+
+  switch (fcode)
+    {
+    default:
+      break;
+
+    case ARC_BUILTIN_SWAP:
+      return fold_build2 (LROTATE_EXPR, integer_type_node, arg[0],
+                          build_int_cst (integer_type_node, 16));
+
+    case ARC_BUILTIN_NORM:
+      if (TREE_CODE (arg[0]) == INTEGER_CST
+	  && !TREE_OVERFLOW (arg[0]))
+	{
+	  wide_int arg0 = wi::to_wide (arg[0], 32);
+	  wide_int result = wi::shwi (wi::clrsb (arg0), 32);
+	  return wide_int_to_tree (integer_type_node, result);
+	}
+      break;
+
+    case ARC_BUILTIN_NORMW:
+      if (TREE_CODE (arg[0]) == INTEGER_CST
+	  && !TREE_OVERFLOW (arg[0]))
+	{
+	  wide_int arg0 = wi::to_wide (arg[0], 16);
+	  wide_int result = wi::shwi (wi::clrsb (arg0), 32);
+	  return wide_int_to_tree (integer_type_node, result);
+	}
+      break;
+    }
+  return NULL_TREE;
+}
+
 /* Returns true if the operands[opno] is a valid compile-time constant to be
    used as register number in the code for builtins.  Else it flags an error
    and returns false.  */
diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md
index 96ff62d..9e81d13 100644
--- a/gcc/config/arc/arc.md
+++ b/gcc/config/arc/arc.md
@@ -116,7 +116,6 @@ 
   UNSPEC_TLS_OFF
   UNSPEC_ARC_NORM
   UNSPEC_ARC_NORMW
-  UNSPEC_ARC_SWAP
   UNSPEC_ARC_DIVAW
   UNSPEC_ARC_DIRECT
   UNSPEC_ARC_LP
@@ -4355,8 +4354,8 @@  archs4x, archs4xd"
 	  (clrsb:HI (match_operand:HI 1 "general_operand" "cL,Cal"))))]
   "TARGET_NORM"
   "@
-   norm%_ \t%0, %1
-   norm%_ \t%0, %1"
+   norm%_\\t%0,%1
+   norm%_\\t%0,%1"
   [(set_attr "length" "4,8")
    (set_attr "type" "two_cycle_core,two_cycle_core")])
 
@@ -4453,18 +4452,6 @@  archs4x, archs4xd"
 [(set_attr "type" "unary")
  (set_attr "length" "20")])
 
-(define_insn "swap"
-  [(set (match_operand:SI  0 "dest_reg_operand" "=w,w,w")
-	(unspec:SI [(match_operand:SI 1 "general_operand" "L,Cal,c")]
-			    UNSPEC_ARC_SWAP))]
-  "TARGET_SWAP"
-  "@
-   swap \t%0, %1
-   swap \t%0, %1
-   swap \t%0, %1"
-  [(set_attr "length" "4,8,4")
-   (set_attr "type" "two_cycle_core,two_cycle_core,two_cycle_core")])
-
 (define_insn "divaw"
   [(set (match_operand:SI 0 "dest_reg_operand" "=&w,&w,&w")
 			  (unspec:SI [(div:SI (match_operand:SI 1 "general_operand" "r,Cal,r")
diff --git a/gcc/config/arc/builtins.def b/gcc/config/arc/builtins.def
index fc5c92b..deb5f73 100644
--- a/gcc/config/arc/builtins.def
+++ b/gcc/config/arc/builtins.def
@@ -50,14 +50,14 @@  DEF_BUILTIN (CORE_WRITE, 2, void_ftype_usint_usint, core_write, 1)
 DEF_BUILTIN (SETI,       1, void_ftype_int,         seti,       TARGET_V2)
 
 /* Regular builtins.  */
-DEF_BUILTIN (NORM,       1, int_ftype_int,          clrsbsi2,   TARGET_NORM)
-DEF_BUILTIN (NORMW,      1, int_ftype_short,        normw,      TARGET_NORM)
-DEF_BUILTIN (SWAP,       1, int_ftype_int,          swap,       TARGET_SWAP)
-DEF_BUILTIN (DIVAW,      2, int_ftype_int_int,      divaw,      TARGET_EA_SET)
-DEF_BUILTIN (CORE_READ,  1, usint_ftype_usint,      core_read,  1)
-DEF_BUILTIN (LR,         1, usint_ftype_usint,      lr,         1)
-DEF_BUILTIN (FFS,        1, int_ftype_int,          ffs,        (TARGET_EM && TARGET_NORM) || TARGET_HS)
-DEF_BUILTIN (FLS,        1, int_ftype_int,          fls,        (TARGET_EM && TARGET_NORM) || TARGET_HS)
+DEF_BUILTIN (NORM,       1, int_ftype_int,     clrsbsi2,      TARGET_NORM)
+DEF_BUILTIN (NORMW,      1, int_ftype_short,   normw,         TARGET_NORM)
+DEF_BUILTIN (SWAP,       1, int_ftype_int,     rotlsi2_cnt16, TARGET_SWAP)
+DEF_BUILTIN (DIVAW,      2, int_ftype_int_int, divaw,         TARGET_EA_SET)
+DEF_BUILTIN (CORE_READ,  1, usint_ftype_usint, core_read,     1)
+DEF_BUILTIN (LR,         1, usint_ftype_usint, lr,            1)
+DEF_BUILTIN (FFS,        1, int_ftype_int,     ffs,           (TARGET_EM && TARGET_NORM) || TARGET_HS)
+DEF_BUILTIN (FLS,        1, int_ftype_int,     fls,           (TARGET_EM && TARGET_NORM) || TARGET_HS)
 
 /* ARC SIMD extenssion.  */
 /* BEGIN SIMD marker.  */
diff --git a/gcc/testsuite/gcc.target/arc/builtin_norm-1.c b/gcc/testsuite/gcc.target/arc/builtin_norm-1.c
new file mode 100644
index 0000000..7cb7e98
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/builtin_norm-1.c
@@ -0,0 +1,9 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -mnorm" } */
+
+int foo(int x)
+{
+  return __builtin_arc_norm (x);
+}
+
+/* { dg-final { scan-assembler "norm\\s+r0,r0" } } */
diff --git a/gcc/testsuite/gcc.target/arc/builtin_norm-2.c b/gcc/testsuite/gcc.target/arc/builtin_norm-2.c
new file mode 100644
index 0000000..d90128b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/builtin_norm-2.c
@@ -0,0 +1,10 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -mnorm" } */
+
+int foo()
+{
+  return __builtin_arc_norm (255);
+}
+
+/* { dg-final { scan-assembler-not "norm\\s+r0,r0" } } */
+/* { dg-final { scan-assembler "mov_s\\s+r0,23" } } */
diff --git a/gcc/testsuite/gcc.target/arc/builtin_normw-1.c b/gcc/testsuite/gcc.target/arc/builtin_normw-1.c
new file mode 100644
index 0000000..f7b46f3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/builtin_normw-1.c
@@ -0,0 +1,9 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -mnorm" } */
+
+int foo(short x)
+{
+  return __builtin_arc_normw (x);
+}
+
+/* { dg-final { scan-assembler "normh\\s+r0, ?r0" } } */
diff --git a/gcc/testsuite/gcc.target/arc/builtin_normw-2.c b/gcc/testsuite/gcc.target/arc/builtin_normw-2.c
new file mode 100644
index 0000000..bb37c84
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/builtin_normw-2.c
@@ -0,0 +1,10 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -mnorm" } */
+
+int foo()
+{
+  return __builtin_arc_normw (255);
+}
+
+/* { dg-final { scan-assembler-not "normh\\s+r" } } */
+/* { dg-final { scan-assembler "mov_s\\s+r0,7" } } */
diff --git a/gcc/testsuite/gcc.target/arc/builtin_swap-1.c b/gcc/testsuite/gcc.target/arc/builtin_swap-1.c
new file mode 100644
index 0000000..5421e26
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/builtin_swap-1.c
@@ -0,0 +1,9 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -mswap" } */
+
+int foo(int x)
+{
+  return __builtin_arc_swap (x);
+}
+
+/* { dg-final { scan-assembler "swap\\s+r0,r0" } } */
diff --git a/gcc/testsuite/gcc.target/arc/builtin_swap-2.c b/gcc/testsuite/gcc.target/arc/builtin_swap-2.c
new file mode 100644
index 0000000..9c2f24a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/builtin_swap-2.c
@@ -0,0 +1,9 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -mswap" } */
+
+int foo()
+{
+  return __builtin_arc_swap (0x12345678);
+}
+
+/* { dg-final { scan-assembler-not "swap\\s+r" } } */
diff --git a/gcc/testsuite/gcc.target/arc/builtin_swap-3.c b/gcc/testsuite/gcc.target/arc/builtin_swap-3.c
new file mode 100644
index 0000000..14a3072
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/builtin_swap-3.c
@@ -0,0 +1,10 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -mswap" } */
+
+int foo(int x)
+{
+  int t = __builtin_arc_swap (x);
+  return __builtin_arc_swap (t);
+}
+
+/* { dg-final { scan-assembler-not "swap\\s+r" } } */