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 <ro...@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 --
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" } } */