Gemeinsame Unterverzeichnisse: ../gcc-4.3.2_orig/gcc/ada und gcc/ada. diff -Nup ../gcc-4.3.2_orig/gcc/builtins.def gcc/builtins.def --- ../gcc-4.3.2_orig/gcc/builtins.def 2008-06-28 12:43:12.000000000 +0200 +++ gcc/builtins.def 2008-08-29 11:42:45.793812666 +0200 @@ -142,6 +142,13 @@ along with GCC; see the file COPYING3. false, true, true, ATTRS, false, \ (flag_openmp || flag_tree_parallelize_loops)) +/* Builtin used by the implementation of GNU TM. These + functions are mapped to the actual implementation of the STM library. */ +#undef DEF_GTM_BUILTIN +#define DEF_GTM_BUILTIN(ENUM, NAME, TYPE, ATTRS) \ + DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE, \ + false, true, true, ATTRS, false, flag_gtm) + /* Define an attribute list for math functions that are normally "impure" because some of them may write into global memory for `errno'. If !flag_errno_math they are instead "const". */ @@ -754,3 +761,6 @@ DEF_EXT_LIB_BUILTIN (BUILT_IN_EMUTLS_REG /* OpenMP builtins. */ #include "omp-builtins.def" + +/* GTM builtins. */ +#include "gtm-builtins.def" diff -Nup ../gcc-4.3.2_orig/gcc/builtin-types.def gcc/builtin-types.def --- ../gcc-4.3.2_orig/gcc/builtin-types.def 2008-06-28 12:43:12.000000000 +0200 +++ gcc/builtin-types.def 2008-08-29 11:38:02.804973098 +0200 @@ -454,3 +454,29 @@ DEF_FUNCTION_TYPE_VAR_5 (BT_FN_INT_STRIN DEF_POINTER_TYPE (BT_PTR_FN_VOID_VAR, BT_FN_VOID_VAR) DEF_FUNCTION_TYPE_3 (BT_FN_PTR_PTR_FN_VOID_VAR_PTR_SIZE, BT_PTR, BT_PTR_FN_VOID_VAR, BT_PTR, BT_SIZE) + +/* GTM special types go here */ +DEF_FUNCTION_TYPE_VAR_2 (BT_FN_INT_PTR_INT, BT_INT, BT_PTR, BT_INT) +DEF_FUNCTION_TYPE_VAR_2 (BT_FN_INT_PTR_VPTR, BT_INT, + BT_PTR, BT_VOLATILE_PTR) +DEF_FUNCTION_TYPE_VAR_2 (BT_FN_I1_PTR_VPTR, BT_I1, + BT_PTR, BT_VOLATILE_PTR) +DEF_FUNCTION_TYPE_VAR_2 (BT_FN_I2_PTR_VPTR, BT_I2, + BT_PTR, BT_VOLATILE_PTR) +DEF_FUNCTION_TYPE_VAR_2 (BT_FN_I4_PTR_VPTR, BT_I4, + BT_PTR, BT_VOLATILE_PTR) +DEF_FUNCTION_TYPE_VAR_2 (BT_FN_I8_PTR_VPTR, BT_I8, + BT_PTR, BT_VOLATILE_PTR) +DEF_FUNCTION_TYPE_VAR_3 (BT_FN_VOID_PTR_PTR_INT_PTR, BT_VOID, BT_PTR, + BT_PTR, BT_INT_PTR) +DEF_FUNCTION_TYPE_VAR_3 (BT_FN_VOID_PTR_VPTR_INT, BT_VOID, BT_PTR, + BT_VOLATILE_PTR, BT_INT) +DEF_FUNCTION_TYPE_VAR_3 (BT_FN_VOID_PTR_VPTR_I1, BT_VOID, BT_PTR, + BT_VOLATILE_PTR, BT_I1) +DEF_FUNCTION_TYPE_VAR_3 (BT_FN_VOID_PTR_VPTR_I2, BT_VOID, BT_PTR, + BT_VOLATILE_PTR, BT_I2) +DEF_FUNCTION_TYPE_VAR_3 (BT_FN_VOID_PTR_VPTR_I4, BT_VOID, BT_PTR, + BT_VOLATILE_PTR, BT_I4) +DEF_FUNCTION_TYPE_VAR_3 (BT_FN_VOID_PTR_VPTR_I8, BT_VOID, BT_PTR, + BT_VOLATILE_PTR, BT_I8) + diff -Nup ../gcc-4.3.2_orig/gcc/c-common.c gcc/c-common.c --- ../gcc-4.3.2_orig/gcc/c-common.c 2008-07-15 17:52:35.000000000 +0200 +++ gcc/c-common.c 2008-08-29 12:00:37.249346056 +0200 @@ -565,6 +565,11 @@ static bool nonnull_check_p (tree, unsig static bool get_nonnull_operand (tree, unsigned HOST_WIDE_INT *); static int resort_field_decl_cmp (const void *, const void *); +static tree handle_gtm_callable_attribute (tree *, tree, tree, int, bool *); +static tree handle_gtm_only_attribute (tree *, tree, tree, int, bool *); +static tree handle_gtm_pure_attribute (tree *, tree, tree, int, bool *); +static tree handle_gtm_unknown_attribute (tree *, tree, tree, int, bool *); + /* Table of machine-independent attributes common to all C-like languages. */ const struct attribute_spec c_common_attribute_table[] = { @@ -631,6 +636,16 @@ const struct attribute_spec c_common_att handle_no_limit_stack_attribute }, { "pure", 0, 0, true, false, false, handle_pure_attribute }, + /* Here the GTM attributes start. */ + { "tm_pure", 0, 0, true, false, false, + handle_gtm_pure_attribute }, + { "tm_callable", 0, 0, true, false, false, + handle_gtm_callable_attribute }, + { "tm_only", 0, 0, true, false, false, + handle_gtm_only_attribute }, + { "tm_unknown", 0, 0, true, false, false, + handle_gtm_unknown_attribute }, + /* End of GTM attributes. */ /* For internal use (marking of builtins) only. The name contains space to prevent its usage in source code. */ { "no vops", 0, 0, true, false, false, @@ -5924,6 +5939,85 @@ handle_pure_attribute (tree *node, tree return NULL_TREE; } +/* Handle a "tm_pure" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_gtm_pure_attribute (tree *node, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + DECL_IS_GTM_PURE (*node) = 1; + /* ??? TODO: Support types. */ + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + gcc_assert(DECL_IS_GTM_PURE (*node) == 1); + return NULL_TREE; +} + +/* Handle a "tm_only" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_gtm_only_attribute (tree *node, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + { + DECL_IS_GTM_ONLY (*node) = 1; + gcc_assert(DECL_IS_GTM_ONLY (*node) == 1); + } + /* ??? TODO: Support types. */ + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "tm_unknown" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_gtm_unknown_attribute (tree *node, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + DECL_IS_GTM_UNKNOWN (*node) = 1; + /* ??? TODO: Support types. */ + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "tm_callable" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_gtm_callable_attribute (tree *node, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + DECL_IS_GTM_CALLABLE (*node) = 1; + /* ??? TODO: Support types. */ + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + /* Handle a "no vops" attribute; arguments as in struct attribute_spec.handler. */ @@ -7167,6 +7261,8 @@ resolve_overloaded_builtin (tree functio case BUILT_IN_VAL_COMPARE_AND_SWAP_N: case BUILT_IN_LOCK_TEST_AND_SET_N: case BUILT_IN_LOCK_RELEASE_N: + case BUILT_IN_GTM_LOAD_N: + case BUILT_IN_GTM_STORE_N: { int n = sync_resolve_size (function, params); tree new_function, result; diff -Nup ../gcc-4.3.2_orig/gcc/c-gtm.c gcc/c-gtm.c --- ../gcc-4.3.2_orig/gcc/c-gtm.c 1970-01-01 01:00:00.000000000 +0100 +++ gcc/c-gtm.c 2008-08-29 11:25:01.333920434 +0200 @@ -0,0 +1,50 @@ +/* This file contains routines to construct GNU GTM constructs, + called from parsing in the C and C++ front ends. + + Copyright (C) 2008 Free Software Foundation, Inc. + Contributed by Martin Schindewolf + +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 "tm.h" +#include "tree.h" +#include "function.h" +#include "c-common.h" +#include "toplev.h" +#include "tree-gimple.h" +#include "bitmap.h" +#include "langhooks.h" + +tree c_finish_gtm (tree); + + +/* Complete a #pragma tm atomic construct. STMT is the structured-block + that follows the pragma. + The pragma marks the beginning of a transaction. */ + +tree +c_finish_gtm (tree body) +{ + tree stmt = make_node (GTM_TXN); + TREE_TYPE (stmt) = void_type_node; + GTM_TXN_BODY (stmt) = body; + return add_stmt (stmt); +} + diff -Nup ../gcc-4.3.2_orig/gcc/common.opt gcc/common.opt --- ../gcc-4.3.2_orig/gcc/common.opt 2008-01-22 15:11:44.000000000 +0100 +++ gcc/common.opt 2008-08-29 14:33:07.409296901 +0200 @@ -524,6 +524,10 @@ Common Report Var(flag_gcse_after_reload Perform global common subexpression elimination after register allocation has finished +fgnu-tm +Common Report Var(flag_gtm) +Enable support for GNU transactional memory Use together with -O1 + fguess-branch-probability Common Report Var(flag_guess_branch_prob) Optimization Enable guessing of branch probabilities Gemeinsame Unterverzeichnisse: ../gcc-4.3.2_orig/gcc/config und gcc/config. Gemeinsame Unterverzeichnisse: ../gcc-4.3.2_orig/gcc/cp und gcc/cp. diff -Nup ../gcc-4.3.2_orig/gcc/c-parser.c gcc/c-parser.c --- ../gcc-4.3.2_orig/gcc/c-parser.c 2008-04-03 23:24:28.000000000 +0200 +++ gcc/c-parser.c 2008-08-29 12:08:41.229217821 +0200 @@ -1016,6 +1016,8 @@ static struct c_expr c_parser_postfix_ex struct c_type_name *); static struct c_expr c_parser_postfix_expression_after_primary (c_parser *, struct c_expr); +static tree c_parser_gtm (c_parser *); +static tree c_parser_gtm_atomic (c_parser *); static struct c_expr c_parser_expression (c_parser *); static struct c_expr c_parser_expression_conv (c_parser *); static tree c_parser_expr_list (c_parser *, bool); @@ -7941,6 +7943,9 @@ c_parser_omp_construct (c_parser *parser case PRAGMA_OMP_SINGLE: stmt = c_parser_omp_single (parser); break; + case PRAGMA_GTM_ATOMIC: + stmt = c_parser_gtm_atomic (parser); + break; default: gcc_unreachable (); } @@ -7996,6 +8001,28 @@ c_parser_omp_threadprivate (c_parser *pa c_parser_skip_to_pragma_eol (parser); } +/* + GTM attempt to intigrate the pragma tm atomic into the front end + + structured-block: + statements +*/ + +static tree +c_parser_gtm_atomic (c_parser *parser) +{ + tree stmt = NULL; + tree block; + + c_parser_skip_to_pragma_eol (parser); + + block = c_begin_gtm_txn (); + c_parser_statement (parser); + stmt = c_finish_gtm_txn (block); + + return stmt; +} + /* Parse a single source file. */ diff -Nup ../gcc-4.3.2_orig/gcc/c-pragma.c gcc/c-pragma.c --- ../gcc-4.3.2_orig/gcc/c-pragma.c 2008-02-14 22:41:40.000000000 +0100 +++ gcc/c-pragma.c 2008-08-29 12:10:34.224542071 +0200 @@ -946,6 +946,10 @@ init_pragma (void) cpp_register_deferred_pragma (parse_in, "omp", omp_pragmas[i].name, omp_pragmas[i].id, true, true); } + + if (flag_gtm) + cpp_register_deferred_pragma (parse_in, "tm", "atomic", + PRAGMA_GTM_ATOMIC, true, true); cpp_register_deferred_pragma (parse_in, "GCC", "pch_preprocess", PRAGMA_GCC_PCH_PREPROCESS, false, false); diff -Nup ../gcc-4.3.2_orig/gcc/c-pragma.h gcc/c-pragma.h --- ../gcc-4.3.2_orig/gcc/c-pragma.h 2007-09-13 22:18:38.000000000 +0200 +++ gcc/c-pragma.h 2008-08-29 12:13:10.218091158 +0200 @@ -43,6 +43,8 @@ typedef enum pragma_kind { PRAGMA_OMP_SINGLE, PRAGMA_OMP_THREADPRIVATE, + PRAGMA_GTM_ATOMIC, + PRAGMA_GCC_PCH_PREPROCESS, PRAGMA_FIRST_EXTERNAL @@ -69,6 +71,13 @@ typedef enum pragma_omp_clause { PRAGMA_OMP_CLAUSE_SHARED } pragma_omp_clause; +/* Clauses defined by GTM. (none up to now) + Implemented to be extendible. + Used internally by both C and C++ parsers. */ +typedef enum pragma_gtm_clause { + PRAGMA_GTM_CLAUSE_NONE = 0 +} pragma_gtm_clause; + extern struct cpp_reader* parse_in; #define HANDLE_PRAGMA_WEAK SUPPORTS_WEAK diff -Nup ../gcc-4.3.2_orig/gcc/c-tree.h gcc/c-tree.h --- ../gcc-4.3.2_orig/gcc/c-tree.h 2007-11-23 00:12:29.000000000 +0100 +++ gcc/c-tree.h 2008-08-29 12:16:51.708873404 +0200 @@ -598,6 +598,8 @@ extern tree c_expr_to_decl (tree, bool * extern tree c_begin_omp_parallel (void); extern tree c_finish_omp_parallel (tree, tree); extern tree c_finish_omp_clauses (tree); +extern tree c_begin_gtm_txn (void); +extern tree c_finish_gtm_txn (tree); /* Set to 0 at beginning of a function definition, set to 1 if a return statement that specifies a return value is seen. */ diff -Nup ../gcc-4.3.2_orig/gcc/c-typeck.c gcc/c-typeck.c --- ../gcc-4.3.2_orig/gcc/c-typeck.c 2008-01-30 00:19:07.000000000 +0100 +++ gcc/c-typeck.c 2008-08-29 12:21:58.195492582 +0200 @@ -8908,6 +8908,71 @@ c_finish_omp_clauses (tree clauses) return clauses; } +/* Similar to c_begin_omp_parallel. */ + +tree +c_begin_gtm_txn (void) +{ + tree block; + + keep_next_level (); + block = c_begin_compound_stmt (true); + + return block; +} + +/* Parse like OMP_PARALLEL in case + OpenMP is used. The lowering + pass of OpenMP will do the rest. + In case the OMP lowering pass is not + triggered simply introduce a new stmt_list + while encountering a BIND_EXPR. Then + gimple-low.c should behave nicely and + add the GTM_RETURN at the end of the + transaction. */ + +tree +c_finish_gtm_txn (tree block) +{ + if (flag_openmp) + { + tree stmt; + + block = c_end_compound_stmt (block, true); + + stmt = make_node (GTM_TXN); + TREE_TYPE (stmt) = void_type_node; + GTM_TXN_BODY (stmt) = block; + + return add_stmt (stmt); + } + else + { + tree stmt; + tree new_body; + tree gtm_ret; + + block = c_end_compound_stmt (block, true); + + stmt = make_node (GTM_TXN); + TREE_TYPE (stmt) = void_type_node; + new_body = block; + + if (TREE_CODE (block) == BIND_EXPR) + { + new_body = alloc_stmt_list (); + append_to_statement_list (block, &new_body); + gtm_ret = make_node (GTM_RETURN); + append_to_statement_list (gtm_ret, &new_body); + } + + GTM_TXN_BODY (stmt) = new_body; + + return add_stmt (stmt); + } +} + + /* Make a variant type in the proper way for C/C++, propagating qualifiers down to the element type of an array. */ Gemeinsame Unterverzeichnisse: ../gcc-4.3.2_orig/gcc/doc und gcc/doc. Gemeinsame Unterverzeichnisse: ../gcc-4.3.2_orig/gcc/fortran und gcc/fortran. diff -Nup ../gcc-4.3.2_orig/gcc/gimple-low.c gcc/gimple-low.c --- ../gcc-4.3.2_orig/gcc/gimple-low.c 2007-10-29 12:05:04.000000000 +0100 +++ gcc/gimple-low.c 2008-08-29 12:36:28.658390332 +0200 @@ -201,6 +201,110 @@ lower_omp_directive (tree_stmt_iterator tsi_delink (tsi); } +static void +mark_gtm_save_vars (tree vars) +{ + for (; vars; vars = TREE_CHAIN (vars)) + { + tree var = vars; + if (TREE_CODE (var) == VAR_DECL) + { + DECL_IS_GTM_PURE_VAR (var) = 1; + } + } + return ; +} + +/* Lower the GTM directive statement pointed by TSI. DATA is + passed through the recursion. */ + +static void +lower_gtm_directive (tree_stmt_iterator *tsi, struct lower_data *data) +{ + tree stmt; + + stmt = tsi_stmt (*tsi); + tree body = GTM_TXN_BODY (stmt); + if (TREE_CODE (body) == STATEMENT_LIST) + { + tree temp; + tree_stmt_iterator ttsi = tsi_start (body); + if (!tsi_end_p (ttsi)) + { + temp = tsi_stmt (ttsi); + } + else gcc_unreachable(); + if (TREE_CODE (temp) == BIND_EXPR) + { + tree vars = BIND_EXPR_VARS (temp); + + if (vars) + { + mark_gtm_save_vars(vars); + } + if (TREE_CODE (BIND_EXPR_BODY (temp)) == STATEMENT_LIST) + { + tree temp2; + tree_stmt_iterator ttsi = tsi_start (BIND_EXPR_BODY (temp)); + + if (!tsi_end_p (ttsi)) + { + temp2 = tsi_stmt (ttsi); + } + else gcc_unreachable(); + + if (TREE_CODE (temp2) == BIND_EXPR) + { + tree vars = BIND_EXPR_VARS (temp2); + + if (vars) + { + mark_gtm_save_vars(vars); + } + } + } + } + } + else + { + if (TREE_CODE (body) == BIND_EXPR) + { + tree vars = BIND_EXPR_VARS (body); + + if (vars) + { + mark_gtm_save_vars(vars); + } + } + if (TREE_CODE (BIND_EXPR_BODY (body)) == STATEMENT_LIST) + { + tree temp; + tree_stmt_iterator ttsi = tsi_start (BIND_EXPR_BODY (body)); + + if (!tsi_end_p (ttsi)) + { + temp = tsi_stmt (ttsi); + } + else gcc_unreachable(); + + if (TREE_CODE (temp) == BIND_EXPR) + { + tree vars = BIND_EXPR_VARS (temp); + + if (vars) + { + mark_gtm_save_vars(vars); + } + } + } + } + + lower_stmt_body (body, data); + tsi_link_before (tsi, stmt, TSI_SAME_STMT); + tsi_link_before (tsi, body, TSI_SAME_STMT); + GTM_TXN_BODY (stmt) = NULL_TREE; + tsi_delink (tsi); +} /* Lower statement TSI. DATA is passed through the recursion. */ @@ -254,6 +358,7 @@ lower_stmt (tree_stmt_iterator *tsi, str case OMP_ATOMIC_LOAD: case OMP_ATOMIC_STORE: case OMP_CONTINUE: + case GTM_RETURN: break; case GIMPLE_MODIFY_STMT: @@ -281,6 +386,10 @@ lower_stmt (tree_stmt_iterator *tsi, str lower_omp_directive (tsi, data); return; + case GTM_TXN: + lower_gtm_directive (tsi, data); + return; + default: gcc_unreachable (); } diff -Nup ../gcc-4.3.2_orig/gcc/gimplify.c gcc/gimplify.c --- ../gcc-4.3.2_orig/gcc/gimplify.c 2008-08-12 16:04:18.000000000 +0200 +++ gcc/gimplify.c 2008-08-29 12:43:06.641844884 +0200 @@ -5563,6 +5563,26 @@ gimplify_omp_atomic (tree *expr_p, tree } +/* Gimplify the contents of an GTM_TXN statement. This involves + gimplification of the body. */ + +static enum gimplify_status +gimplify_gtm_txn (tree *expr_p, tree *pre_p) +{ + tree expr = *expr_p; + + push_gimplify_context (); + + gimplify_stmt (>M_TXN_BODY (expr)); + + if (TREE_CODE (GTM_TXN_BODY (expr)) == BIND_EXPR) + pop_gimplify_context (GTM_TXN_BODY (expr)); + else + pop_gimplify_context (NULL_TREE); + + return GS_ALL_DONE; +} + /* Gimplifies the expression tree pointed to by EXPR_P. Return 0 if gimplification failed. @@ -6043,6 +6063,7 @@ gimplify_expr (tree *expr_p, tree *pre_p case OMP_RETURN: case OMP_CONTINUE: case OMP_ATOMIC_STORE: + case GTM_RETURN: ret = GS_ALL_DONE; break; @@ -6054,6 +6075,10 @@ gimplify_expr (tree *expr_p, tree *pre_p ret = GS_ALL_DONE; break; + case GTM_TXN: + ret = gimplify_gtm_txn (expr_p, pre_p); + break; + case POINTER_PLUS_EXPR: /* Convert ((type *)A)+offset into &A->field_of_type_and_offset. The second is gimple immediate saving a need for extra statement. Gemeinsame Unterverzeichnisse: ../gcc-4.3.2_orig/gcc/ginclude und gcc/ginclude. diff -Nup ../gcc-4.3.2_orig/gcc/gtm-builtins.def gcc/gtm-builtins.def --- ../gcc-4.3.2_orig/gcc/gtm-builtins.def 1970-01-01 01:00:00.000000000 +0100 +++ gcc/gtm-builtins.def 2008-08-29 11:24:34.834755812 +0200 @@ -0,0 +1,37 @@ +DEF_GTM_BUILTIN (BUILT_IN_GTM_TXN_COMMIT, "stm_commit", + BT_FN_INT_PTR, ATTR_NOTHROW_LIST) +DEF_GTM_BUILTIN (BUILT_IN_GTM_TXN_RETRY, "stm_retry", + BT_FN_VOID_PTR, ATTR_NOTHROW_LIST) +DEF_GTM_BUILTIN (BUILT_IN_GTM_NEW, "stm_new", + BT_FN_PTR, ATTR_NOTHROW_LIST) +DEF_GTM_BUILTIN (BUILT_IN_GTM_GET_ENV, "stm_get_env", + BT_FN_PTR_PTR, ATTR_NOTHROW_LIST) +DEF_GTM_BUILTIN (BUILT_IN_GTM_TXN_BEGIN, "stm_start", + BT_FN_VOID_PTR_PTR_INT_PTR, ATTR_NOTHROW_LIST) + +DEF_GTM_BUILTIN (BUILT_IN_GTM_STORE_N, "stm_store", + BT_FN_VOID_VAR, ATTR_NOTHROW_LIST) +DEF_GTM_BUILTIN (BUILT_IN_GTM_STORE_1, "stm_store8", + BT_FN_VOID_PTR_VPTR_I1, ATTR_NOTHROW_LIST) +DEF_GTM_BUILTIN (BUILT_IN_GTM_STORE_2, "stm_store16", + BT_FN_VOID_PTR_VPTR_I2, ATTR_NOTHROW_LIST) +DEF_GTM_BUILTIN (BUILT_IN_GTM_STORE_4, "stm_store32", + BT_FN_VOID_PTR_VPTR_I4, ATTR_NOTHROW_LIST) +DEF_GTM_BUILTIN (BUILT_IN_GTM_STORE_8, "stm_store64", + BT_FN_VOID_PTR_VPTR_I8, ATTR_NOTHROW_LIST) + +DEF_GTM_BUILTIN (BUILT_IN_GTM_LOAD_N, "stm_load", + BT_FN_VOID_VAR, ATTR_NOTHROW_LIST) +DEF_GTM_BUILTIN (BUILT_IN_GTM_LOAD_1, "stm_load8", + BT_FN_I1_PTR_VPTR, ATTR_NOTHROW_LIST) +DEF_GTM_BUILTIN (BUILT_IN_GTM_LOAD_2, "stm_load16", + BT_FN_I2_PTR_VPTR, ATTR_NOTHROW_LIST) +DEF_GTM_BUILTIN (BUILT_IN_GTM_LOAD_4, "stm_load32", + BT_FN_I4_PTR_VPTR, ATTR_NOTHROW_LIST) +DEF_GTM_BUILTIN (BUILT_IN_GTM_LOAD_8, "stm_load64", + BT_FN_I8_PTR_VPTR, ATTR_NOTHROW_LIST) + +DEF_GTM_BUILTIN (BUILT_IN_GTM_INIT, "stm_init", + BT_FN_VOID_INT, ATTR_NOTHROW_LIST) +DEF_GTM_BUILTIN (BUILT_IN_GTM_EXIT, "stm_exit", + BT_FN_VOID_INT, ATTR_NOTHROW_LIST) diff -Nup ../gcc-4.3.2_orig/gcc/gtm-low.c gcc/gtm-low.c --- ../gcc-4.3.2_orig/gcc/gtm-low.c 1970-01-01 01:00:00.000000000 +0100 +++ gcc/gtm-low.c 2008-08-29 17:32:44.637755912 +0200 @@ -0,0 +1,1372 @@ +/* Lowering pass for transactional memory directives. + Converts markers of transactions into explicit calls to + the STM runtime library. + + Copyright (C) 2008 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 + . */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "rtl.h" +#include "tree-gimple.h" +#include "tree-inline.h" +#include "langhooks.h" +#include "diagnostic.h" +#include "tree-flow.h" +#include "timevar.h" +#include "flags.h" +#include "function.h" +#include "expr.h" +#include "toplev.h" +#include "tree-pass.h" +#include "ggc.h" +#include "except.h" +#include "splay-tree.h" +#include "optabs.h" +#include "cfgloop.h" +#include "tree-ssa-live.h" + +struct gtm_region *root_gtm_region; +unsigned int label_index; +unsigned int e_index; +edge edges_to_instrument[NUM_BB_TXN]; + +/* Function declarations for GTM expansion and checkpointing. */ +void check_and_mark_edges (struct gtm_region *, basic_block); +char *check_call_expr (tree); +void checkpoint_live_in_variables (struct gtm_region *, block_stmt_iterator *, basic_block); +void compensate_for_taking_the_address (tree); + +/* Debugging dumps for transactional regions. */ +void dump_gtm_region (FILE *, struct gtm_region *, int); +void debug_gtm_region (struct gtm_region *); +void debug_all_gtm_regions (void); + +void execute_lower_gtm (void); +void execute_checkpoint_gtm (void); +static bool gate_expand_gtm (void); +static bool gate_checkpoint_gtm (void); + +void init_label_table (void); +tree insert_temporary (block_stmt_iterator, tree); +void instrument_edges (tree); +void instrument_return_expr (block_stmt_iterator *, tree); + +void may_repair_rhs (tree, block_stmt_iterator, tree); +void record_bb_into_table (struct gtm_region *, basic_block); + + +/* Dump the gtm region tree rooted at REGION. */ +void +dump_gtm_region (FILE *file, struct gtm_region *region, int indent) +{ + fprintf (file, "%*sbb %d: %s\n", indent, "", region->entry->index, + tree_code_name[region->type]); + + if (region->inner) + dump_gtm_region (file, region->inner, indent + 4); + + if (region->exit) + fprintf (file, "%*sbb %d: GTM_RETURN\n", indent, "", + region->exit->index); + + if (region->next) + dump_gtm_region (file, region->next, indent); +} + +void +debug_gtm_region (struct gtm_region *region) +{ + dump_gtm_region (stderr, region, 0); +} + +void +debug_all_gtm_regions (void) +{ + dump_gtm_region (stderr, root_gtm_region, 0); +} + +/* Create a new gtm region starting at STMT inside region PARENT. */ +struct gtm_region * +new_gtm_region (basic_block bb, enum tree_code type, struct gtm_region *parent) +{ + struct gtm_region *region = xcalloc (1, sizeof (*region)); + + region->outer = parent; + region->entry = bb; + region->type = type; + + if (parent) + { + /* This is a nested region. Add it to the list of inner + regions in PARENT. */ + region->next = parent->inner; + parent->inner = region; + } + else + { + /* This is a toplevel region. Add it to the list of toplevel + regions in ROOT_GTM_REGION. */ + region->next = root_gtm_region; + root_gtm_region = region; + } + + return region; +} + +/* Release the memory associated with the region tree rooted at REGION. */ +static void +free_gtm_region_1 (struct gtm_region *region) +{ + struct gtm_region *i, *n; + + for (i = region->inner; i ; i = n) + { + n = i->next; + free_gtm_region_1 (i); + } + + free (region); +} + +/* Release the memory for the entire gtm region tree. */ +void +free_gtm_regions (void) +{ + struct gtm_region *r, *n; + for (r = root_gtm_region; r ; r = n) + { + n = r->next; + free_gtm_region_1 (r); + } + root_gtm_region = NULL; +} + + +/* Helper for build_gtm_regions. Scan the dominator tree starting at + block BB. PARENT is the region that contains BB. If SINGLE_TREE is + true, the function ends once a single tree is built (like constructing omp region trees). */ +static void +build_gtm_regions_1 (basic_block bb, struct gtm_region *parent, + bool single_tree) +{ + block_stmt_iterator si; + tree stmt; + basic_block son; + + si = bsi_last (bb); + if (!bsi_end_p (si)) /* bsi_stmt should not be NULL */ + { + if (GTM_DIRECTIVE_P (bsi_stmt (si))) + { + struct gtm_region *region; + enum tree_code code; + stmt = bsi_stmt (si); + code = TREE_CODE (stmt); + if (code == GTM_RETURN) + { + /* STMT is the return point out of region PARENT. Mark it + as the exit point and make PARENT the immediately + enclosing region. */ + gcc_assert (parent); + region = parent; + region->exit = bb; + parent = parent->outer; + } + else if (code == GTM_TXN) + { + /* Otherwise, this directive becomes the parent for a new + region. GTM_TXN is the only one left for now. */ + region = new_gtm_region (bb, code, parent); + parent = region; + } + } + } + if (single_tree && !parent) + return; + + for (son = first_dom_son (CDI_DOMINATORS, bb); + son; + son = next_dom_son (CDI_DOMINATORS, son)) + build_gtm_regions_1 (son, parent, single_tree); +} + +/* Scan the CFG and build a tree of GTM regions. + Return the root of the GTM region tree. */ +static void +build_gtm_regions (void) +{ + gcc_assert (root_gtm_region == NULL); + calculate_dominance_info (CDI_DOMINATORS); + build_gtm_regions_1 (ENTRY_BLOCK_PTR, NULL, false); +} + +/* TODO: add mechanism to query the + STM for supported features. */ +static bool +query_STM_for_flat_nesting (void) +{ + return true; +} + +/* Remove entry and exit marker from region. */ +static void +remove_gtm_stmts (struct gtm_region *region) +{ + basic_block entry_bb, exit_bb; + block_stmt_iterator si; + tree stmt; + + entry_bb = region->entry; + exit_bb = region->exit; + + gcc_assert (entry_bb); + gcc_assert (exit_bb); + + si = bsi_last (entry_bb); + stmt = bsi_stmt (si); + + gcc_assert (TREE_CODE (stmt) == GTM_TXN); + + bsi_remove (&si, true); + single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU; + + if (exit_bb) + { + si = bsi_last (exit_bb); + gcc_assert (!bsi_end_p (si) + && TREE_CODE (bsi_stmt (si)) == GTM_RETURN); + + bsi_remove (&si, true); + single_succ_edge (exit_bb)->flags = EDGE_FALLTHRU; + } + + return ; +} + +/* If the STM only supports flat nesting, all + nested transactions are collapsed into + the outermost one. */ +static void +collapse_gtm_regions (struct gtm_region *region) +{ + while (region) + { + /* Collapse only the inner regions. */ + if (region->inner) + { + remove_gtm_stmts (region->inner); + collapse_gtm_regions (region->inner); + free (region->inner); + region->inner = NULL; + } + + gcc_assert ((region->type) == GTM_TXN); + region = region->next; + } + + return ; +} + +/* Determine whether operand has to be + instrumented using a read barrier. */ +/* TODO: check if _all_ cases are covered. */ +static bool +requires_read_barrier (tree operand) +{ + if (TREE_CODE (operand) == SSA_NAME) + operand = SSA_NAME_VAR (operand); + + if ((TREE_CODE (operand) == INDIRECT_REF) + || (TREE_CODE (operand) == COMPONENT_REF) + || (TREE_CODE (operand) == ARRAY_REF)) + return true; + + /* Casts are ignored - descent recursively. */ + if ((TREE_CODE (operand) == NOP_EXPR) + || (TREE_CODE (operand) == FLOAT_EXPR) + || (TREE_CODE (operand) == FIX_TRUNC_EXPR)) + return requires_read_barrier (TREE_OPERAND (operand, 0)); + + /* In case the variable is defined inside the scope of + the transaction, there is no need for instrumentation. */ + if (TREE_CODE (operand) == VAR_DECL) + if (DECL_IS_GTM_PURE_VAR (operand)) + return false; + + if ((CONSTANT_CLASS_P (operand)) + || (DECL_ARTIFICIAL (operand))) + return false; + else + return ((TREE_CODE (operand) == VAR_DECL && is_global_var (operand)) + || (POINTER_TYPE_P (TREE_TYPE (operand))) + || (TREE_ADDRESSABLE (operand))); +} + +/* Determine whether operand has to be instrumented + using a write barrier. */ +/* TODO: check if _all_ cases are covered. */ +static bool +requires_write_barrier (tree operand) +{ + if (TREE_CODE (operand) == SSA_NAME) + operand = SSA_NAME_VAR (operand); + + if ((TREE_CODE (operand) == INDIRECT_REF) + || (TREE_CODE (operand) == COMPONENT_REF) + || (TREE_CODE (operand) == ARRAY_REF)) + return true; + + /* In case the variable is defined inside the scope of + the transaction, there is no need for instrumentation. */ + if (TREE_CODE (operand) == VAR_DECL) + if (DECL_IS_GTM_PURE_VAR (operand)) + return false; + + if ((CONSTANT_CLASS_P (operand)) + || (DECL_ARTIFICIAL (operand))) + return false; + else + return ((TREE_CODE (operand) == VAR_DECL && is_global_var (operand)) + || (POINTER_TYPE_P (TREE_TYPE (operand))) + || (TREE_ADDRESSABLE (operand))); +} + +/* Returns function decl determined by + type size of operand. */ +static tree +get_stm_decl(int builtin, tree op) +{ + HOST_WIDE_INT index; + tree decl; + tree type = TYPE_MAIN_VARIANT (TREE_TYPE (op)); + + index = tree_low_cst (TYPE_SIZE_UNIT (type), 1); + index = exact_log2 (index); + + if (index >= 0 && index <= 4) + decl = built_in_decls[builtin + index + 1]; + else gcc_unreachable(); + + gcc_assert(decl); + + return decl; +} + +/* Insert new temporary variable that + lives in a GIMPLE register and issue + a load of the "old" variable. */ +tree +insert_temporary (block_stmt_iterator bsi, tree op) +{ + tree new_var; + tree stmt; + + new_var = create_tmp_var (TREE_TYPE (op), get_name(op)); + stmt = build_gimple_modify_stmt (new_var, op); + + bsi_insert_before (&bsi, stmt, BSI_SAME_STMT); + return new_var; +} + +/* Check whether variables used in stmts are the + ones to replace by a use of a GIMPLE register. + If they match the replacement is done. */ +void +may_repair_rhs (tree rhs, block_stmt_iterator bsi, tree op) +{ + tree new_var; + + if (UNARY_CLASS_P (rhs)) + { + if (op == rhs) + { + new_var = insert_temporary (bsi, op); + tree stmt = bsi_stmt (bsi); + GIMPLE_STMT_OPERAND (stmt, 1) = new_var; + } + } + else + { + if (BINARY_CLASS_P (rhs)) + { + if (TREE_OPERAND (rhs, 0) == op) + { + new_var = insert_temporary (bsi, op); + TREE_OPERAND (rhs, 0) = new_var; + } + if (TREE_OPERAND (rhs, 1) == op) + { + new_var = insert_temporary (bsi, op); + TREE_OPERAND (rhs, 1) = new_var; + } + } + } + + return; +} + +/* Compensate for taking the address of a local variable. + By using the address of the variable, the variable escapes + the local scope and becomes global. + Since global variables on GIMPLE have to be transferred to + registers before they can be used, this behaviour has to + be added. */ +void +compensate_for_taking_the_address (tree op) +{ + basic_block bb; + block_stmt_iterator bsi; + tree stmt; + tree rhs; + + FOR_EACH_BB (bb) + { + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + stmt = bsi_stmt (bsi); + + /* TODO: add more possible uses of a variable here! */ + if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT) + { + rhs = GIMPLE_STMT_OPERAND (stmt, 1); + may_repair_rhs(rhs, bsi, op); + } + + if (TREE_CODE (stmt) == CALL_EXPR) + { + tree arg; + call_expr_arg_iterator iter; + FOR_EACH_CALL_EXPR_ARG (arg, iter, stmt) + may_repair_rhs (arg, bsi, op); + } + } + } + + return ; +} + +/* Helper function that + composes the STM store function call. */ +static tree +compose_stm_store_call(tree op, tree txn_handle, tree value) +{ + tree call; + tree decl; + bool compensate = false; + + if (TREE_CODE (op) == SSA_NAME) + op = SSA_NAME_VAR (op); + + if (!TREE_ADDRESSABLE (op)) + compensate = true; + + decl = get_stm_decl (BUILT_IN_GTM_STORE_N, op); + call = build_call_expr (decl, 3, txn_handle, + build_fold_addr_expr (op), value); + + if (compensate) + compensate_for_taking_the_address (op); + + return call; +} + +/* Helper function that composes + the STM load function call. */ +static tree +compose_stm_load_call(tree op, tree txn_handle) +{ + tree decl; + tree call; + bool compensate = false; + + if (TREE_CODE (op) == SSA_NAME) + op = SSA_NAME_VAR (op); + + if (!TREE_ADDRESSABLE (op)) + compensate = true; + + decl = get_stm_decl(BUILT_IN_GTM_LOAD_N, op); + call = build_call_expr (decl, 2, txn_handle, + build_fold_addr_expr(op)); + + if (compensate) + compensate_for_taking_the_address (op); + + return call; +} + +/* Emits call to stm_load including the + txn_handle and address of the variable. +*/ +static tree +insert_rhs_stm_call (block_stmt_iterator *bsi, enum bsi_iterator_update m, tree op, tree txn_handle) +{ + tree stmt; + tree t_load = create_tmp_var (TREE_TYPE (op), "txn_tmp"); + + tree call = compose_stm_load_call (op, txn_handle); + + stmt = build_gimple_modify_stmt (t_load, call); + bsi_insert_before (bsi, stmt, m); + + return t_load; +} + +/* Introduce temporary variable if necessary + and emit call to stm_store. */ +static void +replace_lhs (block_stmt_iterator *bsi, enum bsi_iterator_update m, tree op, tree txn_handle) +{ + tree t_store; + tree stmt, call; + tree op_type = TREE_TYPE (op); + tree mod_stmt = bsi_stmt (*bsi); + tree rhs = GIMPLE_STMT_OPERAND (mod_stmt, 1); + + if ((!CONSTANT_CLASS_P (rhs)) + && (!is_gimple_formal_tmp_var (rhs))) + { + t_store = create_tmp_var (op_type, "txn_tmp"); + stmt = build_gimple_modify_stmt (t_store, rhs); + bsi_insert_before (bsi, stmt, m); + } + else + { + t_store = rhs; + } + + call = compose_stm_store_call(op, txn_handle, t_store); + bsi_insert_after (bsi, call, m); + bsi_remove (bsi, true); + + return ; +} + +/* Check whether the operands need a read + barrier and insert it. + TODO: relax handling of ARRAY_REFs. */ +static void +maybe_replace_rhs_stmt (block_stmt_iterator *bsi, enum bsi_iterator_update m, tree stmt, tree txn_handle) +{ + tree t_load; + tree op1, op2; + tree rhs = GIMPLE_STMT_OPERAND (stmt, 1); + + if ((UNARY_CLASS_P (rhs)) + || (CONSTANT_CLASS_P (rhs)) + || (TREE_CODE (rhs) == VAR_DECL)) + { + op1 = rhs; + if (requires_read_barrier (op1)) + { + t_load = insert_rhs_stm_call (bsi, m, op1, txn_handle); + GIMPLE_STMT_OPERAND (stmt, 1) = t_load; + } + } + else + { + if (BINARY_CLASS_P (rhs)) + { + op1 = TREE_OPERAND (rhs, 0); + if (requires_read_barrier (op1)) + { + t_load = insert_rhs_stm_call (bsi, m, op1, txn_handle); + TREE_OPERAND (rhs, 0) = t_load; + } + op2 = TREE_OPERAND (rhs, 1); + if (requires_read_barrier (op2)) + { + t_load = insert_rhs_stm_call (bsi, m, op2, txn_handle); + TREE_OPERAND (rhs, 1) = t_load; + } + } + else + { + if (POINTER_TYPE_P (TREE_TYPE (rhs)) + || (TREE_CODE (rhs) == COMPONENT_REF) + || (TREE_CODE (rhs) == INDIRECT_REF) + || (TREE_CODE (rhs) == ARRAY_REF)) + { + op1 = rhs; + t_load = insert_rhs_stm_call (bsi, m, op1, txn_handle); + GIMPLE_STMT_OPERAND (stmt, 1) = t_load; + } + else debug_tree(stmt); + } + } + + return ; +} + +/* Subsituting a MODIFY_STMT + with calls to the STM runtime, + the worst case looks like this: + + t1 = stm_load(b); + t2 = stm_load(c); + a = b * c; t3 = t1 * t2; + stm_store(a, t3); */ +static void +replace_txn_mod_stmt (block_stmt_iterator *bsi, enum bsi_iterator_update m, tree txn_handle) +{ + tree stmt = bsi_stmt (*bsi); + tree lhs = GIMPLE_STMT_OPERAND (stmt, 0); + + maybe_replace_rhs_stmt (bsi, m, stmt, txn_handle); + + if (requires_write_barrier (lhs)) + { + replace_lhs (bsi, m, lhs, txn_handle); + } + + return ; +} + +/* Return function name or NULL if function + is a STM compiler builtin. */ +char * +check_call_expr (tree ce) +{ + char *name = get_name (CALL_EXPR_FN (ce)); + if (strncmp(name, "__builtin_stm", 13) != 0) + return name; + + return NULL; +} + +/* This function expands the stmts within a + transaction so that the corresponding STM + versions of the stmt is called. */ +static void +replace_txn_stmt (block_stmt_iterator *bsi, enum bsi_iterator_update m, tree txn_handle) +{ + tree stmt = bsi_stmt(*bsi); + char *name; + + switch TREE_CODE (stmt) { + + case MODIFY_EXPR: + case GIMPLE_MODIFY_STMT: + if (TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == CALL_EXPR) + { + name = check_call_expr ((GIMPLE_STMT_OPERAND (stmt, 1))); + if (name) + warning (0, "GTM: Function cloning not implemented. Call to %qs potentially breaks isolation of transactions.", name); + } + else + replace_txn_mod_stmt (bsi, m, txn_handle); + break; + + case CALL_EXPR: + name = check_call_expr (stmt); + if (name) + warning (0, "GTM: Function cloning not implemented. Call to %qs potentially breaks isolation of transactions.", name); + break; + + default: + break; + } + + return; +} + +/* Mark recover_bb with a GTM-Return marker + which is replaced by variables restoring the + previous state during the checkpoint_gtm-pass. */ +static void +setup_recover_bb (basic_block bb, tree label) +{ + block_stmt_iterator bsi = bsi_start (bb); + tree stmt = build1 (LABEL_EXPR, void_type_node, label); + + bsi_insert_before (&bsi, stmt, BSI_SAME_STMT); + stmt = make_node (GTM_RETURN); + bsi_insert_before (&bsi, stmt, BSI_SAME_STMT); + + return ; +} + +/* Helper function that emits a call to STM + run-time indicating the start of a transaction. */ +static void +setup_begin_bb (basic_block bb, tree txn_handle, tree jmp_buf) +{ + tree txn_begin; + tree decl; + tree read_only = build_int_cst (integer_type_node, 0); + block_stmt_iterator bsi = bsi_start (bb); + + decl = built_in_decls[BUILT_IN_GTM_TXN_BEGIN]; + txn_begin = build_call_expr (decl, 3, + txn_handle, jmp_buf, build_fold_addr_expr (read_only)); + bsi_insert_before (&bsi, txn_begin, BSI_SAME_STMT); + + return ; +} + +/* Expand the begin of an transaction to + set up the transaction in an STM-specific way. */ +static tree +expand_gtm_txn_marker (struct gtm_region *region, block_stmt_iterator *bsi, enum bsi_iterator_update m, basic_block recover_bb, basic_block begin_bb) +{ + tree decl; + tree txn_handle; + tree sigsetjmp, ssjval; + tree mask; + tree jmp_buf; + tree new, new_stmt; + tree get; + tree stmt; + tree list; + tree recover_label; + tree ptr_void = build_pointer_type (void_type_node); + + /* stm_txn_t *tx; + tx = stm_new (); */ + txn_handle = create_tmp_var (ptr_void, "txn_handle"); + decl = built_in_decls[BUILT_IN_GTM_NEW]; + new = build_call_expr (decl, 0); + new_stmt = build_gimple_modify_stmt (txn_handle, new); + bsi_insert_before (bsi, new_stmt, m); + + /* jmp_buf *e; + e = stm_get_env (tx); */ + jmp_buf = create_tmp_var (ptr_void, "jmp_buf"); + decl = built_in_decls[BUILT_IN_GTM_GET_ENV]; + get = build_call_expr (decl, 1, txn_handle); + stmt = build_gimple_modify_stmt (jmp_buf, get); + bsi_insert_before (bsi, stmt, m); + + /* CHECK: if sigsetjmp is called with a non-zero + argument it saves the signal mask + as part of the environment. + Currently the setjmp call is done manually. + TODO: Future work would be to use GCC's EH machinery. */ + ssjval = create_tmp_var (integer_type_node, "ssj_value"); + mask = build_int_cst (integer_type_node, 0); + list = build_function_type_list (integer_type_node, ptr_type_node, NULL_TREE); + decl = build_decl (FUNCTION_DECL, get_identifier ("_setjmp"), list); + sigsetjmp = build_call_expr (decl, 1, jmp_buf); + stmt = build_gimple_modify_stmt (ssjval, sigsetjmp); + bsi_insert_before (bsi, stmt, m); + region->setjmp_stmt = stmt; + + recover_label = create_artificial_label (); + + stmt = build3 (COND_EXPR, void_type_node, + fold_build2 (EQ_EXPR, boolean_type_node, ssjval, integer_zero_node), + NULL_TREE, + NULL_TREE); + bsi_insert_after (bsi, stmt, m); + + setup_recover_bb (recover_bb, recover_label); + setup_begin_bb (begin_bb, txn_handle, jmp_buf); + + return txn_handle; +} + +/* Helper function that emits call to + commit the transaction in an STM-specific way. */ +static void +expand_gtm_return (block_stmt_iterator *bsi, enum bsi_iterator_update m, tree txn_handle) +{ + tree decl; + tree call; + tree stm_commit_retval; + tree stmt; + + decl = built_in_decls[BUILT_IN_GTM_TXN_COMMIT]; + call = build_call_expr (decl, 1, txn_handle); + + stm_commit_retval = create_tmp_var (integer_type_node, "stm_commit"); + add_referenced_var (stm_commit_retval); + + stmt = fold_build2 (GIMPLE_MODIFY_STMT, integer_type_node, + stm_commit_retval, call); + bsi_insert_before (bsi, stmt, m); + + return ; +} + +/* Insert call to stm_init at beginning of main function. */ +static void +insert_stm_init(void) +{ + char *name = get_name (current_function_decl); + if ((strncmp(name, "main", 4) != 0) + || (strlen(name) > 4)) + return ; + + basic_block bb; + + FOR_EACH_BB (bb) + { + int idx = bb->index; + /* TODO find a better place to put this call (works so far) */ + if (idx == 2) + { + block_stmt_iterator bsi = bsi_start (bb); + tree decl; + tree call; + + decl = built_in_decls[BUILT_IN_GTM_INIT]; + call = build_call_expr (decl, 1, build_int_cst (integer_type_node, 0)); + + bsi_insert_before (&bsi, call, BSI_SAME_STMT); + return ; + } + } + + gcc_unreachable(); + return ; +} + +/* Insert call to stm_exit at the end of main function. */ +static void +insert_stm_exit(void) +{ + char *name = get_name (current_function_decl); + if ((strncmp(name, "main", 4) != 0) + || (strlen(name) > 4)) + return ; + + basic_block last_bb = EXIT_BLOCK_PTR->prev_bb; + block_stmt_iterator bsi_last_bb = bsi_last (last_bb); + tree decl; + tree call; + tree tmp = bsi_stmt (bsi_last_bb); + + if (TREE_CODE (tmp) == RETURN_EXPR) + { + decl = built_in_decls[BUILT_IN_GTM_EXIT]; + call = build_call_expr (decl, 1, build_int_cst (integer_type_node, 0)); + bsi_insert_before (&bsi_last_bb, call, BSI_SAME_STMT); + } + else + { + gcc_unreachable(); + } + + return ; +} + +/* Initialize global data structures.*/ +void +init_label_table (void) +{ + unsigned int i; + + label_index = 0; + e_index = 0; + + for (i = 0; i < NUM_BB_TXN; i++) + edges_to_instrument[i] = NULL; + + return ; +} + +/* Helper function marking marking all basic blocks + of a transaction. */ +void +record_bb_into_table (struct gtm_region *region, basic_block bb) +{ + if (dump_file) + fprintf (dump_file, "Record TXN Basic block %d\n", bb->index); + region->txn_bbs[label_index] = bb->index; + label_index++; + + return ; +} + +/* Helper function that checks whether an edge from a + basic block leaves the scope of a transaction. If + it does the edge is marked for instrumentation. */ +void +check_and_mark_edges (struct gtm_region *region, basic_block bb) +{ + edge_iterator ei; + edge e; + unsigned int j; + basic_block succ; + bool found = false; + + FOR_EACH_EDGE (e, ei, bb->succs) + { + succ = e->dest; + + for (j = 0; j < label_index; j++) + { + if (region->txn_bbs[j] == succ->index) + { + if (dump_file) + fprintf (dump_file, "found BB index %d in TXN\n", succ->index); + found = true; + break; + } + } + + if ((!found) + && (succ != ENTRY_BLOCK_PTR) + && (succ != EXIT_BLOCK_PTR)) + { + if (dump_file) + fprintf (dump_file, "Did _NOT_ find BB index %d in TXN\n", succ->index); + + edges_to_instrument[e_index] = e; + e_index++; + } + } + + return ; +} + +/* Instrument all previously recorded edges with a call + to stm_commit. */ +void +instrument_edges (tree txn_handle) +{ + unsigned int j; + edge e; + + for (j = 0; j < e_index ; j++) + { + e = edges_to_instrument[j]; + gcc_assert (e); + + basic_block stm_commit_bb = split_edge (e); + block_stmt_iterator bsi = bsi_start (stm_commit_bb); + expand_gtm_return (&bsi, BSI_SAME_STMT, txn_handle); + gcc_assert (single_succ_edge (stm_commit_bb)->flags = EDGE_FALLTHRU); + } + + return ; +} + +/* Instruments a return expression with a call to stm_commit. */ +void +instrument_return_expr (block_stmt_iterator *bsi, tree txn_handle) +{ + tree stmt = bsi_stmt (*bsi); + + if (TREE_CODE (stmt) == RETURN_EXPR) + { + expand_gtm_return (bsi, BSI_SAME_STMT, txn_handle); + } + + return ; +} + +/* Instruments transactions with calls to the STM runtime. + Inserts new basic blocks at the beginning of the transaction + to allow for variable saving and restoring (checkpointing) + on SSA level. */ +static void +expand_gtm_txn (struct gtm_region *region) +{ + basic_block entry_bb, exit_bb, bb; + block_stmt_iterator bsi; + + tree txn; + tree txn_handle; + + entry_bb = region->entry; + exit_bb = region->exit; + + gcc_assert (entry_bb); + gcc_assert (exit_bb); + + bsi = bsi_last (entry_bb); + txn = bsi_stmt (bsi); + + gcc_assert (TREE_CODE (txn) == GTM_TXN); + init_label_table (); + + /* Split basic blocks and make edges: */ + /* BB with setjmp (entry_bb) -> BBrestore + BB with setjmp (entry_bb) -> BBtxnbegin + BBrestore -> BBtxnbegin + */ + basic_block begin_bb = split_edge (single_succ_edge (entry_bb)); + basic_block recover_bb = split_edge (single_succ_edge (entry_bb)); + + /* TODO redirect edge instead of destroy/create */ + /* Content to the basic blocks is added here. */ + txn_handle = expand_gtm_txn_marker (region, &bsi, BSI_SAME_STMT, recover_bb, begin_bb); + bsi_remove (&bsi, true); + remove_edge (single_succ_edge (entry_bb)); + make_edge (entry_bb, recover_bb, EDGE_FALSE_VALUE); + make_edge (entry_bb, begin_bb, EDGE_TRUE_VALUE); + + single_succ_edge (begin_bb)->flags = EDGE_FALLTHRU; + remove_edge (single_succ_edge (recover_bb)); + make_edge (recover_bb, begin_bb, EDGE_FALLTHRU); + + gcc_assert (exit_bb->next_bb); + + FOR_BB_BETWEEN (bb, begin_bb, exit_bb->next_bb, next_bb) + { + if (!bb) + continue; + + record_bb_into_table (region, bb); + + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + instrument_return_expr (&bsi, txn_handle); + replace_txn_stmt (&bsi, BSI_SAME_STMT, txn_handle); + } + } + + FOR_BB_BETWEEN (bb, begin_bb, exit_bb, next_bb) + { + if (!bb) + continue; + + check_and_mark_edges (region, bb); + } + + instrument_edges (txn_handle); + + bsi = bsi_last (exit_bb); + gcc_assert (!bsi_end_p (bsi) + && TREE_CODE (bsi_stmt (bsi)) == GTM_RETURN); + + expand_gtm_return (&bsi, BSI_SAME_STMT, txn_handle); + bsi_remove (&bsi, true); + + return; +} + +/* Instrument the GTM region tree rooted at REGION. + We start with the inner regions first. */ +/* TODO adjust for nested transactions! */ +static void +expand_gtm (struct gtm_region *region) +{ + while (region) + { + /* First, expand the inner regions. */ + if (region->inner) + expand_gtm (region->inner); + + gcc_assert ((region->type) == GTM_TXN); + expand_gtm_txn (region); + region = region->next; + } +} + +/* Main entry point for expanding GTM-GIMPLE + into runtime calls to the STM. */ +static unsigned int +execute_expand_gtm (void) +{ + bool flat_nesting; + + insert_stm_init(); + insert_stm_exit(); + + build_gtm_regions (); + if (!root_gtm_region) + return 0; + + if (dump_file) + { + fprintf (dump_file, "\nGTM region tree\n\n"); + dump_gtm_region (dump_file, root_gtm_region, 0); + fprintf (dump_file, "\n"); + } + + flat_nesting = query_STM_for_flat_nesting(); + + if (flat_nesting) + { + collapse_gtm_regions (root_gtm_region); + + if (dump_file) + { + fprintf (dump_file, "\nGTM region tree after collapsing regions\n\n"); + dump_gtm_region (dump_file, root_gtm_region, 0); + fprintf (dump_file, "\n"); + } + } + + expand_gtm (root_gtm_region); /* instrumentation is done here. */ + + free_dominance_info (CDI_DOMINATORS); + + cleanup_tree_cfg (); + + return 0; +} + +/* GTM expansion -- the default pass, + run before creation of SSA form. */ +static bool +gate_expand_gtm (void) +{ + return flag_gtm; +} + +struct tree_opt_pass pass_expand_gtm = + { + "gtmexp", /* name */ + gate_expand_gtm, /* gate */ + execute_expand_gtm, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + PROP_gimple_any, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + TODO_dump_func, /* todo_flags_start */ + TODO_cleanup_cfg + | TODO_verify_stmts + | TODO_ggc_collect + | TODO_verify_flow, /* todo_flags_finish */ + 0 /* letter */ + }; + +/* Calculate live ranges on SSA. Then checkpoint the + live-in variables to the transaction. */ +void +checkpoint_live_in_variables (struct gtm_region *region, block_stmt_iterator *bsi_recover, basic_block begin_bb) +{ + int index = begin_bb->index; + block_stmt_iterator bsi_save = bsi_for_stmt (region->setjmp_stmt); + basic_block save_bb = bb_for_stmt (region->setjmp_stmt); + basic_block recover_bb = bb_for_stmt (bsi_stmt (*bsi_recover)); + tree ssa_var; + tree_live_info_p liveinfo; + var_map map; + int p; + tree rep; + unsigned int i; + unsigned int j; + bitmap_iterator bi; + + map = init_var_map (num_ssa_names + 1); + + /* Create liveness information for each SSA_NAME. */ + for (j = 0; j < num_ssa_names; j++) + { + ssa_var = ssa_name (j); + if (!ssa_var) + continue; + + if (TREE_CODE (ssa_var) == SSA_NAME) + { + register_ssa_partition (map, ssa_var); + p = partition_find (map->var_partition, SSA_NAME_VERSION (ssa_var)); + gcc_assert (p != NO_PARTITION); + rep = partition_to_var (map, p); + } + } + + liveinfo = calculate_live_ranges (map); + + /* If variable is live-in at beginning of the + transaction checkpoint its value. */ + if (liveinfo->livein) + { + if (dump_file) + fprintf (dump_file, "\nCheckpoint variables for transaction. BB %d : ", index); + + EXECUTE_IF_SET_IN_BITMAP (liveinfo->livein[index], 0, i, bi) + { + tree var = partition_to_var (map, i); + + /* TODO check restricts the use of temporaries by the compiler + may impact other optimisations. + Maybe reordering this part of the checkpointing before introducing + temporary variables would avoid this check. */ + if ((!DECL_ARTIFICIAL (SSA_NAME_VAR (var))) + && (!POINTER_TYPE_P (TREE_TYPE (var)))) + { + if (dump_file) + { + print_generic_expr (dump_file, var, TDF_SLIM); + fprintf (dump_file, " "); + } + /* Create name for temporary variable + that checkpoints value of var. */ + const char* orig = get_name (SSA_NAME_VAR (var)); + int len = strlen (orig); + char *name = xmalloc (sizeof (char) * (len + 10)); + strncpy (name, "txn_save_", 9); + strncpy (name + 9, orig, len); + *(name + len + 9) = '\0'; + + /* Create temporary. */ + tree type = TREE_TYPE (var); + tree save = create_tmp_var (type, name); + add_referenced_var (save); + tree stmt; + + /* Create gimple statement for saving value of var. */ + stmt = fold_build2 (GIMPLE_MODIFY_STMT, type, save, var); + tree real_save = make_ssa_name (save, stmt); + SSA_NAME_OCCURS_IN_ABNORMAL_PHI (real_save) = true; + GIMPLE_STMT_OPERAND (stmt, 0) = real_save; + bsi_insert_before (&bsi_save, stmt, BSI_SAME_STMT); + + /* Create gimple statement for restoring value of var. */ + stmt = fold_build2 (GIMPLE_MODIFY_STMT, type, var, real_save); + tree new_var = make_ssa_name (SSA_NAME_VAR (var), stmt); + GIMPLE_STMT_OPERAND (stmt, 0) = new_var; + bsi_insert_before (bsi_recover, stmt, BSI_SAME_STMT); + + /* Merge saved or recovered values before next basic block. */ + tree phi = create_phi_node (SSA_NAME_VAR (var), begin_bb); + add_phi_arg (phi, new_var, FALLTHRU_EDGE (recover_bb)); + add_phi_arg (phi, var, FALLTHRU_EDGE (save_bb)); + tree new_var_phi = PHI_RESULT (phi); + + free_dominance_info (CDI_DOMINATORS); + calculate_dominance_info (CDI_DOMINATORS); + + tree stmt2; + imm_use_iterator iter; + use_operand_p use_p; + FOR_EACH_IMM_USE_STMT (stmt2, iter, var) + { + if (stmt2 == phi) + continue; + + basic_block tmp_bb = bb_for_stmt (stmt2); + if (dominated_by_p (CDI_DOMINATORS, tmp_bb, begin_bb)) + { + FOR_EACH_IMM_USE_ON_STMT (use_p, iter) + propagate_value (use_p, new_var_phi); + } + } + } + } + if (dump_file) + fprintf (dump_file, "\n"); + + } + update_ssa(TODO_update_ssa); + + return ; +} + +/* Implements the checkpointing of transactions. */ +static void +checkpoint_gtm_txn (struct gtm_region *region) +{ + basic_block entry_bb = region->entry; + + edge branch = BRANCH_EDGE (entry_bb); + edge fall = FALLTHRU_EDGE (entry_bb); + + basic_block begin_bb = fall->dest; + basic_block recover_bb = branch->dest; + basic_block next_bb = single_succ (recover_bb); + + gcc_assert(begin_bb == next_bb); + block_stmt_iterator bsi_recover = bsi_start (recover_bb); + gcc_assert (TREE_CODE (bsi_stmt (bsi_recover)) == LABEL_EXPR); + + bsi_next (&bsi_recover); + gcc_assert (TREE_CODE (bsi_stmt (bsi_recover)) == GTM_RETURN); + + checkpoint_live_in_variables (region, &bsi_recover, begin_bb); + /* Remove the previously set GTM_RETURN markers + from the recover basic block. */ + bsi_remove (&bsi_recover, true); + + return ; +} + +/* Walk the region tree and start checkpointing. */ +static void +checkpoint_gtm (struct gtm_region *region) +{ + while (region) + { + /* First, introduce checkpoints for the inner regions. + TODO: testing. Overlapping of inner and outer + regions not handled correctly. + Nesting of transactions not implemented correctly.*/ + if (region->inner) + { + checkpoint_gtm_txn (region->inner); + } + gcc_assert ((region->type) == GTM_TXN); + + checkpoint_gtm_txn (region); + + region = region->next; + } +} + +/* Entry point to the checkpointing. */ +void +execute_checkpoint_gtm (void) +{ + /* Regions are built during GTM expansion pass. */ + if (!root_gtm_region) + return ; + + /* Checkpointing is done here. */ + checkpoint_gtm (root_gtm_region); + + if (dump_file) + { + fprintf (dump_file, "\nGTM region tree after checkpointing\n\n"); + dump_gtm_region (dump_file, root_gtm_region, 0); + fprintf (dump_file, "\n"); + } + + free_dominance_info (CDI_DOMINATORS); + cleanup_tree_cfg (); + free_gtm_regions (); + + return; +} + +/* Guarding the checkpointing for GTM. */ +static bool +gate_checkpoint_gtm (void) +{ + return flag_gtm; +} + +struct tree_opt_pass pass_checkpoint_gtm = + { + "gtmcheckpoint", /* name */ + gate_checkpoint_gtm, /* gate */ + execute_checkpoint_gtm, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + PROP_ssa | PROP_cfg, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_update_ssa | + TODO_verify_ssa | + TODO_dump_func, /* todo_flags_finish */ + 0 /* letter */ + }; Gemeinsame Unterverzeichnisse: ../gcc-4.3.2_orig/gcc/java und gcc/java. diff -Nup ../gcc-4.3.2_orig/gcc/Makefile.in gcc/Makefile.in --- ../gcc-4.3.2_orig/gcc/Makefile.in 2008-08-01 11:51:03.000000000 +0200 +++ gcc/Makefile.in 2008-08-29 11:33:00.316923114 +0200 @@ -778,7 +778,8 @@ RTL_BASE_H = rtl.h rtl.def $(MACHMODE_H) input.h $(REAL_H) statistics.h vec.h fixed-value.h alias.h RTL_H = $(RTL_BASE_H) genrtl.h PARAMS_H = params.h params.def -BUILTINS_DEF = builtins.def sync-builtins.def omp-builtins.def +BUILTINS_DEF = builtins.def sync-builtins.def omp-builtins.def \ + gtm-builtins.def TREE_H = tree.h tree.def $(MACHMODE_H) tree-check.h $(BUILTINS_DEF) \ input.h statistics.h vec.h treestruct.def $(HASHTAB_H) \ double-int.h alias.h @@ -982,7 +983,7 @@ C_AND_OBJC_OBJS = attribs.o c-errors.o c c-convert.o c-aux-info.o c-common.o c-opts.o c-format.o c-semantics.o \ c-incpath.o cppdefault.o c-ppoutput.o c-cppbuiltin.o prefix.o \ c-objc-common.o c-dump.o c-pch.o c-parser.o $(C_TARGET_OBJS) \ - c-gimplify.o tree-mudflap.o c-pretty-print.o c-omp.o + c-gimplify.o tree-mudflap.o c-gtm.o c-pretty-print.o c-omp.o # Language-specific object files for C. C_OBJS = c-lang.o stub-objc.o $(C_AND_OBJC_OBJS) @@ -1066,6 +1067,7 @@ OBJS-common = \ global.o \ graph.o \ graphds.o \ + gtm-low.o \ gtype-desc.o \ haifa-sched.o \ hooks.o \ @@ -1835,6 +1837,9 @@ c-semantics.o : c-semantics.c $(CONFIG_H c-dump.o : c-dump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(C_TREE_H) $(TREE_DUMP_H) +c-gtm.o : c-gtm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ + $(FUNCTION_H) $(C_COMMON_H) toplev.h $(TREE_GIMPLE_H) + c-pch.o : c-pch.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(CPPLIB_H) $(TREE_H) \ $(C_COMMON_H) output.h toplev.h $(C_PRAGMA_H) $(GGC_H) debug.h \ langhooks.h $(FLAGS_H) hosthooks.h version.h $(TARGET_H) @@ -1932,6 +1937,11 @@ gtype-desc.o: gtype-desc.c $(CONFIG_H) $ cselib.h insn-addr.h $(OPTABS_H) libfuncs.h debug.h $(GGC_H) \ $(CGRAPH_H) $(TREE_FLOW_H) reload.h $(CPP_ID_DATA_H) +gtm-low.o : gtm-low.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ + $(RTL_H) $(TREE_GIMPLE_H) $(TREE_INLINE_H) langhooks.h $(DIAGNOSTIC_H) \ + $(TREE_FLOW_H) $(TIMEVAR_H) $(FLAGS_H) $(EXPR_H) toplev.h tree-pass.h \ + $(GGC_H) $(SPLAY_TREE_H) $(OPTABS_H) $(CFGLOOP_H) + ggc-common.o: ggc-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(GGC_H) \ $(HASHTAB_H) toplev.h $(PARAMS_H) hosthooks.h $(HOSTHOOKS_DEF_H) Gemeinsame Unterverzeichnisse: ../gcc-4.3.2_orig/gcc/objc und gcc/objc. Gemeinsame Unterverzeichnisse: ../gcc-4.3.2_orig/gcc/objcp und gcc/objcp. diff -Nup ../gcc-4.3.2_orig/gcc/omp-low.c gcc/omp-low.c --- ../gcc-4.3.2_orig/gcc/omp-low.c 2008-07-19 21:21:40.000000000 +0200 +++ gcc/omp-low.c 2008-08-29 12:53:24.117802331 +0200 @@ -558,6 +558,7 @@ copy_var_decl (tree var, tree name, tree DECL_IGNORED_P (copy) = DECL_IGNORED_P (var); DECL_CONTEXT (copy) = DECL_CONTEXT (var); DECL_SOURCE_LOCATION (copy) = DECL_SOURCE_LOCATION (var); + DECL_IS_GTM_PURE_VAR (copy) = DECL_IS_GTM_PURE_VAR (var); TREE_USED (copy) = 1; DECL_SEEN_IN_BIND_EXPR_P (copy) = 1; @@ -4942,6 +4943,38 @@ lower_omp_parallel (tree *stmt_p, omp_co pop_gimplify_context (NULL_TREE); } +/* Simply introduces a new stmt_list (needed by gimple-low.c). + Further add the GTM_RETURN at the end of the TXN. + TODO: check for omp constructs in txn! */ + +static void +lower_gtm_txn (tree *stmt_p, omp_context *ctx) +{ + tree txn_body, txn_bind; + tree new_body, t; + tree stmt; + + stmt = *stmt_p; + + push_gimplify_context (); + + txn_bind = GTM_TXN_BODY (stmt); + + txn_body = BIND_EXPR_BODY (txn_bind); + lower_omp (&txn_body, ctx); + + new_body = alloc_stmt_list (); + + append_to_statement_list (txn_bind, &new_body); + + t = make_node (GTM_RETURN); + append_to_statement_list (t, &new_body); + GTM_TXN_BODY (stmt) = new_body; + *stmt_p = stmt; + + pop_gimplify_context (NULL_TREE); +} + /* Callback for lower_omp_1. Return non-NULL if *tp needs to be regimplified. */ @@ -5067,6 +5100,10 @@ lower_omp_1 (tree *tp, omp_context *ctx, lower_omp_critical (tp, ctx); break; + case GTM_TXN: + lower_gtm_txn (tp, ctx); + break; + default: if (ctx && walk_tree (tp, lower_omp_2, ctx, NULL)) { diff -Nup ../gcc-4.3.2_orig/gcc/passes.c gcc/passes.c --- ../gcc-4.3.2_orig/gcc/passes.c 2008-01-22 14:27:52.000000000 +0100 +++ gcc/passes.c 2008-08-29 14:27:03.421681560 +0200 @@ -509,12 +509,14 @@ init_optimization_passes (void) NEXT_PASS (pass_cleanup_cfg); NEXT_PASS (pass_init_datastructures); NEXT_PASS (pass_expand_omp); + NEXT_PASS (pass_expand_gtm); NEXT_PASS (pass_all_early_optimizations); { struct tree_opt_pass **p = &pass_all_early_optimizations.sub; NEXT_PASS (pass_referenced_vars); NEXT_PASS (pass_reset_cc_flags); NEXT_PASS (pass_build_ssa); + NEXT_PASS (pass_checkpoint_gtm); NEXT_PASS (pass_expand_omp_ssa); NEXT_PASS (pass_early_warn_uninitialized); NEXT_PASS (pass_rebuild_cgraph_edges); Gemeinsame Unterverzeichnisse: ../gcc-4.3.2_orig/gcc/po und gcc/po. Gemeinsame Unterverzeichnisse: ../gcc-4.3.2_orig/gcc/testsuite und gcc/testsuite. diff -Nup ../gcc-4.3.2_orig/gcc/tree-cfg.c gcc/tree-cfg.c --- ../gcc-4.3.2_orig/gcc/tree-cfg.c 2008-04-04 20:00:25.000000000 +0200 +++ gcc/tree-cfg.c 2008-08-29 13:10:33.580683534 +0200 @@ -435,6 +435,7 @@ make_edges (void) { basic_block bb; struct omp_region *cur_region = NULL; + struct gtm_region *cur_gtm_region = NULL; /* Create an edge from entry to the first block with executable statements in it. */ @@ -527,9 +528,19 @@ make_edges (void) case OMP_ATOMIC_LOAD: case OMP_ATOMIC_STORE: - fallthru = true; - break; + fallthru = true; + break; + case GTM_TXN: + cur_gtm_region = new_gtm_region (bb, code, cur_gtm_region); + fallthru = true; + break; + + case GTM_RETURN: + cur_gtm_region->exit = bb; + fallthru = true; + cur_gtm_region = cur_gtm_region->outer; + break; case OMP_RETURN: /* In the case of an OMP_SECTION, the edge will go somewhere @@ -582,6 +593,12 @@ make_edges (void) } break; + case GTM_TXN: + case GTM_RETURN: + /* TODO add error or warning here */ + gcc_unreachable (); + break; + default: gcc_unreachable (); } @@ -602,7 +619,10 @@ make_edges (void) if (root_omp_region) free_omp_regions (); - /* Fold COND_EXPR_COND of each COND_EXPR. */ + if (root_gtm_region) + free_gtm_regions(); + + /* Fold COND_EXPR_COND of each COND_EXPR. */ fold_cond_expr_cond (); } @@ -2528,6 +2548,10 @@ is_ctrl_altering_stmt (const_tree t) if (OMP_DIRECTIVE_P (t)) return true; + /* GTM directives alter control flow. */ + if (GTM_DIRECTIVE_P (t)) + return true; + /* If a statement can throw, it alters control flow. */ return tree_can_throw_internal (t); } @@ -4051,6 +4075,13 @@ verify_gimple_stmt (tree stmt) return false; } + if (GTM_DIRECTIVE_P (stmt)) + { + /* The transactional memory primitives should not be + optimised either */ + return false; + } + switch (TREE_CODE (stmt)) { case GIMPLE_MODIFY_STMT: @@ -4926,6 +4957,7 @@ tree_redirect_edge_and_branch (edge e, b e->flags |= EDGE_FALLTHRU; break; + case GTM_RETURN: case OMP_RETURN: case OMP_CONTINUE: case OMP_SECTIONS_SWITCH: diff -Nup ../gcc-4.3.2_orig/gcc/tree.def gcc/tree.def --- ../gcc-4.3.2_orig/gcc/tree.def 2007-10-29 12:05:04.000000000 +0100 +++ gcc/tree.def 2008-08-29 13:16:04.568902375 +0200 @@ -1074,6 +1074,13 @@ DEFTREECODE (OMP_ATOMIC_STORE, "omp_atom /* OpenMP clauses. */ DEFTREECODE (OMP_CLAUSE, "omp_clause", tcc_exceptional, 0) +/* GTM TXN tree code. + Operand 0: GTM_TXN_BODY: contains body of the transaction.*/ +DEFTREECODE (GTM_TXN, "gtm_txn", tcc_statement, 1) + +/* Return from an GTM directive. */ +DEFTREECODE (GTM_RETURN, "gtm_return", tcc_statement, 0) + /* Reduction operations. Operations that take a vector of elements and "reduce" it to a scalar result (e.g. summing the elements of the vector, finding the minimum over diff -Nup ../gcc-4.3.2_orig/gcc/tree-flow.h gcc/tree-flow.h --- ../gcc-4.3.2_orig/gcc/tree-flow.h 2008-07-04 00:03:54.000000000 +0200 +++ gcc/tree-flow.h 2008-08-29 13:19:31.061549910 +0200 @@ -715,6 +715,45 @@ void omp_expand_local (basic_block); extern tree find_omp_clause (tree, enum tree_code); tree copy_var_decl (tree, tree, tree); + +/* GTM region information. + Concept and parts of the implementation + borrowed from OpenMP implementation. */ +#define NUM_BB_TXN 512 + +struct gtm_region +{ + /* The enclosing region. */ + struct gtm_region *outer; + + /* First child region. */ + struct gtm_region *inner; + + /* Next peer region. */ + struct gtm_region *next; + + /* Block containing the GTM directive as its last stmt. */ + basic_block entry; + + /* Block containing the GTM_RETURN as its last stmt. */ + basic_block exit; + + /* Since the blocks change this is the stmt containing the setjmp after expansion. */ + tree setjmp_stmt; + + /* Contains the bb indexes belonging to the transaction. + TODO allocate int array dynamically. */ + int txn_bbs [NUM_BB_TXN]; + + enum tree_code type; +}; + + +extern struct gtm_region *root_gtm_region; +extern struct gtm_region *new_gtm_region (basic_block, enum tree_code, + struct gtm_region *); +extern void free_gtm_regions (void); + /*--------------------------------------------------------------------------- Function prototypes ---------------------------------------------------------------------------*/ diff -Nup ../gcc-4.3.2_orig/gcc/tree-gimple.c gcc/tree-gimple.c --- ../gcc-4.3.2_orig/gcc/tree-gimple.c 2007-12-13 22:49:09.000000000 +0100 +++ gcc/tree-gimple.c 2008-08-29 13:21:41.056920280 +0200 @@ -243,6 +243,8 @@ is_gimple_stmt (tree t) case OMP_CONTINUE: case OMP_ATOMIC_LOAD: case OMP_ATOMIC_STORE: + case GTM_TXN: + case GTM_RETURN: /* These are always void. */ return true; diff -Nup ../gcc-4.3.2_orig/gcc/tree.h gcc/tree.h --- ../gcc-4.3.2_orig/gcc/tree.h 2008-02-08 20:10:25.000000000 +0100 +++ gcc/tree.h 2008-08-29 13:30:49.537489174 +0200 @@ -200,6 +200,12 @@ extern const enum tree_code_class tree_c || TREE_CODE (NODE) == OMP_ATOMIC_STORE \ || TREE_CODE (NODE) == OMP_CONTINUE) +/* Returns nonzero iff NODE is an GTM directive. */ + +#define GTM_DIRECTIVE_P(NODE) \ + (TREE_CODE (NODE) == GTM_TXN \ + || TREE_CODE (NODE) == GTM_RETURN) + /* Number of argument-words in each kind of tree-node. */ extern const unsigned char tree_code_length[]; @@ -1731,6 +1737,9 @@ struct tree_constructor GTY(()) #define CALL_EXPR_ARGP(NODE) \ (&(TREE_OPERAND (CALL_EXPR_CHECK (NODE), 0)) + 3) +/* GTM directives and accessors */ +#define GTM_TXN_BODY(NODE) TREE_OPERAND (GTM_TXN_CHECK (NODE), 0) + /* OpenMP directive and clause accessors. */ #define OMP_BODY(NODE) \ @@ -3124,7 +3133,8 @@ struct tree_decl_with_vis GTY(()) /* Belongs to VAR_DECL exclusively. */ ENUM_BITFIELD(tls_model) tls_model : 3; - /* 11 unused bits. */ + unsigned gtm_var_pure:1; + /* 10 unused bits. */ }; /* In a VAR_DECL that's static, @@ -3136,6 +3146,10 @@ struct tree_decl_with_vis GTY(()) is not error_mark_node, then the decl cannot be put in .common. */ #define DECL_COMMON(NODE) (DECL_WITH_VIS_CHECK (NODE)->decl_with_vis.common_flag) +/* Nonzero if VAR_DECL does not need instrumentation + inside a transaction */ +#define DECL_IS_GTM_PURE_VAR(NODE) (VAR_DECL_CHECK (NODE)->decl_with_vis.gtm_var_pure) + /* In a VAR_DECL, nonzero if the decl is a register variable with an explicit asm specification. */ #define DECL_HARD_REGISTER(NODE) (VAR_DECL_CHECK (NODE)->decl_with_vis.hard_register) @@ -3309,6 +3323,26 @@ struct tree_decl_non_common GTY(()) #define DECL_DECLARED_INLINE_P(NODE) \ (FUNCTION_DECL_CHECK (NODE)->function_decl.declared_inline_flag) +/* Nonzero in a FUNCTION_DECL means this function should be treated + as "tm_pure" function - does not read shared memory that transactions write to. */ +#define DECL_IS_GTM_PURE(NODE) \ + (FUNCTION_DECL_CHECK (NODE)->function_decl.gtm_pure_flag) + +/* Nonzero in a FUNCTION_DECL means this function should be treated + as "tm_only" function - only the tm version of the function exists. */ +#define DECL_IS_GTM_ONLY(NODE) (FUNCTION_DECL_CHECK (NODE)->function_decl.gtm_only_flag) + +/* Nonzero in a FUNCTION_DECL means this function should be treated + as "tm_unknown" function - behaviour of transactions depends + on STM system to supports irrevocable calls. */ +#define DECL_IS_GTM_UNKNOWN(NODE) \ + (FUNCTION_DECL_CHECK (NODE)->function_decl.gtm_unknown_flag) + +/* Nonzero in a FUNCTION_DECL means this function should be treated + as "tm_callable" function - function maybe called from within a transaction. */ +#define DECL_IS_GTM_CALLABLE(NODE) \ + (FUNCTION_DECL_CHECK (NODE)->function_decl.gtm_callable_flag) + /* Nonzero in a FUNCTION_DECL that should be always inlined by the inliner disregarding size and cost heuristics. This is equivalent to using the always_inline attribute without the required diagnostics if the @@ -3369,7 +3403,11 @@ struct tree_function_decl GTY(()) unsigned no_limit_stack : 1; unsigned disregard_inline_limits : 1; - /* 4 bits left */ + unsigned gtm_callable_flag : 1; + unsigned gtm_only_flag : 1; + unsigned gtm_pure_flag : 1; + unsigned gtm_unknown_flag : 1; + /* no bits left */ }; /* For a TYPE_DECL, holds the "original" type. (TREE_TYPE has the copy.) */ diff -Nup ../gcc-4.3.2_orig/gcc/tree-inline.c gcc/tree-inline.c --- ../gcc-4.3.2_orig/gcc/tree-inline.c 2008-04-16 18:07:46.000000000 +0200 +++ gcc/tree-inline.c 2008-08-29 15:58:25.250748118 +0200 @@ -2252,6 +2252,7 @@ estimate_num_insns_1 (tree *tp, int *wal case OMP_CONTINUE: case OMP_SECTIONS_SWITCH: case OMP_ATOMIC_STORE: + case GTM_RETURN: break; /* We don't account constants for now. Assume that the cost is amortized @@ -2486,7 +2487,9 @@ estimate_num_insns_1 (tree *tp, int *wal case OMP_CRITICAL: case OMP_ATOMIC: case OMP_ATOMIC_LOAD: - /* OpenMP directives are generally very expensive. */ + case GTM_TXN: + /* OpenMP directives are generally very expensive. + And the inlining of transactions should be avoided for now. */ d->count += d->weights->omp_cost; break; Gemeinsame Unterverzeichnisse: ../gcc-4.3.2_orig/gcc/treelang und gcc/treelang. diff -Nup ../gcc-4.3.2_orig/gcc/tree-pass.h gcc/tree-pass.h --- ../gcc-4.3.2_orig/gcc/tree-pass.h 2008-02-13 12:15:51.000000000 +0100 +++ gcc/tree-pass.h 2008-08-29 14:00:25.976528700 +0200 @@ -328,6 +328,8 @@ extern struct tree_opt_pass pass_reassoc extern struct tree_opt_pass pass_rebuild_cgraph_edges; extern struct tree_opt_pass pass_build_cgraph_edges; extern struct tree_opt_pass pass_reset_cc_flags; +extern struct tree_opt_pass pass_expand_gtm; +extern struct tree_opt_pass pass_checkpoint_gtm; /* IPA Passes */ extern struct tree_opt_pass pass_ipa_matrix_reorg; diff -Nup ../gcc-4.3.2_orig/gcc/tree-pretty-print.c gcc/tree-pretty-print.c --- ../gcc-4.3.2_orig/gcc/tree-pretty-print.c 2008-01-27 17:48:54.000000000 +0100 +++ gcc/tree-pretty-print.c 2008-08-29 14:04:48.967439283 +0200 @@ -1984,6 +1984,25 @@ dump_generic_node (pretty_printer *buffe is_expr = false; break; + case GTM_RETURN: + pp_string (buffer, "GTM_RETURN"); + is_expr = false; + break; + + case GTM_TXN: + pp_string (buffer, "_Pragma(\"tm atomic\")"); + if (!(flags & TDF_SLIM) && GTM_TXN_BODY (node)) + { + newline_and_indent (buffer, spc); + pp_character (buffer, '{'); + newline_and_indent (buffer, spc + 2); + dump_generic_node (buffer, GTM_TXN_BODY (node), spc + 2, flags, false); + newline_and_indent (buffer, spc); + pp_character (buffer, '}'); + } + is_expr = false; + break; + case REDUC_MAX_EXPR: pp_string (buffer, " REDUC_MAX_EXPR < "); dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); diff -Nup ../gcc-4.3.2_orig/gcc/tree-ssa-live.c gcc/tree-ssa-live.c --- ../gcc-4.3.2_orig/gcc/tree-ssa-live.c 2007-11-26 07:24:54.000000000 +0100 +++ gcc/tree-ssa-live.c 2008-08-29 16:11:47.232197846 +0200 @@ -1085,8 +1085,11 @@ verify_live_on_entry (tree_live_info_p l tree d; bitmap loe; var = partition_to_var (map, i); - stmt = SSA_NAME_DEF_STMT (var); - tmp = bb_for_stmt (stmt); + /* Inserted for GTM because otherwise we have segfault. */ + if (!var) + continue; + stmt = SSA_NAME_DEF_STMT (var); + tmp = bb_for_stmt (stmt); d = gimple_default_def (cfun, SSA_NAME_VAR (var)); loe = live_on_entry (live, e->dest); diff -Nup ../gcc-4.3.2_orig/gcc/tree-ssa-operands.c gcc/tree-ssa-operands.c --- ../gcc-4.3.2_orig/gcc/tree-ssa-operands.c 2008-01-08 17:29:14.000000000 +0100 +++ gcc/tree-ssa-operands.c 2008-08-29 16:04:06.242910074 +0200 @@ -2376,6 +2376,8 @@ get_expr_operands (tree stmt, tree *expr case OMP_RETURN: case OMP_SECTION: case OMP_SECTIONS_SWITCH: + case GTM_TXN: + case GTM_RETURN: /* Expressions that make no memory references. */ return;