From patchwork Fri Aug 13 15:31:26 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [gimplefe] Skeleton GIMPLE front end Date: Fri, 13 Aug 2010 05:31:26 -0000 From: Diego Novillo X-Patchwork-Id: 61698 Message-Id: <20100813153126.GA9315@google.com> To: gcc-patches@gcc.gnu.org, Sandeep Soni This adds a new front end in gcc/gimple. It moves all the parsing bits from lto/lto.c into gimple/gimple.c and nothing else. The front end is built by default, or it can be configured with --enable-languages=gimple. The binary is named gimple1. I have not changed anything else, other than what was needed to get gimple1 built. In particular, it still tries to open /tmp/gimple.txt unconditionally. I will change that in a follow up patch, to recognize .gimple files as source code. Sandeep, when modifying the parser now, you need to edit gcc/gimple/parser.c. ChangeLog entries for everything under gcc/gimple/ should go to gcc/gimple/ChangeLog. Only use gcc/ChangeLog.gimplefe when changing files in gcc/ Tested on x86_64. Committed. ChangeLog.gimplefe: 2010-08-13 Diego Novillo * lto/lto-lang.c (LANG_HOOKS_NAME): Update. * common.opt (fgimple-parser): Remove. * lto/lto.c (lto_main): Do not handle flag_gimple_parser. * lto/lto.c (gimple parse_expect_op1, gimple_parse_assign_stmt, gimple_parse_call_stmt, gimple_parse_cond_stmt, gimple_parse_expect_argument, gimple_parse_expect_false_label, gimple_parse_expect_function_name, gimple_parse_expect_lhs, gimple_parse_expect_op1, gimple_parse_expect_op2, gimple_parse_expect_return_var, gimple_parse_expect_rhs1, gimple_parse_expect_rhs2, gimple_parse_expect_subcode, gimple_parse_expect_token, gimple_parse_expect_true_label, gimple_parse_goto_stmt, gimple_parse_label_stmt, gimple_parse_return_stmt, gimple_parse_stmt, gimple_parse_switch_stmt): Move to gimple/parser.c. gimple/ChangeLog: 2010-08-12 Diego Novillo * parser.c (gimple parse_expect_op1, gimple_parse_assign_stmt, gimple_parse_call_stmt, gimple_parse_cond_stmt, gimple_parse_expect_argument, gimple_parse_expect_false_label, gimple_parse_expect_function_name, gimple_parse_expect_lhs, gimple_parse_expect_op1, gimple_parse_expect_op2, gimple_parse_expect_return_var, gimple_parse_expect_rhs1, gimple_parse_expect_rhs2, gimple_parse_expect_subcode, gimple_parse_expect_token, gimple_parse_expect_true_label, gimple_parse_goto_stmt, gimple_parse_label_stmt, gimple_parse_return_stmt, gimple_parse_stmt, gimple_parse_switch_stmt): Move from ../lto/lto.c. 2010-08-12 Diego Novillo * Make-lang.in: New file. * config-lang.in: New file. * gimple-lang.c: New file. * lang-specs.h: New file. * lang.opt: New file. * parser.c: New file. * parser.h: New file. diff --git a/gcc/common.opt b/gcc/common.opt index ecd2340..0fe09a8 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -605,11 +605,6 @@ Perform global common subexpression elimination after register allocation has finished ; This option is not documented yet as its semantics will change. -fgimple-parser -Common Var(flag_gimple_parser) -This option will be used to invoke the gimple text parser. - -; This option is not documented yet as its semantics will change. fgraphite Common Report Var(flag_graphite) Enable in and out of Graphite representation diff --git a/gcc/gimple/Make-lang.in b/gcc/gimple/Make-lang.in new file mode 100644 index 0000000..bb50d32 --- /dev/null +++ b/gcc/gimple/Make-lang.in @@ -0,0 +1,84 @@ +# Top level -*- makefile -*- fragment for GIMPLE +# Copyright (C) 2010 +# 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 +# . + +# Variables + +# The name of the GIMPLE compiler. +GIMPLE_EXE = gimple1$(exeext) +# The GIMPLE-specific object files inclued in $(GIMPLE_EXE). +GIMPLE_OBJS = gimple/gimple-lang.o gimple/parser.o attribs.o +GIMPLE_PARSER_H = gimple/parser.h +GIMPLE_TREE_H = gimple/gimple-tree.h + +# Rules + +# These hooks are used by the main GCC Makefile. Consult that +# Makefile for documentation. +gimple.all.cross: $(GIMPLE_EXE) +gimple.start.encap: $(GIMPLE_EXE) +gimple.rest.encap: +gimple.tags: +gimple.install-common: +gimple.install-man: +gimple.install-info: +gimple.dvi: +gimple.pdf: +gimple.install-pdf: +gimple.html: +gimple.install-html: +gimple.uninstall: +gimple.info: +gimple.man: +gimple.srcextra: +gimple.srcman: +gimple.srcinfo: +gimple.install-plugin: + +gimple.mostlyclean: + rm -f $(GIMPLE_OBJS) $(GIMPLE_EXE) + +gimple.clean: +gimple.distclean: +gimple.maintainer-clean: +gimple.stage1: +gimple.stage2: +gimple.stage3: +gimple.stage4: +gimple.stageprofile: +gimple.stagefeedback: + +# GIMPLE rules. + +# Use strict warnings for this front end. +gimple-warn = $(STRICT_WARN) + +$(GIMPLE_EXE): $(GIMPLE_OBJS) $(BACKEND) $(LIBDEPS) + $(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \ + $(GIMPLE_OBJS) $(BACKEND) $(BACKENDLIBS) $(LIBS) + +# Dependencies +gimple/gimple-lang.o: gimple/gimple-lang.c $(CONFIG_H) $(SYSTEM_H) \ + coretypes.h flags.h $(TM_H) $(TREE_H) $(TARGET_H) \ + langhooks.h $(LANGHOOKS_DEF_H) debug.h $(GIMPLE_PARSER_H) \ + $(DIAGNOSTIC_CORE_H) $(TOPLEV_H) $(GIMPLE_TREE_H) \ + $(GGC_H) gtype-gimple.h gt-gimple-gimple-lang.h +gimple/parser.o: gimple/parser.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(CPPLIB_H) $(INPUT_H) $(DIAGNOSTIC_H) $(TREE_H) $(GIMPLE_H) \ + $(TOPLEV_H) $(GIMPLE_PARSER_H) diff --git a/gcc/gimple/config-lang.in b/gcc/gimple/config-lang.in new file mode 100644 index 0000000..0ee83ab --- /dev/null +++ b/gcc/gimple/config-lang.in @@ -0,0 +1,27 @@ +# Top level configure fragment for GIMPLE +# +# Copyright (C) 2004, 2005, 2006, 2007 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 +# . + +language="gimple" +compilers="gimple1\$(exeext)" +stagestuff="gimple1\$(exeext)" + +gtfiles="\$(srcdir)/gimple/gimple-tree.h \$(srcdir)/gimple/gimple-lang.c" + +build_by_default=yes diff --git a/gcc/gimple/gimple-lang.c b/gcc/gimple/gimple-lang.c new file mode 100644 index 0000000..51ffb21 --- /dev/null +++ b/gcc/gimple/gimple-lang.c @@ -0,0 +1,1103 @@ +/* Language-dependent hooks for GIMPLE. + + Copyright 2010 Free Software Foundation, Inc. + Contributed by Sandeep Soni and Diego Novillo + +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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "flags.h" +#include "tm.h" +#include "tree.h" +#include "target.h" +#include "langhooks.h" +#include "langhooks-def.h" +#include "debug.h" +#include "parser.h" +#include "gimple.h" +#include "diagnostic-core.h" +#include "toplev.h" +#include "gimple-tree.h" + +static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *); +static tree handle_const_attribute (tree *, tree, tree, int, bool *); +static tree handle_malloc_attribute (tree *, tree, tree, int, bool *); +static tree handle_pure_attribute (tree *, tree, tree, int, bool *); +static tree handle_novops_attribute (tree *, tree, tree, int, bool *); +static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *); +static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *); +static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *); +static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *); +static tree handle_format_attribute (tree *, tree, tree, int, bool *); +static tree handle_format_arg_attribute (tree *, tree, tree, int, bool *); + +/* Table of machine-independent attributes supported in GIMPLE. */ +const struct attribute_spec gimple_attribute_table[] = +{ + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "noreturn", 0, 0, true, false, false, + handle_noreturn_attribute }, + /* The same comments as for noreturn attributes apply to const ones. */ + { "const", 0, 0, true, false, false, + handle_const_attribute }, + { "malloc", 0, 0, true, false, false, + handle_malloc_attribute }, + { "pure", 0, 0, true, false, false, + handle_pure_attribute }, + { "no vops", 0, 0, true, false, false, + handle_novops_attribute }, + { "nonnull", 0, -1, false, true, true, + handle_nonnull_attribute }, + { "nothrow", 0, 0, true, false, false, + handle_nothrow_attribute }, + { "sentinel", 0, 1, false, true, true, + handle_sentinel_attribute }, + { "type generic", 0, 0, false, true, true, + handle_type_generic_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; + +/* Give the specifications for the format attributes, used by C and all + descendants. */ + +const struct attribute_spec gimple_format_attribute_table[] = +{ + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "format", 3, 3, false, true, true, + handle_format_attribute }, + { "format_arg", 1, 1, false, true, true, + handle_format_arg_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; + +enum built_in_attribute +{ +#define DEF_ATTR_NULL_TREE(ENUM) ENUM, +#define DEF_ATTR_INT(ENUM, VALUE) ENUM, +#define DEF_ATTR_IDENT(ENUM, STRING) ENUM, +#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM, +#include "builtin-attrs.def" +#undef DEF_ATTR_NULL_TREE +#undef DEF_ATTR_INT +#undef DEF_ATTR_IDENT +#undef DEF_ATTR_TREE_LIST + ATTR_LAST +}; + +static GTY(()) tree built_in_attributes[(int) ATTR_LAST]; + +/* Builtin types. */ + +enum gimple_builtin_type +{ +#define DEF_PRIMITIVE_TYPE(NAME, VALUE) NAME, +#define DEF_FUNCTION_TYPE_0(NAME, RETURN) NAME, +#define DEF_FUNCTION_TYPE_1(NAME, RETURN, ARG1) NAME, +#define DEF_FUNCTION_TYPE_2(NAME, RETURN, ARG1, ARG2) NAME, +#define DEF_FUNCTION_TYPE_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME, +#define DEF_FUNCTION_TYPE_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME, +#define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME, +#define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME, +#define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME, +#define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME, +#define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME, +#define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME, +#define DEF_FUNCTION_TYPE_VAR_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME, +#define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME, +#define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG6) \ + NAME, +#define DEF_POINTER_TYPE(NAME, TYPE) NAME, +#include "builtin-types.def" +#undef DEF_PRIMITIVE_TYPE +#undef DEF_FUNCTION_TYPE_0 +#undef DEF_FUNCTION_TYPE_1 +#undef DEF_FUNCTION_TYPE_2 +#undef DEF_FUNCTION_TYPE_3 +#undef DEF_FUNCTION_TYPE_4 +#undef DEF_FUNCTION_TYPE_5 +#undef DEF_FUNCTION_TYPE_6 +#undef DEF_FUNCTION_TYPE_7 +#undef DEF_FUNCTION_TYPE_VAR_0 +#undef DEF_FUNCTION_TYPE_VAR_1 +#undef DEF_FUNCTION_TYPE_VAR_2 +#undef DEF_FUNCTION_TYPE_VAR_3 +#undef DEF_FUNCTION_TYPE_VAR_4 +#undef DEF_FUNCTION_TYPE_VAR_5 +#undef DEF_POINTER_TYPE + BT_LAST +}; + +typedef enum gimple_builtin_type builtin_type; + +static GTY(()) tree builtin_types[(int) BT_LAST + 1]; + +static GTY(()) tree string_type_node; +static GTY(()) tree const_string_type_node; +static GTY(()) tree wint_type_node; +static GTY(()) tree intmax_type_node; +static GTY(()) tree uintmax_type_node; +static GTY(()) tree signed_size_type_node; + +/* Flags needed to process builtins.def. */ +int flag_isoc94; +int flag_isoc99; + +/* Attribute handlers. */ + +/* Handle a "noreturn" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_noreturn_attribute (tree *node, tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool * ARG_UNUSED (no_add_attrs)) +{ + tree type = TREE_TYPE (*node); + + if (TREE_CODE (*node) == FUNCTION_DECL) + TREE_THIS_VOLATILE (*node) = 1; + else if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) + TREE_TYPE (*node) + = build_pointer_type + (build_type_variant (TREE_TYPE (type), + TYPE_READONLY (TREE_TYPE (type)), 1)); + else + gcc_unreachable (); + + return NULL_TREE; +} + + +/* Handle a "const" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_const_attribute (tree *node, tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool * ARG_UNUSED (no_add_attrs)) +{ + tree type = TREE_TYPE (*node); + + /* See FIXME comment on noreturn in c_common_attribute_table. */ + if (TREE_CODE (*node) == FUNCTION_DECL) + TREE_READONLY (*node) = 1; + else if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) + TREE_TYPE (*node) + = build_pointer_type + (build_type_variant (TREE_TYPE (type), 1, + TREE_THIS_VOLATILE (TREE_TYPE (type)))); + else + gcc_unreachable (); + + return NULL_TREE; +} + + +/* Handle a "malloc" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_malloc_attribute (tree *node, tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool * ARG_UNUSED (no_add_attrs)) +{ + if (TREE_CODE (*node) == FUNCTION_DECL + && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (*node)))) + DECL_IS_MALLOC (*node) = 1; + else + gcc_unreachable (); + + return NULL_TREE; +} + + +/* Handle a "pure" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_pure_attribute (tree *node, tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool * ARG_UNUSED (no_add_attrs)) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + DECL_PURE_P (*node) = 1; + else + gcc_unreachable (); + + return NULL_TREE; +} + + +/* Handle a "no vops" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_novops_attribute (tree *node, tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool *ARG_UNUSED (no_add_attrs)) +{ + gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); + DECL_IS_NOVOPS (*node) = 1; + return NULL_TREE; +} + + +/* Helper for nonnull attribute handling; fetch the operand number + from the attribute argument list. */ + +static bool +get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp) +{ + /* Verify the arg number is a constant. */ + if (TREE_CODE (arg_num_expr) != INTEGER_CST + || TREE_INT_CST_HIGH (arg_num_expr) != 0) + return false; + + *valp = TREE_INT_CST_LOW (arg_num_expr); + return true; +} + +/* Handle the "nonnull" attribute. */ + +static tree +handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name), + tree args, int ARG_UNUSED (flags), + bool * ARG_UNUSED (no_add_attrs)) +{ + tree type = *node; + + /* If no arguments are specified, all pointer arguments should be + non-null. Verify a full prototype is given so that the arguments + will have the correct types when we actually check them later. */ + if (!args) + { + gcc_assert (TYPE_ARG_TYPES (type)); + return NULL_TREE; + } + + /* Argument list specified. Verify that each argument number references + a pointer argument. */ + for (; args; args = TREE_CHAIN (args)) + { + tree argument; + unsigned HOST_WIDE_INT arg_num = 0, ck_num; + + if (!get_nonnull_operand (TREE_VALUE (args), &arg_num)) + gcc_unreachable (); + + argument = TYPE_ARG_TYPES (type); + if (argument) + { + for (ck_num = 1; ; ck_num++) + { + if (!argument || ck_num == arg_num) + break; + argument = TREE_CHAIN (argument); + } + + gcc_assert (argument + && TREE_CODE (TREE_VALUE (argument)) == POINTER_TYPE); + } + } + + return NULL_TREE; +} + + +/* Handle a "nothrow" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_nothrow_attribute (tree *node, tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool * ARG_UNUSED (no_add_attrs)) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + TREE_NOTHROW (*node) = 1; + else + gcc_unreachable (); + + return NULL_TREE; +} + + +/* Handle a "sentinel" attribute. */ + +static tree +handle_sentinel_attribute (tree *node, tree ARG_UNUSED (name), tree args, + int ARG_UNUSED (flags), + bool * ARG_UNUSED (no_add_attrs)) +{ + tree params = TYPE_ARG_TYPES (*node); + gcc_assert (params); + + while (TREE_CHAIN (params)) + params = TREE_CHAIN (params); + + gcc_assert (!VOID_TYPE_P (TREE_VALUE (params))); + + if (args) + { + tree position = TREE_VALUE (args); + gcc_assert (TREE_CODE (position) == INTEGER_CST); + if (tree_int_cst_lt (position, integer_zero_node)) + gcc_unreachable (); + } + + return NULL_TREE; +} + +/* Handle a "type_generic" attribute. */ + +static tree +handle_type_generic_attribute (tree *node, tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool * ARG_UNUSED (no_add_attrs)) +{ + tree params; + + /* Ensure we have a function type. */ + gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE); + + params = TYPE_ARG_TYPES (*node); + while (params && ! VOID_TYPE_P (TREE_VALUE (params))) + params = TREE_CHAIN (params); + + /* Ensure we have a variadic function. */ + gcc_assert (!params); + + return NULL_TREE; +} + +/* Handle a "format" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_format_attribute (tree * ARG_UNUSED (node), tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool *no_add_attrs) +{ + *no_add_attrs = true; + return NULL_TREE; +} + + +/* Handle a "format_arg" attribute; arguments as in + struct attribute_spec.handler. */ + +tree +handle_format_arg_attribute (tree * ARG_UNUSED (node), tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool *no_add_attrs) +{ + *no_add_attrs = true; + return NULL_TREE; +} + + +/* Cribbed from c-common.c. */ + +static void +def_fn_type (builtin_type def, builtin_type ret, bool var, int n, ...) +{ + tree args = NULL, t; + va_list list; + int i; + + va_start (list, n); + for (i = 0; i < n; ++i) + { + builtin_type a = (builtin_type) va_arg (list, int); + t = builtin_types[a]; + if (t == error_mark_node) + goto egress; + args = tree_cons (NULL_TREE, t, args); + } + va_end (list); + + args = nreverse (args); + if (!var) + args = chainon (args, void_list_node); + + t = builtin_types[ret]; + if (t == error_mark_node) + goto egress; + t = build_function_type (t, args); + + egress: + builtin_types[def] = t; +} + +/* Used to help initialize the builtin-types.def table. When a type of + the correct size doesn't exist, use error_mark_node instead of NULL. + The later results in segfaults even when a decl using the type doesn't + get invoked. */ + +static tree +builtin_type_for_size (int size, bool unsignedp) +{ + tree type = lang_hooks.types.type_for_size (size, unsignedp); + return type ? type : error_mark_node; +} + +/* Support for DEF_BUILTIN. */ + +static void +def_builtin_1 (enum built_in_function fncode, const char *name, + enum built_in_class fnclass, tree fntype, tree libtype, + bool both_p, bool fallback_p, bool nonansi_p, + tree fnattrs, bool implicit_p) +{ + tree decl; + const char *libname; + + if (fntype == error_mark_node) + return; + + libname = name + strlen ("__builtin_"); + decl = add_builtin_function (name, fntype, fncode, fnclass, + (fallback_p ? libname : NULL), + fnattrs); + + if (both_p + && !flag_no_builtin + && !(nonansi_p && flag_no_nonansi_builtin)) + add_builtin_function (libname, libtype, fncode, fnclass, + NULL, fnattrs); + + built_in_decls[(int) fncode] = decl; + if (implicit_p) + implicit_built_in_decls[(int) fncode] = decl; +} + + +/* Initialize the attribute table for all the supported builtins. */ + +static void +gimple_init_attributes (void) +{ + /* Fill in the built_in_attributes array. */ +#define DEF_ATTR_NULL_TREE(ENUM) \ + built_in_attributes[(int) ENUM] = NULL_TREE; +#define DEF_ATTR_INT(ENUM, VALUE) \ + built_in_attributes[(int) ENUM] = build_int_cst (NULL_TREE, VALUE); +#define DEF_ATTR_IDENT(ENUM, STRING) \ + built_in_attributes[(int) ENUM] = get_identifier (STRING); +#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \ + built_in_attributes[(int) ENUM] \ + = tree_cons (built_in_attributes[(int) PURPOSE], \ + built_in_attributes[(int) VALUE], \ + built_in_attributes[(int) CHAIN]); +#include "builtin-attrs.def" +#undef DEF_ATTR_NULL_TREE +#undef DEF_ATTR_INT +#undef DEF_ATTR_IDENT +#undef DEF_ATTR_TREE_LIST +} + +/* Create builtin types and functions. VA_LIST_REF_TYPE_NODE and + VA_LIST_ARG_TYPE_NODE are used in builtin-types.def. */ + +static void +gimple_define_builtins (tree va_list_ref_type_node ATTRIBUTE_UNUSED, + tree va_list_arg_type_node ATTRIBUTE_UNUSED) +{ +#define DEF_PRIMITIVE_TYPE(ENUM, VALUE) \ + builtin_types[ENUM] = VALUE; +#define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \ + def_fn_type (ENUM, RETURN, 0, 0); +#define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1) \ + def_fn_type (ENUM, RETURN, 0, 1, ARG1); +#define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2) \ + def_fn_type (ENUM, RETURN, 0, 2, ARG1, ARG2); +#define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3) \ + def_fn_type (ENUM, RETURN, 0, 3, ARG1, ARG2, ARG3); +#define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \ + def_fn_type (ENUM, RETURN, 0, 4, ARG1, ARG2, ARG3, ARG4); +#define DEF_FUNCTION_TYPE_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \ + def_fn_type (ENUM, RETURN, 0, 5, ARG1, ARG2, ARG3, ARG4, ARG5); +#define DEF_FUNCTION_TYPE_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6) \ + def_fn_type (ENUM, RETURN, 0, 6, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6); +#define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7) \ + def_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7); +#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ + def_fn_type (ENUM, RETURN, 1, 0); +#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \ + def_fn_type (ENUM, RETURN, 1, 1, ARG1); +#define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2) \ + def_fn_type (ENUM, RETURN, 1, 2, ARG1, ARG2); +#define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, ARG1, ARG2, ARG3) \ + def_fn_type (ENUM, RETURN, 1, 3, ARG1, ARG2, ARG3); +#define DEF_FUNCTION_TYPE_VAR_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \ + def_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4); +#define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \ + def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5); +#define DEF_POINTER_TYPE(ENUM, TYPE) \ + builtin_types[(int) ENUM] = build_pointer_type (builtin_types[(int) TYPE]); + +#include "builtin-types.def" + +#undef DEF_PRIMITIVE_TYPE +#undef DEF_FUNCTION_TYPE_1 +#undef DEF_FUNCTION_TYPE_2 +#undef DEF_FUNCTION_TYPE_3 +#undef DEF_FUNCTION_TYPE_4 +#undef DEF_FUNCTION_TYPE_5 +#undef DEF_FUNCTION_TYPE_6 +#undef DEF_FUNCTION_TYPE_VAR_0 +#undef DEF_FUNCTION_TYPE_VAR_1 +#undef DEF_FUNCTION_TYPE_VAR_2 +#undef DEF_FUNCTION_TYPE_VAR_3 +#undef DEF_FUNCTION_TYPE_VAR_4 +#undef DEF_FUNCTION_TYPE_VAR_5 +#undef DEF_POINTER_TYPE + builtin_types[(int) BT_LAST] = NULL_TREE; + + gimple_init_attributes (); + +#define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE, BOTH_P, FALLBACK_P,\ + NONANSI_P, ATTRS, IMPLICIT, COND) \ + if (NAME && COND) \ + def_builtin_1 (ENUM, NAME, CLASS, builtin_types[(int) TYPE], \ + builtin_types[(int) LIBTYPE], BOTH_P, FALLBACK_P, \ + NONANSI_P, built_in_attributes[(int) ATTRS], IMPLICIT); +#include "builtins.def" +#undef DEF_BUILTIN +} + +static GTY(()) tree registered_builtin_types; + +/* A chain of builtin functions that we need to recognize. We will + assume that all other function names we see will be defined by the + user's program. */ +static GTY(()) tree registered_builtin_fndecls; + +/* Language hooks. */ + +static unsigned int +gimple_option_lang_mask (void) +{ + return CL_GIMPLE; +} + +static void +gimple_init_options (unsigned int decoded_options_count ATTRIBUTE_UNUSED, + struct cl_decoded_option *decoded_options ATTRIBUTE_UNUSED) +{ + /* By default, C99-like requirements for complex multiply and divide. + ??? Until the complex method is encoded in the IL this is the only + safe choice. This will pessimize Fortran code with GIMPLE unless + people specify a complex method manually or use -ffast-math. */ + flag_complex_method = 2; +} + + +/* Return an integer type with PRECISION bits of precision, + that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */ + +static tree +gimple_type_for_size (unsigned precision, int unsignedp) +{ + if (precision == TYPE_PRECISION (integer_type_node)) + return unsignedp ? unsigned_type_node : integer_type_node; + + if (precision == TYPE_PRECISION (signed_char_type_node)) + return unsignedp ? unsigned_char_type_node : signed_char_type_node; + + if (precision == TYPE_PRECISION (short_integer_type_node)) + return unsignedp ? short_unsigned_type_node : short_integer_type_node; + + if (precision == TYPE_PRECISION (long_integer_type_node)) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + + if (precision == TYPE_PRECISION (long_long_integer_type_node)) + return unsignedp + ? long_long_unsigned_type_node + : long_long_integer_type_node; + + if (precision <= TYPE_PRECISION (intQI_type_node)) + return unsignedp ? unsigned_intQI_type_node : intQI_type_node; + + if (precision <= TYPE_PRECISION (intHI_type_node)) + return unsignedp ? unsigned_intHI_type_node : intHI_type_node; + + if (precision <= TYPE_PRECISION (intSI_type_node)) + return unsignedp ? unsigned_intSI_type_node : intSI_type_node; + + if (precision <= TYPE_PRECISION (intDI_type_node)) + return unsignedp ? unsigned_intDI_type_node : intDI_type_node; + + if (precision <= TYPE_PRECISION (intTI_type_node)) + return unsignedp ? unsigned_intTI_type_node : intTI_type_node; + + return NULL_TREE; +} + + +/* Return a data type that has machine mode MODE. + If the mode is an integer, + then UNSIGNEDP selects between signed and unsigned types. + If the mode is a fixed-point mode, + then UNSIGNEDP selects between saturating and nonsaturating types. */ + +static tree +gimple_type_for_mode (enum machine_mode mode, int unsigned_p) +{ + tree t; + + if (mode == TYPE_MODE (integer_type_node)) + return unsigned_p ? unsigned_type_node : integer_type_node; + + if (mode == TYPE_MODE (signed_char_type_node)) + return unsigned_p ? unsigned_char_type_node : signed_char_type_node; + + if (mode == TYPE_MODE (short_integer_type_node)) + return unsigned_p ? short_unsigned_type_node : short_integer_type_node; + + if (mode == TYPE_MODE (long_integer_type_node)) + return unsigned_p ? long_unsigned_type_node : long_integer_type_node; + + if (mode == TYPE_MODE (long_long_integer_type_node)) + return unsigned_p ? long_long_unsigned_type_node : long_long_integer_type_node; + + if (mode == QImode) + return unsigned_p ? unsigned_intQI_type_node : intQI_type_node; + + if (mode == HImode) + return unsigned_p ? unsigned_intHI_type_node : intHI_type_node; + + if (mode == SImode) + return unsigned_p ? unsigned_intSI_type_node : intSI_type_node; + + if (mode == DImode) + return unsigned_p ? unsigned_intDI_type_node : intDI_type_node; + +#if HOST_BITS_PER_WIDE_INT >= 64 + if (mode == TYPE_MODE (intTI_type_node)) + return unsigned_p ? unsigned_intTI_type_node : intTI_type_node; +#endif + + if (mode == TYPE_MODE (float_type_node)) + return float_type_node; + + if (mode == TYPE_MODE (double_type_node)) + return double_type_node; + + if (mode == TYPE_MODE (long_double_type_node)) + return long_double_type_node; + + if (mode == TYPE_MODE (void_type_node)) + return void_type_node; + + if (mode == TYPE_MODE (build_pointer_type (char_type_node))) + return (unsigned_p + ? make_unsigned_type (GET_MODE_PRECISION (mode)) + : make_signed_type (GET_MODE_PRECISION (mode))); + + if (mode == TYPE_MODE (build_pointer_type (integer_type_node))) + return (unsigned_p + ? make_unsigned_type (GET_MODE_PRECISION (mode)) + : make_signed_type (GET_MODE_PRECISION (mode))); + + if (COMPLEX_MODE_P (mode)) + { + enum machine_mode inner_mode; + tree inner_type; + + if (mode == TYPE_MODE (complex_float_type_node)) + return complex_float_type_node; + if (mode == TYPE_MODE (complex_double_type_node)) + return complex_double_type_node; + if (mode == TYPE_MODE (complex_long_double_type_node)) + return complex_long_double_type_node; + + if (mode == TYPE_MODE (complex_integer_type_node) && !unsigned_p) + return complex_integer_type_node; + + inner_mode = GET_MODE_INNER (mode); + inner_type = gimple_type_for_mode (inner_mode, unsigned_p); + if (inner_type != NULL_TREE) + return build_complex_type (inner_type); + } + else if (VECTOR_MODE_P (mode)) + { + enum machine_mode inner_mode = GET_MODE_INNER (mode); + tree inner_type = gimple_type_for_mode (inner_mode, unsigned_p); + if (inner_type != NULL_TREE) + return build_vector_type_for_mode (inner_type, mode); + } + + if (mode == TYPE_MODE (dfloat32_type_node)) + return dfloat32_type_node; + if (mode == TYPE_MODE (dfloat64_type_node)) + return dfloat64_type_node; + if (mode == TYPE_MODE (dfloat128_type_node)) + return dfloat128_type_node; + + if (ALL_SCALAR_FIXED_POINT_MODE_P (mode)) + { + if (mode == TYPE_MODE (short_fract_type_node)) + return unsigned_p ? sat_short_fract_type_node : short_fract_type_node; + if (mode == TYPE_MODE (fract_type_node)) + return unsigned_p ? sat_fract_type_node : fract_type_node; + if (mode == TYPE_MODE (long_fract_type_node)) + return unsigned_p ? sat_long_fract_type_node : long_fract_type_node; + if (mode == TYPE_MODE (long_long_fract_type_node)) + return unsigned_p ? sat_long_long_fract_type_node + : long_long_fract_type_node; + + if (mode == TYPE_MODE (unsigned_short_fract_type_node)) + return unsigned_p ? sat_unsigned_short_fract_type_node + : unsigned_short_fract_type_node; + if (mode == TYPE_MODE (unsigned_fract_type_node)) + return unsigned_p ? sat_unsigned_fract_type_node + : unsigned_fract_type_node; + if (mode == TYPE_MODE (unsigned_long_fract_type_node)) + return unsigned_p ? sat_unsigned_long_fract_type_node + : unsigned_long_fract_type_node; + if (mode == TYPE_MODE (unsigned_long_long_fract_type_node)) + return unsigned_p ? sat_unsigned_long_long_fract_type_node + : unsigned_long_long_fract_type_node; + + if (mode == TYPE_MODE (short_accum_type_node)) + return unsigned_p ? sat_short_accum_type_node : short_accum_type_node; + if (mode == TYPE_MODE (accum_type_node)) + return unsigned_p ? sat_accum_type_node : accum_type_node; + if (mode == TYPE_MODE (long_accum_type_node)) + return unsigned_p ? sat_long_accum_type_node : long_accum_type_node; + if (mode == TYPE_MODE (long_long_accum_type_node)) + return unsigned_p ? sat_long_long_accum_type_node + : long_long_accum_type_node; + + if (mode == TYPE_MODE (unsigned_short_accum_type_node)) + return unsigned_p ? sat_unsigned_short_accum_type_node + : unsigned_short_accum_type_node; + if (mode == TYPE_MODE (unsigned_accum_type_node)) + return unsigned_p ? sat_unsigned_accum_type_node + : unsigned_accum_type_node; + if (mode == TYPE_MODE (unsigned_long_accum_type_node)) + return unsigned_p ? sat_unsigned_long_accum_type_node + : unsigned_long_accum_type_node; + if (mode == TYPE_MODE (unsigned_long_long_accum_type_node)) + return unsigned_p ? sat_unsigned_long_long_accum_type_node + : unsigned_long_long_accum_type_node; + + if (mode == QQmode) + return unsigned_p ? sat_qq_type_node : qq_type_node; + if (mode == HQmode) + return unsigned_p ? sat_hq_type_node : hq_type_node; + if (mode == SQmode) + return unsigned_p ? sat_sq_type_node : sq_type_node; + if (mode == DQmode) + return unsigned_p ? sat_dq_type_node : dq_type_node; + if (mode == TQmode) + return unsigned_p ? sat_tq_type_node : tq_type_node; + + if (mode == UQQmode) + return unsigned_p ? sat_uqq_type_node : uqq_type_node; + if (mode == UHQmode) + return unsigned_p ? sat_uhq_type_node : uhq_type_node; + if (mode == USQmode) + return unsigned_p ? sat_usq_type_node : usq_type_node; + if (mode == UDQmode) + return unsigned_p ? sat_udq_type_node : udq_type_node; + if (mode == UTQmode) + return unsigned_p ? sat_utq_type_node : utq_type_node; + + if (mode == HAmode) + return unsigned_p ? sat_ha_type_node : ha_type_node; + if (mode == SAmode) + return unsigned_p ? sat_sa_type_node : sa_type_node; + if (mode == DAmode) + return unsigned_p ? sat_da_type_node : da_type_node; + if (mode == TAmode) + return unsigned_p ? sat_ta_type_node : ta_type_node; + + if (mode == UHAmode) + return unsigned_p ? sat_uha_type_node : uha_type_node; + if (mode == USAmode) + return unsigned_p ? sat_usa_type_node : usa_type_node; + if (mode == UDAmode) + return unsigned_p ? sat_uda_type_node : uda_type_node; + if (mode == UTAmode) + return unsigned_p ? sat_uta_type_node : uta_type_node; + } + + for (t = registered_builtin_types; t; t = TREE_CHAIN (t)) + if (TYPE_MODE (TREE_VALUE (t)) == mode) + return TREE_VALUE (t); + + return NULL_TREE; +} + +static int +gimple_global_bindings_p (void) +{ + return cfun == NULL; +} + +static void +gimple_set_decl_assembler_name (tree decl) +{ + /* This is almost the same as lhd_set_decl_assembler_name, except that + we need to uniquify file-scope names, even if they are not + TREE_PUBLIC, to avoid conflicts between individual files. */ + tree id; + + if (TREE_PUBLIC (decl)) + id = targetm.mangle_decl_assembler_name (decl, DECL_NAME (decl)); + else + { + const char *name = IDENTIFIER_POINTER (DECL_NAME (decl)); + char *label; + + ASM_FORMAT_PRIVATE_NAME (label, name, DECL_UID (decl)); + id = get_identifier (label); + } + + SET_DECL_ASSEMBLER_NAME (decl, id); +} + +static tree +gimple_pushdecl (tree t ATTRIBUTE_UNUSED) +{ + return NULL_TREE; +} + +static tree +gimple_getdecls (void) +{ + return registered_builtin_fndecls; +} + +static tree +gimple_builtin_function (tree decl) +{ + /* Record it. */ + TREE_CHAIN (decl) = registered_builtin_fndecls; + registered_builtin_fndecls = decl; + + return decl; +} + +static void +gimple_register_builtin_type (tree type, const char *name) +{ + tree decl; + + decl = build_decl (UNKNOWN_LOCATION, TYPE_DECL, get_identifier (name), type); + DECL_ARTIFICIAL (decl) = 1; + if (!TYPE_NAME (type)) + TYPE_NAME (type) = decl; + + registered_builtin_types = tree_cons (0, type, registered_builtin_types); +} + +/* Build nodes that would have be created by the C front-end; necessary + for including builtin-types.def and ultimately builtins.def. */ + +static void +gimple_build_c_type_nodes (void) +{ + gcc_assert (void_type_node); + + void_list_node = build_tree_list (NULL_TREE, void_type_node); + string_type_node = build_pointer_type (char_type_node); + const_string_type_node + = build_pointer_type (build_qualified_type (char_type_node, TYPE_QUAL_CONST)); + + if (strcmp (SIZE_TYPE, "unsigned int") == 0) + { + intmax_type_node = integer_type_node; + uintmax_type_node = unsigned_type_node; + signed_size_type_node = integer_type_node; + } + else if (strcmp (SIZE_TYPE, "long unsigned int") == 0) + { + intmax_type_node = long_integer_type_node; + uintmax_type_node = long_unsigned_type_node; + signed_size_type_node = long_integer_type_node; + } + else if (strcmp (SIZE_TYPE, "long long unsigned int") == 0) + { + intmax_type_node = long_long_integer_type_node; + uintmax_type_node = long_long_unsigned_type_node; + signed_size_type_node = long_long_integer_type_node; + } + else + gcc_unreachable (); + + wint_type_node = unsigned_type_node; + pid_type_node = integer_type_node; +} + + +/* Perform GIMPLE-specific initialization. */ + +static bool +gimple_init (void) +{ + /* Initialize libcpp line maps for gcc_assert to work. */ + linemap_add (line_table, LC_RENAME, 0, NULL, 0); + linemap_add (line_table, LC_RENAME, 0, NULL, 0); + + /* Create the basic integer types. */ + build_common_tree_nodes (flag_signed_char); + + /* Share char_type_node with whatever would be the default for the target. + char_type_node will be used for internal types such as + va_list_type_node. */ + /* ??? This breaks the more common case of consistent but non-standard + setting of flag_signed_char, so share according to flag_signed_char. + See PR42528. */ + char_type_node + = flag_signed_char ? signed_char_type_node : unsigned_char_type_node; + + /* Tell the middle end what type to use for the size of objects. */ + if (strcmp (SIZE_TYPE, "unsigned int") == 0) + { + set_sizetype (unsigned_type_node); + size_type_node = unsigned_type_node; + } + else if (strcmp (SIZE_TYPE, "long unsigned int") == 0) + { + set_sizetype (long_unsigned_type_node); + size_type_node = long_unsigned_type_node; + } + else if (strcmp (SIZE_TYPE, "long long unsigned int") == 0) + { + set_sizetype (long_long_unsigned_type_node); + size_type_node = long_long_unsigned_type_node; + } + else + gcc_unreachable (); + + /* The global tree for the main identifier is filled in by + language-specific front-end initialization that is not run in the + GIMPLE front end. It appears that all languages that perform such + initialization currently do so in the same way, so we do it here. */ + if (main_identifier_node == NULL_TREE) + main_identifier_node = get_identifier ("main"); + + /* In the C++ front-end, fileptr_type_node is defined as a variant + copy of of ptr_type_node, rather than ptr_node itself. The + distinction should only be relevant to the front-end, so we + always use the C definition here in gimple1. */ + gcc_assert (fileptr_type_node == ptr_type_node); + + ptrdiff_type_node = integer_type_node; + + /* Create other basic types. */ + build_common_tree_nodes_2 (/*short_double=*/false); + gimple_build_c_type_nodes (); + gcc_assert (va_list_type_node); + + if (TREE_CODE (va_list_type_node) == ARRAY_TYPE) + { + tree x = build_pointer_type (TREE_TYPE (va_list_type_node)); + gimple_define_builtins (x, x); + } + else + { + gimple_define_builtins (va_list_type_node, + build_reference_type (va_list_type_node)); + } + + targetm.init_builtins (); + build_common_builtin_nodes (); + + return true; +} + +/* Initialize tree structures required by the GIMPLE front end. */ + +static void gimple_init_ts (void) +{ + tree_contains_struct[NAMESPACE_DECL][TS_DECL_MINIMAL] = 1; +} + +#undef LANG_HOOKS_NAME +#define LANG_HOOKS_NAME "GNU GIMPLE" +#undef LANG_HOOKS_OPTION_LANG_MASK +#define LANG_HOOKS_OPTION_LANG_MASK gimple_option_lang_mask +#undef LANG_HOOKS_INIT_OPTIONS +#define LANG_HOOKS_INIT_OPTIONS gimple_init_options +#undef LANG_HOOKS_GET_ALIAS_SET +#define LANG_HOOKS_GET_ALIAS_SET gimple_get_alias_set +#undef LANG_HOOKS_TYPE_FOR_MODE +#define LANG_HOOKS_TYPE_FOR_MODE gimple_type_for_mode +#undef LANG_HOOKS_TYPE_FOR_SIZE +#define LANG_HOOKS_TYPE_FOR_SIZE gimple_type_for_size +#undef LANG_HOOKS_SET_DECL_ASSEMBLER_NAME +#define LANG_HOOKS_SET_DECL_ASSEMBLER_NAME gimple_set_decl_assembler_name +#undef LANG_HOOKS_GLOBAL_BINDINGS_P +#define LANG_HOOKS_GLOBAL_BINDINGS_P gimple_global_bindings_p +#undef LANG_HOOKS_PUSHDECL +#define LANG_HOOKS_PUSHDECL gimple_pushdecl +#undef LANG_HOOKS_GETDECLS +#define LANG_HOOKS_GETDECLS gimple_getdecls +#undef LANG_HOOKS_REGISTER_BUILTIN_TYPE +#define LANG_HOOKS_REGISTER_BUILTIN_TYPE gimple_register_builtin_type +#undef LANG_HOOKS_BUILTIN_FUNCTION +#define LANG_HOOKS_BUILTIN_FUNCTION gimple_builtin_function +#undef LANG_HOOKS_INIT +#define LANG_HOOKS_INIT gimple_init +#undef LANG_HOOKS_PARSE_FILE +#define LANG_HOOKS_PARSE_FILE gimple_main +#undef LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION +#define LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION tree_rest_of_compilation +#undef LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS +#define LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS true +#undef LANG_HOOKS_TYPES_COMPATIBLE_P +#define LANG_HOOKS_TYPES_COMPATIBLE_P NULL + +/* Attribute hooks. */ +#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE +#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE gimple_attribute_table +#undef LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE +#define LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE gimple_format_attribute_table + +#undef LANG_HOOKS_INIT_TS +#define LANG_HOOKS_INIT_TS gimple_init_ts + +struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; + +/* Language hooks that are not part of lang_hooks. */ + +tree +convert (tree type ATTRIBUTE_UNUSED, tree expr ATTRIBUTE_UNUSED) +{ + gcc_unreachable (); +} + +/* Tree walking support. */ + +static enum gimple_tree_node_structure_enum +gimple_tree_node_structure (union lang_tree_node *t ATTRIBUTE_UNUSED) +{ + return TS_GIMPLE_GENERIC; +} + +#include "ggc.h" +#include "gtype-gimple.h" +#include "gt-gimple-gimple-lang.h" diff --git a/gcc/gimple/gimple-tree.h b/gcc/gimple/gimple-tree.h new file mode 100644 index 0000000..42b286a --- /dev/null +++ b/gcc/gimple/gimple-tree.h @@ -0,0 +1,58 @@ +/* Definitions for GIMPLE parsing and type checking. + + Copyright (C) 2010 + Free Software Foundation, Inc. + Contributed by Diego Novillo. + +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 +. */ + +#ifndef GIMPLE_GIMPLE_TREE_H +#define GIMPLE_GIMPLE_TREE_H + +struct GTY(()) lang_identifier +{ + struct tree_identifier base; +}; + +struct GTY(()) lang_decl +{ + int dummy; /* Added because ggc does not like empty structs. */ +}; + +struct GTY(()) lang_type +{ + int dummy; /* Added because ggc does not like empty structs. */ +}; + +struct GTY(()) language_function +{ + int dummy; /* Added because ggc does not like empty structs. */ +}; + +enum gimple_tree_node_structure_enum { + TS_GIMPLE_GENERIC +}; + +union GTY((desc ("gimple_tree_node_structure (&%h)"), + chain_next ("(union lang_tree_node *)TREE_CHAIN (&%h.generic)"))) + lang_tree_node +{ + union tree_node GTY ((tag ("TS_GIMPLE_GENERIC"), + desc ("gimple_tree_node_structure (&%h)"))) generic; +}; + +#endif /* GIMPLE_GIMPLE_TREE_H */ diff --git a/gcc/gimple/lang-specs.h b/gcc/gimple/lang-specs.h new file mode 100644 index 0000000..de035ed --- /dev/null +++ b/gcc/gimple/lang-specs.h @@ -0,0 +1,25 @@ +/* GIMPLE driver specs. + + Copyright 2010 Free Software Foundation, Inc. + Contributed by Sandeep Soni and Diego Novillo. + +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 +. */ + +/* GIMPLE contributions to the "compilers" array in gcc.c. */ + + {"@gimple", "gimple1 %(cc1_options) %i %{!fsyntax-only:%(invoke_as)}", + /*cpp_spec=*/NULL, /*combinable=*/1, /*needs_preprocessing=*/1}, diff --git a/gcc/gimple/lang.opt b/gcc/gimple/lang.opt new file mode 100644 index 0000000..a6b21b0 --- /dev/null +++ b/gcc/gimple/lang.opt @@ -0,0 +1,28 @@ +; Options for the GIMPLE front end. +; Copyright (C) 2010 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 +; . + +; See the GCC internals manual for a description of this file's format. + +; Please try to keep this file in ASCII collating order. + +Language +GIMPLE + + +; This comment is to ensure we retain the blank line above. diff --git a/gcc/gimple/parser.c b/gcc/gimple/parser.c new file mode 100644 index 0000000..510fedd --- /dev/null +++ b/gcc/gimple/parser.c @@ -0,0 +1,491 @@ +/* GIMPLE parser. + + Copyright 2010 Free Software Foundation, Inc. + Contributed by Sandeep Soni and Diego Novillo. + +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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "cpplib.h" +#include "input.h" +#include "diagnostic.h" +#include "tree.h" +#include "gimple.h" +#include "toplev.h" +#include "parser.h" + +/* Consumes a token if the EXPECTED_TOKEN_TYPE is exactly the one we + are looking for. The token is obtained by reading it from the reader P. */ + +static const cpp_token * +gimple_parse_expect_token (cpp_reader *p, enum cpp_ttype expected_token_type) +{ + const cpp_token *next_token; + + next_token = cpp_peek_token (p, 0); + + /* If the token type does not match then we must report an error, + otherwise consume the token. */ + + /* FIXME The error reported should be more precise to help + diagnostics similar to that reported by other front ends in + the same case. */ + + if (next_token->type != expected_token_type) + error ("expected token type %s instead of %s", + cpp_type2name (expected_token_type, 0), + cpp_type2name (next_token->type, 0)); + else + next_token = cpp_get_token_with_location (p, &input_location); + + return next_token; +} + + +/* Helper for gimple_parse_assign_stmt and gimple_parse_cond_stmt. + Peeks a token by reading from reader P and looks it up to match + against the tree codes. */ + +static void +gimple_parse_expect_subcode (cpp_reader *p) +{ + const cpp_token *next_token; + const char *text; + int i; + + gimple_parse_expect_token (p, CPP_LESS); + + /* Peeks a token and looks it up for a match. */ + + next_token = cpp_peek_token (p, 0); + text = (const char *) cpp_token_as_text (p, next_token); + for (i = ERROR_MARK; i < LAST_AND_UNUSED_TREE_CODE; i++) + if (strcasecmp (text, tree_code_name[i]) == 0) + break; + + /* If none of the tree codes match, then report an error. Otherwise + consume this token. */ + if (i == LAST_AND_UNUSED_TREE_CODE) + error ("Expected token should be one of the tree codes"); + else + next_token = cpp_get_token (p); + + gimple_parse_expect_token (p, CPP_COMMA); + + /* FIXME From this function we should return the tree code since it + can be used by the other helper functions to recognize precisely. */ +} + +/* Helper for gimple_parse_assign_stmt. The token read from reader P should + be the lhs of the tuple. */ + +static void +gimple_parse_expect_lhs (cpp_reader *p) +{ + const cpp_token *next_token; + + /* Just before the name of the identifier we might get the symbol + of dereference too. If we do get it then consume that token, else + continue recognizing the name. */ + next_token = cpp_peek_token (p, 0); + if (next_token->type == CPP_MULT) + next_token = cpp_get_token (p); + + gimple_parse_expect_token (p, CPP_NAME); + gimple_parse_expect_token (p, CPP_COMMA); +} + +/* Helper for gimple_parse_assign_stmt. The token read from reader P should + be the first operand in rhs of the tuple. */ + +static void +gimple_parse_expect_rhs1 (cpp_reader *p) +{ + const cpp_token *next_token; + next_token = cpp_peek_token (p, 0); + + /* Currently there is duplication in the following blocks but there + would be more stuff added here as we go on. */ + + /* ??? Can there be more possibilities than these ? */ + if (next_token->type == CPP_MULT) + { + next_token = cpp_get_token (p); + gimple_parse_expect_token (p, CPP_NAME); + } + else if (next_token->type == CPP_AND) + { + next_token = cpp_get_token (p); + gimple_parse_expect_token (p, CPP_NAME); + } + else if (next_token->type == CPP_NAME) + next_token = cpp_get_token (p); + else if (next_token->type == CPP_NUMBER) + next_token = cpp_get_token (p); + else if (next_token->type == CPP_STRING) + next_token = cpp_get_token (p); + + gimple_parse_expect_token (p, CPP_COMMA); +} + +/* Helper for gimple_parse_assign_stmt. The token read from reader P should + be the second operand in rhs of the tuple. */ + +static void +gimple_parse_expect_rhs2 (cpp_reader *p) +{ + const cpp_token *next_token; + next_token = cpp_peek_token (p, 0); + + /* ??? Can there be more possibilities than these ? */ + + if (next_token->type == CPP_NAME) + { + /* Handle a special case, this can be NULL too. + + if (!strcasecmp ((const char *) cpp_token_as_text (p, next_token), "Null")); + { + + } */ + + next_token = cpp_get_token (p); + } + else if (next_token->type == CPP_NUMBER) + next_token = cpp_get_token (p); + + gimple_parse_expect_token (p, CPP_GREATER); +} + +/* Parse a gimple_assign tuple that is read from the reader P. For now we + only recognize the tuple. Refer gimple.def for the format of this tuple. */ + +static void +gimple_parse_assign_stmt (cpp_reader *p) +{ + gimple_parse_expect_subcode (p); + gimple_parse_expect_lhs (p); + gimple_parse_expect_rhs1 (p); + gimple_parse_expect_rhs2 (p); +} + +/* Helper for gimple_parse_cond_stmt. The token read from reader P should + be the first operand in the tuple. */ +static void +gimple_parse_expect_op1 (cpp_reader *p) +{ + const cpp_token *next_token; + next_token = cpp_peek_token (p, 0); + + if(next_token->type == CPP_NAME) + next_token = cpp_get_token (p); + else if (next_token->type == CPP_NUMBER) + next_token = cpp_get_token (p); + + gimple_parse_expect_token (p, CPP_COMMA); +} + +/* Helper for gimple_parse_cond_stmt. The token read from reader P should + be the second operand in the tuple. */ + +static void +gimple_parse_expect_op2 (cpp_reader *p) +{ + const cpp_token *next_token; + next_token = cpp_peek_token (p, 0); + + if(next_token->type == CPP_NAME) + next_token = cpp_get_token (p); + else if (next_token->type == CPP_NUMBER) + next_token = cpp_get_token (p); + else if (next_token->type == CPP_STRING) + next_token = cpp_get_token (p); + else if (next_token->type == CPP_AND) + { + next_token = cpp_get_token (p); + gimple_parse_expect_token (p, CPP_NAME); + } + + gimple_parse_expect_token (p, CPP_COMMA); +} + +/* Helper for gimple_parse_cond_stmt. The token read from reader P should + be the true label in the tuple that means the label where the control + jumps if the condition evaluates to true. */ + +static void +gimple_parse_expect_true_label (cpp_reader *p) +{ + gimple_parse_expect_token (p, CPP_LESS); + gimple_parse_expect_token (p, CPP_NAME); + gimple_parse_expect_token (p, CPP_GREATER); + gimple_parse_expect_token (p, CPP_COMMA); +} + +/* Helper for gimple_parse_cond_stmt. The token read from reader P should + be the false label in the tuple that means the label where the control + jumps if the condition evaluates to false. */ + +static void +gimple_parse_expect_false_label (cpp_reader *p) +{ + gimple_parse_expect_token (p, CPP_LESS); + gimple_parse_expect_token (p, CPP_NAME); + gimple_parse_expect_token (p, CPP_RSHIFT); +} + +/* Parse a gimple_cond tuple that is read from the reader P. For now we only + recognize the tuple. Refer gimple.def for the format of this tuple. */ + +static void +gimple_parse_cond_stmt (cpp_reader *p) +{ + gimple_parse_expect_subcode (p); + gimple_parse_expect_op1 (p); + gimple_parse_expect_op2 (p); + gimple_parse_expect_true_label (p); + gimple_parse_expect_false_label (p); +} + +/* Parse a gimple_goto tuple that is read from the reader P. For now we only + recognize the tuple. Refer gimple.def for the format of this tuple. */ + +static void +gimple_parse_goto_stmt (cpp_reader *p) +{ + gimple_parse_expect_token (p, CPP_LSHIFT); + gimple_parse_expect_token (p, CPP_NAME); + gimple_parse_expect_token (p, CPP_RSHIFT); +} + +/* Parse a gimple_label tuple that is read from the reader P. For now we only + recognize the tuple. Refer gimple.def for the format of this tuple. */ + +static void +gimple_parse_label_stmt (cpp_reader *p) +{ + gimple_parse_expect_token (p, CPP_LSHIFT); + gimple_parse_expect_token (p, CPP_NAME); + gimple_parse_expect_token (p, CPP_RSHIFT); +} + +/* Parse a gimple_switch tuple that is read from the reader P. For now we only + recognize the tuple. Refer gimple.def for the format of this tuple. */ + +static void +gimple_parse_switch_stmt (cpp_reader *p) +{ + const cpp_token *next_token; + + gimple_parse_expect_token (p, CPP_LESS); + gimple_parse_expect_token (p, CPP_NAME); + gimple_parse_expect_token (p, CPP_COMMA); + gimple_parse_expect_token (p, CPP_NAME); + gimple_parse_expect_token (p, CPP_COLON); + gimple_parse_expect_token (p, CPP_LESS); + gimple_parse_expect_token (p, CPP_NAME); + + for (;;) + { + next_token = cpp_peek_token (p, 0); + + if (next_token->type == CPP_GREATER) + { + next_token = cpp_get_token (p); + gimple_parse_expect_token (p, CPP_COMMA); + gimple_parse_expect_token (p, CPP_NAME); + gimple_parse_expect_token (p, CPP_NUMBER); + gimple_parse_expect_token (p, CPP_COLON); + gimple_parse_expect_token (p, CPP_LESS); + gimple_parse_expect_token (p, CPP_NAME); + } + else if (next_token->type == CPP_RSHIFT) + { + next_token = cpp_get_token (p); + break; + } + else + error ("Incorrect use of the gimple_switch statement"); + } +} + +/* Helper for gimple_parse_call_stmt. The token read from reader P should + be the name of the function called. */ + +static void +gimple_parse_expect_function_name (cpp_reader *p) +{ + gimple_parse_expect_token (p, CPP_LESS); + gimple_parse_expect_token (p, CPP_NAME); + gimple_parse_expect_token (p, CPP_COMMA); +} + +/* Helper for gimple_parse_call_stmt. The token read from reader P should + be the identifier in which the value is returned. */ + +static void +gimple_parse_expect_return_var (cpp_reader *p) +{ + const cpp_token *next_token; + + next_token = cpp_peek_token (p, 0); + + if (next_token->type == CPP_NAME) + next_token = cpp_get_token (p); + + /* There may be no variable in which the return value is collected. + In that case this field in the tuple will contain NULL. We need + to handle it too. */ +} + +/* Helper for gimple_parse_call_stmt. The token read from reader P should + be the argument in the function call. */ + +static void +gimple_parse_expect_argument (cpp_reader *p) +{ + const cpp_token *next_token; + + next_token = cpp_peek_token (p, 0); + + if (next_token->type == CPP_NUMBER) + next_token = cpp_get_token (p); + else if (next_token->type == CPP_NAME) + next_token = cpp_get_token (p); + else if (next_token->type == CPP_MULT) + { + next_token = cpp_get_token (p); + gimple_parse_expect_token (p, CPP_NAME); + } + else + error ("Incorrect way to specify an argument"); +} + +/* Parse a gimple_call tuple that is read from the reader P. For now we only + recognize the tuple. Refer gimple.def for the format of this tuple. */ + +static void +gimple_parse_call_stmt (cpp_reader *p) +{ + const cpp_token *next_token; + + gimple_parse_expect_function_name (p); + gimple_parse_expect_return_var (p); + + for (;;) + { + next_token = cpp_peek_token (p, 0); + if (next_token->type == CPP_GREATER) + { + next_token = cpp_get_token (p); + break; + } + else if (next_token->type == CPP_COMMA) + { + next_token = cpp_get_token (p); + gimple_parse_expect_argument (p); + } + } +} + +/* Parse a gimple_return tuple that is read from the reader P. For now we only + recognize the tuple. Refer gimple.def for the format of this tuple. */ + +static void +gimple_parse_return_stmt (cpp_reader *p) +{ + gimple_parse_expect_token (p, CPP_LESS); + gimple_parse_expect_token (p, CPP_NAME); + gimple_parse_expect_token (p, CPP_GREATER); +} + +/* The TOK read from the reader P is looked up for a match. Calls the + corresponding function to do the parsing for the match. */ + +static void +gimple_parse_stmt (cpp_reader *p, const cpp_token *tok) +{ + const char *text; + int i; + text = (const char *) cpp_token_as_text (p, tok); + for (i = GIMPLE_ERROR_MARK; i < LAST_AND_UNUSED_GIMPLE_CODE; i++) + if (strcasecmp (text, gimple_code_name[i]) == 0) + break; + + if (i == LAST_AND_UNUSED_GIMPLE_CODE) + error ("Invalid gimple code used"); + else + { + switch (i) + { + case GIMPLE_ASSIGN: + gimple_parse_assign_stmt (p); + break; + case GIMPLE_COND: + gimple_parse_cond_stmt (p); + break; + case GIMPLE_LABEL: + gimple_parse_label_stmt (p); + break; + case GIMPLE_GOTO: + gimple_parse_goto_stmt (p); + break; + case GIMPLE_SWITCH: + gimple_parse_switch_stmt (p); + break; + case GIMPLE_CALL: + gimple_parse_call_stmt (p); + break; + case GIMPLE_RETURN: + gimple_parse_return_stmt (p); + break; + default: + break; + } + } +} + + +/* Main entry point for the GIMPLE front end. */ + +void +gimple_main (int debug_p ATTRIBUTE_UNUSED) +{ + /* We invoke the parser here. */ + cpp_reader *p; + const cpp_token *tok; + const char *input_file = "/tmp/gimple.txt"; + const char *output_file; + + struct line_maps *line_tab; + line_tab = ggc_alloc_cleared_line_maps (); + linemap_init (line_tab); + p = cpp_create_reader (CLK_GNUC99, ident_hash, line_tab); + output_file = cpp_read_main_file (p,input_file); + if (output_file) + { + tok = cpp_get_token (p); + while (tok->type != CPP_EOF) + { + gimple_parse_stmt (p, tok); + tok = cpp_get_token (p); + } + } + cpp_finish (p,NULL); + cpp_destroy (p); +} diff --git a/gcc/gimple/parser.h b/gcc/gimple/parser.h new file mode 100644 index 0000000..36181d2 --- /dev/null +++ b/gcc/gimple/parser.h @@ -0,0 +1,28 @@ +/* GIMPLE parser declarations + + Copyright 2010 Free Software Foundation, Inc. + Contributed by Sandeep Soni and Diego Novillo + +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 +. */ + +#ifndef GIMPLE_PARSER_H +#define GIMPLE_PARSER_H + +/* In parser.c */ +extern void gimple_main (int); + +#endif /* GIMPLE_PARSER_H */ diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c index 388a46c..b03d7cc 100644 --- a/gcc/lto/lto-lang.c +++ b/gcc/lto/lto-lang.c @@ -1133,7 +1133,7 @@ static void lto_init_ts (void) } #undef LANG_HOOKS_NAME -#define LANG_HOOKS_NAME "GNU GIMPLE" +#define LANG_HOOKS_NAME "GNU GIMPLE BC" #undef LANG_HOOKS_OPTION_LANG_MASK #define LANG_HOOKS_OPTION_LANG_MASK lto_option_lang_mask #undef LANG_HOOKS_COMPLAIN_WRONG_LANG_P diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c index 40b56ba..e4ee214 100644 --- a/gcc/lto/lto.c +++ b/gcc/lto/lto.c @@ -1992,434 +1992,6 @@ lto_eh_personality (void) return lto_eh_personality_decl; } -/* Consumes a token if the EXPECTED_TOKEN_TYPE is exactly the one we - are looking for. The token is obtained by reading it from the reader P. */ - -static const cpp_token * -gimple_parse_expect_token (cpp_reader *p, enum cpp_ttype expected_token_type) -{ - const cpp_token *next_token; - - next_token = cpp_peek_token (p, 0); - - /* If the token type does not match then we must report an error, - otherwise consume the token. */ - - /* FIXME The error reported should be more precise to help - diagnostics similar to that reported by other front ends in - the same case. */ - - if (next_token->type != expected_token_type) - error ("expected token type %s instead of %s", - cpp_type2name (expected_token_type, 0), - cpp_type2name (next_token->type, 0)); - else - next_token = cpp_get_token_with_location (p, &input_location); - - return next_token; -} - -/* Helper for gimple_parse_assign_stmt and gimple_parse_cond_stmt. - Peeks a token by reading from reader P and looks it up to match - against the tree codes. */ - -static void -gimple_parse_expect_subcode (cpp_reader *p) -{ - const cpp_token *next_token; - const char *text; - int i; - - gimple_parse_expect_token (p, CPP_LESS); - - /* Peeks a token and looks it up for a match. */ - - next_token = cpp_peek_token (p, 0); - text = (const char *) cpp_token_as_text (p, next_token); - for (i = ERROR_MARK; i < LAST_AND_UNUSED_TREE_CODE; i++) - if (strcasecmp (text, tree_code_name[i]) == 0) - break; - - /* If none of the tree codes match, then report an error. Otherwise - consume this token. */ - if (i == LAST_AND_UNUSED_TREE_CODE) - error ("Expected token should be one of the tree codes"); - else - next_token = cpp_get_token (p); - - gimple_parse_expect_token (p, CPP_COMMA); - - /* FIXME From this function we should return the tree code since it - can be used by the other helper functions to recognize precisely. */ -} - -/* Helper for gimple_parse_assign_stmt. The token read from reader P should - be the lhs of the tuple. */ - -static void -gimple_parse_expect_lhs (cpp_reader *p) -{ - const cpp_token *next_token; - - /* Just before the name of the identifier we might get the symbol - of dereference too. If we do get it then consume that token, else - continue recognizing the name. */ - next_token = cpp_peek_token (p, 0); - if (next_token->type == CPP_MULT) - next_token = cpp_get_token (p); - - gimple_parse_expect_token (p, CPP_NAME); - gimple_parse_expect_token (p, CPP_COMMA); -} - -/* Helper for gimple_parse_assign_stmt. The token read from reader P should - be the first operand in rhs of the tuple. */ - -static void -gimple_parse_expect_rhs1 (cpp_reader *p) -{ - const cpp_token *next_token; - next_token = cpp_peek_token (p, 0); - - /* Currently there is duplication in the following blocks but there - would be more stuff added here as we go on. */ - - /* ??? Can there be more possibilities than these ? */ - if (next_token->type == CPP_MULT) - { - next_token = cpp_get_token (p); - gimple_parse_expect_token (p, CPP_NAME); - } - else if (next_token->type == CPP_AND) - { - next_token = cpp_get_token (p); - gimple_parse_expect_token (p, CPP_NAME); - } - else if (next_token->type == CPP_NAME) - next_token = cpp_get_token (p); - else if (next_token->type == CPP_NUMBER) - next_token = cpp_get_token (p); - else if (next_token->type == CPP_STRING) - next_token = cpp_get_token (p); - - gimple_parse_expect_token (p, CPP_COMMA); -} - -/* Helper for gimple_parse_assign_stmt. The token read from reader P should - be the second operand in rhs of the tuple. */ - -static void -gimple_parse_expect_rhs2 (cpp_reader *p) -{ - const cpp_token *next_token; - next_token = cpp_peek_token (p, 0); - - /* ??? Can there be more possibilities than these ? */ - - if (next_token->type == CPP_NAME) - { - /* Handle a special case, this can be NULL too. - - if (!strcasecmp ((const char *) cpp_token_as_text (p, next_token), "Null")); - { - - } */ - - next_token = cpp_get_token (p); - } - else if (next_token->type == CPP_NUMBER) - next_token = cpp_get_token (p); - - gimple_parse_expect_token (p, CPP_GREATER); -} - -/* Parse a gimple_assign tuple that is read from the reader P. For now we - only recognize the tuple. Refer gimple.def for the format of this tuple. */ - -static void -gimple_parse_assign_stmt (cpp_reader *p) -{ - gimple_parse_expect_subcode (p); - gimple_parse_expect_lhs (p); - gimple_parse_expect_rhs1 (p); - gimple_parse_expect_rhs2 (p); -} - -/* Helper for gimple_parse_cond_stmt. The token read from reader P should - be the first operand in the tuple. */ -static void -gimple_parse_expect_op1 (cpp_reader *p) -{ - const cpp_token *next_token; - next_token = cpp_peek_token (p, 0); - - if(next_token->type == CPP_NAME) - next_token = cpp_get_token (p); - else if (next_token->type == CPP_NUMBER) - next_token = cpp_get_token (p); - - gimple_parse_expect_token (p, CPP_COMMA); -} - -/* Helper for gimple_parse_cond_stmt. The token read from reader P should - be the second operand in the tuple. */ - -static void -gimple_parse_expect_op2 (cpp_reader *p) -{ - const cpp_token *next_token; - next_token = cpp_peek_token (p, 0); - - if(next_token->type == CPP_NAME) - next_token = cpp_get_token (p); - else if (next_token->type == CPP_NUMBER) - next_token = cpp_get_token (p); - else if (next_token->type == CPP_STRING) - next_token = cpp_get_token (p); - else if (next_token->type == CPP_AND) - { - next_token = cpp_get_token (p); - gimple_parse_expect_token (p, CPP_NAME); - } - - gimple_parse_expect_token (p, CPP_COMMA); -} - -/* Helper for gimple_parse_cond_stmt. The token read from reader P should - be the true label in the tuple that means the label where the control - jumps if the condition evaluates to true. */ - -static void -gimple_parse_expect_true_label (cpp_reader *p) -{ - gimple_parse_expect_token (p, CPP_LESS); - gimple_parse_expect_token (p, CPP_NAME); - gimple_parse_expect_token (p, CPP_GREATER); - gimple_parse_expect_token (p, CPP_COMMA); -} - -/* Helper for gimple_parse_cond_stmt. The token read from reader P should - be the false label in the tuple that means the label where the control - jumps if the condition evaluates to false. */ - -static void -gimple_parse_expect_false_label (cpp_reader *p) -{ - gimple_parse_expect_token (p, CPP_LESS); - gimple_parse_expect_token (p, CPP_NAME); - gimple_parse_expect_token (p, CPP_RSHIFT); -} - -/* Parse a gimple_cond tuple that is read from the reader P. For now we only - recognize the tuple. Refer gimple.def for the format of this tuple. */ - -static void -gimple_parse_cond_stmt (cpp_reader *p) -{ - gimple_parse_expect_subcode (p); - gimple_parse_expect_op1 (p); - gimple_parse_expect_op2 (p); - gimple_parse_expect_true_label (p); - gimple_parse_expect_false_label (p); -} - -/* Parse a gimple_goto tuple that is read from the reader P. For now we only - recognize the tuple. Refer gimple.def for the format of this tuple. */ - -static void -gimple_parse_goto_stmt (cpp_reader *p) -{ - gimple_parse_expect_token (p, CPP_LSHIFT); - gimple_parse_expect_token (p, CPP_NAME); - gimple_parse_expect_token (p, CPP_RSHIFT); -} - -/* Parse a gimple_label tuple that is read from the reader P. For now we only - recognize the tuple. Refer gimple.def for the format of this tuple. */ - -static void -gimple_parse_label_stmt (cpp_reader *p) -{ - gimple_parse_expect_token (p, CPP_LSHIFT); - gimple_parse_expect_token (p, CPP_NAME); - gimple_parse_expect_token (p, CPP_RSHIFT); -} - -/* Parse a gimple_switch tuple that is read from the reader P. For now we only - recognize the tuple. Refer gimple.def for the format of this tuple. */ - -static void -gimple_parse_switch_stmt (cpp_reader *p) -{ - const cpp_token *next_token; - - gimple_parse_expect_token (p, CPP_LESS); - gimple_parse_expect_token (p, CPP_NAME); - gimple_parse_expect_token (p, CPP_COMMA); - gimple_parse_expect_token (p, CPP_NAME); - gimple_parse_expect_token (p, CPP_COLON); - gimple_parse_expect_token (p, CPP_LESS); - gimple_parse_expect_token (p, CPP_NAME); - - for (;;) - { - next_token = cpp_peek_token (p, 0); - - if (next_token->type == CPP_GREATER) - { - next_token = cpp_get_token (p); - gimple_parse_expect_token (p, CPP_COMMA); - gimple_parse_expect_token (p, CPP_NAME); - gimple_parse_expect_token (p, CPP_NUMBER); - gimple_parse_expect_token (p, CPP_COLON); - gimple_parse_expect_token (p, CPP_LESS); - gimple_parse_expect_token (p, CPP_NAME); - } - else if (next_token->type == CPP_RSHIFT) - { - next_token = cpp_get_token (p); - break; - } - else - error ("Incorrect use of the gimple_switch statement"); - } -} - -/* Helper for gimple_parse_call_stmt. The token read from reader P should - be the name of the function called. */ - -static void -gimple_parse_expect_function_name (cpp_reader *p) -{ - gimple_parse_expect_token (p, CPP_LESS); - gimple_parse_expect_token (p, CPP_NAME); - gimple_parse_expect_token (p, CPP_COMMA); -} - -/* Helper for gimple_parse_call_stmt. The token read from reader P should - be the identifier in which the value is returned. */ - -static void -gimple_parse_expect_return_var (cpp_reader *p) -{ - const cpp_token *next_token; - - next_token = cpp_peek_token (p, 0); - - if (next_token->type == CPP_NAME) - next_token = cpp_get_token (p); - - /* There may be no variable in which the return value is collected. - In that case this field in the tuple will contain NULL. We need - to handle it too. */ -} - -/* Helper for gimple_parse_call_stmt. The token read from reader P should - be the argument in the function call. */ - -static void -gimple_parse_expect_argument (cpp_reader *p) -{ - const cpp_token *next_token; - - next_token = cpp_peek_token (p, 0); - - if (next_token->type == CPP_NUMBER) - next_token = cpp_get_token (p); - else if (next_token->type == CPP_NAME) - next_token = cpp_get_token (p); - else if (next_token->type == CPP_MULT) - { - next_token = cpp_get_token (p); - gimple_parse_expect_token (p, CPP_NAME); - } - else - error ("Incorrect way to specify an argument"); -} - -/* Parse a gimple_call tuple that is read from the reader P. For now we only - recognize the tuple. Refer gimple.def for the format of this tuple. */ - -static void -gimple_parse_call_stmt (cpp_reader *p) -{ - const cpp_token *next_token; - - gimple_parse_expect_function_name (p); - gimple_parse_expect_return_var (p); - - for (;;) - { - next_token = cpp_peek_token (p, 0); - if (next_token->type == CPP_GREATER) - { - next_token = cpp_get_token (p); - break; - } - else if (next_token->type == CPP_COMMA) - { - next_token = cpp_get_token (p); - gimple_parse_expect_argument (p); - } - } -} - -/* Parse a gimple_return tuple that is read from the reader P. For now we only - recognize the tuple. Refer gimple.def for the format of this tuple. */ - -static void -gimple_parse_return_stmt (cpp_reader *p) -{ - gimple_parse_expect_token (p, CPP_LESS); - gimple_parse_expect_token (p, CPP_NAME); - gimple_parse_expect_token (p, CPP_GREATER); -} - -/* The TOK read from the reader P is looked up for a match. Calls the - corresponding function to do the parsing for the match. */ - -static void -gimple_parse_stmt (cpp_reader *p, const cpp_token *tok) -{ - const char *text; - int i; - text = (const char *) cpp_token_as_text (p, tok); - for (i = GIMPLE_ERROR_MARK; i < LAST_AND_UNUSED_GIMPLE_CODE; i++) - if (strcasecmp (text, gimple_code_name[i]) == 0) - break; - - if (i == LAST_AND_UNUSED_GIMPLE_CODE) - error ("Invalid gimple code used"); - else - { - switch (i) - { - case GIMPLE_ASSIGN: - gimple_parse_assign_stmt (p); - break; - case GIMPLE_COND: - gimple_parse_cond_stmt (p); - break; - case GIMPLE_LABEL: - gimple_parse_label_stmt (p); - break; - case GIMPLE_GOTO: - gimple_parse_goto_stmt (p); - break; - case GIMPLE_SWITCH: - gimple_parse_switch_stmt (p); - break; - case GIMPLE_CALL: - gimple_parse_call_stmt (p); - break; - case GIMPLE_RETURN: - gimple_parse_return_stmt (p); - break; - default: - break; - } - } -} /* Main entry point for the GIMPLE front end. This front end has three main personalities: @@ -2452,36 +2024,9 @@ lto_main (int debug_p ATTRIBUTE_UNUSED) if (!seen_error ()) { - if (flag_gimple_parser) - { - /* We invoke the parser here. */ - cpp_reader *p; - const cpp_token *tok; - const char *input_file = "/tmp/gimple.txt"; - const char *output_file; - - struct line_maps *line_tab; - line_tab = ggc_alloc_cleared_line_maps (); - linemap_init (line_tab); - p = cpp_create_reader (CLK_GNUC99,ident_hash,line_tab); - output_file = cpp_read_main_file (p,input_file); - if (output_file) - { - tok = cpp_get_token (p); - while (tok->type != CPP_EOF) - { - gimple_parse_stmt (p, tok); - tok = cpp_get_token (p); - } - } - cpp_finish (p,NULL); - cpp_destroy (p); - } - /* If WPA is enabled analyze the whole call graph and create an optimization plan. Otherwise, read in all the function bodies and continue with optimization. */ - if (flag_wpa) do_whole_program_analysis (); else