Makefile.in (OBJS): Add gimple-match.o and generic-match.o.
2014-10-22 Richard Biener <rguenther@suse.de> Prathamesh Kulkarni <bilbotheelffriend@gmail.com> * Makefile.in (OBJS): Add gimple-match.o and generic-match.o. (MOSTLYCLEANFILES): Add gimple-match.c and generic-match.c. (gimple-match.c): Generate by triggering s-match. (generic-match.c): Likewise. (s-match): Rule to build gimple-match.c and generic-match.c by running the genmatch generator program. (build/hash-table.o): Dependencies to build hash-table.c for the host. (build/genmatch.o): Dependencies to build genmatch. (genprog): Add match. (build/genmatch): Likewise. (TEXI_GCCINT_FILES): Add match-and-simplify.texi. * generic-match-head.c: New file. * gimple-match-head.c: Likewise. * gimple-match.h: Likewise. * genmatch.c: Likewise. * match.pd: Likewise. * builtins.h (fold_builtin_n): Export. * builtins.c (fold_builtin_n): Likewise. * gimple-fold.h (gimple_build): Declare various overloads. (gimple_simplify): Likewise. (gimple_convert): Re-implement in terms of gimple_build. * gimple-fold.c (gimple_convert): Remove. (gimple_build): New functions. * doc/match-and-simplify.texi: New file. * doc/gccint.texi: Add menu item Match and Simplify and include match-and-simplify.texi. Co-Authored-By: Prathamesh Kulkarni <bilbotheelffriend@gmail.com> From-SVN: r216542
This commit is contained in:
parent
7d9f1cd276
commit
3d2cf79f81
|
@ -1,3 +1,33 @@
|
|||
2014-10-22 Richard Biener <rguenther@suse.de>
|
||||
Prathamesh Kulkarni <bilbotheelffriend@gmail.com>
|
||||
|
||||
* Makefile.in (OBJS): Add gimple-match.o and generic-match.o.
|
||||
(MOSTLYCLEANFILES): Add gimple-match.c and generic-match.c.
|
||||
(gimple-match.c): Generate by triggering s-match.
|
||||
(generic-match.c): Likewise.
|
||||
(s-match): Rule to build gimple-match.c and generic-match.c
|
||||
by running the genmatch generator program.
|
||||
(build/hash-table.o): Dependencies to build hash-table.c for the host.
|
||||
(build/genmatch.o): Dependencies to build genmatch.
|
||||
(genprog): Add match.
|
||||
(build/genmatch): Likewise.
|
||||
(TEXI_GCCINT_FILES): Add match-and-simplify.texi.
|
||||
* generic-match-head.c: New file.
|
||||
* gimple-match-head.c: Likewise.
|
||||
* gimple-match.h: Likewise.
|
||||
* genmatch.c: Likewise.
|
||||
* match.pd: Likewise.
|
||||
* builtins.h (fold_builtin_n): Export.
|
||||
* builtins.c (fold_builtin_n): Likewise.
|
||||
* gimple-fold.h (gimple_build): Declare various overloads.
|
||||
(gimple_simplify): Likewise.
|
||||
(gimple_convert): Re-implement in terms of gimple_build.
|
||||
* gimple-fold.c (gimple_convert): Remove.
|
||||
(gimple_build): New functions.
|
||||
* doc/match-and-simplify.texi: New file.
|
||||
* doc/gccint.texi: Add menu item Match and Simplify and include
|
||||
match-and-simplify.texi.
|
||||
|
||||
2014-10-22 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR target/63594
|
||||
|
|
|
@ -204,6 +204,8 @@ gengtype-lex.o-warn = -Wno-error
|
|||
libgcov-util.o-warn = -Wno-error
|
||||
libgcov-driver-tool.o-warn = -Wno-error
|
||||
libgcov-merge-tool.o-warn = -Wno-error
|
||||
gimple-match.o-warn = -Wno-unused-variable -Wno-unused-parameter
|
||||
generic-match.o-warn = -Wno-unused-variable -Wno-unused-parameter
|
||||
|
||||
# All warnings have to be shut off in stage1 if the compiler used then
|
||||
# isn't gcc; configure determines that. WARN_CFLAGS will be either
|
||||
|
@ -1227,6 +1229,8 @@ OBJS = \
|
|||
gimple-iterator.o \
|
||||
gimple-fold.o \
|
||||
gimple-low.o \
|
||||
gimple-match.o \
|
||||
generic-match.o \
|
||||
gimple-pretty-print.o \
|
||||
gimple-ssa-isolate-paths.o \
|
||||
gimple-ssa-strength-reduction.o \
|
||||
|
@ -1504,7 +1508,7 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
|
|||
insn-output.c insn-recog.c insn-emit.c insn-extract.c insn-peep.c \
|
||||
insn-attr.h insn-attr-common.h insn-attrtab.c insn-dfatab.c \
|
||||
insn-latencytab.c insn-opinit.c insn-opinit.h insn-preds.c insn-constants.h \
|
||||
tm-preds.h tm-constrs.h checksum-options \
|
||||
tm-preds.h tm-constrs.h checksum-options gimple-match.c generic-match.c \
|
||||
tree-check.h min-insn-modes.c insn-modes.c insn-modes.h \
|
||||
genrtl.h gt-*.h gtype-*.h gtype-desc.c gtyp-input.list \
|
||||
xgcc$(exeext) cpp$(exeext) \
|
||||
|
@ -2021,7 +2025,7 @@ $(common_out_object_file): $(common_out_file)
|
|||
.PRECIOUS: insn-config.h insn-flags.h insn-codes.h insn-constants.h \
|
||||
insn-emit.c insn-recog.c insn-extract.c insn-output.c insn-peep.c \
|
||||
insn-attr.h insn-attr-common.h insn-attrtab.c insn-dfatab.c \
|
||||
insn-latencytab.c insn-preds.c
|
||||
insn-latencytab.c insn-preds.c gimple-match.c generic-match.c
|
||||
|
||||
# Dependencies for the md file. The first time through, we just assume
|
||||
# the md file itself and the generated dependency file (in order to get
|
||||
|
@ -2230,6 +2234,20 @@ s-tm-texi: build/genhooks$(build_exeext) $(srcdir)/doc/tm.texi.in
|
|||
false; \
|
||||
fi
|
||||
|
||||
gimple-match.c: s-match gimple-match-head.c ; @true
|
||||
generic-match.c: s-match generic-match-head.c ; @true
|
||||
|
||||
s-match: build/genmatch$(build_exeext) $(srcdir)/match*.pd
|
||||
$(RUN_GEN) build/genmatch$(build_exeext) --gimple $(srcdir)/match.pd \
|
||||
> tmp-gimple-match.c
|
||||
$(RUN_GEN) build/genmatch$(build_exeext) --generic $(srcdir)/match.pd \
|
||||
> tmp-generic-match.c
|
||||
$(SHELL) $(srcdir)/../move-if-change tmp-gimple-match.c \
|
||||
gimple-match.c
|
||||
$(SHELL) $(srcdir)/../move-if-change tmp-generic-match.c \
|
||||
generic-match.c
|
||||
$(STAMP) s-match
|
||||
|
||||
GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
|
||||
$(host_xm_file_list) \
|
||||
$(tm_file_list) $(HASHTAB_H) $(SPLAY_TREE_H) $(srcdir)/bitmap.h \
|
||||
|
@ -2378,6 +2396,8 @@ build/rtl.o: rtl.c $(BCONFIG_H) coretypes.h $(GTM_H) $(SYSTEM_H) \
|
|||
$(RTL_H) $(GGC_H) errors.h
|
||||
build/vec.o : vec.c $(BCONFIG_H) $(SYSTEM_H) coretypes.h $(VEC_H) \
|
||||
$(GGC_H) toplev.h $(DIAGNOSTIC_CORE_H)
|
||||
build/hash-table.o : hash-table.c $(BCONFIG_H) $(SYSTEM_H) coretypes.h \
|
||||
$(HASH_TABLE_H) $(GGC_H) toplev.h $(DIAGNOSTIC_CORE_H)
|
||||
build/gencondmd.o : build/gencondmd.c $(BCONFIG_H) $(SYSTEM_H) \
|
||||
coretypes.h $(GTM_H) insn-constants.h \
|
||||
$(filter-out insn-flags.h, $(RTL_H) $(TM_P_H) $(FUNCTION_H) $(REGS_H) \
|
||||
|
@ -2473,6 +2493,8 @@ build/genhooks.o : genhooks.c $(TARGET_DEF) $(C_TARGET_DEF) \
|
|||
$(COMMON_TARGET_DEF) $(BCONFIG_H) $(SYSTEM_H) errors.h
|
||||
build/genmddump.o : genmddump.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H) \
|
||||
coretypes.h $(GTM_H) errors.h $(READ_MD_H) gensupport.h
|
||||
build/genmatch.o : genmatch.c $(BCONFIG_H) $(SYSTEM_H) \
|
||||
coretypes.h errors.h
|
||||
|
||||
# Compile the programs that generate insn-* from the machine description.
|
||||
# They are compiled with $(COMPILER_FOR_BUILD), and associated libraries,
|
||||
|
@ -2493,11 +2515,14 @@ genprogerr = $(genprogmd) genrtl modes gtype hooks
|
|||
$(genprogerr:%=build/gen%$(build_exeext)): $(BUILD_ERRORS)
|
||||
|
||||
# Remaining build programs.
|
||||
genprog = $(genprogerr) check checksum condmd
|
||||
genprog = $(genprogerr) check checksum condmd match
|
||||
|
||||
# These programs need libs over and above what they get from the above list.
|
||||
build/genautomata$(build_exeext) : BUILD_LIBS += -lm
|
||||
|
||||
build/genmatch$(build_exeext) : $(CPPLIB) $(LIBIBERTY) \
|
||||
$(BUILD_ERRORS) build/vec.o build/hash-table.o
|
||||
|
||||
# These programs are not linked with the MD reader.
|
||||
build/gengtype$(build_exeext) : build/gengtype-lex.o build/gengtype-parse.o \
|
||||
build/gengtype-state.o build/version.o build/errors.o
|
||||
|
@ -2832,7 +2857,8 @@ TEXI_GCCINT_FILES = gccint.texi gcc-common.texi gcc-vers.texi \
|
|||
configfiles.texi collect2.texi headerdirs.texi funding.texi \
|
||||
gnu.texi gpl_v3.texi fdl.texi contrib.texi languages.texi \
|
||||
sourcebuild.texi gty.texi libgcc.texi cfg.texi tree-ssa.texi \
|
||||
loop.texi generic.texi gimple.texi plugins.texi optinfo.texi
|
||||
loop.texi generic.texi gimple.texi plugins.texi optinfo.texi \
|
||||
match-and-simplify.texi
|
||||
|
||||
TEXI_GCCINSTALL_FILES = install.texi install-old.texi fdl.texi \
|
||||
gcc-common.texi gcc-vers.texi
|
||||
|
|
|
@ -180,7 +180,6 @@ static tree fold_builtin_fabs (location_t, tree, tree);
|
|||
static tree fold_builtin_abs (location_t, tree, tree);
|
||||
static tree fold_builtin_unordered_cmp (location_t, tree, tree, tree, enum tree_code,
|
||||
enum tree_code);
|
||||
static tree fold_builtin_n (location_t, tree, tree *, int, bool);
|
||||
static tree fold_builtin_0 (location_t, tree, bool);
|
||||
static tree fold_builtin_1 (location_t, tree, tree, bool);
|
||||
static tree fold_builtin_2 (location_t, tree, tree, tree, bool);
|
||||
|
@ -10395,7 +10394,7 @@ fold_builtin_4 (location_t loc, tree fndecl,
|
|||
|
||||
#define MAX_ARGS_TO_FOLD_BUILTIN 4
|
||||
|
||||
static tree
|
||||
tree
|
||||
fold_builtin_n (location_t loc, tree fndecl, tree *args, int nargs, bool ignore)
|
||||
{
|
||||
tree ret = NULL_TREE;
|
||||
|
|
|
@ -75,6 +75,7 @@ extern tree fold_fma (location_t, tree, tree, tree, tree);
|
|||
extern bool avoid_folding_inline_builtin (tree);
|
||||
extern tree fold_call_expr (location_t, tree, bool);
|
||||
extern tree fold_builtin_call_array (location_t, tree, tree, int, tree *);
|
||||
extern tree fold_builtin_n (location_t, tree, tree *, int, bool);
|
||||
extern bool validate_gimple_arglist (const_gimple, ...);
|
||||
extern rtx default_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
|
||||
extern bool fold_builtin_next_arg (tree, bool);
|
||||
|
|
|
@ -123,6 +123,7 @@ Additional tutorial information is linked to from
|
|||
* Plugins:: Extending the compiler with plugins.
|
||||
* LTO:: Using Link-Time Optimization.
|
||||
|
||||
* Match and Simplify:: How to write expression simplification patterns for GIMPLE and GENERIC
|
||||
* Funding:: How to help assure funding for free software.
|
||||
* GNU Project:: The GNU Project and GNU/Linux.
|
||||
|
||||
|
@ -158,6 +159,7 @@ Additional tutorial information is linked to from
|
|||
@include gty.texi
|
||||
@include plugins.texi
|
||||
@include lto.texi
|
||||
@include match-and-simplify.texi
|
||||
|
||||
@include funding.texi
|
||||
@include gnu.texi
|
||||
|
|
|
@ -0,0 +1,314 @@
|
|||
@c Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
@c Free Software Foundation, Inc.
|
||||
@c This is part of the GCC manual.
|
||||
@c For copying conditions, see the file gcc.texi.
|
||||
|
||||
@node Match and Simplify
|
||||
@chapter Match and Simplify
|
||||
@cindex Match and Simplify
|
||||
|
||||
The GIMPLE and GENERIC pattern matching project match-and-simplify
|
||||
tries to address several issues.
|
||||
|
||||
@enumerate
|
||||
@item unify expression simplifications currently spread and duplicated
|
||||
over separate files like fold-const.c, gimple-fold.c and builtins.c
|
||||
@item allow for a cheap way to implement building and simplifying
|
||||
non-trivial GIMPLE expressions, avoiding the need to go through
|
||||
building and simplifying GENERIC via fold_buildN and then
|
||||
gimplifying via force_gimple_operand
|
||||
@end enumerate
|
||||
|
||||
To address these the project introduces a simple domain specific language
|
||||
to write expression simplifications from which code targeting GIMPLE
|
||||
and GENERIC is auto-generated. The GENERIC variant follows the
|
||||
fold_buildN API while for the GIMPLE variant and to address 2) new
|
||||
APIs are introduced.
|
||||
|
||||
@menu
|
||||
* GIMPLE API::
|
||||
* The Language::
|
||||
@end menu
|
||||
|
||||
@node GIMPLE API
|
||||
@section GIMPLE API
|
||||
@cindex GIMPLE API
|
||||
|
||||
@deftypefn {GIMPLE function} tree gimple_simplify (enum tree_code, tree, tree, gimple_seq *, tree (*)(tree))
|
||||
@deftypefnx {GIMPLE function} tree gimple_simplify (enum tree_code, tree, tree, tree, gimple_seq *, tree (*)(tree))
|
||||
@deftypefnx {GIMPLE function} tree gimple_simplify (enum tree_code, tree, tree, tree, tree, gimple_seq *, tree (*)(tree))
|
||||
@deftypefnx {GIMPLE function} tree gimple_simplify (enum built_in_function, tree, tree, gimple_seq *, tree (*)(tree))
|
||||
@deftypefnx {GIMPLE function} tree gimple_simplify (enum built_in_function, tree, tree, tree, gimple_seq *, tree (*)(tree))
|
||||
@deftypefnx {GIMPLE function} tree gimple_simplify (enum built_in_function, tree, tree, tree, gimple_seq *, tree (*)(tree))
|
||||
The main GIMPLE API entry to the expression simplifications mimicing
|
||||
that of the GENERIC fold_@{unary,binary,ternary@} functions.
|
||||
@end deftypefn
|
||||
|
||||
thus providing n-ary overloads for operation or function. The
|
||||
additional arguments are a gimple_seq where built statements are
|
||||
inserted on (if @code{NULL} then simplifications requiring new statements
|
||||
are not performed) and a valueization hook that can be used to
|
||||
tie simplifications to a SSA lattice.
|
||||
|
||||
In addition to those APIs @code{fold_stmt} is overloaded with
|
||||
a valueization hook:
|
||||
|
||||
@deftypefn bool fold_stmt (gimple_stmt_iterator *, tree (*)(tree));
|
||||
@end deftypefn
|
||||
|
||||
|
||||
Ontop of these a @code{fold_buildN}-like API for GIMPLE is introduced:
|
||||
|
||||
@deftypefn {GIMPLE function} tree gimple_build (gimple_seq *, location_t, enum tree_code, tree, tree, tree (*valueize) (tree) = NULL);
|
||||
@deftypefnx {GIMPLE function} tree gimple_build (gimple_seq *, location_t, enum tree_code, tree, tree, tree, tree (*valueize) (tree) = NULL);
|
||||
@deftypefnx {GIMPLE function} tree gimple_build (gimple_seq *, location_t, enum tree_code, tree, tree, tree, tree, tree (*valueize) (tree) = NULL);
|
||||
@deftypefnx {GIMPLE function} tree gimple_build (gimple_seq *, location_t, enum built_in_function, tree, tree, tree (*valueize) (tree) = NULL);
|
||||
@deftypefnx {GIMPLE function} tree gimple_build (gimple_seq *, location_t, enum built_in_function, tree, tree, tree, tree (*valueize) (tree) = NULL);
|
||||
@deftypefnx {GIMPLE function} tree gimple_convert (gimple_seq *, location_t, tree, tree);
|
||||
@end deftypefn
|
||||
|
||||
which is supposed to replace @code{force_gimple_operand (fold_buildN (...), ...)}
|
||||
and calls to @code{fold_convert}. Overloads without the @code{location_t}
|
||||
argument exist. Built statements are inserted on the provided sequence
|
||||
and simplification is performed using the optional valueization hook.
|
||||
|
||||
|
||||
@node The Language
|
||||
@section The Language
|
||||
@cindex The Language
|
||||
|
||||
The language to write expression simplifications in resembles other
|
||||
domain-specific languages GCC uses. Thus it is lispy. Lets start
|
||||
with an example from the match.pd file:
|
||||
|
||||
@smallexample
|
||||
(simplify
|
||||
(bit_and @@0 integer_all_onesp)
|
||||
@@0)
|
||||
@end smallexample
|
||||
|
||||
This example contains all required parts of an expression simplification.
|
||||
A simplification is wrapped inside a @code{(simplify ...)} expression.
|
||||
That contains at least two operands - an expression that is matched
|
||||
with the GIMPLE or GENERIC IL and a replacement expression that is
|
||||
returned if the match was successful.
|
||||
|
||||
Expressions have an operator ID, @code{bit_and} in this case. Expressions can
|
||||
be lower-case tree codes with @code{_expr} stripped off or builtin
|
||||
function code names in all-caps, like @code{BUILT_IN_SQRT}.
|
||||
|
||||
@code{@@n} denotes a so-called capture. It captures the operand and lets
|
||||
you refer to it in other places of the match-and-simplify. In the
|
||||
above example it is refered to in the replacement expression. Captures
|
||||
are @code{@@} followed by a number or an identifier.
|
||||
|
||||
@smallexample
|
||||
(simplify
|
||||
(bit_xor @@0 @@0)
|
||||
@{ build_zero_cst (type); @})
|
||||
@end smallexample
|
||||
|
||||
In this example @code{@@0} is mentioned twice which constrains the matched
|
||||
expression to have two equal operands. This example also introduces
|
||||
operands written in C code. These can be used in the expression
|
||||
replacements and are supposed to evaluate to a tree node which has to
|
||||
be a valid GIMPLE operand (so you cannot generate expressions in C code).
|
||||
|
||||
@smallexample
|
||||
(simplify
|
||||
(trunc_mod integer_zerop@@0 @@1)
|
||||
(if (!integer_zerop (@@1)))
|
||||
@@0)
|
||||
@end smallexample
|
||||
|
||||
Here @code{@@0} captures the first operand of the trunc_mod expression
|
||||
which is also predicated with @code{integer_zerop}. Expression operands
|
||||
may be either expressions, predicates or captures. Captures
|
||||
can be unconstrained or capture expresions or predicates.
|
||||
|
||||
This example introduces an optional operand of simplify,
|
||||
the if-expression. This condition is evaluated after the
|
||||
expression matched in the IL and is required to evaluate to true
|
||||
to enable the replacement expression. The expression operand
|
||||
of the @code{if} is a standard C expression which may contain references
|
||||
to captures.
|
||||
|
||||
A @code{if} expression can be used to specify a common condition
|
||||
for multiple simplify patterns, avoiding the need
|
||||
to repeat that multiple times:
|
||||
|
||||
@smallexample
|
||||
(if (!TYPE_SATURATING (type)
|
||||
&& !FLOAT_TYPE_P (type) && !FIXED_POINT_TYPE_P (type))
|
||||
(simplify
|
||||
(minus (plus @@0 @@1) @@0)
|
||||
@@1)
|
||||
(simplify
|
||||
(minus (minus @@0 @@1) @@0)
|
||||
(negate @@1)))
|
||||
@end smallexample
|
||||
|
||||
Ifs can be nested.
|
||||
|
||||
Captures can also be used for capturing results of sub-expressions.
|
||||
|
||||
@smallexample
|
||||
#if GIMPLE
|
||||
(simplify
|
||||
(pointer_plus (addr@@2 @@0) INTEGER_CST_P@@1)
|
||||
(if (is_gimple_min_invariant (@@2)))
|
||||
@{
|
||||
HOST_WIDE_INT off;
|
||||
tree base = get_addr_base_and_unit_offset (@@0, &off);
|
||||
off += tree_to_uhwi (@@1);
|
||||
/* Now with that we should be able to simply write
|
||||
(addr (mem_ref (addr @@base) (plus @@off @@1))) */
|
||||
build1 (ADDR_EXPR, type,
|
||||
build2 (MEM_REF, TREE_TYPE (TREE_TYPE (@@2)),
|
||||
build_fold_addr_expr (base),
|
||||
build_int_cst (ptr_type_node, off)));
|
||||
@})
|
||||
#endif
|
||||
@end smallexample
|
||||
|
||||
In the above example, @code{@@2} captures the result of the expression
|
||||
@code{(addr @@0)}. For outermost expression only its type can be captured,
|
||||
and the keyword @code{type} is reserved for this purpose. The above
|
||||
example also gives a way to conditionalize patterns to only apply
|
||||
to @code{GIMPLE} or @code{GENERIC} by means of using the pre-defined
|
||||
preprocessor macros @code{GIMPLE} and @code{GENERIC} and using
|
||||
preprocessor directives.
|
||||
|
||||
@smallexample
|
||||
(simplify
|
||||
(bit_and:c integral_op_p@@0 (bit_ior:c (bit_not @@0) @@1))
|
||||
(bit_and @@1 @@0))
|
||||
@end smallexample
|
||||
|
||||
Here we introduce flags on match expressions. There is currently
|
||||
a single flag, @code{c}, which denotes that the expression should
|
||||
be also matched commutated. Thus the above match expression
|
||||
is really the following four match expressions:
|
||||
|
||||
(bit_and integral_op_p@@0 (bit_ior (bit_not @@0) @@1))
|
||||
(bit_and (bit_ior (bit_not @@0) @@1) integral_op_p@@0)
|
||||
(bit_and integral_op_p@@0 (bit_ior @@1 (bit_not @@0)))
|
||||
(bit_and (bit_ior @@1 (bit_not @@0)) integral_op_p@@0)
|
||||
|
||||
Usual canonicalizations you know from GENERIC expressions are
|
||||
applied before matching, so for example constant operands always
|
||||
come second in commutative expressions.
|
||||
|
||||
More features exist to avoid too much repetition.
|
||||
|
||||
@smallexample
|
||||
(for op (plus pointer_plus minus bit_ior bit_xor)
|
||||
(simplify
|
||||
(op @@0 integer_zerop)
|
||||
@@0))
|
||||
@end smallexample
|
||||
|
||||
A @code{for} expression can be used to repeat a pattern for each
|
||||
operator specified, substituting @code{op}. @code{for} can be
|
||||
nested and a @code{for} can have multiple operators to iterate.
|
||||
|
||||
@smallexample
|
||||
(for opa (plus minus)
|
||||
opb (minus plus)
|
||||
(for opc (plus minus)
|
||||
(simplify...
|
||||
@end smallexample
|
||||
|
||||
In this example the pattern will be repeated four times with
|
||||
@code{opa, opb, opc} being @code{plus, minus, plus},
|
||||
@code{plus, minus, minus}, @code{minus, plus, plus},
|
||||
@code{minus, plus, minus}.
|
||||
|
||||
Another building block are @code{with} expressions in the
|
||||
result expression which nest the generated code in a new C block
|
||||
followed by its argument:
|
||||
|
||||
@smallexample
|
||||
(simplify
|
||||
(convert (mult @@0 @@1))
|
||||
(with @{ tree utype = unsigned_type_for (type); @}
|
||||
(convert (mult (convert:utype @@0) (convert:utype @@1)))))
|
||||
@end smallexample
|
||||
|
||||
This allows code nested in the @code{with} to refer to the declared
|
||||
variables. In the above case we use the feature to specify the
|
||||
type of a generated expression with the @code{:type} syntax where
|
||||
@code{type} needs to be an identifier that refers to the desired type.
|
||||
Usually the types of the generated result expressions are
|
||||
determined from the context, but sometimes like in the above case
|
||||
it is required that you specify them explicitely.
|
||||
|
||||
As intermediate conversions are often optional there is a way to
|
||||
avoid the need to repeat patterns both with and without such
|
||||
conversions. Namely you can mark a conversion as being optional
|
||||
with a @code{?}:
|
||||
|
||||
@smallexample
|
||||
(simplify
|
||||
(eq (convert@@0 @@1) (convert? @@2))
|
||||
(eq @@1 (convert @@2)))
|
||||
@end smallexample
|
||||
|
||||
which will match both @code{(eq (convert @@1) (convert @@2))} and
|
||||
@code{(eq (convert @@1) @@2)}. The optional converts are supposed
|
||||
to be all either present or not, thus
|
||||
@code{(eq (convert? @@1) (convert? @@2))} will result in two
|
||||
patterns only. If you want to match all four combinations you
|
||||
have access to two additional conditional converts as in
|
||||
@code{(eq (convert1? @@1) (convert2? @@2))}.
|
||||
|
||||
Predicates available from the GCC middle-end need to be made
|
||||
available explicitely via @code{define_predicates}:
|
||||
|
||||
@smallexample
|
||||
(define_predicates
|
||||
integer_onep integer_zerop integer_all_onesp)
|
||||
@end smallexample
|
||||
|
||||
You can also define predicates using the pattern matching language
|
||||
and the @code{match} form:
|
||||
|
||||
@smallexample
|
||||
(match negate_expr_p
|
||||
INTEGER_CST
|
||||
(if (TYPE_OVERFLOW_WRAPS (type)
|
||||
|| may_negate_without_overflow_p (t))))
|
||||
(match negate_expr_p
|
||||
(negate @@0))
|
||||
@end smallexample
|
||||
|
||||
This shows that for @code{match} expressions there is @code{t}
|
||||
available which captures the outermost expression (something
|
||||
not possible in the @code{simplify} context). As you can see
|
||||
@code{match} has an identifier as first operand which is how
|
||||
you refer to the predicate in patterns. Multiple @code{match}
|
||||
for the same identifier add additional cases where the predicate
|
||||
matches.
|
||||
|
||||
Predicates can also match an expression in which case you need
|
||||
to provide a template specifying the identifier and where to
|
||||
get its operands from:
|
||||
|
||||
@smallexample
|
||||
(match (logical_inverted_value @@0)
|
||||
(eq @@0 integer_zerop))
|
||||
(match (logical_inverted_value @@0)
|
||||
(bit_not truth_valued_p@@0))
|
||||
@end smallexample
|
||||
|
||||
You can use the above predicate like
|
||||
|
||||
@smallexample
|
||||
(simplify
|
||||
(bit_and @@0 (logical_inverted_value @@0))
|
||||
@{ build_zero_cst (type); @})
|
||||
@end smallexample
|
||||
|
||||
Which will match a bitwise and of an operand with its logical
|
||||
inverted value.
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/* Preamble and helpers for the autogenerated generic-match.c file.
|
||||
Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
#include "stringpool.h"
|
||||
#include "stor-layout.h"
|
||||
#include "flags.h"
|
||||
#include "tm.h"
|
||||
#include "hard-reg-set.h"
|
||||
#include "function.h"
|
||||
#include "basic-block.h"
|
||||
#include "tree-ssa-alias.h"
|
||||
#include "internal-fn.h"
|
||||
#include "gimple-expr.h"
|
||||
#include "is-a.h"
|
||||
#include "gimple.h"
|
||||
#include "gimple-ssa.h"
|
||||
#include "tree-ssanames.h"
|
||||
#include "gimple-fold.h"
|
||||
#include "gimple-iterator.h"
|
||||
#include "expr.h"
|
||||
#include "tree-dfa.h"
|
||||
#include "builtins.h"
|
||||
#include "tree-phinodes.h"
|
||||
#include "ssa-iterators.h"
|
||||
#include "dumpfile.h"
|
||||
#include "gimple-match.h"
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -5364,19 +5364,202 @@ rewrite_to_defined_overflow (gimple stmt)
|
|||
return stmts;
|
||||
}
|
||||
|
||||
/* Return OP converted to TYPE by emitting a conversion statement on SEQ
|
||||
if required using location LOC. Note that OP will be returned
|
||||
unmodified if GIMPLE does not require an explicit conversion between
|
||||
its type and TYPE. */
|
||||
|
||||
/* Build the expression CODE OP0 of type TYPE with location LOC,
|
||||
simplifying it first if possible using VALUEIZE if not NULL.
|
||||
OP0 is expected to be valueized already. Returns the built
|
||||
expression value and appends statements possibly defining it
|
||||
to SEQ. */
|
||||
|
||||
tree
|
||||
gimple_build (gimple_seq *seq, location_t loc,
|
||||
enum tree_code code, tree type, tree op0,
|
||||
tree (*valueize)(tree))
|
||||
{
|
||||
tree res = gimple_simplify (code, type, op0, seq, valueize);
|
||||
if (!res)
|
||||
{
|
||||
if (gimple_in_ssa_p (cfun))
|
||||
res = make_ssa_name (type, NULL);
|
||||
else
|
||||
res = create_tmp_reg (type, NULL);
|
||||
gimple stmt;
|
||||
if (code == REALPART_EXPR
|
||||
|| code == IMAGPART_EXPR
|
||||
|| code == VIEW_CONVERT_EXPR)
|
||||
stmt = gimple_build_assign_with_ops (code, res,
|
||||
build1 (code, type,
|
||||
op0), NULL_TREE);
|
||||
else
|
||||
stmt = gimple_build_assign_with_ops (code, res, op0, NULL_TREE);
|
||||
gimple_set_location (stmt, loc);
|
||||
gimple_seq_add_stmt_without_update (seq, stmt);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Build the expression OP0 CODE OP1 of type TYPE with location LOC,
|
||||
simplifying it first if possible using VALUEIZE if not NULL.
|
||||
OP0 and OP1 are expected to be valueized already. Returns the built
|
||||
expression value and appends statements possibly defining it
|
||||
to SEQ. */
|
||||
|
||||
tree
|
||||
gimple_build (gimple_seq *seq, location_t loc,
|
||||
enum tree_code code, tree type, tree op0, tree op1,
|
||||
tree (*valueize)(tree))
|
||||
{
|
||||
tree res = gimple_simplify (code, type, op0, op1, seq, valueize);
|
||||
if (!res)
|
||||
{
|
||||
if (gimple_in_ssa_p (cfun))
|
||||
res = make_ssa_name (type, NULL);
|
||||
else
|
||||
res = create_tmp_reg (type, NULL);
|
||||
gimple stmt = gimple_build_assign_with_ops (code, res, op0, op1);
|
||||
gimple_set_location (stmt, loc);
|
||||
gimple_seq_add_stmt_without_update (seq, stmt);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Build the expression (CODE OP0 OP1 OP2) of type TYPE with location LOC,
|
||||
simplifying it first if possible using VALUEIZE if not NULL.
|
||||
OP0, OP1 and OP2 are expected to be valueized already. Returns the built
|
||||
expression value and appends statements possibly defining it
|
||||
to SEQ. */
|
||||
|
||||
tree
|
||||
gimple_build (gimple_seq *seq, location_t loc,
|
||||
enum tree_code code, tree type, tree op0, tree op1, tree op2,
|
||||
tree (*valueize)(tree))
|
||||
{
|
||||
tree res = gimple_simplify (code, type, op0, op1, op2,
|
||||
seq, valueize);
|
||||
if (!res)
|
||||
{
|
||||
if (gimple_in_ssa_p (cfun))
|
||||
res = make_ssa_name (type, NULL);
|
||||
else
|
||||
res = create_tmp_reg (type, NULL);
|
||||
gimple stmt;
|
||||
if (code == BIT_FIELD_REF)
|
||||
stmt = gimple_build_assign_with_ops (code, res,
|
||||
build3 (BIT_FIELD_REF, type,
|
||||
op0, op1, op2),
|
||||
NULL_TREE);
|
||||
else
|
||||
stmt = gimple_build_assign_with_ops (code, res, op0, op1, op2);
|
||||
gimple_set_location (stmt, loc);
|
||||
gimple_seq_add_stmt_without_update (seq, stmt);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Build the call FN (ARG0) with a result of type TYPE
|
||||
(or no result if TYPE is void) with location LOC,
|
||||
simplifying it first if possible using VALUEIZE if not NULL.
|
||||
ARG0 is expected to be valueized already. Returns the built
|
||||
expression value (or NULL_TREE if TYPE is void) and appends
|
||||
statements possibly defining it to SEQ. */
|
||||
|
||||
tree
|
||||
gimple_build (gimple_seq *seq, location_t loc,
|
||||
enum built_in_function fn, tree type, tree arg0,
|
||||
tree (*valueize)(tree))
|
||||
{
|
||||
tree res = gimple_simplify (fn, type, arg0, seq, valueize);
|
||||
if (!res)
|
||||
{
|
||||
tree decl = builtin_decl_implicit (fn);
|
||||
gimple stmt = gimple_build_call (decl, 1, arg0);
|
||||
if (!VOID_TYPE_P (type))
|
||||
{
|
||||
if (gimple_in_ssa_p (cfun))
|
||||
res = make_ssa_name (type, NULL);
|
||||
else
|
||||
res = create_tmp_reg (type, NULL);
|
||||
gimple_call_set_lhs (stmt, res);
|
||||
}
|
||||
gimple_set_location (stmt, loc);
|
||||
gimple_seq_add_stmt_without_update (seq, stmt);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Build the call FN (ARG0, ARG1) with a result of type TYPE
|
||||
(or no result if TYPE is void) with location LOC,
|
||||
simplifying it first if possible using VALUEIZE if not NULL.
|
||||
ARG0 is expected to be valueized already. Returns the built
|
||||
expression value (or NULL_TREE if TYPE is void) and appends
|
||||
statements possibly defining it to SEQ. */
|
||||
|
||||
tree
|
||||
gimple_build (gimple_seq *seq, location_t loc,
|
||||
enum built_in_function fn, tree type, tree arg0, tree arg1,
|
||||
tree (*valueize)(tree))
|
||||
{
|
||||
tree res = gimple_simplify (fn, type, arg0, arg1, seq, valueize);
|
||||
if (!res)
|
||||
{
|
||||
tree decl = builtin_decl_implicit (fn);
|
||||
gimple stmt = gimple_build_call (decl, 2, arg0, arg1);
|
||||
if (!VOID_TYPE_P (type))
|
||||
{
|
||||
if (gimple_in_ssa_p (cfun))
|
||||
res = make_ssa_name (type, NULL);
|
||||
else
|
||||
res = create_tmp_reg (type, NULL);
|
||||
gimple_call_set_lhs (stmt, res);
|
||||
}
|
||||
gimple_set_location (stmt, loc);
|
||||
gimple_seq_add_stmt_without_update (seq, stmt);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Build the call FN (ARG0, ARG1, ARG2) with a result of type TYPE
|
||||
(or no result if TYPE is void) with location LOC,
|
||||
simplifying it first if possible using VALUEIZE if not NULL.
|
||||
ARG0 is expected to be valueized already. Returns the built
|
||||
expression value (or NULL_TREE if TYPE is void) and appends
|
||||
statements possibly defining it to SEQ. */
|
||||
|
||||
tree
|
||||
gimple_build (gimple_seq *seq, location_t loc,
|
||||
enum built_in_function fn, tree type,
|
||||
tree arg0, tree arg1, tree arg2,
|
||||
tree (*valueize)(tree))
|
||||
{
|
||||
tree res = gimple_simplify (fn, type, arg0, arg1, arg2, seq, valueize);
|
||||
if (!res)
|
||||
{
|
||||
tree decl = builtin_decl_implicit (fn);
|
||||
gimple stmt = gimple_build_call (decl, 3, arg0, arg1, arg2);
|
||||
if (!VOID_TYPE_P (type))
|
||||
{
|
||||
if (gimple_in_ssa_p (cfun))
|
||||
res = make_ssa_name (type, NULL);
|
||||
else
|
||||
res = create_tmp_reg (type, NULL);
|
||||
gimple_call_set_lhs (stmt, res);
|
||||
}
|
||||
gimple_set_location (stmt, loc);
|
||||
gimple_seq_add_stmt_without_update (seq, stmt);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Build the conversion (TYPE) OP with a result of type TYPE
|
||||
with location LOC if such conversion is neccesary in GIMPLE,
|
||||
simplifying it first.
|
||||
Returns the built expression value and appends
|
||||
statements possibly defining it to SEQ. */
|
||||
|
||||
tree
|
||||
gimple_convert (gimple_seq *seq, location_t loc, tree type, tree op)
|
||||
{
|
||||
if (useless_type_conversion_p (type, TREE_TYPE (op)))
|
||||
return op;
|
||||
op = fold_convert_loc (loc, type, op);
|
||||
gimple_seq stmts = NULL;
|
||||
op = force_gimple_operand (op, &stmts, true, NULL_TREE);
|
||||
gimple_seq_add_seq_without_update (seq, stmts);
|
||||
return op;
|
||||
return gimple_build (seq, loc, NOP_EXPR, type, op);
|
||||
}
|
||||
|
|
|
@ -45,6 +45,65 @@ extern tree gimple_fold_indirect_ref (tree);
|
|||
extern bool arith_code_with_undefined_signed_overflow (tree_code);
|
||||
extern gimple_seq rewrite_to_defined_overflow (gimple);
|
||||
|
||||
/* gimple_build, functionally matching fold_buildN, outputs stmts
|
||||
int the provided sequence, matching and simplifying them on-the-fly.
|
||||
Supposed to replace force_gimple_operand (fold_buildN (...), ...). */
|
||||
extern tree gimple_build (gimple_seq *, location_t,
|
||||
enum tree_code, tree, tree,
|
||||
tree (*valueize) (tree) = NULL);
|
||||
inline tree
|
||||
gimple_build (gimple_seq *seq,
|
||||
enum tree_code code, tree type, tree op0)
|
||||
{
|
||||
return gimple_build (seq, UNKNOWN_LOCATION, code, type, op0);
|
||||
}
|
||||
extern tree gimple_build (gimple_seq *, location_t,
|
||||
enum tree_code, tree, tree, tree,
|
||||
tree (*valueize) (tree) = NULL);
|
||||
inline tree
|
||||
gimple_build (gimple_seq *seq,
|
||||
enum tree_code code, tree type, tree op0, tree op1)
|
||||
{
|
||||
return gimple_build (seq, UNKNOWN_LOCATION, code, type, op0, op1);
|
||||
}
|
||||
extern tree gimple_build (gimple_seq *, location_t,
|
||||
enum tree_code, tree, tree, tree, tree,
|
||||
tree (*valueize) (tree) = NULL);
|
||||
inline tree
|
||||
gimple_build (gimple_seq *seq,
|
||||
enum tree_code code, tree type, tree op0, tree op1, tree op2)
|
||||
{
|
||||
return gimple_build (seq, UNKNOWN_LOCATION, code, type, op0, op1, op2);
|
||||
}
|
||||
extern tree gimple_build (gimple_seq *, location_t,
|
||||
enum built_in_function, tree, tree,
|
||||
tree (*valueize) (tree) = NULL);
|
||||
inline tree
|
||||
gimple_build (gimple_seq *seq,
|
||||
enum built_in_function fn, tree type, tree arg0)
|
||||
{
|
||||
return gimple_build (seq, UNKNOWN_LOCATION, fn, type, arg0);
|
||||
}
|
||||
extern tree gimple_build (gimple_seq *, location_t,
|
||||
enum built_in_function, tree, tree, tree,
|
||||
tree (*valueize) (tree) = NULL);
|
||||
inline tree
|
||||
gimple_build (gimple_seq *seq,
|
||||
enum built_in_function fn, tree type, tree arg0, tree arg1)
|
||||
{
|
||||
return gimple_build (seq, UNKNOWN_LOCATION, fn, type, arg0, arg1);
|
||||
}
|
||||
extern tree gimple_build (gimple_seq *, location_t,
|
||||
enum built_in_function, tree, tree, tree, tree,
|
||||
tree (*valueize) (tree) = NULL);
|
||||
inline tree
|
||||
gimple_build (gimple_seq *seq,
|
||||
enum built_in_function fn, tree type,
|
||||
tree arg0, tree arg1, tree arg2)
|
||||
{
|
||||
return gimple_build (seq, UNKNOWN_LOCATION, fn, type, arg0, arg1, arg2);
|
||||
}
|
||||
|
||||
extern tree gimple_convert (gimple_seq *, location_t, tree, tree);
|
||||
inline tree
|
||||
gimple_convert (gimple_seq *seq, tree type, tree op)
|
||||
|
@ -52,4 +111,18 @@ gimple_convert (gimple_seq *seq, tree type, tree op)
|
|||
return gimple_convert (seq, UNKNOWN_LOCATION, type, op);
|
||||
}
|
||||
|
||||
/* In gimple-match.c. */
|
||||
extern tree gimple_simplify (enum tree_code, tree, tree,
|
||||
gimple_seq *, tree (*)(tree));
|
||||
extern tree gimple_simplify (enum tree_code, tree, tree, tree,
|
||||
gimple_seq *, tree (*)(tree));
|
||||
extern tree gimple_simplify (enum tree_code, tree, tree, tree, tree,
|
||||
gimple_seq *, tree (*)(tree));
|
||||
extern tree gimple_simplify (enum built_in_function, tree, tree,
|
||||
gimple_seq *, tree (*)(tree));
|
||||
extern tree gimple_simplify (enum built_in_function, tree, tree, tree,
|
||||
gimple_seq *, tree (*)(tree));
|
||||
extern tree gimple_simplify (enum built_in_function, tree, tree, tree, tree,
|
||||
gimple_seq *, tree (*)(tree));
|
||||
|
||||
#endif /* GCC_GIMPLE_FOLD_H */
|
||||
|
|
|
@ -0,0 +1,838 @@
|
|||
/* Preamble and helpers for the autogenerated gimple-match.c file.
|
||||
Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
#include "stringpool.h"
|
||||
#include "stor-layout.h"
|
||||
#include "flags.h"
|
||||
#include "tm.h"
|
||||
#include "hard-reg-set.h"
|
||||
#include "function.h"
|
||||
#include "basic-block.h"
|
||||
#include "tree-ssa-alias.h"
|
||||
#include "internal-fn.h"
|
||||
#include "gimple-expr.h"
|
||||
#include "is-a.h"
|
||||
#include "gimple.h"
|
||||
#include "gimple-ssa.h"
|
||||
#include "tree-ssanames.h"
|
||||
#include "gimple-fold.h"
|
||||
#include "gimple-iterator.h"
|
||||
#include "expr.h"
|
||||
#include "tree-dfa.h"
|
||||
#include "builtins.h"
|
||||
#include "tree-phinodes.h"
|
||||
#include "ssa-iterators.h"
|
||||
#include "dumpfile.h"
|
||||
#include "gimple-match.h"
|
||||
|
||||
|
||||
/* Forward declarations of the private auto-generated matchers.
|
||||
They expect valueized operands in canonical order and do not
|
||||
perform simplification of all-constant operands. */
|
||||
static bool gimple_simplify (code_helper *, tree *,
|
||||
gimple_seq *, tree (*)(tree),
|
||||
code_helper, tree, tree);
|
||||
static bool gimple_simplify (code_helper *, tree *,
|
||||
gimple_seq *, tree (*)(tree),
|
||||
code_helper, tree, tree, tree);
|
||||
static bool gimple_simplify (code_helper *, tree *,
|
||||
gimple_seq *, tree (*)(tree),
|
||||
code_helper, tree, tree, tree, tree);
|
||||
|
||||
|
||||
/* Return whether T is a constant that we'll dispatch to fold to
|
||||
evaluate fully constant expressions. */
|
||||
|
||||
static inline bool
|
||||
constant_for_folding (tree t)
|
||||
{
|
||||
return (CONSTANT_CLASS_P (t)
|
||||
/* The following is only interesting to string builtins. */
|
||||
|| (TREE_CODE (t) == ADDR_EXPR
|
||||
&& TREE_CODE (TREE_OPERAND (t, 0)) == STRING_CST));
|
||||
}
|
||||
|
||||
|
||||
/* Helper that matches and simplifies the toplevel result from
|
||||
a gimple_simplify run (where we don't want to build
|
||||
a stmt in case it's used in in-place folding). Replaces
|
||||
*RES_CODE and *RES_OPS with a simplified and/or canonicalized
|
||||
result and returns whether any change was made. */
|
||||
|
||||
static bool
|
||||
gimple_resimplify1 (gimple_seq *seq,
|
||||
code_helper *res_code, tree type, tree *res_ops,
|
||||
tree (*valueize)(tree))
|
||||
{
|
||||
if (constant_for_folding (res_ops[0]))
|
||||
{
|
||||
tree tem = NULL_TREE;
|
||||
if (res_code->is_tree_code ())
|
||||
tem = fold_unary_to_constant (*res_code, type, res_ops[0]);
|
||||
else
|
||||
{
|
||||
tree decl = builtin_decl_implicit (*res_code);
|
||||
if (decl)
|
||||
{
|
||||
tem = fold_builtin_n (UNKNOWN_LOCATION, decl, res_ops, 1, false);
|
||||
if (tem)
|
||||
{
|
||||
/* fold_builtin_n wraps the result inside a NOP_EXPR. */
|
||||
STRIP_NOPS (tem);
|
||||
tem = fold_convert (type, tem);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tem != NULL_TREE
|
||||
&& CONSTANT_CLASS_P (tem))
|
||||
{
|
||||
res_ops[0] = tem;
|
||||
res_ops[1] = NULL_TREE;
|
||||
res_ops[2] = NULL_TREE;
|
||||
*res_code = TREE_CODE (res_ops[0]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
code_helper res_code2;
|
||||
tree res_ops2[3] = {};
|
||||
if (gimple_simplify (&res_code2, res_ops2, seq, valueize,
|
||||
*res_code, type, res_ops[0]))
|
||||
{
|
||||
*res_code = res_code2;
|
||||
res_ops[0] = res_ops2[0];
|
||||
res_ops[1] = res_ops2[1];
|
||||
res_ops[2] = res_ops2[2];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Helper that matches and simplifies the toplevel result from
|
||||
a gimple_simplify run (where we don't want to build
|
||||
a stmt in case it's used in in-place folding). Replaces
|
||||
*RES_CODE and *RES_OPS with a simplified and/or canonicalized
|
||||
result and returns whether any change was made. */
|
||||
|
||||
static bool
|
||||
gimple_resimplify2 (gimple_seq *seq,
|
||||
code_helper *res_code, tree type, tree *res_ops,
|
||||
tree (*valueize)(tree))
|
||||
{
|
||||
if (constant_for_folding (res_ops[0]) && constant_for_folding (res_ops[1]))
|
||||
{
|
||||
tree tem = NULL_TREE;
|
||||
if (res_code->is_tree_code ())
|
||||
tem = fold_binary_to_constant (*res_code, type,
|
||||
res_ops[0], res_ops[1]);
|
||||
else
|
||||
{
|
||||
tree decl = builtin_decl_implicit (*res_code);
|
||||
if (decl)
|
||||
{
|
||||
tem = fold_builtin_n (UNKNOWN_LOCATION, decl, res_ops, 2, false);
|
||||
if (tem)
|
||||
{
|
||||
/* fold_builtin_n wraps the result inside a NOP_EXPR. */
|
||||
STRIP_NOPS (tem);
|
||||
tem = fold_convert (type, tem);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tem != NULL_TREE
|
||||
&& CONSTANT_CLASS_P (tem))
|
||||
{
|
||||
res_ops[0] = tem;
|
||||
res_ops[1] = NULL_TREE;
|
||||
res_ops[2] = NULL_TREE;
|
||||
*res_code = TREE_CODE (res_ops[0]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Canonicalize operand order. */
|
||||
bool canonicalized = false;
|
||||
if (res_code->is_tree_code ()
|
||||
&& (TREE_CODE_CLASS ((enum tree_code) *res_code) == tcc_comparison
|
||||
|| commutative_tree_code (*res_code))
|
||||
&& tree_swap_operands_p (res_ops[0], res_ops[1], false))
|
||||
{
|
||||
tree tem = res_ops[0];
|
||||
res_ops[0] = res_ops[1];
|
||||
res_ops[1] = tem;
|
||||
if (TREE_CODE_CLASS ((enum tree_code) *res_code) == tcc_comparison)
|
||||
*res_code = swap_tree_comparison (*res_code);
|
||||
canonicalized = true;
|
||||
}
|
||||
|
||||
code_helper res_code2;
|
||||
tree res_ops2[3] = {};
|
||||
if (gimple_simplify (&res_code2, res_ops2, seq, valueize,
|
||||
*res_code, type, res_ops[0], res_ops[1]))
|
||||
{
|
||||
*res_code = res_code2;
|
||||
res_ops[0] = res_ops2[0];
|
||||
res_ops[1] = res_ops2[1];
|
||||
res_ops[2] = res_ops2[2];
|
||||
return true;
|
||||
}
|
||||
|
||||
return canonicalized;
|
||||
}
|
||||
|
||||
/* Helper that matches and simplifies the toplevel result from
|
||||
a gimple_simplify run (where we don't want to build
|
||||
a stmt in case it's used in in-place folding). Replaces
|
||||
*RES_CODE and *RES_OPS with a simplified and/or canonicalized
|
||||
result and returns whether any change was made. */
|
||||
|
||||
static bool
|
||||
gimple_resimplify3 (gimple_seq *seq,
|
||||
code_helper *res_code, tree type, tree *res_ops,
|
||||
tree (*valueize)(tree))
|
||||
{
|
||||
if (constant_for_folding (res_ops[0]) && constant_for_folding (res_ops[1])
|
||||
&& constant_for_folding (res_ops[2]))
|
||||
{
|
||||
tree tem = NULL_TREE;
|
||||
if (res_code->is_tree_code ())
|
||||
tem = fold_ternary/*_to_constant*/ (*res_code, type, res_ops[0],
|
||||
res_ops[1], res_ops[2]);
|
||||
else
|
||||
{
|
||||
tree decl = builtin_decl_implicit (*res_code);
|
||||
if (decl)
|
||||
{
|
||||
tem = fold_builtin_n (UNKNOWN_LOCATION, decl, res_ops, 3, false);
|
||||
if (tem)
|
||||
{
|
||||
/* fold_builtin_n wraps the result inside a NOP_EXPR. */
|
||||
STRIP_NOPS (tem);
|
||||
tem = fold_convert (type, tem);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tem != NULL_TREE
|
||||
&& CONSTANT_CLASS_P (tem))
|
||||
{
|
||||
res_ops[0] = tem;
|
||||
res_ops[1] = NULL_TREE;
|
||||
res_ops[2] = NULL_TREE;
|
||||
*res_code = TREE_CODE (res_ops[0]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Canonicalize operand order. */
|
||||
bool canonicalized = false;
|
||||
if (res_code->is_tree_code ()
|
||||
&& commutative_ternary_tree_code (*res_code)
|
||||
&& tree_swap_operands_p (res_ops[0], res_ops[1], false))
|
||||
{
|
||||
tree tem = res_ops[0];
|
||||
res_ops[0] = res_ops[1];
|
||||
res_ops[1] = tem;
|
||||
canonicalized = true;
|
||||
}
|
||||
|
||||
code_helper res_code2;
|
||||
tree res_ops2[3] = {};
|
||||
if (gimple_simplify (&res_code2, res_ops2, seq, valueize,
|
||||
*res_code, type,
|
||||
res_ops[0], res_ops[1], res_ops[2]))
|
||||
{
|
||||
*res_code = res_code2;
|
||||
res_ops[0] = res_ops2[0];
|
||||
res_ops[1] = res_ops2[1];
|
||||
res_ops[2] = res_ops2[2];
|
||||
return true;
|
||||
}
|
||||
|
||||
return canonicalized;
|
||||
}
|
||||
|
||||
|
||||
/* If in GIMPLE expressions with CODE go as single-rhs build
|
||||
a GENERIC tree for that expression into *OP0. */
|
||||
|
||||
void
|
||||
maybe_build_generic_op (enum tree_code code, tree type,
|
||||
tree *op0, tree op1, tree op2)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case REALPART_EXPR:
|
||||
case IMAGPART_EXPR:
|
||||
case VIEW_CONVERT_EXPR:
|
||||
*op0 = build1 (code, type, *op0);
|
||||
break;
|
||||
case BIT_FIELD_REF:
|
||||
*op0 = build3 (code, type, *op0, op1, op2);
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
/* Push the exploded expression described by RCODE, TYPE and OPS
|
||||
as a statement to SEQ if necessary and return a gimple value
|
||||
denoting the value of the expression. If RES is not NULL
|
||||
then the result will be always RES and even gimple values are
|
||||
pushed to SEQ. */
|
||||
|
||||
tree
|
||||
maybe_push_res_to_seq (code_helper rcode, tree type, tree *ops,
|
||||
gimple_seq *seq, tree res)
|
||||
{
|
||||
if (rcode.is_tree_code ())
|
||||
{
|
||||
if (!res
|
||||
&& (TREE_CODE_LENGTH ((tree_code) rcode) == 0
|
||||
|| ((tree_code) rcode) == ADDR_EXPR)
|
||||
&& is_gimple_val (ops[0]))
|
||||
return ops[0];
|
||||
if (!seq)
|
||||
return NULL_TREE;
|
||||
/* Play safe and do not allow abnormals to be mentioned in
|
||||
newly created statements. */
|
||||
if ((TREE_CODE (ops[0]) == SSA_NAME
|
||||
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[0]))
|
||||
|| (ops[1]
|
||||
&& TREE_CODE (ops[1]) == SSA_NAME
|
||||
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[1]))
|
||||
|| (ops[2]
|
||||
&& TREE_CODE (ops[2]) == SSA_NAME
|
||||
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[2])))
|
||||
return NULL_TREE;
|
||||
if (!res)
|
||||
res = make_ssa_name (type, NULL);
|
||||
maybe_build_generic_op (rcode, type, &ops[0], ops[1], ops[2]);
|
||||
gimple new_stmt = gimple_build_assign_with_ops (rcode, res,
|
||||
ops[0], ops[1], ops[2]);
|
||||
gimple_seq_add_stmt_without_update (seq, new_stmt);
|
||||
return res;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!seq)
|
||||
return NULL_TREE;
|
||||
tree decl = builtin_decl_implicit (rcode);
|
||||
if (!decl)
|
||||
return NULL_TREE;
|
||||
unsigned nargs = type_num_arguments (TREE_TYPE (decl));
|
||||
gcc_assert (nargs <= 3);
|
||||
/* Play safe and do not allow abnormals to be mentioned in
|
||||
newly created statements. */
|
||||
if ((TREE_CODE (ops[0]) == SSA_NAME
|
||||
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[0]))
|
||||
|| (nargs >= 2
|
||||
&& TREE_CODE (ops[1]) == SSA_NAME
|
||||
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[1]))
|
||||
|| (nargs == 3
|
||||
&& TREE_CODE (ops[2]) == SSA_NAME
|
||||
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[2])))
|
||||
return NULL_TREE;
|
||||
if (!res)
|
||||
res = make_ssa_name (type, NULL);
|
||||
gimple new_stmt = gimple_build_call (decl, nargs, ops[0], ops[1], ops[2]);
|
||||
gimple_call_set_lhs (new_stmt, res);
|
||||
gimple_seq_add_stmt_without_update (seq, new_stmt);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Public API overloads follow for operation being tree_code or
|
||||
built_in_function and for one to three operands or arguments.
|
||||
They return NULL_TREE if nothing could be simplified or
|
||||
the resulting simplified value with parts pushed to SEQ.
|
||||
If SEQ is NULL then if the simplification needs to create
|
||||
new stmts it will fail. If VALUEIZE is non-NULL then all
|
||||
SSA names will be valueized using that hook prior to
|
||||
applying simplifications. */
|
||||
|
||||
/* Unary ops. */
|
||||
|
||||
tree
|
||||
gimple_simplify (enum tree_code code, tree type,
|
||||
tree op0,
|
||||
gimple_seq *seq, tree (*valueize)(tree))
|
||||
{
|
||||
if (constant_for_folding (op0))
|
||||
{
|
||||
tree res = fold_unary_to_constant (code, type, op0);
|
||||
if (res != NULL_TREE
|
||||
&& CONSTANT_CLASS_P (res))
|
||||
return res;
|
||||
}
|
||||
|
||||
code_helper rcode;
|
||||
tree ops[3] = {};
|
||||
if (!gimple_simplify (&rcode, ops, seq, valueize,
|
||||
code, type, op0))
|
||||
return NULL_TREE;
|
||||
return maybe_push_res_to_seq (rcode, type, ops, seq);
|
||||
}
|
||||
|
||||
/* Binary ops. */
|
||||
|
||||
tree
|
||||
gimple_simplify (enum tree_code code, tree type,
|
||||
tree op0, tree op1,
|
||||
gimple_seq *seq, tree (*valueize)(tree))
|
||||
{
|
||||
if (constant_for_folding (op0) && constant_for_folding (op1))
|
||||
{
|
||||
tree res = fold_binary_to_constant (code, type, op0, op1);
|
||||
if (res != NULL_TREE
|
||||
&& CONSTANT_CLASS_P (res))
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Canonicalize operand order both for matching and fallback stmt
|
||||
generation. */
|
||||
if ((commutative_tree_code (code)
|
||||
|| TREE_CODE_CLASS (code) == tcc_comparison)
|
||||
&& tree_swap_operands_p (op0, op1, false))
|
||||
{
|
||||
tree tem = op0;
|
||||
op0 = op1;
|
||||
op1 = tem;
|
||||
if (TREE_CODE_CLASS (code) == tcc_comparison)
|
||||
code = swap_tree_comparison (code);
|
||||
}
|
||||
|
||||
code_helper rcode;
|
||||
tree ops[3] = {};
|
||||
if (!gimple_simplify (&rcode, ops, seq, valueize,
|
||||
code, type, op0, op1))
|
||||
return NULL_TREE;
|
||||
return maybe_push_res_to_seq (rcode, type, ops, seq);
|
||||
}
|
||||
|
||||
/* Ternary ops. */
|
||||
|
||||
tree
|
||||
gimple_simplify (enum tree_code code, tree type,
|
||||
tree op0, tree op1, tree op2,
|
||||
gimple_seq *seq, tree (*valueize)(tree))
|
||||
{
|
||||
if (constant_for_folding (op0) && constant_for_folding (op1)
|
||||
&& constant_for_folding (op2))
|
||||
{
|
||||
tree res = fold_ternary/*_to_constant */ (code, type, op0, op1, op2);
|
||||
if (res != NULL_TREE
|
||||
&& CONSTANT_CLASS_P (res))
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Canonicalize operand order both for matching and fallback stmt
|
||||
generation. */
|
||||
if (commutative_ternary_tree_code (code)
|
||||
&& tree_swap_operands_p (op0, op1, false))
|
||||
{
|
||||
tree tem = op0;
|
||||
op0 = op1;
|
||||
op1 = tem;
|
||||
}
|
||||
|
||||
code_helper rcode;
|
||||
tree ops[3] = {};
|
||||
if (!gimple_simplify (&rcode, ops, seq, valueize,
|
||||
code, type, op0, op1, op2))
|
||||
return NULL_TREE;
|
||||
return maybe_push_res_to_seq (rcode, type, ops, seq);
|
||||
}
|
||||
|
||||
/* Builtin function with one argument. */
|
||||
|
||||
tree
|
||||
gimple_simplify (enum built_in_function fn, tree type,
|
||||
tree arg0,
|
||||
gimple_seq *seq, tree (*valueize)(tree))
|
||||
{
|
||||
if (constant_for_folding (arg0))
|
||||
{
|
||||
tree decl = builtin_decl_implicit (fn);
|
||||
if (decl)
|
||||
{
|
||||
tree res = fold_builtin_n (UNKNOWN_LOCATION, decl, &arg0, 1, false);
|
||||
if (res)
|
||||
{
|
||||
/* fold_builtin_n wraps the result inside a NOP_EXPR. */
|
||||
STRIP_NOPS (res);
|
||||
res = fold_convert (type, res);
|
||||
if (CONSTANT_CLASS_P (res))
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
code_helper rcode;
|
||||
tree ops[3] = {};
|
||||
if (!gimple_simplify (&rcode, ops, seq, valueize,
|
||||
fn, type, arg0))
|
||||
return NULL_TREE;
|
||||
return maybe_push_res_to_seq (rcode, type, ops, seq);
|
||||
}
|
||||
|
||||
/* Builtin function with two arguments. */
|
||||
|
||||
tree
|
||||
gimple_simplify (enum built_in_function fn, tree type,
|
||||
tree arg0, tree arg1,
|
||||
gimple_seq *seq, tree (*valueize)(tree))
|
||||
{
|
||||
if (constant_for_folding (arg0)
|
||||
&& constant_for_folding (arg1))
|
||||
{
|
||||
tree decl = builtin_decl_implicit (fn);
|
||||
if (decl)
|
||||
{
|
||||
tree args[2];
|
||||
args[0] = arg0;
|
||||
args[1] = arg1;
|
||||
tree res = fold_builtin_n (UNKNOWN_LOCATION, decl, args, 2, false);
|
||||
if (res)
|
||||
{
|
||||
/* fold_builtin_n wraps the result inside a NOP_EXPR. */
|
||||
STRIP_NOPS (res);
|
||||
res = fold_convert (type, res);
|
||||
if (CONSTANT_CLASS_P (res))
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
code_helper rcode;
|
||||
tree ops[3] = {};
|
||||
if (!gimple_simplify (&rcode, ops, seq, valueize,
|
||||
fn, type, arg0, arg1))
|
||||
return NULL_TREE;
|
||||
return maybe_push_res_to_seq (rcode, type, ops, seq);
|
||||
}
|
||||
|
||||
/* Builtin function with three arguments. */
|
||||
|
||||
tree
|
||||
gimple_simplify (enum built_in_function fn, tree type,
|
||||
tree arg0, tree arg1, tree arg2,
|
||||
gimple_seq *seq, tree (*valueize)(tree))
|
||||
{
|
||||
if (constant_for_folding (arg0)
|
||||
&& constant_for_folding (arg1)
|
||||
&& constant_for_folding (arg2))
|
||||
{
|
||||
tree decl = builtin_decl_implicit (fn);
|
||||
if (decl)
|
||||
{
|
||||
tree args[3];
|
||||
args[0] = arg0;
|
||||
args[1] = arg1;
|
||||
args[2] = arg2;
|
||||
tree res = fold_builtin_n (UNKNOWN_LOCATION, decl, args, 3, false);
|
||||
if (res)
|
||||
{
|
||||
/* fold_builtin_n wraps the result inside a NOP_EXPR. */
|
||||
STRIP_NOPS (res);
|
||||
res = fold_convert (type, res);
|
||||
if (CONSTANT_CLASS_P (res))
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
code_helper rcode;
|
||||
tree ops[3] = {};
|
||||
if (!gimple_simplify (&rcode, ops, seq, valueize,
|
||||
fn, type, arg0, arg1, arg2))
|
||||
return NULL_TREE;
|
||||
return maybe_push_res_to_seq (rcode, type, ops, seq);
|
||||
}
|
||||
|
||||
|
||||
/* The main STMT based simplification entry. It is used by the fold_stmt
|
||||
and the fold_stmt_to_constant APIs. */
|
||||
|
||||
bool
|
||||
gimple_simplify (gimple stmt,
|
||||
code_helper *rcode, tree *ops,
|
||||
gimple_seq *seq, tree (*valueize)(tree))
|
||||
{
|
||||
switch (gimple_code (stmt))
|
||||
{
|
||||
case GIMPLE_ASSIGN:
|
||||
{
|
||||
enum tree_code code = gimple_assign_rhs_code (stmt);
|
||||
tree type = TREE_TYPE (gimple_assign_lhs (stmt));
|
||||
switch (gimple_assign_rhs_class (stmt))
|
||||
{
|
||||
case GIMPLE_SINGLE_RHS:
|
||||
if (code == REALPART_EXPR
|
||||
|| code == IMAGPART_EXPR
|
||||
|| code == VIEW_CONVERT_EXPR)
|
||||
{
|
||||
tree op0 = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0);
|
||||
if (valueize && TREE_CODE (op0) == SSA_NAME)
|
||||
{
|
||||
tree tem = valueize (op0);
|
||||
if (tem)
|
||||
op0 = tem;
|
||||
}
|
||||
*rcode = code;
|
||||
ops[0] = op0;
|
||||
return gimple_resimplify1 (seq, rcode, type, ops, valueize);
|
||||
}
|
||||
else if (code == BIT_FIELD_REF)
|
||||
{
|
||||
tree rhs1 = gimple_assign_rhs1 (stmt);
|
||||
tree op0 = TREE_OPERAND (rhs1, 0);
|
||||
if (valueize && TREE_CODE (op0) == SSA_NAME)
|
||||
{
|
||||
tree tem = valueize (op0);
|
||||
if (tem)
|
||||
op0 = tem;
|
||||
}
|
||||
*rcode = code;
|
||||
ops[0] = op0;
|
||||
ops[1] = TREE_OPERAND (rhs1, 1);
|
||||
ops[2] = TREE_OPERAND (rhs1, 2);
|
||||
return gimple_resimplify3 (seq, rcode, type, ops, valueize);
|
||||
}
|
||||
else if (code == SSA_NAME
|
||||
&& valueize)
|
||||
{
|
||||
tree op0 = gimple_assign_rhs1 (stmt);
|
||||
tree valueized = valueize (op0);
|
||||
if (!valueized || op0 == valueized)
|
||||
return false;
|
||||
ops[0] = valueized;
|
||||
*rcode = TREE_CODE (op0);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case GIMPLE_UNARY_RHS:
|
||||
{
|
||||
tree rhs1 = gimple_assign_rhs1 (stmt);
|
||||
if (valueize && TREE_CODE (rhs1) == SSA_NAME)
|
||||
{
|
||||
tree tem = valueize (rhs1);
|
||||
if (tem)
|
||||
rhs1 = tem;
|
||||
}
|
||||
*rcode = code;
|
||||
ops[0] = rhs1;
|
||||
return gimple_resimplify1 (seq, rcode, type, ops, valueize);
|
||||
}
|
||||
case GIMPLE_BINARY_RHS:
|
||||
{
|
||||
tree rhs1 = gimple_assign_rhs1 (stmt);
|
||||
if (valueize && TREE_CODE (rhs1) == SSA_NAME)
|
||||
{
|
||||
tree tem = valueize (rhs1);
|
||||
if (tem)
|
||||
rhs1 = tem;
|
||||
}
|
||||
tree rhs2 = gimple_assign_rhs2 (stmt);
|
||||
if (valueize && TREE_CODE (rhs2) == SSA_NAME)
|
||||
{
|
||||
tree tem = valueize (rhs2);
|
||||
if (tem)
|
||||
rhs2 = tem;
|
||||
}
|
||||
*rcode = code;
|
||||
ops[0] = rhs1;
|
||||
ops[1] = rhs2;
|
||||
return gimple_resimplify2 (seq, rcode, type, ops, valueize);
|
||||
}
|
||||
case GIMPLE_TERNARY_RHS:
|
||||
{
|
||||
tree rhs1 = gimple_assign_rhs1 (stmt);
|
||||
if (valueize && TREE_CODE (rhs1) == SSA_NAME)
|
||||
{
|
||||
tree tem = valueize (rhs1);
|
||||
if (tem)
|
||||
rhs1 = tem;
|
||||
}
|
||||
tree rhs2 = gimple_assign_rhs2 (stmt);
|
||||
if (valueize && TREE_CODE (rhs2) == SSA_NAME)
|
||||
{
|
||||
tree tem = valueize (rhs2);
|
||||
if (tem)
|
||||
rhs2 = tem;
|
||||
}
|
||||
tree rhs3 = gimple_assign_rhs3 (stmt);
|
||||
if (valueize && TREE_CODE (rhs3) == SSA_NAME)
|
||||
{
|
||||
tree tem = valueize (rhs3);
|
||||
if (tem)
|
||||
rhs3 = tem;
|
||||
}
|
||||
*rcode = code;
|
||||
ops[0] = rhs1;
|
||||
ops[1] = rhs2;
|
||||
ops[2] = rhs3;
|
||||
return gimple_resimplify3 (seq, rcode, type, ops, valueize);
|
||||
}
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case GIMPLE_CALL:
|
||||
/* ??? This way we can't simplify calls with side-effects. */
|
||||
if (gimple_call_lhs (stmt) != NULL_TREE)
|
||||
{
|
||||
tree fn = gimple_call_fn (stmt);
|
||||
/* ??? Internal function support missing. */
|
||||
if (!fn)
|
||||
return false;
|
||||
if (valueize && TREE_CODE (fn) == SSA_NAME)
|
||||
{
|
||||
tree tem = valueize (fn);
|
||||
if (tem)
|
||||
fn = tem;
|
||||
}
|
||||
if (!fn
|
||||
|| TREE_CODE (fn) != ADDR_EXPR
|
||||
|| TREE_CODE (TREE_OPERAND (fn, 0)) != FUNCTION_DECL
|
||||
|| DECL_BUILT_IN_CLASS (TREE_OPERAND (fn, 0)) != BUILT_IN_NORMAL
|
||||
|| !builtin_decl_implicit (DECL_FUNCTION_CODE (TREE_OPERAND (fn, 0)))
|
||||
|| !gimple_builtin_call_types_compatible_p (stmt,
|
||||
TREE_OPERAND (fn, 0)))
|
||||
return false;
|
||||
|
||||
tree decl = TREE_OPERAND (fn, 0);
|
||||
tree type = TREE_TYPE (gimple_call_lhs (stmt));
|
||||
switch (gimple_call_num_args (stmt))
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
tree arg1 = gimple_call_arg (stmt, 0);
|
||||
if (valueize && TREE_CODE (arg1) == SSA_NAME)
|
||||
{
|
||||
tree tem = valueize (arg1);
|
||||
if (tem)
|
||||
arg1 = tem;
|
||||
}
|
||||
*rcode = DECL_FUNCTION_CODE (decl);
|
||||
ops[0] = arg1;
|
||||
return gimple_resimplify1 (seq, rcode, type, ops, valueize);
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
tree arg1 = gimple_call_arg (stmt, 0);
|
||||
if (valueize && TREE_CODE (arg1) == SSA_NAME)
|
||||
{
|
||||
tree tem = valueize (arg1);
|
||||
if (tem)
|
||||
arg1 = tem;
|
||||
}
|
||||
tree arg2 = gimple_call_arg (stmt, 1);
|
||||
if (valueize && TREE_CODE (arg2) == SSA_NAME)
|
||||
{
|
||||
tree tem = valueize (arg2);
|
||||
if (tem)
|
||||
arg2 = tem;
|
||||
}
|
||||
*rcode = DECL_FUNCTION_CODE (decl);
|
||||
ops[0] = arg1;
|
||||
ops[1] = arg2;
|
||||
return gimple_resimplify2 (seq, rcode, type, ops, valueize);
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
tree arg1 = gimple_call_arg (stmt, 0);
|
||||
if (valueize && TREE_CODE (arg1) == SSA_NAME)
|
||||
{
|
||||
tree tem = valueize (arg1);
|
||||
if (tem)
|
||||
arg1 = tem;
|
||||
}
|
||||
tree arg2 = gimple_call_arg (stmt, 1);
|
||||
if (valueize && TREE_CODE (arg2) == SSA_NAME)
|
||||
{
|
||||
tree tem = valueize (arg2);
|
||||
if (tem)
|
||||
arg2 = tem;
|
||||
}
|
||||
tree arg3 = gimple_call_arg (stmt, 2);
|
||||
if (valueize && TREE_CODE (arg3) == SSA_NAME)
|
||||
{
|
||||
tree tem = valueize (arg3);
|
||||
if (tem)
|
||||
arg3 = tem;
|
||||
}
|
||||
*rcode = DECL_FUNCTION_CODE (decl);
|
||||
ops[0] = arg1;
|
||||
ops[1] = arg2;
|
||||
ops[2] = arg3;
|
||||
return gimple_resimplify3 (seq, rcode, type, ops, valueize);
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GIMPLE_COND:
|
||||
{
|
||||
tree lhs = gimple_cond_lhs (stmt);
|
||||
if (valueize && TREE_CODE (lhs) == SSA_NAME)
|
||||
{
|
||||
tree tem = valueize (lhs);
|
||||
if (tem)
|
||||
lhs = tem;
|
||||
}
|
||||
tree rhs = gimple_cond_rhs (stmt);
|
||||
if (valueize && TREE_CODE (rhs) == SSA_NAME)
|
||||
{
|
||||
tree tem = valueize (rhs);
|
||||
if (tem)
|
||||
rhs = tem;
|
||||
}
|
||||
*rcode = gimple_cond_code (stmt);
|
||||
ops[0] = lhs;
|
||||
ops[1] = rhs;
|
||||
return gimple_resimplify2 (seq, rcode, boolean_type_node, ops, valueize);
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Helper for the autogenerated code, valueize OP. */
|
||||
|
||||
inline tree
|
||||
do_valueize (tree (*valueize)(tree), tree op)
|
||||
{
|
||||
if (valueize && TREE_CODE (op) == SSA_NAME)
|
||||
return valueize (op);
|
||||
return op;
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/* Gimple simplify definitions.
|
||||
|
||||
Copyright (C) 2011-2014 Free Software Foundation, Inc.
|
||||
Contributed by Richard Guenther <rguenther@suse.de>
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef GCC_GIMPLE_MATCH_H
|
||||
#define GCC_GIMPLE_MATCH_H
|
||||
|
||||
|
||||
/* Helper to transparently allow tree codes and builtin function codes
|
||||
exist in one storage entity. */
|
||||
class code_helper
|
||||
{
|
||||
public:
|
||||
code_helper () {}
|
||||
code_helper (tree_code code) : rep ((int) code) {}
|
||||
code_helper (built_in_function fn) : rep (-(int) fn) {}
|
||||
operator tree_code () const { return (tree_code) rep; }
|
||||
operator built_in_function () const { return (built_in_function) -rep; }
|
||||
bool is_tree_code () const { return rep > 0; }
|
||||
bool is_fn_code () const { return rep < 0; }
|
||||
int get_rep () const { return rep; }
|
||||
private:
|
||||
int rep;
|
||||
};
|
||||
|
||||
bool gimple_simplify (gimple, code_helper *, tree *, gimple_seq *,
|
||||
tree (*)(tree));
|
||||
tree maybe_push_res_to_seq (code_helper, tree, tree *,
|
||||
gimple_seq *, tree res = NULL_TREE);
|
||||
void maybe_build_generic_op (enum tree_code, tree, tree *, tree, tree);
|
||||
|
||||
|
||||
#endif /* GCC_GIMPLE_MATCH_H */
|
|
@ -0,0 +1,30 @@
|
|||
/* Match-and-simplify patterns for shared GENERIC and GIMPLE folding.
|
||||
This file is consumed by genmatch which produces gimple-match.c
|
||||
and generic-match.c from it.
|
||||
|
||||
Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
Contributed by Richard Biener <rguenther@suse.de>
|
||||
and Prathamesh Kulkarni <bilbotheelffriend@gmail.com>
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
/* Generic tree predicates we inherit. */
|
||||
(define_predicates
|
||||
integer_onep integer_zerop integer_all_onesp
|
||||
real_zerop real_onep
|
||||
CONSTANT_CLASS_P)
|
Loading…
Reference in New Issue