Hi Richard,
Thanks for your feedback. This does feel like a much nicer solution now.
> Yes, it looks basically ok. I'd probably restrict it to folding target
> builtins
> though - similar to what TARGET_FOLD_BUILTIN did. Exactly to not
> expose all stmts to the backends. That is, move the target hook call
> to gimple_fold_call, after the inplace check (and remove the inplace
> argument of the target hook), and call it only for DECL_BUILT_IN_CLASS
> BUILT_IN_MD.
This seems sensible - hopefully something like the attached will be
closer to an acceptable implementation. The aarch64 portion certainly
looks much cleaner now.
> Not sure if TARGET_FOLD_STMT is then still an appropriate name ...
> TARGET_FOLD_BUILTIN is already taken unfortunately. Maybe
> TARGET_FOLD_BUILTIN_MD_CALL?
I've gone for TARGET_GIMPLE_FOLD_BUILTIN (to fit with the
non-target-specific gimple_fold_builtin).
I've also updated the documentation for TARGET_FOLD_BUILTIN to
make it clear that the tree returned must be valid in GENERIC
and GIMPLE.
Thanks again for your help.
James
Graduate Engineer
ARM.
---
gcc/
2013-04-19 James Greenhalgh <james.greenha...@arm.com>
* coretypes.h (gimple_stmt_iterator_d): Forward declare.
(gimple_stmt_iterator): New typedef.
* gimple.h (gimple_stmt_iterator): Rename to...
(gimple_stmt_iterator_d): ... This.
* doc/tm.texi.in (TARGET_FOLD_BUILTIN): Detail restriction that
trees be valid for GIMPLE and GENERIC.
(TARGET_GIMPLE_FOLD_BUILTIN): New.
* gimple-fold.c (gimple_fold_call): Call target hook
gimple_fold_builtin.
* hooks.c (hook_bool_gsiptr_false): New.
* hooks.h (hook_bool_gsiptr_false): New.
* target.def (fold_stmt): New.
* doc/tm.texi: Regenerate.
2013-04-19 James Greenhalgh <james.greenha...@arm.com>
* config/aarch64/aarch64-builtins.c
(aarch64_fold_builtin): Move folds to gimple-specific tree codes
to aarch64_gimple_fold_builtin.
(aarch64_gimple_fold_builtin): New.
* config/aarch64/aarch64-protos.h (aarch64_gimple_fold_builtin): New.
* config/aarch64/aarch64.c (TARGET_GIMPLE_FOLD_BUILTIN): Define.
diff --git a/gcc/coretypes.h b/gcc/coretypes.h
index 320b4dd..76fc4aa 100644
--- a/gcc/coretypes.h
+++ b/gcc/coretypes.h
@@ -62,6 +62,8 @@ union gimple_statement_d;
typedef union gimple_statement_d *gimple;
typedef const union gimple_statement_d *const_gimple;
typedef gimple gimple_seq;
+struct gimple_stmt_iterator_d;
+typedef gimple_stmt_iterator_d gimple_stmt_iterator;
union section;
typedef union section section;
struct gcc_options;
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 91a756c..908da0b 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -10772,10 +10772,13 @@ Fold a call to a machine specific built-in function that was set up by
@samp{TARGET_INIT_BUILTINS}. @var{fndecl} is the declaration of the
built-in function. @var{n_args} is the number of arguments passed to
the function; the arguments themselves are pointed to by @var{argp}.
-The result is another tree containing a simplified expression for the
-call's result. If @var{ignore} is true the value will be ignored.
+The result is another tree, valid for both GIMPLE and GENERIC,
+containing a simplified expression for the call's result. If
+@var{ignore} is true the value will be ignored.
@end deftypefn
+@hook TARGET_GIMPLE_FOLD_BUILTIN
+
@hook TARGET_COMPARE_VERSION_PRIORITY
This hook is used to compare the target attributes in two functions to
determine which function's features get higher priority. This is used
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index b9211a9..d1dbf8e 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -1145,6 +1145,13 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
}
}
+ /* Call target-specific, GIMPLE only fold routines. */
+ callee = gimple_call_fndecl (stmt);
+ if (!changed
+ && callee
+ && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_MD)
+ changed |= targetm.gimple_fold_builtin (gsi);
+
return changed;
}
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 475d2ea..17ad409 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -130,7 +130,7 @@ enum plf_mask {
/* Iterator object for GIMPLE statement sequences. */
-typedef struct
+struct gimple_stmt_iterator_d
{
/* Sequence node holding the current statement. */
gimple_seq_node ptr;
@@ -141,8 +141,7 @@ typedef struct
block/sequence is removed. */
gimple_seq *seq;
basic_block bb;
-} gimple_stmt_iterator;
-
+};
/* Data structure definitions for GIMPLE tuples. NOTE: word markers
are for 64 bit hosts. */
diff --git a/gcc/hooks.c b/gcc/hooks.c
index 3b54dfa..3259658 100644
--- a/gcc/hooks.c
+++ b/gcc/hooks.c
@@ -147,6 +147,14 @@ hook_bool_FILEptr_rtx_false (FILE *a ATTRIBUTE_UNUSED,
return false;
}
+/* Generic hook that takes (gimple_stmt_iterator *) and returns
+ false. */
+bool
+hook_bool_gsiptr_false (gimple_stmt_iterator *a ATTRIBUTE_UNUSED)
+{
+ return false;
+}
+
/* Used for the TARGET_ASM_CAN_OUTPUT_MI_THUNK hook. */
bool
hook_bool_const_tree_hwi_hwi_const_tree_false (const_tree a ATTRIBUTE_UNUSED,
diff --git a/gcc/hooks.h b/gcc/hooks.h
index 50bcc6a..eaf4b03 100644
--- a/gcc/hooks.h
+++ b/gcc/hooks.h
@@ -42,6 +42,7 @@ extern bool hook_bool_tree_false (tree);
extern bool hook_bool_const_tree_false (const_tree);
extern bool hook_bool_tree_true (tree);
extern bool hook_bool_const_tree_true (const_tree);
+extern bool hook_bool_gsiptr_false (gimple_stmt_iterator *);
extern bool hook_bool_const_tree_hwi_hwi_const_tree_false (const_tree,
HOST_WIDE_INT,
HOST_WIDE_INT,
diff --git a/gcc/target.def b/gcc/target.def
index 3ad5870..46375aa 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -1289,13 +1289,25 @@ DEFHOOK
"",
tree, (unsigned int /*location_t*/ loc, tree fndecl, void *arglist), NULL)
-/* Fold a target-specific builtin. */
+/* Fold a target-specific builtin to a tree valid for both GIMPLE
+ and GENERIC. */
DEFHOOK
(fold_builtin,
"",
tree, (tree fndecl, int n_args, tree *argp, bool ignore),
hook_tree_tree_int_treep_bool_null)
+/* Fold a target-specific builtin to a valid GIMPLE tree. */
+DEFHOOK
+(gimple_fold_builtin,
+ "Like @samp{TARGET_FOLD_BUILTIN}, but without the restriction that\n\
+the result tree be valid for GENERIC. Fold a call to a machine specific\n\
+built-in function that was set up by @samp{TARGET_INIT_BUILTINS}.\n\
+@var{gsi} points to the gimple statement holding the function call.\n\
+Returns true if any change was made to the GIMPLE stream.",
+ bool, (gimple_stmt_iterator *gsi),
+ hook_bool_gsiptr_false)
+
/* Target hook is used to compare the target attributes in two functions to
determine which function's features get higher priority. This is used
during function multi-versioning to figure out the order in which two
diff --git a/gcc/config/aarch64/aarch64-builtins.c b/gcc/config/aarch64/aarch64-builtins.c
index 8361632..7a65d59 100644
--- a/gcc/config/aarch64/aarch64-builtins.c
+++ b/gcc/config/aarch64/aarch64-builtins.c
@@ -30,6 +30,9 @@
#include "langhooks.h"
#include "diagnostic-core.h"
#include "optabs.h"
+#include "gimple.h"
+#include "tree-ssa-propagate.h"
+#include "gimple-fold.h"
enum aarch64_simd_builtin_type_mode
{
@@ -1310,21 +1313,11 @@ aarch64_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *args,
{
int fcode = DECL_FUNCTION_CODE (fndecl);
tree type = TREE_TYPE (TREE_TYPE (fndecl));
-
switch (fcode)
{
- BUILTIN_VALL (UNOP, reduc_splus_, 10)
- return fold_build1 (REDUC_PLUS_EXPR, type, args[0]);
- break;
- BUILTIN_VDQIF (UNOP, reduc_smax_, 10)
- return fold_build1 (REDUC_MAX_EXPR, type, args[0]);
- break;
- BUILTIN_VDQIF (UNOP, reduc_smin_, 10)
- return fold_build1 (REDUC_MIN_EXPR, type, args[0]);
- break;
BUILTIN_VDQF (UNOP, abs, 2)
return fold_build1 (ABS_EXPR, type, args[0]);
- break;
+ break;
BUILTIN_VDQF (BINOP, cmge, 0)
BUILTIN_VDQF (BINOP, cmgt, 0)
BUILTIN_VDQF (BINOP, cmeq, 0)
@@ -1340,15 +1333,15 @@ aarch64_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *args,
{
BUILTIN_VDQF (BINOP, cmge, 0)
cmp = fold_build2 (GE_EXPR, type, args[0], args[1]);
- break;
+ break;
BUILTIN_VDQF (BINOP, cmgt, 0)
cmp = fold_build2 (GT_EXPR, type, args[0], args[1]);
- break;
+ break;
BUILTIN_VDQF (BINOP, cmeq, 0)
cmp = fold_build2 (EQ_EXPR, type, args[0], args[1]);
- break;
- default:
- gcc_unreachable ();
+ break;
+ default:
+ gcc_unreachable ();
}
return fold_build3 (VEC_COND_EXPR, type, cmp, vect_true, vect_false);
break;
@@ -1357,14 +1350,70 @@ aarch64_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *args,
VAR1 (UNOP, floatv4si, 2, v4sf)
VAR1 (UNOP, floatv2di, 2, v2df)
return fold_build1 (FLOAT_EXPR, type, args[0]);
- break;
- default:
- break;
+ break;
+ default:
+ break;
}
return NULL_TREE;
}
+bool
+aarch64_gimple_fold_builtin (gimple_stmt_iterator *gsi)
+{
+ bool changed = false;
+ gimple stmt = gsi_stmt (*gsi);
+ tree call = gimple_call_fn (stmt);
+ tree fndecl;
+ gimple new_stmt = NULL;
+ if (call)
+ {
+ fndecl = gimple_call_fndecl (stmt);
+ if (fndecl)
+ {
+ int fcode = DECL_FUNCTION_CODE (fndecl);
+ int nargs = gimple_call_num_args (stmt);
+ tree *args = (nargs > 0
+ ? gimple_call_arg_ptr (stmt, 0)
+ : &error_mark_node);
+
+ switch (fcode)
+ {
+ BUILTIN_VALL (UNOP, reduc_splus_, 10)
+ new_stmt = gimple_build_assign_with_ops (
+ REDUC_PLUS_EXPR,
+ gimple_call_lhs (stmt),
+ args[0],
+ NULL_TREE);
+ break;
+ BUILTIN_VDQIF (UNOP, reduc_smax_, 10)
+ new_stmt = gimple_build_assign_with_ops (
+ REDUC_MAX_EXPR,
+ gimple_call_lhs (stmt),
+ args[0],
+ NULL_TREE);
+ break;
+ BUILTIN_VDQIF (UNOP, reduc_smin_, 10)
+ new_stmt = gimple_build_assign_with_ops (
+ REDUC_MIN_EXPR,
+ gimple_call_lhs (stmt),
+ args[0],
+ NULL_TREE);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (new_stmt)
+ {
+ gsi_replace (gsi, new_stmt, true);
+ changed = true;
+ }
+ return changed;
+}
+
#undef AARCH64_CHECK_BUILTIN_MODE
#undef AARCH64_FIND_FRINT_VARIANT
#undef BUILTIN_DX
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index 2400239..4a53f32 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -179,6 +179,7 @@ bool aarch64_simd_mem_operand_p (rtx);
rtx aarch64_simd_vect_par_cnst_half (enum machine_mode, bool);
rtx aarch64_tls_get_addr (void);
tree aarch64_fold_builtin (tree, int, tree *, bool);
+bool aarch64_gimple_fold_builtin (gimple_stmt_iterator *);
unsigned aarch64_dbx_register_number (unsigned);
unsigned aarch64_trampoline_size (void);
void aarch64_asm_output_labelref (FILE *, const char *);
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index d3b349f..b9535bf 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -7859,6 +7859,9 @@ aarch64_vectorize_vec_perm_const_ok (enum machine_mode vmode,
#undef TARGET_FOLD_BUILTIN
#define TARGET_FOLD_BUILTIN aarch64_fold_builtin
+#undef TARGET_GIMPLE_FOLD_BUILTIN
+#define TARGET_GIMPLE_FOLD_BUILTIN aarch64_gimple_fold_builtin
+
#undef TARGET_FUNCTION_ARG
#define TARGET_FUNCTION_ARG aarch64_function_arg