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 <[email protected]>
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
--
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" } } */