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:
Richard Biener 2014-10-22 08:42:37 +00:00 committed by Richard Biener
parent 7d9f1cd276
commit 3d2cf79f81
13 changed files with 4648 additions and 15 deletions

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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.

48
gcc/generic-match-head.c Normal file
View File

@ -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"

3039
gcc/genmatch.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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);
}

View File

@ -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 */

838
gcc/gimple-match-head.c Normal file
View File

@ -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;
}

50
gcc/gimple-match.h Normal file
View File

@ -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 */

30
gcc/match.pd Normal file
View File

@ -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)