From patchwork Mon Nov 18 21:50:55 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Iyer, Balaji V" X-Patchwork-Id: 292208 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 3F2682C0097 for ; Tue, 19 Nov 2013 08:52:37 +1100 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:references:in-reply-to :content-type:mime-version; q=dns; s=default; b=MuksPEoJgZlLyxRN HqEIazdLJJemwmdcNvrkw57NBD5M11YdwZpEyhUdoSsHEhkGFJ7aTIaUDaVndAy1 GPj1J91S1R/9syXF9k8heyh+G+W4sjgLZF6ufC4TAyBshKA+ohPBPnylmk5/rHeQ bCtmAG3OA3PD0PVLjWfYA+MLY88= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:references:in-reply-to :content-type:mime-version; s=default; bh=X4WAgRHaneYnd6j70zgtEK zlExE=; b=aQKEQVdX77qi7WV/Z/Hvh7NpqjG/gOsqWIjiC5Kxq37psY/Zh8uUUb y/haAMVVEChqmu+cnoE1UWS6UW8kPGIW9ahYR0LtFlpN15qio+UNtekiWyPoTPTu 2jvqTdc+Q0/o8TX6tRcCkgQQsEFrMNZVWyyqsqOGnz3FKjGciXV+E= Received: (qmail 12636 invoked by alias); 18 Nov 2013 21:52:15 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 12617 invoked by uid 89); 18 Nov 2013 21:52:14 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=2.6 required=5.0 tests=AWL, BAYES_60, RDNS_NONE, SPF_PASS, TBC, URIBL_BLOCKED autolearn=no version=3.3.2 X-HELO: mga01.intel.com Received: from Unknown (HELO mga01.intel.com) (192.55.52.88) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 18 Nov 2013 21:51:07 +0000 Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga101.fm.intel.com with ESMTP; 18 Nov 2013 13:50:59 -0800 X-ExtLoop1: 1 Received: from fmsmsx105.amr.corp.intel.com ([10.19.9.36]) by fmsmga002.fm.intel.com with ESMTP; 18 Nov 2013 13:50:57 -0800 Received: from FMSMSX110.amr.corp.intel.com (10.18.116.10) by FMSMSX105.amr.corp.intel.com (10.19.9.36) with Microsoft SMTP Server (TLS) id 14.3.123.3; Mon, 18 Nov 2013 13:50:56 -0800 Received: from fmsmsx101.amr.corp.intel.com ([169.254.1.227]) by FMSMSX110.amr.corp.intel.com ([169.254.1.171]) with mapi id 14.03.0123.003; Mon, 18 Nov 2013 13:50:56 -0800 From: "Iyer, Balaji V" To: Aldy Hernandez CC: "gcc-patches@gcc.gnu.org" , Jeff Law , "Jason Merrill (jason@redhat.com)" , "rth@redhat.com" Subject: RE: [PATCH] _Cilk_for for C and C++ Date: Mon, 18 Nov 2013 21:50:55 +0000 Message-ID: References: <52869727.4060307@redhat.com> In-Reply-To: <52869727.4060307@redhat.com> MIME-Version: 1.0 X-IsSubscribed: yes Hello Everyone, Please see my comment below: > -----Original Message----- > From: Aldy Hernandez [mailto:aldyh@redhat.com] > Sent: Friday, November 15, 2013 4:51 PM > To: Iyer, Balaji V > Cc: gcc-patches@gcc.gnu.org; Jeff Law; Jason Merrill (jason@redhat.com); > rth@redhat.com > Subject: Re: [PATCH] _Cilk_for for C and C++ > > On 11/15/13 12:23, Iyer, Balaji V wrote: > > > This patch is dependent on the following patches: > > > > #pragma simd work (they both share the same parser routines) > > I have just committed this to trunk, so it shouldn't be a blocker. > > Also, in the past 2 days the #pragma simd parsing has been merged with the > OpenMP parsing routines, so please adjust your patch accordingly. Attached, please find a refreshed patches (one for C and 1 for C++). The trunk was "diffed" after Aldy's check in of pragma simd was in. So, now this patch is only dependent on _Cilk_spawn and _Cilk_sync (mostly for execution of tests). They are tested on x86_64 and works successfully. Here are the fixed Changelog entries (C related changelogs are given first then C++): C- Related Changes ===================================================================================== gcc/ChangeLog. 2013-11-18 Balaji V. Iyer * cilk-builtins.def: Added 2 builtin functions: __cilkrts_cilk_for_64 and __cilkrts_cilk_for_32. * cilk-common.c (cilk_declare_looper): New function. (cilk_init_builtins): Added two calls to cilk_declare_looper. * cilk.h (enum cilk_tree_index): Added two enums: CILK_TI_F_LOOP_32 and CILK_TI_F_LOOP_64. (enum add_variable_type): Moved here from c-family/cilk.c (enum cilk_block_type): Likewise. (struct wrapper_data): Likewise. (struct cilk_for_desc): New struct. (cilk_for_32_fndecl): New #define. (cilk_for_64_fndecl): Likewise. * tree.h (CILK_FOR_INIT): Likewise. (CILK_FOR_COND): Likewise. (CILK_FOR_EXPR): Likewise. (CILK_FOR_BODY): Likewise. (CILK_FOR_SCOPE): Likewise. (CILK_FOR_GRAIN): Likewise. (CILK_FOR_VAR): Likewise. * gimplify.c (gimplify_expr): Added CILK_FOR_STMT case. * tree-pretty-print.c (dump_generic_node): Likewise. * langhooks-def.h (LANG_HOOKS_CILKPLUS_GIMPLIFY_CILK_FOR): New #define. (LANG_HOOKS_CILKPLUS): Added LANG_HOOKS_CILKPLUS_GIMPLIFY_FOR field. * langhooks.h (struct lang_hooks_for_cilkplus): Added a new field gimplify_cilk_for. * tree.def: Added a new tree CILK_FOR_STMT. gcc/c-family/ChangeLog. 2013-11-18 Balaji V. Iyer * c-cilkplus.c (c_check_cilk_loop_incr): New function. (c_validate_cilk_plus_loop): Likewise. (c_check_cilk_loop): Likewise. (c_finish_cilk_for_loops): Likewise. (cp_finish_cilk_for_loops): Likewise. * c-common.c (c_common_resword): Added _Cilk_for keyword. * c-common.h (enum rid): Added RID_CILK_FOR. (cp_finish_cilk_for_loop): New prototype. (c_finish_cilk_for_loop): Likewise. (c_validate_cilk_loop): Likewise. (c_check_cilk_loop): Likewise. (cilk_init_fd): Likewise. (cilk_extract_free_variables): Likewise. (cilk_create_cilk_helper_decl): Likewise. (cilk_call_graph_add_fn): Likewise. (cilk_outline_body): Likewise. (cilk_check_loop_difference_type): Likewise. (declare_cilk_for_parms): Likewise. (declare_cilk_for_vars): Likewise. (cilk_loop_convert): Likewise. (cilk_divide_count): Likewise. (cilk_calc_forward_div_op): Likewise. (cilk_compute_loop_count): Likewise. (insert_cilk_for_nested_fn): Likewise. (cilk_compute_loop_var): Likewise. (cilk_set_inclusive_and_direction): Likewise. (cilk_set_iter_difftype): Likewise. (cilk_set_incr_info): Likewise. (cilk_set_init_info): Likewise. (clk_simplify_tree): Likewise. (cilk_find_code_from_call): Likewise. (cilk_tree_operand_noconv): Likewise. (cilk_resolve_continue_stmts): Likewise. * c-pragma.c (init_pragma): Added pragma grainsize. * c-pragma.h (enum pragma_kind): Added PRAGMA_CILK_GRAINSIZE. * cilk.c (enum add_variable_type): Moved to ../cilk.h. (enum cilk_block_type): Likewise. (struct wrapper_data): Likewise. (cilk_call_graph_add_fn): New function. (cilk_create_cilk_helper_decl): Likewise. (cilk_outline): Renamed to cilk_outline_body. Also added a parameter to hold throw flag for C++. (cilk_create_wrapper_body): Renamed create_cilk_helper_decl, call_graph_add_fn and cilk_outline to cilk_create_cilk_helper_decl, cilk_call_graph_add_fn, and cilk_outline_body, respectively. (create_cilk_wrapper): Renamed extact_free_variables to cilk_extract_free_variables. (extract_free_variables): Likewise. (cilk_init_cfd): New function. (find_cilk_for_library_fn): Likewise. (cilk_compute_incr_direction): Likewise. (cilk_check_loop_difference_type): Likewise. (cilk_simplify_tree): Likewise. (declare_cilk_for_vars): Likewise. (declare_cilk_for_parms): Likewise. (cilk_loop_convert): Likewise. (cilk_divide_count): Likewise. (cilk_calc_forward_div_op): Likewise. (cilk_compute_loop_count): Likewise. (insert_cilk_for_nested_fn): Likewise. (cilk_compute_loop_var): Likewise. (cilk_tree_operand_noconv): Likewise. (cilk_find_code_from_call): Likewise. (cilk_set_init_info): Likewise. (cilk_set_inclusive_and_direction): Likewise. (cilk_set_iter_difftype): Likewise. (cilk_set_incr_info): Likewise. gcc/c/ChangeLog. 2013-11-18 Balaji V. Iyer * Make-lang.in (C_AND_OBJC_OBJS): Added c/c-cilk.o. * c-cilk.c: New file. * c-objc-common.h (LANG_HOOKS_CILKPLUS_GIMPLIFY_CILK_FOR): New #define. * c-parser.c (c_parser_cilk_for_statement): New function prototype. (c_parser_cilk_grainsize): New function prototype and function. (c_parser_statement_after_labels): Added RID_CILK_FOR case. (c_parser_pragma): Added PRAGMA_CILK_GRAINSIZE case. (c_parser_cilk_for_statement): Renamed a parameter. Added code to accomodate RID_CILK_FOR tree (i.e. to parse _Cilk_for statements). * c-tree.h (c_gimplify_cilk_for): New prototype. gcc/testsuite/ChangeLog. 2013-11-18 Balaji V. Iyer * g++.dg/cilk-plus/CK/cilk-for-start-at-5.cc: New test. * g++.dg/cilk-plus/CK/cilk-for-tplt.cc: Likewise. * g++.dg/cilk-plus/CK/cilk-for.cc: Likewise. * g++.dg/cilk-plus/CK/cilk_for_cont_inside_for.cc: Likewise. * g++.dg/cilk-plus/CK/cilk_for_cont_with_for.cc: Likewise. * g++.dg/cilk-plus/CK/cilk_for_cont_with_if.cc: Likewise. * g++.dg/cilk-plus/CK/cilk_for_cont_with_while.cc: Likewise. * g++.dg/cilk-plus/CK/cilk_for_genricize_test.cc: Likewise. * g++.dg/cilk-plus/CK/cilk_for_grainsize.cc: Likewise. * g++.dg/cilk-plus/CK/cilk_for_p_errors.cc: Likewise. * g++.dg/cilk-plus/CK/cilk_for_t_errors.cc: Likewise. * g++.dg/cilk-plus/CK/explicit_ctor.cc: Likewise. * g++.dg/cilk-plus/CK/label_test.cc: Likewise. * g++.dg/cilk-plus/CK/no-opp-overload-error.cc: Likewise. * g++.dg/cilk-plus/CK/plus-equal-one.cc: Likewise. * g++.dg/cilk-plus/CK/plus-equal-test.cc: Likewise. * g++.dg/cilk-plus/CK/stl_iter.cc: Likewise. * g++.dg/cilk-plus/CK/stl_test.cc: Likewise. * g++.dg/cilk-plus/cilk-plus.exp: Added support to call _Cilk_for testcodes. ============================================================================================= Here are the C++ related ChangeLogs: gcc/cp/ChangeLog. 2013-11-18 Balaji V. Iyer * cp-cilk.c: Added langhooks.h and tree.h. (callable): New function. (calc_count_up_count_down): Likewise. (compute_loop_var_cp_iter_hdl): Likewise. (cp_create_cilk_for_body): Likewise. (create_cilk_for_nested_fn): Likewise. (gimplify_cilk_for_1): Likewise. (cp_extract_cilk_for_fields): Likewise. (cp_gimplify_cilk_for): Likewise. * cp-gimplify.c (genericize_cilk_for_stmt): Likewise. (cp_genericize_r): Added a check for CILK_FOR_STMT. * cp-objcp-common.h (LANG_HOOKS_CILKPLUS_GIMPLIFY_CILK_FOR): New #define. * cp-tree.h (begin_cilk_for_stmt): New prototype. (finish_cilk_for_stmt): Likewise. (finish_cilk_for_init_stmt): Likewise. (cp_gimplify_cilk_for): Likewise. * name-lookup.c (begin_scope): Added sk_cilk_for case. * name-lookup.h (enum scope_kind): Added sk_cilk_for. * parser.c (cp_parser_cilk_grainsize): New function and prototype. (cp_parser_init_declarator): Added a new parameter to hold the initial value. (cp_parser_statement): Added RID_CILK_FOR case. (cp_parser_iteration_statement): Likewise. (cp_parser_jump_statement): Added IN_CILK_FOR_STMT case (twice). (cp_parser_pragma): Added PRAGMA_CILK_GRAINSIZE case. (cp_parser_cilk_for_init_statement): New function. (cp_parser_cilk_for): Renamed a parameter and added support for parsing _Cilk_for loops that are part of Cilk keywords. * parser.h (IN_CILK_FOR_STMT): New #define. * pt.c (tsubst_expr): Added CILK_FOR_STMT case. * semantics.c (begin_for_scope): Added "_Cilk_for statement" in the header comment. (finish_for_expr): Added support for CILK_FOR_STMT to use this function. (finish_cilk_for_cond): Added support for processing templates. (begin_cilk_for_stmt): New function. (finish_cilk_for_init_stmt): Likewise. (finish_clk_for_stmt): Likewise. gcc/testsuite/ChangeLog. 2013-11-18 Balaji V. Iyer * gcc.dg/cilk-plus/CK/cilk-for.c: New test. * gcc.dg/cilk-plus/CK/cilk_for_decr.c: Likewise. * gcc.dg/cilk-plus/CK/cilk_for_errors.c: Likewise. * gcc.dg/cilk-plus/CK/cilk_for_grain.c: Likewise. * gcc.dg/cilk-plus/CK/cilk_for_grain_errors.c: Likewise. * gcc.dg/cilk-plus/CK/cilk_for_ptr_iter.c: Likewise. * gcc.dg/cilk-plus/CK/cilk_for_warning.c: Likewise. * gcc.dg/cilk-plus/cilk-plus.exp: Added support to call _Cilk_for testcodes. Thanks, Balaji V. Iyer. diff --git a/gcc/cp/cp-cilk.c b/gcc/cp/cp-cilk.c old mode 100644 new mode 100755 index 0da95e8..bd114c8 --- a/gcc/cp/cp-cilk.c +++ b/gcc/cp/cp-cilk.c @@ -23,8 +23,13 @@ #include "system.h" #include "coretypes.h" #include "cp-tree.h" +#include "tree.h" #include "tree-iterator.h" #include "cilk.h" +#include "langhooks.h" +#include "cgraph.h" +#include "gimple.h" +#include "gimplify.h" /* Sets the EXCEPTION bit (0x10) in the FRAME.flags field. */ @@ -116,3 +121,483 @@ cilk_create_lambda_fn_tmp_var (tree lambda_fn) add_local_decl (cfun, return_var); return return_var; } + +/* Returns an overloaded function that does operation based on CODE using + OP0 and OP1. If CRY is set to true, then the function complains when + it is unable to find an overloaded operator. */ + +static tree +callable (location_t loc, enum tree_code code, tree op0, tree op1, bool cry) +{ + vec *op1_vec = make_tree_vector_single (op1); + if (code == INIT_EXPR) + return build_special_member_call (NULL_TREE, complete_ctor_identifier, + &op1_vec, + TYPE_MAIN_VARIANT (TREE_TYPE (op1)), 0, + cry); + + if (code == PSEUDO_DTOR_EXPR) + return build_special_member_call (NULL_TREE, complete_dtor_identifier, + &op1_vec, + TYPE_MAIN_VARIANT (TREE_TYPE (op1)), 0, + cry); + + int flags = LOOKUP_PROTECT | LOOKUP_ONLYCONVERTING; + tree exp = build_new_op (EXPR_LOCATION (op1), code, flags, op0, op1, + NULL_TREE, NULL, 0); + if (exp == error_mark_node) + exp = build_x_modify_expr (EXPR_LOCATION (op1), op0, code, op1, tf_none); + if (exp && exp != error_mark_node) + return exp; + + const char *op = operator_name_info[(int) code].name; + const char *explain = cry ? "" : "accessible, unambiguous"; + if (op1) + error_at (loc, "No%s operator%s(%T,%T) for _Cilk_for loop", explain, op, + TREE_TYPE (op0), TREE_TYPE (op1)); + else + error_at (loc, "No%s operator%s(%T,%T) for _Cilk_for loop", explain, op, + TREE_TYPE (op0), TREE_TYPE (op0)); + return NULL_TREE; +} + +/* Calculates the COUNT_UP and/or COUNT_DOWN values for a _Cilk_for loop using + its characteristics stored in *CFD. */ + +static void +calc_count_up_count_down (struct cilk_for_desc *cfd, tree *count_up, + tree *count_down) +{ + /* Reasoning for high and low variables can be found in + cilk_compute_loop_count in c-family/cilk.c. */ + tree high = cfd->end_var ? cfd->end_var : cfd->end_expr; + tree low = cfd->lower_bound ? cfd->lower_bound : cfd->var; + + /* When these are invalid, we flag them in cilk_compute_loop_var. This + condition is a bit rare. */ + if (high == error_mark_node || low == error_mark_node) + return; + + /* Only call this function if we are using an iterator. */ + gcc_assert (cfd->iterator); + + if (TREE_CODE (high) == TARGET_EXPR) + high = TARGET_EXPR_INITIAL (high); + if (TREE_CODE (low) == TARGET_EXPR) + low = TARGET_EXPR_INITIAL (low); + + if (TREE_CODE (low) == TREE_LIST) + low = TREE_VALUE (low); + high = cilk_tree_operand_noconv (high); + if (cfd->direction >= 0) + { + *count_up = build_x_binary_op (cfd->loc, MINUS_EXPR, high, + TREE_CODE (high), low, TREE_CODE (low), + NULL, tf_warning_or_error); + /* We should have already failed if this operator is not callable. */ + gcc_assert (*count_up != error_mark_node); + } + else + { + *count_down = build_x_binary_op (cfd->loc, MINUS_EXPR, low, + TREE_CODE (low), high, TREE_CODE (high), + NULL, tf_warning_or_error); + /* ...same reasoning as count up for the assert below. */ + gcc_assert (*count_down != error_mark_node); + } +} + +/* Handler for iterator to compute the loop variable. ADD_OP indicates + whether we need a '+' or '-' operation. LOW indicates the starting point + and LOOP_VAR is the induction variable. Returns an expression (or a + STATEMENT_LIST of expressions). If it is unable to find the appropriate + iteration, then it returns an error mark node and its parent will set + the loop as invalid. */ + +static tree +compute_loop_var_cp_iter_hdl (location_t loc, enum tree_code add_op, + tree low, tree loop_var, tree var2) +{ + tree exp = build_new_op (loc, add_op, 0, low, loop_var, NULL_TREE, 0, + tf_none); + if (exp == error_mark_node) + { + /* If we are here then operator+ or operator- could not be found. + So, the other option is to use +=. This requires storing values + in the variable and then adding them one by one. */ + tree new_var = var2; + exp = alloc_stmt_list (); + tree new_stmt = build_x_modify_expr (loc, new_var, INIT_EXPR, + build_zero_cst (TREE_TYPE (new_var)), + tf_warning_or_error); + if (new_stmt == error_mark_node) + return error_mark_node; + append_to_statement_list (new_stmt, &exp); + new_stmt = build_x_modify_expr (loc, new_var, NOP_EXPR, low, + tf_warning_or_error); + if (new_stmt == error_mark_node) + return error_mark_node; + append_to_statement_list (new_stmt, &exp); + new_stmt = build_x_modify_expr (loc, new_var, add_op, loop_var, + tf_warning_or_error); + if (new_stmt == error_mark_node) + return error_mark_node; + append_to_statement_list (new_stmt, &exp); + return exp; + } + exp = cp_build_modify_expr (var2, INIT_EXPR, exp, tf_warning_or_error); + return exp; +} + +/* Returns the body of the nested function for a _Cilk_for using the loop's + characteristic information from CFD. The returned tree will be a + STATEMENT LIST. */ + +static tree +cp_create_cilk_for_body (struct cilk_for_desc *cfd) +{ + push_function_context (); + declare_cilk_for_parms (cfd); + cfd->wd.fntype = build_function_type (void_type_node, cfd->wd.argtypes); + + tree fndecl = cilk_create_cilk_helper_decl (&cfd->wd); + fndecl = build_lang_decl (FUNCTION_DECL, DECL_NAME (fndecl), cfd->wd.fntype); + if (cfd->nested_ok) + DECL_CONTEXT (fndecl) = current_function_decl; + else + DECL_CONTEXT (fndecl) = DECL_CONTEXT (current_function_decl); + + tree outer = current_function_decl; + SET_DECL_LANGUAGE (fndecl, lang_c); + start_preparsed_function (fndecl, NULL_TREE, SF_PRE_PARSED); + + declare_cilk_for_vars (cfd, fndecl); + + tree lower_bound = cfd->lower_bound; + struct gimplify_ctx gctx; + + tree body = begin_compound_stmt (BCS_FN_BODY); + push_gimplify_context (&gctx); + + gimple_add_tmp_var (cfd->var2); + + /* Get the lower bound into a variable unless it is a constant or a + non-copyable value. If non-copyable value, then reference value from + the outer frame. */ + if (!lower_bound) + { + lower_bound = cfd->var; + tree hack = build_decl (cfd->loc, VAR_DECL, NULL_TREE, + TREE_TYPE (lower_bound)); + DECL_CONTEXT (hack) = DECL_CONTEXT (lower_bound); + *pointer_map_insert (cfd->wd.decl_map, hack) = lower_bound; + lower_bound = hack; + } + tree cast_max_expr, count_type, pre, loop_var; + if (INTEGRAL_TYPE_P (cfd->var_type)) + { + loop_var = create_tmp_var (cfd->var_type, NULL); + count_type = cfd->var_type; + tree cvt_expr = cp_fold_convert (cfd->var_type, cfd->min_parm); + pre = build_x_modify_expr (cfd->loc, loop_var, NOP_EXPR, cvt_expr, + tf_warning_or_error); + cast_max_expr = cp_fold_convert (count_type, cfd->max_parm); + } + else + { + loop_var = create_tmp_var (TREE_TYPE (cfd->min_parm), NULL); + count_type = cfd->count_type; + pre = fold_build2 (INIT_EXPR, void_type_node, loop_var, cfd->min_parm); + cast_max_expr = cfd->max_parm; + } + + tree loop_body = alloc_stmt_list (); + + /* Concat. the control variable initialization with the loop body. + Do not call gimplify_and_add to append to list because we need + to wrap the entire list in a cleanup point expr to delay destruction + of the control variable to the end of the loop if it is an iterator. */ + tree loop_end_comp = cilk_compute_loop_var (cfd, loop_var, lower_bound, + compute_loop_var_cp_iter_hdl); + if (loop_end_comp == error_mark_node) + { + cfd->invalid = true; + return error_mark_node; + } + append_to_statement_list (loop_end_comp, &loop_body); + tree cleanup = cxx_maybe_build_cleanup (cfd->var2, tf_none); + if (cleanup) + { + append_to_statement_list (cfd->body, &loop_body); + append_to_statement_list (cleanup, &loop_body); + } + else + append_to_statement_list (cfd->body, &loop_body); + + loop_body = fold_build_cleanup_point_expr (void_type_node, loop_body); + DECL_SEEN_IN_BIND_EXPR_P (cfd->var2) = 1; + + cfd->wd.context = outer; + bool throws = flag_exceptions ? cp_function_chain->can_throw : false; + cilk_outline_body (fndecl, &loop_body, &cfd->wd, &throws); + cp_function_chain->can_throw = throws; + + /* We have to manually create this loop for two reasons: + a. We need to have access to continue and start label since we need + to resolve continue and breaks by hand. + b. C++ doesn't provide a c_finish_loop function like C does. */ + tree c_for_loop = push_stmt_list (); + tree slab = build_decl (cfd->loc, LABEL_DECL, NULL_TREE, void_type_node); + DECL_ARTIFICIAL (slab) = 0; + DECL_IGNORED_P (slab) = 1; + DECL_CONTEXT (slab) = fndecl; + tree top_label = build1 (LABEL_EXPR, void_type_node, slab); + + tree cont_lab = build_decl (cfd->loc, LABEL_DECL, NULL_TREE, void_type_node); + DECL_ARTIFICIAL (cont_lab) = 0; + DECL_IGNORED_P (cont_lab) = 1; + DECL_CONTEXT (cont_lab) = fndecl; + + tree continue_label = build1 (LABEL_EXPR, void_type_node, cont_lab); + tree loop_cond = fold_build2 (LT_EXPR, boolean_type_node, loop_var, + cast_max_expr); + tree cond_expr = build3 (COND_EXPR, void_type_node, loop_cond, + build1 (GOTO_EXPR, void_type_node, slab), + build_empty_stmt (cfd->loc)); + tree mod_expr = fold_build2 (MODIFY_EXPR, void_type_node, loop_var, + build2 (PLUS_EXPR, count_type, loop_var, + build_one_cst (count_type))); + add_stmt (pre); + add_stmt (top_label); + add_stmt (loop_body); + add_stmt (continue_label); + add_stmt (mod_expr); + add_stmt (cond_expr); + pop_stmt_list (c_for_loop); + + /* Resolve all the continues in the _Cilk_for body here. */ + walk_tree (&c_for_loop, cilk_resolve_continue_stmts, (void *) cont_lab, NULL); + add_stmt (c_for_loop); + + DECL_INITIAL (fndecl) = make_node (BLOCK); + TREE_USED (DECL_INITIAL (fndecl)) = 1; + BLOCK_VARS (DECL_INITIAL (fndecl)) = loop_var; + TREE_CHAIN (loop_var) = cfd->var2; + + body = build3 (BIND_EXPR, void_type_node, loop_var, body, + DECL_INITIAL (fndecl)); + DECL_CONTEXT (cfd->var2) = fndecl; + pop_gimplify_context (0); + + finish_function_body (body); + + /* A nested function canot be expanded or deferred until its parent is done. + So, don't call expand_or_defer_fn here. A non-nested function must be + done here. */ + if (!cfd->nested_ok) + expand_or_defer_fn (fndecl); + + pop_function_context (); + return fndecl; +} + +/* Creates a nested function for the _Cilk_for statement using its information + in CFD. PRE_P is the preceeding gimple trees function. */ + +static tree +create_cilk_for_nested_fn (struct cilk_for_desc *cfd, gimple_seq *pre_p) +{ + tree var = cfd->var; + DECL_CONTEXT (var) = current_function_decl; + + if (POINTER_TYPE_P (TREE_TYPE (var))) + cilk_extract_free_variables (cfd->lower_bound, &cfd->wd, ADD_WRITE); + else + cilk_extract_free_variables (cfd->lower_bound, &cfd->wd, ADD_READ); + + tree incr = cfd->incr; + + /* If the loop increment is not an integer constant and is not a DECL, + copy it to a temporary. if it is modified during the loop the behavior + is undefined. Races could be avoided by copying it to a temporary + variable. */ + if (TREE_CODE (incr) != INTEGER_CST && !DECL_P (incr)) + { + incr = get_formal_tmp_var (incr, pre_p); + cfd->incr = incr; + } + + if (DECL_P (incr) && !TREE_STATIC (incr) && !DECL_EXTERNAL (incr)) + *pointer_map_insert (cfd->wd.decl_map, incr) = incr; + + /* Map the loop variable to integer_minus_one_node if we won't really be + passing it into hte loop body. Otherwise map to integer_zero_node. */ + *pointer_map_insert (cfd->wd.decl_map, var) = + (void *) (cfd->lower_bound ? integer_minus_one_node : integer_zero_node); + cilk_extract_free_variables (cfd->body, &cfd->wd, ADD_READ); + + tree fn = cp_create_cilk_for_body (cfd); + + /* One of the reasons why FN is error_mark_node is because the function + couldn't find the appropriate overloaded operation. */ + if (fn == error_mark_node) + return error_mark_node; + + DECL_UNINLINABLE (fn) = 1; + DECL_STATIC_CHAIN (fn) = 1; + + current_function_decl = fn; + /* Genericize the _Cilk_for body, mainly split up the _Cilk_for body and + the for-loop we inserted. */ + cp_genericize (fn); + return fn; +} + +/* Helper function to gimplify a CILK_FOR_STMT. CFD holds all the values + extracted a CILK_FOR_STMT and *PRE_P is the preceeding sequence. */ + +static void +gimplify_cilk_for_1 (struct cilk_for_desc cfd, gimple_seq *pre_p) +{ + bool order_variable = false; + tree parent_function = current_function_decl; + + if (TREE_SIDE_EFFECTS (cfd.end_expr)) + { + enum tree_code ecode = TREE_CODE (cfd.end_expr); + if (ecode == INIT_EXPR || ecode == MODIFY_EXPR) + cfd.end_var = TREE_OPERAND (cfd.end_expr, 0); + else if (ecode == TARGET_EXPR) + { + cfd.end_var = TARGET_EXPR_INITIAL (cfd.end_expr); + if (TREE_CODE (cfd.end_var) == AGGR_INIT_EXPR) + cfd.end_var = TARGET_EXPR_SLOT (cfd.end_expr); + else + cfd.end_var = get_formal_tmp_var (cfd.end_var, pre_p); + } + else if (ecode == CALL_EXPR) + cfd.end_var = cfd.end_expr; + else + { + tree ii_tree = cfd.end_expr; + while (TREE_CODE_CLASS (TREE_CODE (ii_tree)) == tcc_unary) + ii_tree = TREE_OPERAND (ii_tree, 0); + if (TREE_CODE (ii_tree) == ADDR_EXPR) + ii_tree = TREE_OPERAND (ii_tree, 0); + ecode = TREE_CODE (ii_tree); + tree tmp_var = cilk_tree_operand_noconv (cfd.end_expr); + cfd.end_var = get_formal_tmp_var (tmp_var, pre_p); + order_variable = true; + } + } + tree cond = cfd.cond; + tree op1 = TREE_OPERAND (cond, 1); + tree op0 = TREE_OPERAND (cond, 0); + enum tree_code cond_code = TREE_CODE (cond); + + /* In this case below, we have an overloaded boolean comparison operation. */ + if (cond_code == CALL_EXPR) + { + cond_code = cilk_find_code_from_call (CALL_EXPR_FN (cond)); + op1 = cilk_tree_operand_noconv (CALL_EXPR_ARG (cond, 1)); + op0 = cilk_tree_operand_noconv (CALL_EXPR_ARG (cond, 0)); + if (TREE_CODE (op0) == ADDR_EXPR || TREE_CODE (op0) == INDIRECT_REF) + op0 = TREE_OPERAND (op0, 0); + } + if (order_variable && op1 == cfd.end_expr) + op1 = cfd.end_var; + else if (order_variable && op0 == cfd.end_expr) + op0 = cfd.end_var; + + cond = callable (cfd.loc, cond_code, op0, op1, false); + gcc_assert (cond != NULL_TREE); + + if (TREE_CODE (TREE_TYPE (cond)) != BOOLEAN_TYPE) + cond = perform_implicit_conversion (boolean_type_node, cond, + tf_warning_or_error); + enum tree_code div_op = NOP_EXPR; + tree forward = NULL_TREE, count_up = NULL_TREE, count_down = NULL_TREE; + cilk_calc_forward_div_op (&cfd, &div_op, &forward); + if (cfd.iterator) + calc_count_up_count_down (&cfd, &count_up, &count_down); + + tree count = cilk_compute_loop_count (&cfd, div_op, forward, count_up, + count_down); + tree fn = create_cilk_for_nested_fn (&cfd, pre_p); + if (fn == error_mark_node) + return; + cfd.cond = cond; + + current_function_decl = parent_function; + gimple_seq inner_seq = insert_cilk_for_nested_fn (&cfd, count, fn); + gimple_seq_add_seq (pre_p, inner_seq); +} + +/* Extract all the relevant information from CFOR, a CILK_FOR_STMT tree + and store them in CFD structure. */ + +static void +cp_extract_cilk_for_fields (struct cilk_for_desc *cfd, tree cfor) +{ + cfd->var = CILK_FOR_VAR (cfor); + cfd->cond = CILK_FOR_COND (cfor); + cfd->lower_bound = CILK_FOR_INIT (cfor); + cfd->incr = CILK_FOR_EXPR (cfor); + cfd->loc = EXPR_LOCATION (cfor); + cfd->body = CILK_FOR_BODY (cfor); + cfd->grain = CILK_FOR_GRAIN (cfor); + cfd->invalid = false; + + /* This function shouldn't be setting these two variables. */ + cfd->ctx_arg = NULL_TREE; + cfd->count = NULL_TREE; + + cilk_set_init_info (cfd); + cilk_set_inclusive_and_direction (cfd); + cilk_set_iter_difftype (cfd); + + if (cfd->iterator) + { + tree exp = NULL_TREE; + tree hack = build_decl (cfd->loc, VAR_DECL, NULL_TREE, + TREE_TYPE (cfd->var)); + if (cfd->direction >= 0) + exp = callable (cfd->loc, MINUS_EXPR, hack, cfd->var,true); + else + exp = callable (cfd->loc, MINUS_EXPR, cfd->var, hack, true); + if (!exp) + { + cfd->invalid = true; + return; + } + cfd->difference_type = TYPE_MAIN_VARIANT (TREE_TYPE (exp)); + } + cfd->count_type = cilk_check_loop_difference_type (cfd->difference_type); + cilk_set_incr_info (cfd, true); +} + +/* Entry function to gimplify a CILK_FOR_STMT, *FOR_P. *PRE_P and *POST_P are + preceeding and proceeding gimple sequences of *FOR_P, respectively. */ + +int +cp_gimplify_cilk_for (tree *for_p, gimple_seq *pre_p, + gimple_seq *post_p ATTRIBUTE_UNUSED) +{ + struct cilk_for_desc cfd; + + cfun->is_cilk_function = 1; + cilk_init_cfd (&cfd); + + cp_extract_cilk_for_fields (&cfd, *for_p); + if (cfd.invalid) + { + *for_p = build_empty_stmt (cfd.loc); + return GS_ERROR; + } + cfd.nested_ok = !DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (current_function_decl); + gimplify_cilk_for_1 (cfd, pre_p); + *for_p = NULL_TREE; + + return GS_ALL_DONE; +} + diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index c464719..b40e9a6 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -269,6 +269,23 @@ genericize_cp_loop (tree *stmt_p, location_t start_locus, tree cond, tree body, *stmt_p = stmt_list; } +/* Genericize a CILK_FOR_STMT node *STMT_P. */ + +static void +genericize_cilk_for_stmt (tree *stmt_p, int *walk_subtrees, void *data) +{ + tree stmt = *stmt_p; + cp_walk_tree (&CILK_FOR_COND (stmt), cp_genericize_r, data, NULL); + cp_walk_tree (&CILK_FOR_INIT (stmt), cp_genericize_r, data, NULL); + cp_walk_tree (&CILK_FOR_GRAIN (stmt), cp_genericize_r, data, NULL); + cp_walk_tree (&CILK_FOR_VAR (stmt), cp_genericize_r, data, NULL); + cp_walk_tree (&CILK_FOR_EXPR (stmt), cp_genericize_r, data, NULL); + + /* _Cilk_for body will be resolved after it is inserted into a nested + function. */ + *walk_subtrees = 0; +} + /* Genericize a FOR_STMT node *STMT_P. */ static void @@ -1121,6 +1138,8 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) gcc_assert (!CONVERT_EXPR_VBASE_PATH (stmt)); else if (TREE_CODE (stmt) == FOR_STMT) genericize_for_stmt (stmt_p, walk_subtrees, data); + else if (TREE_CODE (stmt) == CILK_FOR_STMT) + genericize_cilk_for_stmt (stmt_p, walk_subtrees, data); else if (TREE_CODE (stmt) == WHILE_STMT) genericize_while_stmt (stmt_p, walk_subtrees, data); else if (TREE_CODE (stmt) == DO_STMT) diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h index 77a66c3..baf3ee3 100644 --- a/gcc/cp/cp-objcp-common.h +++ b/gcc/cp/cp-objcp-common.h @@ -164,4 +164,7 @@ extern void cp_common_init_ts (void); #undef LANG_HOOKS_CILKPLUS_FRAME_CLEANUP #define LANG_HOOKS_CILKPLUS_FRAME_CLEANUP cp_cilk_install_body_wframe_cleanup +#undef LANG_HOOKS_CILKPLUS_GIMPLIFY_CILK_FOR +#define LANG_HOOKS_CILKPLUS_GIMPLIFY_CILK_FOR cp_gimplify_cilk_for + #endif /* GCC_CP_OBJCP_COMMON */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 351158e..ee045b8 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5686,6 +5686,10 @@ extern void finish_for_init_stmt (tree); extern void finish_for_cond (tree, tree, bool); extern void finish_for_expr (tree, tree); extern void finish_for_stmt (tree); +extern tree begin_cilk_for_stmt (tree, tree); +extern void finish_cilk_for_init_stmt (tree); +extern tree finish_cilk_for_stmt (tree); +extern tree finish_cilk_for_cond (tree); extern tree begin_range_for_stmt (tree, tree); extern void finish_range_for_decl (tree, tree, tree); extern void finish_range_for_stmt (tree); @@ -6192,6 +6196,8 @@ extern int gimplify_cilk_spawn (tree *, gimple_seq *, /* In cp/cp-cilk.c */ extern void cp_cilk_install_body_wframe_cleanup (tree, tree); extern tree cilk_create_lambda_fn_tmp_var (tree); +extern int cp_gimplify_cilk_for (tree *, gimple_seq *, + gimple_seq *); /* -- end of C++ */ #endif /* ! GCC_CP_TREE_H */ diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index ced596e..ae03c56 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -1542,6 +1542,7 @@ begin_scope (scope_kind kind, tree entity) case sk_try: case sk_catch: case sk_for: + case sk_cilk_for: case sk_cond: case sk_class: case sk_scoped_enum: diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 57641a1..66d1876 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -107,6 +107,8 @@ typedef enum scope_kind { sk_catch, /* A catch-block. */ sk_for, /* The scope of the variable declared in a for-init-statement. */ + sk_cilk_for, /* The scope of the variable declared in _Cilk_for init + statement. */ sk_cond, /* The scope of the variable declared in the condition of an if or switch statement. */ sk_function_parms, /* The scope containing function parameters. */ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 29be9a8..0b5621d 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -235,6 +235,10 @@ static tree cp_literal_operator_id static void cp_parser_cilk_simd (cp_parser *, cp_token *); +static tree cp_parser_cilk_for + (cp_parser *, tree); +static void cp_parser_cilk_grainsize + (cp_parser *, cp_token *); static bool cp_parser_omp_declare_reduction_exprs (tree, cp_parser *); @@ -2060,7 +2064,8 @@ static tree cp_parser_decltype /* Declarators [gram.dcl.decl] */ static tree cp_parser_init_declarator - (cp_parser *, cp_decl_specifier_seq *, vec *, bool, bool, int, bool *, tree *); + (cp_parser *, cp_decl_specifier_seq *, vec *, + bool, bool, int, bool *, tree *, tree *); static cp_declarator *cp_parser_declarator (cp_parser *, cp_parser_declarator_kind, int *, bool *, bool); static cp_declarator *cp_parser_direct_declarator @@ -9350,6 +9355,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, case RID_WHILE: case RID_DO: + case RID_CILK_FOR: case RID_FOR: statement = cp_parser_iteration_statement (parser, false); break; @@ -10505,6 +10511,17 @@ cp_parser_iteration_statement (cp_parser* parser, bool ivdep) } break; + case RID_CILK_FOR: + if (!flag_enable_cilkplus) + { + error_at (token->location, + "-fcilkplus must be enabled t use %<_Cilk_for%>"); + statement = error_mark_node; + } + else + statement = cp_parser_cilk_for (parser, NULL_TREE); + break; + default: cp_parser_error (parser, "expected iteration-statement"); statement = error_mark_node; @@ -10624,9 +10641,15 @@ cp_parser_jump_statement (cp_parser* parser) case IN_OMP_FOR: error_at (token->location, "break statement used with OpenMP for loop"); break; + case IN_CILK_SIMD_FOR: error_at (token->location, "break statement used with Cilk Plus for loop"); break; + + case IN_CILK_FOR_STMT: + error_at (token->location, + "break statement used in _Cilk_for loop body"); + break; } cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); break; @@ -10642,6 +10665,7 @@ cp_parser_jump_statement (cp_parser* parser) "continue statement within %<#pragma simd%> loop body"); /* Fall through. */ case IN_ITERATION_STMT: + case IN_CILK_FOR_STMT: case IN_OMP_FOR: statement = finish_continue_stmt (); break; @@ -11188,7 +11212,7 @@ cp_parser_simple_declaration (cp_parser* parser, /*member_p=*/false, declares_class_or_enum, &function_definition_p, - maybe_range_for_decl); + maybe_range_for_decl, NULL); /* If an error occurred while parsing tentatively, exit quickly. (That usually happens when in the body of a function; each statement is treated as a declaration-statement until proven @@ -16439,7 +16463,8 @@ cp_parser_init_declarator (cp_parser* parser, bool member_p, int declares_class_or_enum, bool* function_definition_p, - tree* maybe_range_for_decl) + tree* maybe_range_for_decl, + tree* init) { cp_token *token = NULL, *asm_spec_start_token = NULL, *attributes_start_token = NULL; @@ -16447,7 +16472,9 @@ cp_parser_init_declarator (cp_parser* parser, tree prefix_attributes; tree attributes = NULL; tree asm_specification; - tree initializer; + /* Initialize initalizer to remove a "using potentially unset variable" + warning/error. */ + tree initializer = NULL_TREE; tree decl = NULL_TREE; tree scope; int is_initialized; @@ -16584,7 +16611,8 @@ cp_parser_init_declarator (cp_parser* parser, DECL_STRUCT_FUNCTION (decl)->function_start_locus = func_brace_location; } - + if (init) + *init = initializer; return decl; } } @@ -16819,6 +16847,8 @@ cp_parser_init_declarator (cp_parser* parser, finish_fully_implicit_template (parser, /*member_decl_opt=*/0); } + if (init) + *init = initializer; return decl; } @@ -22984,6 +23014,7 @@ cp_parser_single_declaration (cp_parser* parser, member_p, declares_class_or_enum, &function_definition_p, + NULL, NULL); /* 7.1.1-1 [dcl.stc] @@ -31253,6 +31284,21 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) cp_parser_cilk_simd (parser, pragma_tok); return true; + case PRAGMA_CILK_GRAINSIZE: + if (context == pragma_external) + { + error_at (pragma_tok->location, + "%<#pragma cilk grainsize%> may only be be used inside a " + "function"); + break; + } + + /* Ignore the pragma if Cilk Plus is not enabled. */ + if (flag_enable_cilkplus) + { + cp_parser_cilk_grainsize (parser, pragma_tok); + return true; + } default: gcc_assert (id >= PRAGMA_FIRST_EXTERNAL); c_invoke_pragma_handler (id); @@ -31569,6 +31615,213 @@ cp_parser_cilk_simd (cp_parser *parser, cp_token *pragma_token) return; } +static tree +cp_parser_cilk_for_init_statement (cp_parser *parser, tree *init) +{ + cp_token *token = cp_lexer_peek_token (parser->lexer); + location_t loc = token->location; + tree decl_init = NULL_TREE; + if (token->type == CPP_SEMICOLON) + { + error_at (loc, "expected induction variable"); + return error_mark_node; + } + + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_STATIC) + || cp_lexer_next_token_is_keyword (parser->lexer, RID_REGISTER) + || cp_lexer_next_token_is_keyword (parser->lexer, RID_EXTERN) + || cp_lexer_next_token_is_keyword (parser->lexer, RID_MUTABLE) + || cp_lexer_next_token_is_keyword (parser->lexer, RID_THREAD)) + { + error_at (loc, "storage class is not allowed"); + cp_lexer_consume_token (parser->lexer); + } + + if (token->type == CPP_NAME) + { + tree type = cp_parser_lookup_name_simple (parser, token->u.value, loc); + if (TREE_CODE (type) == VAR_DECL || TREE_CODE (type) == PARM_DECL) + { + error_at (loc, "_Cilk_for loop initializer must declare variable"); + cp_parser_skip_to_end_of_statement (parser); + return error_mark_node; + } + } + int flags = 0; + cp_decl_specifier_seq specs; + cp_parser_decl_specifier_seq (parser, CP_PARSER_FLAGS_NONE, &specs, &flags); + tree decl = cp_parser_init_declarator (parser, &specs, NULL, false, false, + flags, NULL, NULL, &decl_init); + /* Sometimes if the initial is constant, it won't save in DECL_INITIAL, + and thus we need to get the initial value. Now, if it saved the + DECL_INITIAL value, then just use it since it will have all the + necessary type casting. */ + if (DECL_INITIAL (decl)) + decl_init = DECL_INITIAL (decl); + + + if (processing_template_decl) + add_stmt (decl_init); + else + *init = decl_init; + parser->scope = NULL_TREE; + parser->qualifying_scope = NULL_TREE; + parser->object_scope = NULL_TREE; + + if (decl == error_mark_node || DECL_INITIAL (decl) == error_mark_node + || TREE_TYPE (decl) == error_mark_node) + { + cp_parser_skip_to_end_of_statement (parser); + gcc_assert (errorcount || sorrycount); + return error_mark_node; + } + return decl; +} + +static void +cp_parser_cilk_grainsize (cp_parser *parser, cp_token *pragma_tok) +{ + if (cp_parser_require (parser, CPP_EQ, RT_EQ)) + { + tree exp = cp_parser_binary_expression (parser, false, false, + PREC_NOT_OPERATOR, NULL); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + if (!exp || exp == error_mark_node) + { + error_at (pragma_tok->location, "invalid grainsize for _Cilk_for"); + return; + } + cp_token *n_tok = cp_lexer_peek_token (parser->lexer); + + /* Make sure the next token is _Cilk_for, it is invalid otherwise. */ + if (n_tok && n_tok->type == CPP_KEYWORD && n_tok->keyword == RID_CILK_FOR) + { + cp_lexer_consume_token (parser->lexer); + tree cfor = cp_parser_cilk_for (parser, exp); + if (cfor && STATEMENT_CODE_P (TREE_CODE (cfor))) + SET_EXPR_LOCATION (cfor, n_tok->location); + } + else + warning (0, "%<#pragma cilk grainsize%> is not followed by " + "%<_Cilk_for%>"); + return; + } + cp_parser_skip_to_pragma_eol (parser, pragma_tok); +} + +/* Top-level function to parse _Cilk_for and the for statement + following <#pragma simd>. */ + +static tree +cp_parser_cilk_for (cp_parser *parser, tree grain) +{ + bool valid = true; + tree cond = NULL_TREE; + tree incr_expr = NULL_TREE; + tree init = NULL_TREE; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + tree scope = begin_for_scope (&init); + tree statement = begin_cilk_for_stmt (scope, init); + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + { + cp_parser_skip_to_end_of_statement (parser); + return error_mark_node; + } + + /* Parse initialization. */ + tree decl = cp_parser_cilk_for_init_statement (parser, &init); + + if (decl == error_mark_node) + valid = false; + else if (!decl || (TREE_CODE (decl) != VAR_DECL + && TREE_CODE (decl) != DECL_EXPR)) + { + error_at (loc, "_Cilk_for loop initializer does not declare a variable"); + valid = false; + decl = error_mark_node; + } + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + { + error_at (loc, "_Cilk_for loop initializer cannot have multiple variable" + " declarations"); + cp_parser_skip_to_end_of_statement (parser); + valid = false; + } + + if (!valid) + /* Skip to the semicolon ending the init. */ + cp_parser_skip_to_end_of_statement (parser); + else + { + CILK_FOR_INIT (statement) = init; + CILK_FOR_VAR (statement) = decl; + finish_cilk_for_init_stmt (statement); + } + + /* Parse condition. */ + if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) + return error_mark_node; + if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + { + error_at (loc, "missing condition"); + cond = error_mark_node; + } + else + { + cond = cp_parser_condition (parser); + cond = finish_cilk_for_cond (cond); + CILK_FOR_COND (statement) = cond; + } + + if (cond == error_mark_node) + valid = false; + cp_parser_consume_semicolon_at_end_of_statement (parser); + + /* Parse increment. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)) + { + error_at (loc, "missing increment"); + incr_expr = error_mark_node; + } + else + incr_expr = cp_parser_expression (parser, false, NULL); + if (TREE_CODE (incr_expr) == ERROR_MARK) + { + cp_parser_skip_to_closing_parenthesis (parser, true, false, false); + valid = false; + } + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + { + cp_parser_skip_to_end_of_statement (parser); + valid = false; + } + + if (!valid) + { + gcc_assert (sorrycount || errorcount); + return error_mark_node; + } + + finish_for_expr (incr_expr, statement); + CILK_FOR_EXPR (statement) = incr_expr; + int saved_in_statement = parser->in_statement; + parser->in_statement = IN_CILK_FOR_STMT; + cp_parser_already_scoped_statement (parser); + parser->in_statement = saved_in_statement; + + CILK_FOR_GRAIN (statement) = grain; + statement = finish_cilk_for_stmt (statement); + + /* Check if the body satisfies all the requirement of _Cilk_for. + If invalid, then just return error_mark_node. */ + if (statement == error_mark_node + || !cpp_validate_cilk_plus_loop (CILK_FOR_BODY (statement))) + return error_mark_node; + return statement; +} + /* Create an identifier for a generic parameter type (a synthesized template parameter implied by `auto' or a concept identifier). */ diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index e26e350..8d1ce44 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -302,6 +302,8 @@ typedef struct GTY(()) cp_parser { #define IN_IF_STMT 16 #define IN_CILK_SIMD_FOR 32 #define IN_CILK_SPAWN 64 +#define IN_CILK_FOR_STMT 128 + unsigned char in_statement; /* TRUE if we are presently parsing the body of a switch statement. diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 1b34434..302163f 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13335,6 +13335,45 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, finish_for_stmt (stmt); break; + case CILK_FOR_STMT: + { + stmt = begin_cilk_for_stmt (NULL_TREE, NULL_TREE); + CILK_FOR_INIT (stmt) = RECUR (CILK_FOR_INIT (t)); + finish_cilk_for_init_stmt (stmt); + tmp = RECUR (CILK_FOR_VAR (t)); + CILK_FOR_VAR (stmt) = tmp; + CILK_FOR_GRAIN (stmt) = CILK_FOR_GRAIN (t); + + tmp = CILK_FOR_COND (t); + if (COMPARISON_CLASS_P (tmp)) + { + tree op0 = RECUR (TREE_OPERAND (tmp, 0)); + tree op1 = RECUR (TREE_OPERAND (tmp, 1)); + tmp = build2 (TREE_CODE (tmp), boolean_type_node, op0, op1); + } + CILK_FOR_COND (stmt) = tmp; + + tmp = CILK_FOR_EXPR (t); + if (TREE_CODE (tmp) == MODIFY_EXPR) + { + tree lhs = TREE_OPERAND (tmp, 0); + tree rhs = TREE_OPERAND (tmp, 1); + lhs = RECUR (lhs); + rhs = build2 (TREE_CODE (rhs), TREE_TYPE (lhs), + RECUR (TREE_OPERAND (rhs, 0)), + RECUR (TREE_OPERAND (rhs, 1))); + tmp = build2 (MODIFY_EXPR, void_type_node, lhs, rhs); + } + else + tmp = build2 (TREE_CODE (tmp), void_type_node, + RECUR (TREE_OPERAND (tmp, 0)), + RECUR (TREE_OPERAND (tmp, 1))); + finish_for_expr (tmp, stmt); + RECUR (CILK_FOR_BODY (t)); + stmt = finish_cilk_for_stmt (stmt); + CILK_FOR_GRAIN (stmt) = RECUR (CILK_FOR_GRAIN (t)); + break; + } case RANGE_FOR_STMT: { tree decl, expr; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 5d68250..23565ae 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -826,7 +826,8 @@ finish_return_stmt (tree expr) return r; } -/* Begin the scope of a for-statement or a range-for-statement. +/* Begin the scope of a for-statement _Cilk_for statement + or a range-for-statement. Both the returned trees are to be used in a call to begin_for_stmt or begin_range_for_stmt. */ @@ -899,7 +900,7 @@ finish_for_cond (tree cond, tree for_stmt, bool ivdep) } /* Finish the increment-EXPRESSION in a for-statement, which may be - given by FOR_STMT. */ + given by FOR_STMT or CILK_FOR_STMT. */ void finish_for_expr (tree expr, tree for_stmt) @@ -926,7 +927,10 @@ finish_for_expr (tree expr, tree for_stmt) expr = maybe_cleanup_point_expr_void (expr); if (check_for_bare_parameter_packs (expr)) expr = error_mark_node; - FOR_EXPR (for_stmt) = expr; + if (TREE_CODE (for_stmt) == CILK_FOR_STMT) + CILK_FOR_EXPR (for_stmt) = expr; + else + FOR_EXPR (for_stmt) = expr; } /* Finish the body of a for-statement, which may be given by @@ -6663,6 +6667,18 @@ finish_omp_cancellation_point (tree clauses) finish_expr_stmt (stmt); } + +/* Perform any canonicalization of the conditional in a Cilk for loop. */ +tree +finish_cilk_for_cond (tree cond) +{ + if (!processing_template_decl) + return cp_truthvalue_conversion (cond); + else + return cond; +} + + /* Begin a __transaction_atomic or __transaction_relaxed statement. If PCOMPOUND is non-null, this is for a function-transaction-block, and we should create an extra compound stmt. */ @@ -10615,4 +10631,51 @@ capture_decltype (tree decl) return type; } +/* Begin a _Cilk_for-statement. Returns a new FOR_STMT. + SCOPE and INIT should be the return of begin_for_scope, + or both NULL_TREE */ + +tree +begin_cilk_for_stmt (tree scope, tree init) +{ + tree cilk_for_stmt = build_stmt (input_location, CILK_FOR_STMT, NULL_TREE, + NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE, + NULL_TREE, NULL_TREE); + if (scope == NULL_TREE) + { + if (!init) + scope = begin_for_scope (&init); + } + CILK_FOR_INIT (cilk_for_stmt) = init; + CILK_FOR_SCOPE (cilk_for_stmt) = scope; + return cilk_for_stmt; +} + +/* Finish the for-init-statement of a for-statement, which may be given + by C_FOR_STMT. */ + +void +finish_cilk_for_init_stmt (tree c_for_stmt) +{ + if (processing_template_decl) + CILK_FOR_INIT (c_for_stmt) = pop_stmt_list (CILK_FOR_INIT (c_for_stmt)); + CILK_FOR_BODY (c_for_stmt) = do_pushlevel (sk_block); +} + +/* Finish the body of a for-statement, which may be given by FOR_STMT. + Returns a CILK_FOR_STMT that is type checked. */ + +tree +finish_cilk_for_stmt (tree cilk_for_stmt) +{ + CILK_FOR_BODY (cilk_for_stmt) = do_poplevel (CILK_FOR_BODY (cilk_for_stmt)); + tree *scope_ptr = &CILK_FOR_SCOPE (cilk_for_stmt); + tree scope = *scope_ptr; + *scope_ptr = NULL; + add_stmt (do_poplevel (scope)); + cp_finish_cilk_for_loop (&cilk_for_stmt, processing_template_decl); + add_stmt (cilk_for_stmt); + return cilk_for_stmt; +} + #include "gt-cp-semantics.h" diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/cilk-for-start-at-5.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk-for-start-at-5.cc new file mode 100644 index 0000000..dec650c --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk-for-start-at-5.cc @@ -0,0 +1,42 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + + + + +int j[10]; + +int main(void) +{ + int error = 0; + int j_serial[10]; + for (int ii = 0; ii < 10; ii++) + { + j[ii] = 10; + j_serial[ii] = 10; + } + _Cilk_for (int ii = 5; ii < 10; ii++) + { + j[ii]=ii; + } + + for (int ii = 5; ii < 10; ii++) + { + j_serial[ii] = ii; + } + + for (int ii = 0; ii < 10; ii++) + { + if (j[ii] != j_serial[ii]) + error = 1; + } + + if (error) + __builtin_abort (); + else + return 0; + + return j[9]; +} + diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/cilk-for-tplt.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk-for-tplt.cc new file mode 100644 index 0000000..8221371 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk-for-tplt.cc @@ -0,0 +1,25 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + +#define SIZE 100 +#define CHECK_VALUE 5 + +template +int func (T start, T end) +{ + int Array[SIZE]; + _Cilk_for (T ii = 0; ii < end; ii++) + Array[ii] = CHECK_VALUE; + + for (T ii = 0; ii < end; ii++) + if (Array[ii] != CHECK_VALUE) + __builtin_abort (); + + return 0; +} + +int main (void) +{ + return func (0, 100) + func (0, 100); +} diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/cilk-for.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk-for.cc new file mode 100644 index 0000000..30ea29d --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk-for.cc @@ -0,0 +1,34 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + +int main(int argc, char **argv) +{ + char Array1[26], Array2[26]; + char Array1_Serial[26], Array2_Serial[26]; + + for (int ii = 0; ii < 26; ii++) + { + Array1[ii] = 'A'+ii; + Array1_Serial[ii] = 'A'+ii; + } + for (int ii = 0; ii < 26; ii++) + { + Array2[ii] = 'a'+ii; + Array2_Serial[ii] = 'a'+ii; + } + + _Cilk_for (int ii = 0 ; ii < 26; ii++) + Array1[ii] = Array2[ii]; + + for (int ii = 0; ii < 26; ii++) + Array1_Serial[ii] = Array2_Serial[ii]; + + for (int ii = 0; ii < 26; ii++) { + if (Array1_Serial[ii] != Array1[ii]) { + __builtin_abort (); + } + } + + return 0; +} diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_cont_inside_for.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_cont_inside_for.cc new file mode 100644 index 0000000..3759a36 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_cont_inside_for.cc @@ -0,0 +1,22 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + +int q[10], seq[10]; +int main (int argc, char** argv) +{ + + int max = 10, start = 0; + _Cilk_for(int ii=max - 1; ii>=start; ii--) + { + for (int jj = 0; jj < 10; jj++) + { + if (seq[jj] == 5) + continue; + else + seq[jj] = 2; + } + } + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_cont_with_for.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_cont_with_for.cc new file mode 100644 index 0000000..38c4d51 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_cont_with_for.cc @@ -0,0 +1,19 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + + +int q[10], seq2[10]; +int main (int argc, char** argv) +{ + + int max = 10, start = 0; + _Cilk_for(int ii=max - 1; ii>=start; ii--) + { + for (int jj = 0; jj < 10; jj++) + seq2[jj] = 5; + continue; + } + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_cont_with_if.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_cont_with_if.cc new file mode 100644 index 0000000..e68c700 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_cont_with_if.cc @@ -0,0 +1,18 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + + +int q[10], seq2[10]; +int main (int argc, char** argv) +{ + + int max = 10, start = 0; + _Cilk_for(int ii = max - 1; ii >= start; ii--) + { + if (q[ii] != 0) + continue; + } + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_cont_with_while.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_cont_with_while.cc new file mode 100644 index 0000000..17fd064 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_cont_with_while.cc @@ -0,0 +1,23 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + + +int q[10], seq2[10]; +int main (int argc, char** argv) +{ + + int max = 10, start = 0; + _Cilk_for(int ii=max - 1; ii>=start; ii--) + { + int jj = 0; + while (jj < 10) + { + seq2[jj] = 1; + jj++; + } + continue; + } + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_genricize_test.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_genricize_test.cc new file mode 100644 index 0000000..f0ad2a3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_genricize_test.cc @@ -0,0 +1,42 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + + +#include +#include +#include +#include +#include +#if HAVE_IO +#include +#endif +#define NUMBER 500 +#include +typedef std::pair my_type_t; + +long +valid_pairs(std::vector< my_type_t > my_list) +{ + _Cilk_for (int ii = 0; ii < my_list.size(); ii++) + { +#if HAVE_IO + fprintf(stderr, "my_list index: %d, size: %zu.\n", ii, my_list.size()); +#endif + if (ii < 0 || ii >= my_list.size()) + abort (); + } + return 0; +} + +int main(int argc, char **argv) +{ + std::vector my_list; + + for (int ii = 0; ii < NUMBER; ii++) + my_list.push_back(my_type_t(ii, ii)); + long res = valid_pairs(my_list); + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_grainsize.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_grainsize.cc new file mode 100644 index 0000000..7d54828 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_grainsize.cc @@ -0,0 +1,77 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + +int x = 5; +int q = 25; +int z = 2; + +int square (int b) +{ + return (b*b); +} + +template +int templated_func (T a, T b, T c) +{ + T Array[10]; +#pragma cilk grainsize = a + _Cilk_for (int ii = 0; ii < 10; ii++) + Array[ii] = a; + + for (int ii = 0; ii < 10; ii++) + if (Array[ii] != a) + __builtin_abort (); + +#pragma cilk grainsize = square ((int) (b/c)) + _Cilk_for (int ii = 0; ii < 10; ii++) + Array[ii] = b; + + for (int ii = 0; ii < 10; ii++) + if (Array[ii] != b) + __builtin_abort (); + +#pragma cilk grainsize = 2 + _Cilk_for (int ii = 0; ii < 10; ii++) + Array[ii] = c; + + for (int ii = 0; ii < 10; ii++) + if (Array[ii] != c) + __builtin_abort (); + + return 0; +} + + + +int main (void) +{ + int Array[10]; +#pragma cilk grainsize = 5 + _Cilk_for (int ii = 0; ii < 10; ii++) + Array[ii] = 5; + + for (int ii = 0; ii < 10; ii++) + if (Array[ii] != 5) + __builtin_abort (); + + +#pragma cilk grainsize = x + _Cilk_for (int ii = 0; ii < 10; ii++) + Array[ii] = 10; + + for (int ii = 0; ii < 10; ii++) + if (Array[ii] != 10) + __builtin_abort (); + +#pragma cilk grainsize = square (z) + _Cilk_for (int ii = 0; ii < 10; ii++) + Array[ii] = 15; + + for (int ii = 0; ii < 10; ii++) + if (Array[ii] != 15) + __builtin_abort (); + + int r = 5, s=10, t =15; + return templated_func (r, s, t); +} diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_p_errors.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_p_errors.cc new file mode 100644 index 0000000..4c69712 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_p_errors.cc @@ -0,0 +1,52 @@ +/* { dg-options "-fcilkplus -Wunknown-pragmas" } */ + +int main (void) +{ + int a, iii = 0; + _Cilk_for (; iii < 10; iii++) /* { dg-error "expected induction variable" } */ + a = 5; + + _Cilk_for (iii = 0; iii < 10; iii++) /* { dg-error " must declare variable" } */ + a = 5; + + _Cilk_for (int qq = 0, jj = 0; qq < 10; qq++) /* { dg-error " initializer cannot have multiple variable declarations" } */ + a = 5; + + _Cilk_for (int ii = 0, int jj = 0; ii < 10; ii++) /* { dg-error " initializer cannot have multiple variable declarations" } */ + a = 5; + + _Cilk_for (int rr = 0; ; rr++) /* { dg-error "missing condition" } */ + a = 5; + + _Cilk_for (int ii = 0; ii = 5; ii++) /* { dg-error "invalid controlling predicate" } */ + a = 5; + + _Cilk_for (int ii = 0; ii == 5; ii++) /* { dg-error "invalid controlling predicate" } */ + a = 5; + + _Cilk_for (int ii = 0; ii < 10;) /* { dg-error "missing increment" } */ + a = 5; + + _Cilk_for (int ii = 0; ii < 10; ii ) /* { dg-error "invalid increment expression" } */ + a = 5; + + _Cilk_for (int ii = 0; ii < 10; ii++) + { + a = 5; + if (ii == 5) + break; /* { dg-error "break statement used in _Cilk_for loop body" } */ + } + +#pragma cilk grainsize 5 /* { dg-error "expected '=' before numeric constant" } */ + _Cilk_for (int ii = 0; ii < 10; ii++) + a = 5; + +#pragma Silk grainsize = 5 /* { dg-warning "ignoring #pragma Silk grainsize" } */ + _Cilk_for (int ii = 0; ii < 10; ii++) + a = 5; +#pragma cilk grainsiz = 5 /* { dg-warning "ignoring #pragma cilk grainsiz" } */ + _Cilk_for (int ii = 0; ii < 10; ii++) + a = 5; + + return 0; +} diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_t_errors.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_t_errors.cc new file mode 100644 index 0000000..b597764 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/CK/cilk_for_t_errors.cc @@ -0,0 +1,30 @@ +/* { dg-options "-fcilkplus" } */ + +#include +int main (void) +{ + int a, iii = 0; + + _Cilk_for (volatile int ii = 0; ii < 10; ii++) /* { dg-error "iteration variable cannot be volatile" } */ + a = 5; + + _Cilk_for (static int ii = 0; ii < 10; ii++) /* { dg-error "storage class is not allowed" } */ + a = 5; + _Cilk_for (register int ii = 0; ii < 10; ii++) /* { dg-error "storage class is not allowed" } */ + a = 5; + + _Cilk_for (extern int ii = 0; ii < 10; ii++) /* { dg-error "storage class is not allowed" } */ + a = 5; + + _Cilk_for (float ii = 0.0; ii < 10.0; ii += 0.5) /* { dg-error "induction variable must be of integral record or pointer type" } */ + a = 5; + + jmp_buf env; + _Cilk_for (int ii = 0; ii < 10; ii++) + { + a = 5; + setjmp (env); /* { dg-error "calls to setjmp are not allowed within" } */ + } + + return 0; +} diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/explicit_ctor.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/explicit_ctor.cc new file mode 100644 index 0000000..89f6403 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/CK/explicit_ctor.cc @@ -0,0 +1,27 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + + + +struct BruceBoxleitner { + int m; + BruceBoxleitner (int n = 0) : m(n) { } + BruceBoxleitner operator--() { --m; return *this; } +}; + +int operator- (BruceBoxleitner a, BruceBoxleitner b) { return a.m - b.m; } + +struct BruceLee { + int m; + explicit BruceLee (int n) : m(n) { } +}; + +bool operator> (BruceBoxleitner a, BruceLee b) { return a.m > b.m; } +int operator- (BruceBoxleitner a, BruceLee b) { return a.m - b.m; } + +int main () { + _Cilk_for (BruceBoxleitner i = 10; i > BruceLee(0); --i) + ; + return 0; +} diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/label_test.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/label_test.cc new file mode 100644 index 0000000..495e9b4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/CK/label_test.cc @@ -0,0 +1,26 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + + +int main(void) +{ + int jj = 0; + int total = 0; + + _Cilk_for (int ii = 0; ii < 10; ii++) + { + if ((ii % 2) == 0) + goto hello_label; + else + goto world_label; + +hello_label: + total++; +world_label: + total++; + } + if (total != 15) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/no-opp-overload-error.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/no-opp-overload-error.cc new file mode 100644 index 0000000..582ef60 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/CK/no-opp-overload-error.cc @@ -0,0 +1,88 @@ +/* { dg-options "-fcilkplus" } */ + + +#define NUMBER_OF_ELEMENTS 10 + +#include + +class my_class { +private: + int value; +public: + + my_class (); + my_class (const my_class &val); + my_class (my_class &val); + my_class (int val); + ~my_class (); + int getValue(); + my_class &operator= (my_class &new_value); + my_class &operator= (int x); + my_class &operator+= (int val) + { + value += val; + return *this; + } + bool operator< (const my_class &val) + { + return (value < val.value); + } +}; + + +my_class::my_class () +{ + value = 0; +} + +my_class::my_class(int val) +{ + value = val; +} + +my_class::my_class (my_class &val) +{ + value = val.value; +} + +my_class::my_class (const my_class &val) +{ + value = val.value; +} + +my_class::~my_class () +{ + value = -1; +} + +int my_class::getValue () +{ + return value; +} + +my_class & my_class::operator= (my_class &new_value) +{ + value = new_value.value; + return *this; +} + +my_class &my_class::operator= (int x) +{ + value = x; + return *this; +} + +int main (void) +{ + int n, *array_parallel; + my_class length (NUMBER_OF_ELEMENTS); + n = NUMBER_OF_ELEMENTS; + + array_parallel = new int[NUMBER_OF_ELEMENTS]; + _Cilk_for (my_class ii (0); ii < length; ii += 1) { /* { dg-error " No operator-" } */ + int x = ii.getValue(); + array_parallel [x] = x * 2; + } + + return 0; +} diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/plus-equal-one.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/plus-equal-one.cc new file mode 100644 index 0000000..1326308 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/CK/plus-equal-one.cc @@ -0,0 +1,59 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + + +#if HAVE_IO +#include +#endif +#define TEST 1 + + +#define ITER 300 + +int n_errors; +#if TEST +void test (int *array, int n, int val) { +#if HAVE_IO + for (int i = 0; i < n; i++) + std::printf("array[%3d] = %2d\n", i, array[i]); +#endif + for (int i = 0; i < n; ++i) { + if (array[i] != val) { + __builtin_abort (); + } + } +} +#endif + + +int main () { + int array[ITER]; + + for (int ii = 0; ii < ITER; ii++) + array[ii] = 9; + _Cilk_for (int *j = (array); j < array + ITER; j += 1) { + *j = 6; + } +#if TEST + test(array, ITER, 6); +#endif + + _Cilk_for (int *i = array; i < array + ITER; i += 1) { + *i = 1; + } + +#if TEST + test(array, ITER, 1); +#endif + + _Cilk_for (int *k = array+ITER-1; k >= array; k -= 1) { + *k = 8; + } +#if TEST + test(array, ITER, 8); +#endif + + return 0; + +} diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/plus-equal-test.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/plus-equal-test.cc new file mode 100644 index 0000000..0ca588d --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/CK/plus-equal-test.cc @@ -0,0 +1,111 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + + +#define NUMBER_OF_ELEMENTS 10 + +#include + +#if HAVE_IO +#include +#endif + +class my_class { +private: + int value; +public: + + my_class (); + my_class (const my_class &val); + my_class (my_class &val); + my_class (int val); + ~my_class (); + int getValue(); + my_class &operator= (my_class &new_value); + my_class &operator+= (int val) + { + value += val; + return *this; + } + bool operator< (const my_class &val) + { + return (value < val.value); + } +}; + + +my_class::my_class () +{ + value = 0; +} + +my_class::my_class(int val) +{ + value = val; +} + +my_class::my_class (my_class &val) +{ + value = val.value; +} + +my_class::my_class (const my_class &val) +{ + value = val.value; +} + +my_class::~my_class () +{ + value = -1; +} + +int my_class::getValue () +{ + return value; +} + +my_class & my_class::operator= (my_class &new_value) +{ + value = new_value.value; + return *this; +} + +int operator- (my_class x, my_class y) +{ + int val_x = x.getValue (); + int val_y = y.getValue (); + return (val_x - val_y); +} + + +int main (void) +{ + int n, *array_parallel, *array_serial; + my_class length (NUMBER_OF_ELEMENTS); + n = NUMBER_OF_ELEMENTS; + + array_parallel = new int[NUMBER_OF_ELEMENTS]; + array_serial = new int[NUMBER_OF_ELEMENTS]; + + _Cilk_for (my_class ii (0); ii < length; ii += 1) { +#if HAVE_IO + std::printf("ii.getValue() = %d\n", ii.getValue ()); +#endif + array_parallel [ii.getValue ()] = ii.getValue() * 2; + } + + for (my_class ii (0); ii < length; ii += 1) + array_serial [ii.getValue ()] = ii.getValue () * 2; + + for (int ii = 0; ii < NUMBER_OF_ELEMENTS; ii++) + if (array_serial[ii] != array_parallel[ii]) { +#if HAVE_IO + std::printf("array_serial[%3d] = %6d\tarray_parallel[%3d] = %6d\n", ii, + array_serial[ii], ii, array_parallel[ii]); +#endif + __builtin_abort (); + } + + return 0; +} diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/stl_iter.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/stl_iter.cc new file mode 100644 index 0000000..e4f2ee5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/CK/stl_iter.cc @@ -0,0 +1,58 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + + + + +#include +#include +#include +#include + +using namespace std; + +int main(void) +{ +vector array; +vector array_serial; + +#if 1 +for (int ii = -1; ii < 10; ii++) +{ + array.push_back(ii); + array_serial.push_back (ii); +} +#endif +#if 1 +_Cilk_for (vector::iterator iter = array.begin(); iter != array.end(); + iter++) +{ + if (*iter == 6) + *iter = 13; +} +#endif +for (vector::iterator iter2 = array_serial.begin(); + iter2 != array_serial.end(); iter2++) +{ + if (*iter2 == 6) + *iter2 = 13; +} +sort (array.begin(), array.end()); +sort (array_serial.begin(), array_serial.end()); + +vector ::iterator iter3 = array.begin (); +vector ::iterator iter_serial = array_serial.begin (); + +while (iter3 != array.end () && iter_serial != array_serial.end ()) +{ + if (*iter3 != *iter_serial) + abort (); + iter3++; + iter_serial++; +} + +return 0; +} + + diff --git a/gcc/testsuite/g++.dg/cilk-plus/CK/stl_test.cc b/gcc/testsuite/g++.dg/cilk-plus/CK/stl_test.cc new file mode 100644 index 0000000..3e350a1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/CK/stl_test.cc @@ -0,0 +1,50 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + + +#include +#include +#include +#include +#include +#include + +using namespace std; + + +int main(int argc, char **argv) +{ + vector number_list, number_list_serial; + int new_number = 0; + int no_elements = 0; + + if (argc != 2) + { + no_elements = 10000; + } + + + number_list.clear(); + number_list_serial.clear(); + for (int ii = 0; ii < no_elements; ii++) + { + number_list.push_back(new_number); + number_list_serial.push_back(new_number); + } + + _Cilk_for (int jj = 0; jj < no_elements; jj++) + { + number_list[jj] = jj + no_elements; + } + for (int jj = 0; jj < no_elements; jj++) + { + number_list_serial[jj] = jj + no_elements; + } + + for (int jj = 0; jj < no_elements; jj++) + if (number_list_serial[jj] != number_list[jj]) + abort (); + + return 0; +} diff --git a/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp b/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp index 27412e8..ff5ea33 100644 --- a/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp +++ b/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp @@ -64,12 +64,10 @@ dg-finish dg-init dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -fcilkplus" " " -dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -O0 -fcilkplus" " " dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -O1 -fcilkplus" " " dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -O2 -fcilkplus" " " dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -O3 -fcilkplus" " " dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -g -fcilkplus" " " -dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -g -O0 -fcilkplus" " " dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -g -O1 -fcilkplus" " " dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -g -O2 -ftree-vectorize -fcilkplus" " " dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/CK/*.cc]] " -g -O3 -fcilkplus" " " @@ -77,7 +75,6 @@ dg-finish dg-init dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -fcilkplus" " " -dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O0 -fcilkplus" " " dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O1 -fcilkplus" " " dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O2 -fcilkplus" " " dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O3 -fcilkplus" " " diff --git a/gcc/c-family/c-cilkplus.c b/gcc/c-family/c-cilkplus.c index 6fa979d..010d39d 100644 --- a/gcc/c-family/c-cilkplus.c +++ b/gcc/c-family/c-cilkplus.c @@ -26,8 +26,7 @@ along with GCC; see the file COPYING3. If not see #include "tree.h" #include "c-common.h" -/* Validate the body of a _Cilk_for construct or a <#pragma simd> for - loop. +/* Validate the body of a <#pragma simd> for loop. Returns true if there were no errors, false otherwise. */ @@ -91,3 +90,401 @@ c_finish_cilk_clauses (tree clauses) } return clauses; } + +/* Helper function for c_check_cilk_for_loop. + + Validate the increment in a _Cilk_for construct or a <#pragma simd> + for loop. + + LOC is the location of the `for' keyword. DECL is the induction + variable. INCR is the original increment expression. + + Returns the canonicalized increment expression for an OMP_FOR_INCR. + If there is a validation error, returns error_mark_node. */ + +static tree +c_check_cilk_loop_incr (location_t loc, tree decl, tree incr) +{ + tree orig_incr = incr; + if (!incr) + { + error_at (loc, "missing increment"); + return error_mark_node; + } + + if (EXPR_HAS_LOCATION (incr)) + loc = EXPR_LOCATION (incr); + + /* We hit this if-statement if we have an overloaded operand like + this: *my_class::operator+= (&ii, 1). For example, see the testscase + plus-equal-test.cc. */ + if (TREE_CODE (incr) == INDIRECT_REF + || TREE_CODE (incr) == CLEANUP_POINT_EXPR) + incr = TREE_OPERAND (incr, 0); + + if (TREE_CODE (incr) == TARGET_EXPR) + incr = TARGET_EXPR_INITIAL (incr); + + switch (TREE_CODE (incr)) + { + case POSTINCREMENT_EXPR: + case PREINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case PREDECREMENT_EXPR: + if (TREE_OPERAND (incr, 0) != decl) + break; + + return incr; + + case MODIFY_EXPR: + { + tree rhs; + + if (TREE_OPERAND (incr, 0) != decl) + break; + + rhs = TREE_OPERAND (incr, 1); + if ((TREE_CODE (rhs) == PLUS_EXPR + || TREE_CODE (rhs) == POINTER_PLUS_EXPR) + && (TREE_OPERAND (rhs, 0) == decl + || TREE_OPERAND (rhs, 1) == decl) + && (INTEGRAL_TYPE_P (TREE_TYPE (rhs)) + || POINTER_TYPE_P (TREE_TYPE (rhs)))) + return incr; + else if (TREE_CODE (rhs) == MINUS_EXPR + && TREE_OPERAND (rhs, 0) == decl + && INTEGRAL_TYPE_P (TREE_TYPE (rhs))) + return incr; + // Otherwise fail because only PLUS_EXPR and MINUS_EXPR are + // allowed. + break; + } + + /* We encounter CALL_EXPR in C++ when we have a case like this: + operator+= (&ii, 1); */ + case CALL_EXPR: + { + enum tree_code code = cilk_find_code_from_call (CALL_EXPR_FN (incr)); + if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR + || code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR) + { + tree val = CALL_EXPR_ARG (incr, 0); + if (TREE_CODE (val) == ADDR_EXPR + || TREE_CODE (val) == INDIRECT_REF) + val = TREE_OPERAND (val, 0); + if (val != decl) + break; + return incr; + } + for (int ii = 0; ii < call_expr_nargs (incr); ii++) + { + tree val = CALL_EXPR_ARG (incr, ii); + if (TREE_CODE (val) == ADDR_EXPR) + val = TREE_OPERAND (val, 0); + if (val == decl) + continue; + else + { + tree rhs = val; + if (TREE_CODE (rhs) == INTEGER_CST) + return orig_incr; + if ((TREE_CODE (rhs) == PLUS_EXPR + || TREE_CODE (rhs) == POINTER_PLUS_EXPR) + && (TREE_OPERAND (rhs, 0) == decl + || TREE_OPERAND (rhs, 1) == decl) + && (INTEGRAL_TYPE_P (TREE_TYPE (rhs)) + || POINTER_TYPE_P (TREE_TYPE (rhs)))) + return orig_incr; + else if (TREE_CODE (rhs) == MINUS_EXPR + && TREE_OPERAND (rhs, 0) == decl + && INTEGRAL_TYPE_P (TREE_TYPE (rhs))) + return orig_incr; + } + } + } + + default: + break; + } + + error_at (loc, "invalid increment expression"); + return error_mark_node; +} + +/* Callback for walk_tree to validate the body of a pragma simd loop + or _cilk_for loop. + + This function is passed in as a function pointer to walk_tree. *TP is + the current tree pointer, *WALK_SUBTREES is set to 0 by this function if + recursing into TP's subtrees is unnecessary. *DATA is a bool variable that + is set to false if an error has occured. */ + +tree +c_validate_cilk_plus_loop (tree *tp, int *walk_subtrees, void *data) +{ + if (!tp || !*tp) + return NULL_TREE; + + bool *valid = (bool *) data; + + switch (TREE_CODE (*tp)) + { + case CALL_EXPR: + { + tree fndecl = CALL_EXPR_FN (*tp); + + if (TREE_CODE (fndecl) == ADDR_EXPR) + fndecl = TREE_OPERAND (fndecl, 0); + if (TREE_CODE (fndecl) == FUNCTION_DECL) + { + if (setjmp_call_p (fndecl)) + { + error_at (EXPR_LOCATION (*tp), + "calls to setjmp are not allowed within loops " + "annotated with #pragma simd or _Cilk_for loops"); + *valid = false; + *walk_subtrees = 0; + } + } + break; + } + + case OMP_PARALLEL: + case OMP_TASK: + case OMP_FOR: + case OMP_SIMD: + case OMP_SECTIONS: + case OMP_SINGLE: + case OMP_SECTION: + case OMP_MASTER: + case OMP_ORDERED: + case OMP_CRITICAL: + case OMP_ATOMIC: + case OMP_ATOMIC_READ: + case OMP_ATOMIC_CAPTURE_OLD: + case OMP_ATOMIC_CAPTURE_NEW: + error_at (EXPR_LOCATION (*tp), "OpenMP statements are not allowed " + "within loops annotated with #pragma simd"); + *valid = false; + *walk_subtrees = 0; + break; + + default: + break; + } + return NULL_TREE; +} + +/* Validate the body of a _Cilk_for construct or a <#pragma simd> for + loop. + + Returns true if there were no errors, false otherwise. */ + +static bool +c_check_cilk_loop_body (tree body) +{ + bool valid = true; + walk_tree (&body, c_validate_cilk_plus_loop, (void *) &valid, NULL); + return valid; +} + +/* Validate a _Cilk_for construct (or a #pragma simd for loop, which + has the same syntactic restrictions). + + Returns TRUE if there were no errors, FALSE otherwise. + + LOC is the location of the for. + DECL is the controlling variable. + COND is the condition. + + INCRP is a pointer the increment expression (in case the increment + needs to be canonicalized). + + BODY is the body of the LOOP. + SCAN_BODY is true if the body must be checked. */ + +static bool +c_check_cilk_for_loop (location_t loc, tree decl, tree cond, tree *incrp, + tree body, bool scan_body, bool is_cpp, + bool proc_templates_p) +{ + tree incr = *incrp; + + if (TREE_THIS_VOLATILE (decl)) + { + error_at (loc, "iteration variable cannot be volatile"); + return false; + } + if (TREE_STATIC (decl)) + { + error_at (loc, "induction variable cannot be static"); + return false; + } + if (DECL_REGISTER (decl)) + { + error_at (loc, "induction variable cannot be declared register"); + return false; + } + if (!INTEGRAL_TYPE_P (TREE_TYPE (decl)) + && !POINTER_TYPE_P (TREE_TYPE (decl))) + { + /* In C++ iterators are allowed. */ + if (!is_cpp) + { + error_at (loc, "induction variable must be of integral " + "or pointer type (have %qT)", TREE_TYPE (decl)); + return false; + } + /* If we are processing templates then these checks are done + in pt.c. */ + else if (!proc_templates_p + && TREE_CODE (TREE_TYPE (decl)) != RECORD_TYPE) + { + error_at (loc, "induction variable must be of integral " + "record or pointer type (have %qT)", TREE_TYPE (decl)); + return false; + } + } + + /* Validate the condition. */ + if (!cond) + { + error_at (loc, "missing condition"); + return false; + } + bool cond_ok = false; + if (TREE_CODE (cond) == NE_EXPR + || TREE_CODE (cond) == CALL_EXPR + || TREE_CODE (cond) == LT_EXPR + || TREE_CODE (cond) == LE_EXPR + || TREE_CODE (cond) == GT_EXPR + || TREE_CODE (cond) == GE_EXPR) + { + /* Comparison must either be: + DECL EXPR + EXPR DECL + */ + if (decl == cilk_simplify_tree (TREE_OPERAND (cond, 0))) + cond_ok = true; + else if (decl == cilk_simplify_tree (TREE_OPERAND (cond, 1))) + { + /* Canonicalize the comparison so the DECL is on the LHS. */ + TREE_SET_CODE (cond, + swap_tree_comparison (TREE_CODE (cond))); + TREE_OPERAND (cond, 1) = TREE_OPERAND (cond, 0); + TREE_OPERAND (cond, 0) = decl; + cond_ok = true; + } + } + + /* In C++ you can have cases like this: x < 5 + where '<' is overloaded and so it is translated like this: + operator< (x, 5), and this is acceptable. */ + cond = cilk_simplify_tree (cond); + if (!cond_ok && is_cpp && TREE_CODE (cond) == CALL_EXPR) + { + if (call_expr_nargs (cond) < 2) + cond_ok = false; + for (int ii = 0; ii < call_expr_nargs (cond); ii++) + { + tree val = cilk_simplify_tree (CALL_EXPR_ARG (cond, ii)); + if (TREE_CODE (val) == ADDR_EXPR) + val = TREE_OPERAND (val, 0); + else if (TREE_CODE (val) == TARGET_EXPR) + val = TARGET_EXPR_INITIAL (val); + if (decl == val) + { + cond_ok = true; + break; + } + } + } + if (!cond_ok) + { + error_at (loc, "invalid controlling predicate"); + return false; + } + + /* Validate and canonicalize the increment. */ + incr = c_check_cilk_loop_incr (loc, decl, incr); + if (incr == error_mark_node) + return false; + *incrp = incr; + + if (scan_body && !c_check_cilk_loop_body (body)) + return false; + + return true; +} + +/* Validate and emit code for the _Cilk_for loop + + LOC is the location of the location of the _Cilk_for. + DECL is the iteration variable. + INIT is the initialization expression. + COND is the controlling predicate. + INCR is the increment expression. + BODY is the body of the loop. + SCAN_BODY is true if the body of the loop must be verified. + + Returns the generated statement. */ + +tree +c_finish_cilk_for_loop (location_t loc, tree decl, tree init, tree cond, + tree incr, tree body, tree grain, bool is_cpp, + bool proc_templates_p) +{ + if (!c_check_cilk_for_loop (loc, decl, cond, &incr, body, true, is_cpp, + proc_templates_p)) + return NULL; + + /* In the case for "_Cilk_for (int i = 0...)", init will be a decl. It + should have a DECL_INITIAL that we can turn into an assignment. */ + if (init == decl) + { + location_t rhs_loc = DECL_SOURCE_LOCATION (decl); + init = DECL_INITIAL (decl); + if (!init) + { + error_at (rhs_loc, "%qE is not initialized", decl); + init = integer_zero_node; + return NULL; + } + init = build2 (INIT_EXPR, TREE_TYPE (decl), decl, init); + DECL_INITIAL (decl) = NULL; + } + + tree t = make_node (CILK_FOR_STMT); + TREE_TYPE (t) = void_type_node; + + init = build2 (INIT_EXPR, TREE_TYPE (decl), decl, init); + CILK_FOR_INIT (t) = init; + CILK_FOR_COND (t) = cond; + CILK_FOR_EXPR (t) = incr; + CILK_FOR_BODY (t) = body; + CILK_FOR_SCOPE (t) = NULL_TREE; + CILK_FOR_VAR (t) = decl; + CILK_FOR_GRAIN (t) = grain; + + SET_EXPR_LOCATION (t, loc); + return add_stmt (t); +} + +/* Similar to c_finish_cilk_for_loop, but don't actually create the + CILK_FOR_STMT tree ad return it. *CILK_FOR_STMT is the CILK_FOR_STMT + tree and proc_templates_p is set if we are processing templates. */ + +void +cp_finish_cilk_for_loop (tree *cilk_for_stmt, bool proc_templates_p) +{ + tree cfor = *cilk_for_stmt; + tree incr = CILK_FOR_EXPR (cfor); + if (!c_check_cilk_for_loop (EXPR_LOCATION (cfor), CILK_FOR_VAR (cfor), + CILK_FOR_COND (cfor), &incr, + CILK_FOR_BODY (cfor), true, true, + proc_templates_p)) + *cilk_for_stmt = error_mark_node; + else + CILK_FOR_EXPR (*cilk_for_stmt) = incr; +} + diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index d7d5cb2..e500b20 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -416,6 +416,7 @@ const struct c_common_resword c_common_reswords[] = { "_Complex", RID_COMPLEX, 0 }, { "_Cilk_spawn", RID_CILK_SPAWN, 0 }, { "_Cilk_sync", RID_CILK_SYNC, 0 }, + { "_Cilk_for", RID_CILK_FOR, 0 }, { "_Imaginary", RID_IMAGINARY, D_CONLY }, { "_Decimal32", RID_DFLOAT32, D_CONLY | D_EXT }, { "_Decimal64", RID_DFLOAT64, D_CONLY | D_EXT }, diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h old mode 100644 new mode 100755 index b931fd6..507f62d --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -149,7 +149,7 @@ enum rid RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT, /* Cilk Plus keywords. */ - RID_CILK_SPAWN, RID_CILK_SYNC, + RID_CILK_SPAWN, RID_CILK_SYNC, RID_CILK_FOR, /* Objective-C ("AT" reserved words - they are only keywords when they follow '@') */ @@ -524,6 +524,14 @@ struct GTY(()) c_language_function { #define building_stmt_list_p() (stmt_list_stack && !stmt_list_stack->is_empty()) +/* In c-cilkplus.c */ +extern void cp_finish_cilk_for_loop (tree *, bool); +extern tree c_validate_cilk_plus_loop (tree *, int *, void *); +extern bool c_check_cilk_loop (location_t, tree); +extern tree c_finish_cilk_for_loop (location_t, tree, tree, tree, tree, tree, + tree, bool, bool); + /* Language-specific hooks. */ /* If non-NULL, this function is called after a precompile header file @@ -1292,7 +1300,6 @@ extern enum stv_conv scalar_to_vector (location_t loc, enum tree_code code, /* In c-cilkplus.c */ extern tree c_finish_cilk_clauses (tree); extern tree c_validate_cilk_plus_loop (tree *, int *, void *); -extern bool c_check_cilk_loop (location_t, tree); /* These #defines allow users to access different operands of the array notation tree. */ @@ -1377,5 +1384,31 @@ extern tree build_cilk_spawn (location_t, tree); extern tree make_cilk_frame (tree); extern tree create_cilk_function_exit (tree, bool, bool); extern tree cilk_install_body_pedigree_operations (tree); - +extern void cilk_init_cfd (struct cilk_for_desc *); +extern void cilk_extract_free_variables (tree, struct wrapper_data *, int); +extern tree cilk_create_cilk_helper_decl (struct wrapper_data *); +extern void cilk_call_graph_add_fn (tree); +extern void cilk_outline_body (tree, tree *, struct wrapper_data *, bool *); +extern tree cilk_check_loop_difference_type (tree); +extern void declare_cilk_for_parms (struct cilk_for_desc *); +extern void declare_cilk_for_vars (struct cilk_for_desc *, tree); +extern tree cilk_loop_convert (tree, tree); +extern tree cilk_divide_count (tree, enum tree_code, tree, bool, tree); +extern void cilk_calc_forward_div_op (struct cilk_for_desc *, enum tree_code *, + tree *); +extern tree cilk_compute_loop_count (struct cilk_for_desc *, enum tree_code, + tree, tree, tree); +extern gimple_seq insert_cilk_for_nested_fn (struct cilk_for_desc *, tree, + tree); +extern tree cilk_compute_loop_var (struct cilk_for_desc *, tree, tree, + tree (*)(location_t, enum tree_code, tree, + tree, tree)); +extern void cilk_set_inclusive_and_direction (struct cilk_for_desc *); +extern void cilk_set_iter_difftype (struct cilk_for_desc *); +extern void cilk_set_incr_info (struct cilk_for_desc *, bool); +extern void cilk_set_init_info (struct cilk_for_desc *); +extern tree cilk_simplify_tree (tree); +extern enum tree_code cilk_find_code_from_call (tree); +extern tree cilk_tree_operand_noconv (tree); +extern tree cilk_resolve_continue_stmts (tree *, int *, void *); #endif /* ! GCC_C_COMMON_H */ diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c index 029ab1e..7f5f3df 100644 --- a/gcc/c-family/c-pragma.c +++ b/gcc/c-family/c-pragma.c @@ -1390,6 +1390,11 @@ init_pragma (void) cpp_register_deferred_pragma (parse_in, "GCC", "ivdep", PRAGMA_IVDEP, false, false); + + if (flag_enable_cilkplus && !flag_preprocess_only) + cpp_register_deferred_pragma (parse_in, "cilk", "grainsize", + PRAGMA_CILK_GRAINSIZE, true, false); + #ifdef HANDLE_PRAGMA_PACK_WITH_EXPANSION c_register_pragma_with_expansion (0, "pack", handle_pragma_pack); #else diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index 5379b9e..ca8b190 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -55,6 +55,9 @@ typedef enum pragma_kind { /* Top level clause to handle all Cilk Plus pragma simd clauses. */ PRAGMA_CILK_SIMD, + /* This pragma handles setting of grainsize for a _Cilk_for. */ + PRAGMA_CILK_GRAINSIZE, + PRAGMA_GCC_PCH_PREPROCESS, PRAGMA_IVDEP, diff --git a/gcc/c-family/cilk.c b/gcc/c-family/cilk.c old mode 100644 new mode 100755 index 165348f..a313816 --- a/gcc/c-family/cilk.c +++ b/gcc/c-family/cilk.c @@ -35,47 +35,6 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic.h" #include "cilk.h" -enum add_variable_type { - /* Reference to previously-defined variable. */ - ADD_READ, - /* Definition of a new variable in inner-scope. */ - ADD_BIND, - /* Write to possibly previously-defined variable. */ - ADD_WRITE -}; - -enum cilk_block_type { - /* Indicates a _Cilk_spawn block. 30 was an arbitary number picked for - ease of debugging. */ - CILK_BLOCK_SPAWN = 30, - /* Indicates _Cilk_for statement block. */ - CILK_BLOCK_FOR -}; - -struct wrapper_data -{ - /* Kind of function to be created. */ - enum cilk_block_type type; - /* Signature of helper function. */ - tree fntype; - /* Containing function. */ - tree context; - /* Disposition of all variables in the inner statement. */ - struct pointer_map_t *decl_map; - /* True if this function needs a static chain. */ - bool nested; - /* Arguments to be passed to wrapper function, currently a list. */ - tree arglist; - /* Argument types, a list. */ - tree argtypes; - /* Incoming parameters. */ - tree parms; - /* Outer BLOCK object. */ - tree block; -}; - -static void extract_free_variables (tree, struct wrapper_data *, - enum add_variable_type); static HOST_WIDE_INT cilk_wrapper_count; /* Marks the CALL_EXPR or FUNCTION_DECL, FCALL, as a spawned function call @@ -156,8 +115,8 @@ pop_cfun_to (tree outer) /* This function does whatever is necessary to make the compiler emit a newly generated function, FNDECL. */ -static void -call_graph_add_fn (tree fndecl) +void +cilk_call_graph_add_fn (tree fndecl) { const tree outer = current_function_decl; struct function *f = DECL_STRUCT_FUNCTION (fndecl); @@ -283,8 +242,8 @@ cilk_detect_spawn_and_unwrap (tree *exp0) /* This function will build and return a FUNCTION_DECL using information from *WD. */ -static tree -create_cilk_helper_decl (struct wrapper_data *wd) +tree +cilk_create_cilk_helper_decl (struct wrapper_data *wd) { char name[20]; if (wd->type == CILK_BLOCK_FOR) @@ -452,6 +411,8 @@ for_local_cb (const void *k_v, void **vp, void *p) tree k = *(tree *) &k_v; tree v = (tree) *vp; + if (k == v) + return true; if (v == error_mark_node) *vp = copy_decl_no_change (k, (copy_body_data *) p); return true; @@ -472,15 +433,18 @@ wrapper_local_cb (const void *k_v, void **vp, void *data) return true; } -/* Alter a tree STMT from OUTER_FN to form the body of INNER_FN. */ +/* Alter a tree STMT from OUTER_FN to form the body of INNER_FN. THR is set + to true if the original function has exception enabled (only applicable for + C++ Cilk_for nested function). This value is evaluated and then + passed back into cp_function_tree->can_throw. */ -static void -cilk_outline (tree inner_fn, tree *stmt_p, struct wrapper_data *wd) +void +cilk_outline_body (tree inner_fn, tree *stmt_p, struct wrapper_data *wd, + bool *thr) { const tree outer_fn = wd->context; const bool nested = (wd->type == CILK_BLOCK_FOR); copy_body_data id; - bool throws; DECL_STATIC_CHAIN (outer_fn) = 1; @@ -496,7 +460,7 @@ cilk_outline (tree inner_fn, tree *stmt_p, struct wrapper_data *wd) id.retvar = 0; id.decl_map = wd->decl_map; id.copy_decl = nested ? copy_decl_no_change : copy_decl_for_cilk; - id.block = DECL_INITIAL (inner_fn); + id.block = 0; id.transform_lang_insert_block = NULL; id.transform_new_cfg = true; @@ -515,8 +479,10 @@ cilk_outline (tree inner_fn, tree *stmt_p, struct wrapper_data *wd) /* See if this function can throw or calls something that should not be spawned. The exception part is only necessary if flag_exceptions && !flag_non_call_exceptions. */ - throws = false ; + bool throws = thr ? *thr : false; (void) walk_tree_without_duplicates (stmt_p, check_outlined_calls, &throws); + if (thr) + *thr = throws; } /* Generate the body of a wrapper function that assigns the @@ -538,7 +504,7 @@ create_cilk_wrapper_body (tree stmt, struct wrapper_data *wd) /* Emit a function that takes WRAPPER_PARMS incoming and applies ARGS (modified) to the wrapped function. Return the wrapper and modified ARGS to the caller to generate a function call. */ - fndecl = create_cilk_helper_decl (wd); + fndecl = cilk_create_cilk_helper_decl (wd); push_struct_function (fndecl); if (wd->nested && (wd->type == CILK_BLOCK_FOR)) { @@ -551,7 +517,7 @@ create_cilk_wrapper_body (tree stmt, struct wrapper_data *wd) for (p = wd->parms; p; p = TREE_CHAIN (p)) DECL_CONTEXT (p) = fndecl; - cilk_outline (fndecl, &stmt, wd); + cilk_outline_body (fndecl, &stmt, wd, NULL); stmt = fold_build_cleanup_point_expr (void_type_node, stmt); gcc_assert (!DECL_SAVED_TREE (fndecl)); lang_hooks.cilkplus.install_body_with_frame_cleanup (fndecl, stmt); @@ -560,7 +526,7 @@ create_cilk_wrapper_body (tree stmt, struct wrapper_data *wd) pop_cfun_to (outer); /* Recognize the new function. */ - call_graph_add_fn (fndecl); + cilk_call_graph_add_fn (fndecl); return fndecl; } @@ -702,14 +668,14 @@ create_cilk_wrapper (tree exp, tree *args_out) by spawn and the variable must remain in the outer function. */ if (TREE_CODE (exp) == INIT_EXPR) { - extract_free_variables (TREE_OPERAND (exp, 0), &wd, ADD_WRITE); - extract_free_variables (TREE_OPERAND (exp, 1), &wd, ADD_READ); + cilk_extract_free_variables (TREE_OPERAND (exp, 0), &wd, ADD_WRITE); + cilk_extract_free_variables (TREE_OPERAND (exp, 1), &wd, ADD_READ); /* TREE_TYPE should be void. Be defensive. */ if (TREE_TYPE (exp) != void_type_node) - extract_free_variables (TREE_TYPE (exp), &wd, ADD_READ); + cilk_extract_free_variables (TREE_TYPE (exp), &wd, ADD_READ); } else - extract_free_variables (exp, &wd, ADD_READ); + cilk_extract_free_variables (exp, &wd, ADD_READ); pointer_map_traverse (wd.decl_map, declare_one_free_variable, &wd); wd.block = TREE_BLOCK (exp); if (!wd.block) @@ -996,14 +962,14 @@ add_variable (struct wrapper_data *wd, tree var, enum add_variable_type how) /* Find the variables referenced in an expression T. This does not avoid duplicates because a variable may be read in one context and written in - another. HOW describes the context in which the reference is seen. If + another. HOW_T describes the context in which the reference is seen. If NESTED is true a nested function is being generated and variables in the original context should not be remapped. */ -static void -extract_free_variables (tree t, struct wrapper_data *wd, - enum add_variable_type how) +void +cilk_extract_free_variables (tree t, struct wrapper_data *wd, int how_t) { + enum add_variable_type how = (enum add_variable_type) how_t; if (t == NULL_TREE) return; @@ -1011,7 +977,7 @@ extract_free_variables (tree t, struct wrapper_data *wd, bool is_expr = IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)); if (is_expr) - extract_free_variables (TREE_TYPE (t), wd, ADD_READ); + cilk_extract_free_variables (TREE_TYPE (t), wd, ADD_READ); switch (code) { @@ -1031,7 +997,7 @@ extract_free_variables (tree t, struct wrapper_data *wd, case SSA_NAME: /* Currently we don't see SSA_NAME. */ - extract_free_variables (SSA_NAME_VAR (t), wd, how); + cilk_extract_free_variables (SSA_NAME_VAR (t), wd, how); return; case LABEL_DECL: @@ -1053,12 +1019,12 @@ extract_free_variables (tree t, struct wrapper_data *wd, case NON_LVALUE_EXPR: case CONVERT_EXPR: case NOP_EXPR: - extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_READ); + cilk_extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_READ); return; case INIT_EXPR: - extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_BIND); - extract_free_variables (TREE_OPERAND (t, 1), wd, ADD_READ); + cilk_extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_BIND); + cilk_extract_free_variables (TREE_OPERAND (t, 1), wd, ADD_READ); return; case MODIFY_EXPR: @@ -1067,8 +1033,8 @@ extract_free_variables (tree t, struct wrapper_data *wd, case POSTDECREMENT_EXPR: case POSTINCREMENT_EXPR: /* These write their result. */ - extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_WRITE); - extract_free_variables (TREE_OPERAND (t, 1), wd, ADD_READ); + cilk_extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_WRITE); + cilk_extract_free_variables (TREE_OPERAND (t, 1), wd, ADD_READ); return; case ADDR_EXPR: @@ -1079,9 +1045,9 @@ extract_free_variables (tree t, struct wrapper_data *wd, be addressable, and marking it modified will cause a spurious warning about writing the control variable. */ if (wd->type != CILK_BLOCK_SPAWN) - extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_READ); + cilk_extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_READ); else - extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_WRITE); + cilk_extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_WRITE); return; case ARRAY_REF: @@ -1093,17 +1059,17 @@ extract_free_variables (tree t, struct wrapper_data *wd, is being accessed here. As for ADDR_EXPR, don't do this in a nested loop, unless the access is to a fixed index. */ if (wd->type != CILK_BLOCK_FOR || TREE_CONSTANT (TREE_OPERAND (t, 1))) - extract_free_variables (TREE_OPERAND (t, 0), wd, how); + cilk_extract_free_variables (TREE_OPERAND (t, 0), wd, how); else - extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_READ); - extract_free_variables (TREE_OPERAND (t, 1), wd, ADD_READ); - extract_free_variables (TREE_OPERAND (t, 2), wd, ADD_READ); + cilk_extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_READ); + cilk_extract_free_variables (TREE_OPERAND (t, 1), wd, ADD_READ); + cilk_extract_free_variables (TREE_OPERAND (t, 2), wd, ADD_READ); return; case TREE_LIST: - extract_free_variables (TREE_PURPOSE (t), wd, ADD_READ); - extract_free_variables (TREE_VALUE (t), wd, ADD_READ); - extract_free_variables (TREE_CHAIN (t), wd, ADD_READ); + cilk_extract_free_variables (TREE_PURPOSE (t), wd, ADD_READ); + cilk_extract_free_variables (TREE_VALUE (t), wd, ADD_READ); + cilk_extract_free_variables (TREE_CHAIN (t), wd, ADD_READ); return; case TREE_VEC: @@ -1111,7 +1077,7 @@ extract_free_variables (tree t, struct wrapper_data *wd, int len = TREE_VEC_LENGTH (t); int i; for (i = 0; i < len; i++) - extract_free_variables (TREE_VEC_ELT (t, i), wd, ADD_READ); + cilk_extract_free_variables (TREE_VEC_ELT (t, i), wd, ADD_READ); return; } @@ -1119,13 +1085,13 @@ extract_free_variables (tree t, struct wrapper_data *wd, { unsigned ii = 0; for (ii = 0; ii < VECTOR_CST_NELTS (t); ii++) - extract_free_variables (VECTOR_CST_ELT (t, ii), wd, ADD_READ); + cilk_extract_free_variables (VECTOR_CST_ELT (t, ii), wd, ADD_READ); break; } case COMPLEX_CST: - extract_free_variables (TREE_REALPART (t), wd, ADD_READ); - extract_free_variables (TREE_IMAGPART (t), wd, ADD_READ); + cilk_extract_free_variables (TREE_REALPART (t), wd, ADD_READ); + cilk_extract_free_variables (TREE_IMAGPART (t), wd, ADD_READ); return; case BIND_EXPR: @@ -1136,11 +1102,11 @@ extract_free_variables (tree t, struct wrapper_data *wd, add_variable (wd, decl, ADD_BIND); /* A self-referential initialization is no problem because we already entered the variable into the map as local. */ - extract_free_variables (DECL_INITIAL (decl), wd, ADD_READ); - extract_free_variables (DECL_SIZE (decl), wd, ADD_READ); - extract_free_variables (DECL_SIZE_UNIT (decl), wd, ADD_READ); + cilk_extract_free_variables (DECL_INITIAL (decl), wd, ADD_READ); + cilk_extract_free_variables (DECL_SIZE (decl), wd, ADD_READ); + cilk_extract_free_variables (DECL_SIZE_UNIT (decl), wd, ADD_READ); } - extract_free_variables (BIND_EXPR_BODY (t), wd, ADD_READ); + cilk_extract_free_variables (BIND_EXPR_BODY (t), wd, ADD_READ); return; } @@ -1148,17 +1114,17 @@ extract_free_variables (tree t, struct wrapper_data *wd, { tree_stmt_iterator i; for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) - extract_free_variables (*tsi_stmt_ptr (i), wd, ADD_READ); + cilk_extract_free_variables (*tsi_stmt_ptr (i), wd, ADD_READ); return; } case TARGET_EXPR: { - extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_BIND); - extract_free_variables (TREE_OPERAND (t, 1), wd, ADD_READ); - extract_free_variables (TREE_OPERAND (t, 2), wd, ADD_READ); + cilk_extract_free_variables (TREE_OPERAND (t, 0), wd, ADD_BIND); + cilk_extract_free_variables (TREE_OPERAND (t, 1), wd, ADD_READ); + cilk_extract_free_variables (TREE_OPERAND (t, 2), wd, ADD_READ); if (TREE_OPERAND (t, 3) != TREE_OPERAND (t, 1)) - extract_free_variables (TREE_OPERAND (t, 3), wd, ADD_READ); + cilk_extract_free_variables (TREE_OPERAND (t, 3), wd, ADD_READ); return; } @@ -1172,32 +1138,32 @@ extract_free_variables (tree t, struct wrapper_data *wd, case DECL_EXPR: if (TREE_CODE (DECL_EXPR_DECL (t)) != TYPE_DECL) - extract_free_variables (DECL_EXPR_DECL (t), wd, ADD_BIND); + cilk_extract_free_variables (DECL_EXPR_DECL (t), wd, ADD_BIND); return; case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE: - extract_free_variables (TYPE_MIN_VALUE (t), wd, ADD_READ); - extract_free_variables (TYPE_MAX_VALUE (t), wd, ADD_READ); + cilk_extract_free_variables (TYPE_MIN_VALUE (t), wd, ADD_READ); + cilk_extract_free_variables (TYPE_MAX_VALUE (t), wd, ADD_READ); return; case POINTER_TYPE: - extract_free_variables (TREE_TYPE (t), wd, ADD_READ); + cilk_extract_free_variables (TREE_TYPE (t), wd, ADD_READ); break; case ARRAY_TYPE: - extract_free_variables (TREE_TYPE (t), wd, ADD_READ); - extract_free_variables (TYPE_DOMAIN (t), wd, ADD_READ); + cilk_extract_free_variables (TREE_TYPE (t), wd, ADD_READ); + cilk_extract_free_variables (TYPE_DOMAIN (t), wd, ADD_READ); return; case RECORD_TYPE: - extract_free_variables (TYPE_FIELDS (t), wd, ADD_READ); + cilk_extract_free_variables (TYPE_FIELDS (t), wd, ADD_READ); return; case METHOD_TYPE: - extract_free_variables (TYPE_ARG_TYPES (t), wd, ADD_READ); - extract_free_variables (TYPE_METHOD_BASETYPE (t), wd, ADD_READ); + cilk_extract_free_variables (TYPE_ARG_TYPES (t), wd, ADD_READ); + cilk_extract_free_variables (TYPE_METHOD_BASETYPE (t), wd, ADD_READ); return; case AGGR_INIT_EXPR: @@ -1210,8 +1176,8 @@ extract_free_variables (tree t, struct wrapper_data *wd, len = TREE_INT_CST_LOW (TREE_OPERAND (t, 0)); for (ii = 0; ii < len; ii++) - extract_free_variables (TREE_OPERAND (t, ii), wd, ADD_READ); - extract_free_variables (TREE_TYPE (t), wd, ADD_READ); + cilk_extract_free_variables (TREE_OPERAND (t, ii), wd, ADD_READ); + cilk_extract_free_variables (TREE_TYPE (t), wd, ADD_READ); } break; } @@ -1227,7 +1193,7 @@ extract_free_variables (tree t, struct wrapper_data *wd, /* Go through the subtrees. We need to do this in forward order so that the scope of a FOR_EXPR is handled properly. */ for (i = 0; i < len; ++i) - extract_free_variables (TREE_OPERAND (t, i), wd, ADD_READ); + cilk_extract_free_variables (TREE_OPERAND (t, i), wd, ADD_READ); } } } @@ -1304,3 +1270,872 @@ build_cilk_sync (void) TREE_SIDE_EFFECTS (sync) = 1; return sync; } + +/* Zeros out all the fields in CFD. */ + +void +cilk_init_cfd (struct cilk_for_desc *cfd) +{ + memset (cfd, 0, sizeof *cfd); + init_wd (&cfd->wd, CILK_BLOCK_FOR); +} + +/* Returns a CALL_EXPR based on the TYPE_PRECISON of COUNT_TYPE. */ + +static tree +find_cilk_for_library_fn (tree count_type) +{ + if (TYPE_PRECISION (count_type) == 32) + return cilk_for_32_fndecl; + else if (TYPE_PRECISION (count_type) == 64) + return cilk_for_64_fndecl; + else + gcc_unreachable (); +} + +/* This function finds the direction INCR, the increment expression, of the + loop: Return 0 if the sign of INCR_DIRECTION is unknown, + +1 if the value is exactly +1, + +2 if the value is known to be positive, and + -2 if the value is known to be negative. */ + +static int +cilk_compute_incr_direction (tree incr) +{ + if (TREE_CODE (incr) != INTEGER_CST) + return tree_expr_nonnegative_p (incr) ? 2 : 0; + else if (integer_onep (incr)) + return 1; + else + return 2 * tree_int_cst_sgn (incr); +} + +/* Return the count type based on TYPE of a Cilk for loop, or unsigned long if + there is no acceptable type. */ + +tree +cilk_check_loop_difference_type (tree type) +{ + if ((TYPE_PRECISION (type) > TYPE_PRECISION (long_unsigned_type_node)) + || (TYPE_MAIN_VARIANT (type) == long_long_integer_type_node) + || (TYPE_MAIN_VARIANT (type) == long_long_unsigned_type_node)) + return long_long_unsigned_type_node; + + return long_unsigned_type_node; +} + +/* Removes unwanted wrappers from a tree, T. */ + +tree +cilk_simplify_tree (tree t) +{ + extern tree tree_ssa_strip_useless_type_conversions (tree); + + if (TREE_CODE (t) == CLEANUP_POINT_EXPR) + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == NOP_EXPR) + t = TREE_OPERAND (t, 0); + if ((TREE_CODE (t) == CONVERT_EXPR) && (VOID_TYPE_P (TREE_TYPE (t)) != 0)) + t = TREE_OPERAND (t, 0); + + STRIP_USELESS_TYPE_CONVERSION (t); + + return t; +} + +/* Set up the variable mapping for the FNDECL and install parameters after + declaring the function and scanning the loop body's variable use. + Information about the _Cilk_for statement is stored in *CFD. */ + +void +declare_cilk_for_vars (struct cilk_for_desc *cfd, tree fndecl) +{ + tree var2 = build_decl (cfd->loc, VAR_DECL, DECL_NAME (cfd->var), + cfd->var_type); + DECL_CONTEXT (var2) = fndecl; + cfd->var2 = var2; + + void **mapped = pointer_map_contains (cfd->wd.decl_map, cfd->var); + /* The loop control variable must be mapped. */ + gcc_assert (mapped); + const_tree t = (const_tree) *mapped; + + /* The loop control variable may appear as mapped to itself + or mapped to integer_one_node depending on its type and + how it was modified. */ + if ((TREE_CODE (t) != INTEGER_CST) || (t == integer_one_node)) + { + tree save_function = current_function_decl; + current_function_decl = DECL_CONTEXT (cfd->var); + warning (0, "loop body modifies control variable %qD", cfd->var); + current_function_decl = save_function; + } + *mapped = (void *) var2; + + tree p = cfd->wd.parms; + DECL_ARGUMENTS (fndecl) = p; + do + { + DECL_CONTEXT (p) = fndecl; + p = TREE_CHAIN (p); + } + while (p); +} + +/* Set up the signature and parameters of the _Cilk_for body function + before declaring the function using information stored in CFD. */ + +void +declare_cilk_for_parms (struct cilk_for_desc *cfd) +{ + tree count_type = cfd->count_type; + tree ro_count = build_qualified_type (count_type, TYPE_QUAL_CONST); + tree ctx = build_decl (cfd->loc, PARM_DECL, NULL_TREE, ptr_type_node); + tree t1 = get_identifier ("__low"); + tree min_parm = build_decl (cfd->loc, PARM_DECL, t1, ro_count); + tree t2 = get_identifier ("__high"); + tree max_parm = build_decl (cfd->loc, PARM_DECL, t2, ro_count); + + DECL_ARG_TYPE (max_parm) = count_type; + DECL_ARTIFICIAL (max_parm) = 1; + TREE_READONLY (max_parm) = 1; + + DECL_ARG_TYPE (min_parm) = count_type; + DECL_ARTIFICIAL (min_parm) = 1; + TREE_READONLY (min_parm) = 1; + + DECL_ARG_TYPE (ctx) = ptr_type_node; + DECL_ARTIFICIAL (ctx) = 1; + TREE_READONLY (ctx) = 1; + + TREE_CHAIN (min_parm) = max_parm; + TREE_CHAIN (ctx) = min_parm; + + tree types = tree_cons (NULL_TREE, TREE_TYPE (max_parm), void_list_node); + types = tree_cons (NULL_TREE, TREE_TYPE (min_parm), types); + types = tree_cons (NULL_TREE, TREE_TYPE (ctx), types); + + cfd->min_parm = min_parm; + cfd->max_parm = max_parm; + cfd->wd.argtypes = types; + cfd->wd.arglist = NULL_TREE; + cfd->wd.parms = ctx; +} + +/* Convert a loop, EXP, to the way required by _Cilk_for and sets it type as + indicated by TYPE. */ + +tree +cilk_loop_convert (tree type, tree exp) +{ + enum tree_code code; + int inprec, outprec; + if (type == TREE_TYPE (exp)) + return exp; + inprec = TYPE_PRECISION (TREE_TYPE (exp)); + outprec = TYPE_PRECISION (type); + if (outprec > inprec && !TYPE_UNSIGNED (TREE_TYPE (exp))) + code = CONVERT_EXPR; + else + code = NOP_EXPR; + return fold_build1 (code, type, exp); +} + +/* Returns the number of times a loop is divided. */ + +tree +cilk_divide_count (tree count, enum tree_code op, tree incr, bool negate, + tree type) +{ + tree dtype; + + if (!count) + return NULL_TREE; + + tree ctype = TREE_TYPE (count); + tree itype = TREE_TYPE (incr); + + if (op == NOP_EXPR && !negate) + return cilk_loop_convert (type, count); + /* Return -(unsigned) count instead of (unsigned)-count in case the negate + overflows. */ + if (op == NOP_EXPR && negate) + return fold_build1 (NEGATE_EXPR, type, cilk_loop_convert (type, count)); + + /* We are dividing two positive values or else the user has invoked + undefined behavior. That means we can divide in a common narrow + type and widen after. This does not work if we must negate signed + INCR to get a positive value because we could be negating INT_MIN. */ + + if (ctype != itype || (negate && !TYPE_UNSIGNED (itype))) + { + incr = cilk_loop_convert (type, incr); + count = cilk_loop_convert (type, count); + dtype = type; + } + else + dtype = ctype; + + if (negate) + incr = fold_build1 (NEGATE_EXPR, TREE_TYPE (incr), incr); + + count = fold_build2 (op, dtype, count, incr); + if (dtype != type) + count = cilk_loop_convert (type, count); + + return count; +} + +/* Sets *DIV_OP to the appropriate operation to divide the loop and + the *FORWARD tree with condition expression based on DIRECTION, INCR_SIGN + and EXACTLY_ONE. */ + +void +cilk_calc_forward_div_op (struct cilk_for_desc *cfd, enum tree_code *div_op, + tree *forward) +{ + switch (cfd->direction) + { + case -2: + *forward = boolean_false_node; + *div_op = CEIL_DIV_EXPR; + break; + case -1: + *forward = boolean_false_node; + *div_op = EXACT_DIV_EXPR; + break; + case 0: + *forward = build2 (cfd->incr_sign > 0 ? GE_EXPR : LT_EXPR, + boolean_type_node, cfd->incr, integer_zero_node); + /* Loops with indeterminate direction use != and are always exact. */ + *div_op = EXACT_DIV_EXPR; + break; + case 1: + *forward = boolean_true_node; + *div_op = EXACT_DIV_EXPR; + break; + case 2: + *forward = boolean_true_node; + *div_op = CEIL_DIV_EXPR; + break; + default: + gcc_unreachable (); + } + if (cfd->exactly_one) + *div_op = NOP_EXPR; +} + +/* Returns the loop-count based on the _Cilk_for loop's characteristics given + in *CFD. DIV_OP indicates whether we have exact division or a CEILING + operation need to be performed. COUNT_UP and COUNT_DOWN are not + NULL_TREE if the increment and decrement operation are done using an + iterator. */ + +tree +cilk_compute_loop_count (struct cilk_for_desc *cfd, enum tree_code div_op, + tree forward, tree count_up, tree count_down) +{ + /* if initial value is not given, the use the variable since it holds the + lower value. */ + tree low = cfd->lower_bound ? cfd->lower_bound : cfd->var; + + /* Same logic as low for high variable. */ + tree high = cfd->end_var ? cfd->end_var : cfd->end_expr; + + if (low == error_mark_node || high == error_mark_node) + { + gcc_assert (errorcount || sorrycount); + return error_mark_node; + } + + /* If either count_up or count_down are not NULL, then it is an indication + that we have an interator for loop computation, so we check if + cfd->iterator is set to true. */ + if (count_up != NULL_TREE || count_down != NULL_TREE) + gcc_assert (cfd->iterator); + else + { + tree low_type = TREE_TYPE (low); + tree high_type = TREE_TYPE (high); + tree sub_type = NULL_TREE; + + if (TREE_CODE (TREE_TYPE (cfd->var)) == POINTER_TYPE) + sub_type = ptrdiff_type_node; + else + { + /* We need to compute HIGH - LOW or LOW - HIGH without overflow. */ + sub_type = common_type (low_type, high_type); + + /* If subtracting two signed vars. without widening then convert them + to unsigned. */ + if (!TYPE_UNSIGNED (sub_type) + && (TYPE_PRECISION (sub_type) == TYPE_PRECISION (low_type) + || TYPE_PRECISION (sub_type) == TYPE_PRECISION (high_type))) + sub_type = unsigned_type_for (sub_type); + } + if (low_type != sub_type) + low = convert (sub_type, low); + if (high_type != sub_type) + high = convert (sub_type, high); + + if (cfd->direction <= 0) + count_down = fold_build2 (MINUS_EXPR, sub_type, low, high); + if (cfd->direction >= 0) + count_up = fold_build2 (MINUS_EXPR, sub_type, high, low); + } + + /* if the loop is not exact add one before dividing. Otherwise add 1 after + dividing. Assumed that it can't overflow (meaning that loop range cannot + exceed the range of the loop variable or difference type). */ + if (cfd->inclusive && div_op == CEIL_DIV_EXPR) + { + if (count_up) + count_up = fold_build2 (PLUS_EXPR, TREE_TYPE (count_up), count_up, + build_one_cst (TREE_TYPE (count_up))); + if (count_down) + count_down = fold_build2 (PLUS_EXPR, TREE_TYPE (count_down), count_down, + build_one_cst (TREE_TYPE (count_down))); + } + + /* Serial semantics: INCR is converted to the common type of VAR and INCR then + the result is converted to the type of VAR. */ + tree incr = cfd->incr; + if (!cfd->iterator && TREE_CODE (TREE_TYPE (cfd->var)) != POINTER_TYPE) + incr = cilk_loop_convert (common_type (TREE_TYPE (cfd->var), + TREE_TYPE (incr)), incr); + + /* Now separately divide each count by +/- INCR yielding a value with type + TYPE. */ + count_up = cilk_divide_count (count_up, div_op, incr, cfd->incr_sign < 0, + cfd->count_type); + count_down = cilk_divide_count (count_down, div_op, incr, cfd->incr_sign > 0, + cfd->count_type); + /* Merge forward and backward counts. */ + tree count = NULL_TREE; + if (!count_up) + count = count_down; + else if (!count_down) + count = count_up; + else + count = fold_build3 (COND_EXPR, cfd->count_type, forward, count_up, + count_down); + + /* Add one, maybe. */ + if (cfd->inclusive && div_op != CEIL_DIV_EXPR) + count = fold_build2 (PLUS_EXPR, cfd->count_type, count, + build_one_cst (cfd->count_type)); + + return count; +} + +/* Returns a GIMPLE_SEQ that contains a call to the Cilk library function and + the necessary temporary variables. COUNT and FN are parameters to the + library function indicating the loop-count and nested function, + respectively. */ + +gimple_seq +insert_cilk_for_nested_fn (struct cilk_for_desc *cfd, tree count, tree fn) +{ + /* INNER_SEQ contains evaluation of variables holding loop increment and + count. These are evaluated inside the loop guard. */ + gimple_seq inner_seq = 0; + if (!TREE_CONSTANT (count)) + { + count = fold_build_cleanup_point_expr (TREE_TYPE (count), count); + count = get_formal_tmp_var (count, &inner_seq); + } + + if (TREE_SIDE_EFFECTS (cfd->incr)) + cfd->incr = get_formal_tmp_var (cfd->incr, &inner_seq); + + tree libfun = find_cilk_for_library_fn (cfd->count_type); + tree ctx = cfd->ctx_arg; + if (ctx) + { + if (TREE_TYPE (ctx) != ptr_type_node) + ctx = fold_build1 (NOP_EXPR, ptr_type_node, ctx); + if (!DECL_P (ctx)) + ctx = get_formal_tmp_var (ctx, &inner_seq); + } + else + { + ctx = fold_build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn); + ctx = get_formal_tmp_var (ctx, &inner_seq); + } + fn = fold_build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn); + TREE_CONSTANT (fn) = 1; + fn = get_formal_tmp_var (fn, &inner_seq); + + tree grain = cfd->grain; + tree tmv_count_type = TYPE_MAIN_VARIANT (cfd->count_type); + if (!grain) + grain = get_formal_tmp_var (build_zero_cst (cfd->count_type), &inner_seq); + else if (TYPE_MAIN_VARIANT (TREE_TYPE (grain)) != tmv_count_type) + grain = convert (cfd->count_type, grain); + + tree libfun_call = build_call_expr (libfun, 4, fn, ctx, count, grain); + gimplify_and_add (libfun_call, &inner_seq); + return inner_seq; +} + +/* The loop function looks like + + body (void *, unsigned long max, unsigned long min) + const T start = [outer_context] var; + T var'; + for (unsigned long i = min; i < max; i++) { + var' = start + (T) i * (T) incr; + body (var'); + } + + COMPUTE_LOOP_VAR returns an expression for + var' = start + i * incr; + or + var' = start - i * decr; + with suitable type conversions. + + If direction is known we know the sign of INCR (or else it's + undefined behavior) and we can work with positive unsigned + numbers until the last addition or subtraction. + + If direction is not known then the increment and loop variable + are signed but the product of the loop count and increment may + not be representable as a signed value. + + We can't do the last addition or subtraction in C without + a conditional operation because the conversion of unsigned + to signed is undefined for "negative" values of the unsigned + number. For now we just pretend this isn't a problem. We + may fail on targets with signed overflow. + + For iterator loops we require that the difference type have + enough range and simply pass the value to operator+ or operator- + based on the static direction of the loop. Iterator loop case is + handled by the function passed in a function pointer, *ITER_HANDLER. + + LOOP_VAR has type COUNT_TYPE. */ + +tree +cilk_compute_loop_var (struct cilk_for_desc *cfd, tree loop_var, + tree lower_bound, + tree (*iter_handler) (location_t, enum tree_code, + tree, tree, tree)) +{ + tree count_type = NULL_TREE; + if (INTEGRAL_TYPE_P (TREE_TYPE (loop_var))) + count_type = TREE_TYPE (loop_var); + else + count_type = cfd->count_type; + + /* Compute an expression to be added or subtracted. + + We want to add or subtract LOOP_VAR * INCR. INCR may be negative. + If the static direction is indeterminate we don't know that at + compile time. The code to convert to unsigned and multiply does + the right thing in the end. For iterator loops we don't need to + go to that trouble, but scalar loops can have range that can not + be represented in the signed loop variable. */ + tree scaled = NULL_TREE, incr = NULL_TREE; + if (integer_onep (cfd->incr)) + scaled = loop_var; + else + { + incr = cilk_loop_convert (count_type, cfd->incr); + scaled = fold_build2 (MULT_EXPR, count_type, loop_var, incr); + } + + enum tree_code add_op = cfd->incr_sign >= 0 ? PLUS_EXPR : MINUS_EXPR; + if (cfd->iterator) + { + /* Convert LOOP_VAR to T3 (difference_type) so that + operator+(T1, T3) is preferred over operator+(T1, count_type) + operator+ constructs the object if it returns by value. + Use operator- if the user wrote -=. */ + if (count_type != cfd->difference_type) + loop_var = convert (cfd->difference_type, scaled); + tree low = lower_bound ? lower_bound : cfd->var; + if (TREE_CODE (low) == TREE_LIST) + low = TREE_VALUE (low); + tree exp = iter_handler (cfd->loc, add_op, low, loop_var, cfd->var2); + return exp; + } + /* The scaled count may not be representable in the type of the + loop variable, e.g. if the loop range is INT_MIN+1 to INT_MAX-1 + the range does not fit in a signed int. The sum of the lower + bound and the count is representable. Do the addition or + subtraction in the wider type, then narrow. */ + tree cvt_val = cilk_loop_convert (count_type, lower_bound); + tree adjusted = fold_build2 (add_op, count_type, cvt_val, scaled); + tree exp = fold_build2 (MODIFY_EXPR, void_type_node, cfd->var2, + cilk_loop_convert (cfd->var_type, adjusted)); + return exp; +} + +/* Remove NOP_EXPR, ADDR_EXPR and INDIRECT_REF wrappers from EXP and + return. */ + +tree +cilk_tree_operand_noconv (tree exp) +{ + tree op = exp; + while (TREE_CODE (op) == NOP_EXPR + || TREE_CODE (op) == ADDR_EXPR + || TREE_CODE (op) == INDIRECT_REF) + op = TREE_OPERAND (op, 0); + return op; +} + +/* Return the TREE_CODE for an overloaded function call, FN_CALL. */ + +enum tree_code +cilk_find_code_from_call (tree fn_call) +{ + /* Unwrap the ADDR_EXPR layer. */ + tree call = TREE_OPERAND (fn_call, 0); + call = DECL_NAME (call); + const char *name = IDENTIFIER_POINTER (call); + char op_name[2]; + op_name[1] = name[strlen (name) - 1]; + if (name [strlen (name) - 2] != 'r') + op_name[0] = name [strlen (name) - 2]; + else + op_name[0] = ' '; + + if (op_name[1] == '<') + return LT_EXPR; + else if (op_name[1] == '>') + return GT_EXPR; + else if (op_name[1] == '=') + { + if (op_name[0] == '<') + return LE_EXPR; + else if (op_name[0] == '>') + return GE_EXPR; + else if (op_name[0] == '!') + return NE_EXPR; + else if (op_name[0] == '=') + return EQ_EXPR; + else if (op_name[0] == '+') + return PLUS_EXPR; + else if (op_name[0] == '-') + return MINUS_EXPR; + else + gcc_unreachable (); + } + else if (op_name[1] == '+' && op_name[0] == '+') + /* This could be post or pre increment expression, but for our case + it really does not matter. */ + return POSTINCREMENT_EXPR; + else if (op_name[1] == '-' && op_name[0] == '-') + /* Same reasoning as above for decrement expression. */ + return POSTDECREMENT_EXPR; + else + gcc_unreachable (); + return NOP_EXPR; +} + +/* Extracts the initial value of the initalizer for a CILK_FOR_STMT. This + information is stored in CFD->LOWER_BOUND. */ + +void +cilk_set_init_info (struct cilk_for_desc *cfd) +{ + if (!cfd->lower_bound) + return; + else if (TREE_CODE (cfd->lower_bound) == MODIFY_EXPR + || TREE_CODE (cfd->lower_bound) == INIT_EXPR) + { + tree op0 = TREE_OPERAND (cfd->lower_bound, 0); + tree op1 = TREE_OPERAND (cfd->lower_bound, 1); + + gcc_assert (op0 == cfd->var); + cfd->lower_bound = op1; + } +} + +/* Sets the CFD->INCLUSIVE, CFD->END_EXPR and CFD->DIRECTION based on the + characteristics of the Cilk for statement. */ + +void +cilk_set_inclusive_and_direction (struct cilk_for_desc *cfd) +{ + tree cond = cfd->cond; + enum tree_code cond_code = TREE_CODE (cond); + if (cond_code == CALL_EXPR) + cond_code = cilk_find_code_from_call (CALL_EXPR_FN (cond)); + + switch (cond_code) + { + case NE_EXPR: + cfd->inclusive = false; + cfd->direction = 0; + break; + case GE_EXPR: + cfd->inclusive = true; + cfd->direction = -2; + break; + case GT_EXPR: + cfd->inclusive = false; + cfd->direction = -2; + break; + case LE_EXPR: + cfd->inclusive = true; + cfd->direction = 2; + break; + case LT_EXPR: + cfd->inclusive = false; + cfd->direction = 2; + break; + default: + /* == is not allowed. */ + gcc_unreachable (); + } + tree limit = NULL_TREE; + tree arg0, arg1; + + if (TREE_CODE (cond) == CALL_EXPR) + { + arg0 = CALL_EXPR_ARG (cond, 0); + arg1 = CALL_EXPR_ARG (cond, 1); + } + else + { + arg0 = TREE_OPERAND (cond, 0); + arg1 = TREE_OPERAND (cond, 1); + } + + if (cilk_tree_operand_noconv (arg0) == cfd->var) + limit = arg1; + else + { + /* If we are here, then we have a case like this: 10 > ii; */ + limit = arg0; + cfd->direction = -cfd->direction; + } + + cfd->end_expr = limit; +} + +/* Sets CFD->ITERATOR and CFD->DIFFERENCE_TYPE based on the characteristics of + the _Cilk_for statement. */ + +void +cilk_set_iter_difftype (struct cilk_for_desc *cfd) +{ + tree var_type = TREE_TYPE (cfd->var); + gcc_assert (var_type); + + switch (TREE_CODE (var_type)) + { + case POINTER_TYPE: + cfd->iterator = false; + cfd->difference_type = ptrdiff_type_node; + break; + case ENUMERAL_TYPE: + case BOOLEAN_TYPE: + case INTEGER_TYPE: + cfd->iterator = false; + cfd->difference_type = lang_hooks.types.type_promotes_to (var_type); + break; + case RECORD_TYPE: + case UNION_TYPE: + cfd->iterator = true; + cfd->difference_type = NULL; /* This will be set later for C++. */ + break; + default: + gcc_unreachable (); + } +} + +/* Populate CFD with characteristics of the increment expression. If + HANDLE_PTR_MULT is set, then increment is multiplied by the size of + pointer. This is necessary for C++ but not for C. */ + +void +cilk_set_incr_info (struct cilk_for_desc *cfd, bool handle_ptr_mult) +{ + int negate_incr = 0, incr_direction = 0; + + cfd->incr = cilk_simplify_tree (cfd->incr); + enum tree_code inc_op = TREE_CODE (cfd->incr); + bool is_incr = false; + tree op0, op1; + tree incr; + if (inc_op == ADDR_EXPR || inc_op == CALL_EXPR || inc_op == INDIRECT_REF) + /* This indicates that the increment operation is overloaded. */ + incr = cilk_tree_operand_noconv (cfd->incr); + else if (inc_op == TARGET_EXPR) + incr = TARGET_EXPR_INITIAL (cfd->incr); + else + incr = cfd->incr; + + if (TREE_CODE (incr) == CALL_EXPR) + { + inc_op = cilk_find_code_from_call (CALL_EXPR_FN (incr)); + if (inc_op == PLUS_EXPR || inc_op == MINUS_EXPR) + { + op1 = CALL_EXPR_ARG (incr, 1); + op0 = cilk_tree_operand_noconv (CALL_EXPR_ARG (incr, 0)); + inc_op = (inc_op == PLUS_EXPR ? PREINCREMENT_EXPR + : PREDECREMENT_EXPR); + } + else if (inc_op == POSTINCREMENT_EXPR || inc_op == POSTDECREMENT_EXPR + || inc_op == PREDECREMENT_EXPR || inc_op == PREINCREMENT_EXPR) + op1 = integer_one_node; + else + op1 = CALL_EXPR_ARG (incr, 0); + } + else + op1 = TREE_OPERAND (cfd->incr, 1); + + is_incr = (inc_op == PREINCREMENT_EXPR || inc_op == POSTINCREMENT_EXPR); + switch (inc_op) + { + case POSTDECREMENT_EXPR: + case PREDECREMENT_EXPR: + case PREINCREMENT_EXPR: + case POSTINCREMENT_EXPR: + negate_incr = is_incr ? false : true; + incr_direction = is_incr ? -1 : 1; + cfd->incr = op1; + if (!cfd->incr) + { + tree var_type = TREE_TYPE (cfd->var); + if (TREE_CODE (var_type) == POINTER_TYPE) + cfd->incr = size_in_bytes (TREE_TYPE (var_type)); + else + cfd->incr = integer_one_node; + } + cfd->exactly_one = integer_onep (cfd->incr); + break; + case MODIFY_EXPR: + { + /* In here the expressions will have the form var incr or + op = op incr. */ + cfd->incr = (TREE_CODE (cfd->incr) != MODIFY_EXPR ? op1 + : TREE_OPERAND (cfd->incr, 1)); + enum tree_code increment_code = TREE_CODE (cfd->incr); + if (increment_code == PLUS_EXPR || increment_code == POINTER_PLUS_EXPR) + { + op0 = TREE_OPERAND (cfd->incr, 0); + op1 = TREE_OPERAND (cfd->incr, 1); + + if (op0 == cfd->var || DECL_NAME (op0) == DECL_NAME (cfd->var)) + cfd->incr = op1; + else if (op1 == cfd->var || DECL_NAME (op1) == DECL_NAME (cfd->var)) + cfd->incr = op0; + else + gcc_unreachable (); + + negate_incr = false; + incr_direction = cilk_compute_incr_direction (cfd->incr); + + /* Adding a negative number treated as unsigned is like adding a + large positive number. */ + if (TYPE_UNSIGNED (cfd->difference_type) && incr_direction < 0) + incr_direction = 2; + cfd->exactly_one = (incr_direction == 1); + + /* Don't need to do this in POINTER_PLUS_EXPR since it already + does this for you. */ + if (handle_ptr_mult && increment_code != POINTER_PLUS_EXPR) + { + tree var_type = TREE_TYPE (cfd->var); + if (TREE_CODE (var_type) == POINTER_TYPE) + { + tree size = size_in_bytes (TREE_TYPE (var_type)); + if (!integer_onep (size)) + { + cfd->exactly_one = 0; + /* For example, in the following _Cilk_for statement: + _Cilk_for (int *p = a, p < b; p += (char)c) + We need to do the match in a type wider than c. + "build_binary_op" will do the default conversions + which should be enough if SIZE is size_t. */ + cfd->incr = build_binary_op (cfd->loc, MULT_EXPR, + cfd->incr, size, 0); + } + } + } + } + else if (TREE_CODE (cfd->incr) == MINUS_EXPR) + { + op1 = TREE_OPERAND (cfd->incr, 1); + op0 = TREE_OPERAND (cfd->incr, 0); + + gcc_assert (op0 == cfd->var + || DECL_NAME (op0) == DECL_NAME (cfd->var)); + cfd->incr = op1; + negate_incr = true; + incr_direction = -cilk_compute_incr_direction (cfd->incr); + + /* Subtracting a negative number is treated as adding a + positive. */ + if (TYPE_UNSIGNED (cfd->difference_type) && incr_direction > 0) + incr_direction = -2; + cfd->exactly_one = (incr_direction == -1); + + /* In C++ we need to handle the pointer arithmetic manually, but + in C it seem to automatically figure this out. */ + if (handle_ptr_mult) + { + tree var_type = TREE_TYPE (cfd->var); + if (TREE_CODE (var_type) == POINTER_TYPE) + { + tree size = size_in_bytes (TREE_TYPE (var_type)); + if (!integer_onep (size)) + { + cfd->exactly_one = 0; + /* For example, in the following _Cilk_for statement: + _Cilk_for (int *p = a, p < b; p += (char)c) + We need to do the match in a type wider than c. + "build_binary_op" will do the default conversions + which should be enough if SIZE is size_t. */ + cfd->incr = build_binary_op (cfd->loc, MULT_EXPR, + cfd->incr, size, 0); + } + } + } + } + else + { + location_t incr_loc = EXPR_LOCATION (cfd->incr); + error_at (incr_loc, "invalid loop increment operation"); + cfd->invalid = true; + return; + } + } + break; + default: + gcc_unreachable (); + } + cfd->var_type = TREE_TYPE (cfd->var); + cfd->incr_sign = negate_incr ? -1 : 1; +} + +/* Helper function for walk_tree. Fixes up all the continues inside a + _Cilk_for body. */ + +tree +cilk_resolve_continue_stmts (tree *tp, int *walk_subtrees, void *data) +{ + tree goto_label = NULL_TREE, goto_stmt = NULL_TREE; + if (!tp || !*tp) + return NULL_TREE; + + if (TREE_CODE (*tp) == CONTINUE_STMT) + { + goto_label = (tree) data; + goto_stmt = build1 (GOTO_EXPR, void_type_node, goto_label); + *tp = goto_stmt; + *walk_subtrees = 0; + } + else if (TREE_CODE (*tp) == FOR_STMT || TREE_CODE (*tp) == WHILE_STMT + || TREE_CODE (*tp) == DO_STMT || TREE_CODE (*tp) == CILK_FOR_STMT) + /* Inside these statements, the continue goes to a different place not + end of cilk_for. You do not want to go into these trees because we + will resolve those later. */ + *walk_subtrees = 0; + + return NULL_TREE; +} diff --git a/gcc/c/Make-lang.in b/gcc/c/Make-lang.in index d79fc4f..baa8af2 100644 --- a/gcc/c/Make-lang.in +++ b/gcc/c/Make-lang.in @@ -51,7 +51,7 @@ CFLAGS-c/gccspec.o += $(DRIVER_DEFINES) # Language-specific object files for C and Objective C. C_AND_OBJC_OBJS = attribs.o c/c-errors.o c/c-decl.o c/c-typeck.o \ c/c-convert.o c/c-aux-info.o c/c-objc-common.o c/c-parser.o \ - c/c-array-notation.o $(C_COMMON_OBJS) $(C_TARGET_OBJS) + c/c-array-notation.o c/c-cilk.o $(C_COMMON_OBJS) $(C_TARGET_OBJS) # Language-specific object files for C. C_OBJS = c/c-lang.o c-family/stub-objc.o $(C_AND_OBJC_OBJS) diff --git a/gcc/c/c-cilk.c b/gcc/c/c-cilk.c new file mode 100755 index 0000000..982b0de --- /dev/null +++ b/gcc/c/c-cilk.c @@ -0,0 +1,359 @@ +/* This file is part of the Intel (R) Cilk (TM) Plus support + This file contains the functions required to handle _Cilk_for + for the C language. + Copyright (C) 2013 Free Software Foundation, Inc. + Contributed by Balaji V. Iyer , + Intel Corporation + +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 "tree.h" +#include "c-tree.h" +#include "langhooks.h" +#include "gimple.h" +#include "tree-iterator.h" +#include "tree-inline.h" +#include "c-family/c-common.h" +#include "toplev.h" +#include "cgraph.h" +#include "diagnostic.h" +#include "cilk.h" +#include "gimplify.h" + +/* Get a block for the CILK_FOR_STMT, CFOR. */ + +static tree +block_cilk_for_loop (tree cfor) +{ + tree block = tree_block (cfor); + if (block) + return block; + return DECL_INITIAL (current_function_decl); +} + +/* Create or discover the variable to be used in the loop termination + condition. Return true if the cfd->end_var should be used in the + guard test around the runtime call. Otherwise the guard test uses + the complex expression, which in C++ may initialize the variable. + + For example, if END_EXPR is + + (target_expr limit (call constructor ...)) + + the variable limit is not initialized until the target_expr is + evaluated. */ + +static bool +cilk_for_end (struct cilk_for_desc *cfd, gimple_seq *pre_p) +{ + tree end = cfd->end_expr; + if (TREE_SIDE_EFFECTS (end)) + { + enum tree_code ecode = TREE_CODE (end); + if (ecode == INIT_EXPR || ecode == MODIFY_EXPR || ecode == TARGET_EXPR) + { + cfd->end_var = TREE_OPERAND (end, 0); + return false; + } + else + { + /* Copy the result of evaluating the expression into a variable. + The compiler will probably crash if there's anything + complicated in it -- a complicated value needs to go through + the other branch of this IF using an explicit temporary. */ + cfd->end_var = get_formal_tmp_var (end, pre_p); + return true; + } + } + cfd->end_var = end; + return false; +} + +/* Handler for iterator to compute the loop variable. LOW indicates the + starting point and LOOP_VAR is the induction variable, and VAR2 is the + original induction variable in the Cilk_for. Returns an expression + (or a STATEMENT_LIST of expressions). */ + +static tree +compute_loop_var_c_iter_hdl (location_t loc, enum tree_code add_op, tree low, + tree loop_var, tree var2) +{ + tree exp = fold_build2 (add_op, TREE_TYPE (loop_var), low, loop_var); + gcc_assert (exp != error_mark_node); + + exp = build_modify_expr (loc, var2, TREE_TYPE (var2), INIT_EXPR, loc, exp, + TREE_TYPE (exp)); + gcc_assert (exp != error_mark_node); + return exp; +} + + +/* Creates a body of the _Cilk_for wrapper function with the information + in *CFD. */ + +static tree +create_cilk_for_body (struct cilk_for_desc *cfd) +{ + declare_cilk_for_parms (cfd); + cfd->wd.fntype = build_function_type (void_type_node, cfd->wd.argtypes); + tree fndecl = cilk_create_cilk_helper_decl (&cfd->wd); + + tree outer = current_function_decl; + push_struct_function (fndecl); + current_function_decl = fndecl; + + declare_cilk_for_vars (cfd, fndecl); + + tree body = push_stmt_list (); + tree mod_expr = NULL_TREE, loop_var = NULL_TREE; + tree lower_bound = cfd->lower_bound; + if (!lower_bound) + { + lower_bound = cfd->var; + tree hack = build_decl (EXPR_LOCATION (cfd->var), VAR_DECL, NULL_TREE, + TREE_TYPE (lower_bound)); + DECL_CONTEXT (hack) = DECL_CONTEXT (lower_bound); + DECL_NAME (hack) = DECL_NAME (lower_bound); + *pointer_map_insert (cfd->wd.decl_map, hack) = lower_bound; + lower_bound = hack; + } + if (INTEGRAL_TYPE_P (cfd->var_type)) + { + tree new_min_parm = fold_build1 (CONVERT_EXPR, cfd->var_type, + cfd->min_parm); + loop_var = create_tmp_var (cfd->var_type, NULL); + location_t loc = EXPR_LOCATION (cfd->var); + mod_expr = build_modify_expr (loc, loop_var, cfd->var_type, NOP_EXPR, + loc, new_min_parm, cfd->var_type); + } + else + { + loop_var = create_tmp_var (TREE_TYPE (cfd->min_parm), NULL); + mod_expr = fold_build2 (INIT_EXPR, void_type_node, loop_var, + cfd->min_parm); + } + add_stmt (mod_expr); + tree loop_body = NULL_TREE; + tree new_max_parm = NULL_TREE; + + if (!INTEGRAL_TYPE_P (cfd->var_type)) + new_max_parm = cfd->max_parm; + else + new_max_parm = fold_build1 (CONVERT_EXPR, cfd->var_type, cfd->max_parm); + + tree end_comp = cilk_compute_loop_var (cfd, loop_var, lower_bound, + compute_loop_var_c_iter_hdl); + append_to_statement_list (end_comp, &loop_body); + append_to_statement_list (cfd->body, &loop_body); + loop_body = fold_build_cleanup_point_expr (void_type_node, loop_body); + DECL_SEEN_IN_BIND_EXPR_P (cfd->var2) = 1; + + cilk_outline_body (fndecl, &loop_body, &cfd->wd, NULL); + + tree loop = push_stmt_list (); + /* Now create a loop with c_finish_loop. */ + tree incr = fold_build2 (PLUS_EXPR, TREE_TYPE (loop_var), loop_var, + build_one_cst (TREE_TYPE (loop_var))); + incr = fold_build2 (MODIFY_EXPR, void_type_node, loop_var, incr); + tree cond = fold_build2 (LT_EXPR, boolean_type_node, loop_var, new_max_parm); + c_finish_loop (EXPR_LOCATION (cfd->var), cond, incr, loop_body, NULL_TREE, + NULL_TREE, false); + loop = pop_stmt_list (loop); + add_stmt (loop); + body = pop_stmt_list (body); + + tree block = DECL_INITIAL (fndecl); + BLOCK_VARS (block) = loop_var; + body = build3 (BIND_EXPR, void_type_node, loop_var, body, block); + TREE_CHAIN (loop_var) = cfd->var2; + if (cilk_detect_spawn_and_unwrap (&body)) + lang_hooks.cilkplus.install_body_with_frame_cleanup (fndecl, body); + else + DECL_SAVED_TREE (fndecl) = body; + + pop_cfun (); + current_function_decl = outer; + return fndecl; +} + +/* Creates a wrapper function for the body of a _Cilk_for statement with the + information stored in *CFD. */ + +static tree +create_cilk_for_wrapper (struct cilk_for_desc *cfd) +{ + tree old_cfd = current_function_decl; + tree incr = cfd->incr; + tree var = cfd->var; + + if (POINTER_TYPE_P (TREE_TYPE (var))) + cilk_extract_free_variables (cfd->lower_bound, &cfd->wd, ADD_WRITE); + else + cilk_extract_free_variables (cfd->lower_bound, &cfd->wd, ADD_READ); + + cilk_extract_free_variables (incr, &cfd->wd, ADD_READ); + + /* Map the loop variable to integer_minus_one_node if we won't really + be passing it to the loop body and integer_zero_node otherwise. + + If the map ends up integer_one_node then somebody wrote to the loop + variable and that's a user error. + The correct map will be installed in declare_for_loop_variables. */ + *pointer_map_insert (cfd->wd.decl_map, var) = + (void *) (cfd->lower_bound ? integer_minus_one_node : integer_zero_node); + + /* Note that variables are not extracted from the loop condition + and increment. They are evaluated, to the extent they are + evaluated, in the context containing the for loop. */ + cilk_extract_free_variables (cfd->body, &cfd->wd, ADD_READ); + + tree fn = create_cilk_for_body (cfd); + DECL_UNINLINABLE (fn) = 1; + current_function_decl = old_cfd; + set_cfun (DECL_STRUCT_FUNCTION (current_function_decl)); + cfun->is_cilk_function = 1; + + /* Add the new function to the cgraph list. */ + cilk_call_graph_add_fn (fn); + return fn; +} + +/* Helper function for gimplify_cilk_for. *CFD contains all the relevant + information extracted from a _Cilk_for statement passed into the parent + function gimplify_cilk_for. */ + +void +gimplify_cilk_for_1 (struct cilk_for_desc *cfd, gimple_seq *pre_p) +{ + /* We don't have to evaluate INCR only once, but we do have + to evaluate it no more times than in the serial loop. + The naive method evaluates INCR exactly that many times + except if the static loop direction is indeterminate. + + Storing the increment in a variable is thus mandatory + if cfd.direction == 0. It is an optimization otherwise + and there seems no harm and some benefit in doing it. + + The evaluation is on the inner statement list. The + increment can not be referenced prior to the loop test. */ + if (TREE_SIDE_EFFECTS (cfd->incr)) + sorry ("_Cilk_for increment with side effects"); + + tree cond = cfd->cond; + tree op0 = TREE_OPERAND (cond, 0); + tree op1 = TREE_OPERAND (cond, 1); + if (!cilk_for_end (cfd, pre_p) && cfd->end_var != cfd->end_expr) + { + if (op1 == cfd->end_expr) + op1 = cfd->end_var; + else + op0 = cfd->end_var; + } + cond = fold_build2 (TREE_CODE (cond), boolean_type_node, op0, op1); + + tree forward = NULL_TREE; + + /* This is set to NOP_EXPR to have an initial value since we are passing in + an address to the function below. */ + enum tree_code div_op = NOP_EXPR; + + cilk_calc_forward_div_op (cfd, &div_op, &forward); + + tree count = cilk_compute_loop_count (cfd, div_op, forward, NULL_TREE, + NULL_TREE); + tree fn = create_cilk_for_wrapper (cfd); + + /* Set condition correctly, so that the function below can use it. */ + cfd->cond = cond; + gimple_seq inner_seq = insert_cilk_for_nested_fn (cfd, count, fn); + gimple_seq_add_seq (pre_p, inner_seq); +} + +/* Extracts all the relevant information from CFOR, a CILK_FOR_STMT tree and + stores them in CFD structure. */ + +static void +c_extract_cilk_for_fields (struct cilk_for_desc *cfd, tree cfor) +{ + cfd->var = CILK_FOR_VAR (cfor); + cfd->cond = CILK_FOR_COND (cfor); + cfd->lower_bound = CILK_FOR_INIT (cfor); + cfd->incr = CILK_FOR_EXPR (cfor); + cfd->loc = EXPR_LOCATION (cfor); + cfd->body = CILK_FOR_BODY (cfor); + cfd->grain = CILK_FOR_GRAIN (cfor); + cfd->invalid = false; + + /* This function shouldn't be setting these two variables. */ + cfd->ctx_arg = NULL_TREE; + cfd->count = NULL_TREE; + + if (TREE_CODE (cfd->lower_bound) == MODIFY_EXPR + || TREE_CODE (cfd->lower_bound) == INIT_EXPR) + { + tree op0 = TREE_OPERAND (cfd->lower_bound, 0); + tree op1 = TREE_OPERAND (cfd->lower_bound, 1); + + gcc_assert (op0 == cfd->var); + cfd->lower_bound = op1; + } + + cilk_set_inclusive_and_direction (cfd); + cilk_set_iter_difftype (cfd); + + /* Difference type cannot be NULL_TREE here for C. */ + cfd->count_type = cilk_check_loop_difference_type (cfd->difference_type); + if (cfd->count_type == NULL_TREE) + { + cfd->invalid = true; + return; + } + + cilk_set_incr_info (cfd, false); +} + +/* Main entry-point function to gimplify a cilk_for statement. *EXPR_P should + be a CILK_FOR_STMT tree. */ + +int +c_gimplify_cilk_for (tree *expr_p, gimple_seq *pre_p, + gimple_seq *post_p ATTRIBUTE_UNUSED) +{ + struct cilk_for_desc cfd; + tree cfor_expr = *expr_p; + + cfun->is_cilk_function = 1; + cilk_init_cfd (&cfd); + cfd.wd.block = block_cilk_for_loop (cfor_expr); + + c_extract_cilk_for_fields (&cfd, cfor_expr); + + *expr_p = NULL_TREE; + if (cfd.invalid) + return GS_ERROR; + + tree var = CILK_FOR_VAR (cfor_expr); + tree init = CILK_FOR_INIT (cfor_expr); + tree init_expr = fold_build2 (MODIFY_EXPR, void_type_node, var, init); + + gimplify_and_add (init_expr, pre_p); + gimplify_cilk_for_1 (&cfd, pre_p); + return GS_ALL_DONE; +} diff --git a/gcc/c/c-objc-common.h b/gcc/c/c-objc-common.h index 6ae7b3e..ca7fa4a 100644 --- a/gcc/c/c-objc-common.h +++ b/gcc/c/c-objc-common.h @@ -114,4 +114,7 @@ along with GCC; see the file COPYING3. If not see #undef LANG_HOOKS_CILKPLUS_DETECT_SPAWN_AND_UNWRAP #define LANG_HOOKS_CILKPLUS_DETECT_SPAWN_AND_UNWRAP \ cilk_detect_spawn_and_unwrap + +#undef LANG_HOOKS_CILKPLUS_GIMPLIFY_CILK_FOR +#define LANG_HOOKS_CILKPLUS_GIMPLIFY_CILK_FOR c_gimplify_cilk_for #endif /* GCC_C_OBJC_COMMON */ diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 6f03402..b7fb11a 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1165,6 +1165,8 @@ static void c_parser_switch_statement (c_parser *); static void c_parser_while_statement (c_parser *, bool); static void c_parser_do_statement (c_parser *, bool); static void c_parser_for_statement (c_parser *, bool); +static void c_parser_cilk_for_statement (c_parser *, tree); +static void c_parser_cilk_grainsize (c_parser *parser); static tree c_parser_asm_statement (c_parser *); static tree c_parser_asm_operands (c_parser *); static tree c_parser_asm_goto_operands (c_parser *); @@ -4771,6 +4773,12 @@ c_parser_statement_after_labels (c_parser *parser) case RID_FOR: c_parser_for_statement (parser, false); break; + case RID_CILK_FOR: + if (!flag_enable_cilkplus) + error_at (loc, "-fcilkplus must be enabled to use %<_Cilk_for%>"); + else + c_parser_cilk_for_statement (parser, NULL_TREE); + break; case RID_CILK_SYNC: c_parser_consume_token (parser); c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); @@ -9381,6 +9389,24 @@ c_parser_pragma (c_parser *parser, enum pragma_context context) c_parser_cilk_simd (parser); return false; + case PRAGMA_CILK_GRAINSIZE: + if (!flag_enable_cilkplus) + { + warning (0, "%<#pragma grainsize%> ignored because -fcilkplus is not" + " enabled"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + } + if (context == pragma_external) + { + error_at (c_parser_peek_token (parser)->location, + "%<#pragma grainsize%> must be inside a function"); + c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); + return false; + } + c_parser_cilk_grainsize (parser); + return false; + default: if (id < PRAGMA_FIRST_EXTERNAL) { @@ -13558,6 +13584,174 @@ c_parser_cilk_all_clauses (c_parser *parser) return c_finish_cilk_clauses (clauses); } +/* Parses a _Cilk_for statement. + + GRAIN is used to pass the Grain value from <#pragma cilk grainsize>. If + this field is NULL then runtime will find an appropriate grain size + (highly recommended!). */ + +static void +c_parser_cilk_for_statement (c_parser *parser, tree grain) +{ + tree init, decl, stmt; + tree body; + bool fail = false; + + if (!c_parser_next_token_is_keyword (parser, RID_CILK_FOR)) + { + c_parser_error (parser, "_Cilk_for statement expected"); + return; + } + + c_parser_consume_token (parser); + location_t loc = c_parser_peek_token (parser)->location; + + tree block = c_begin_compound_stmt (true); + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + add_stmt (c_end_compound_stmt (loc, block, true)); + return; + } + + /* Parse the initialization declaration. */ + if (c_parser_next_tokens_start_declaration (parser)) + { + vec none_clauses = vNULL; + c_token eof_token; + memset (&eof_token, 0, sizeof (eof_token)); + eof_token.type = CPP_EOF; + none_clauses.safe_push (eof_token); + none_clauses.safe_push (eof_token); + c_parser_declaration_or_fndef (parser, true, false, false, + false, false, NULL, none_clauses); + decl = check_for_loop_decls (loc, flag_isoc99); + if (decl == NULL) + goto error_init; + if (DECL_INITIAL (decl) == error_mark_node) + decl = error_mark_node; + init = decl; + } + else if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_EQ) + { + struct c_expr decl_exp; + struct c_expr init_exp; + location_t init_loc; + + decl_exp = c_parser_postfix_expression (parser); + decl = decl_exp.value; + + c_parser_require (parser, CPP_EQ, "expected %<=%>"); + + init_loc = c_parser_peek_token (parser)->location; + init_exp = c_parser_expr_no_commas (parser, NULL); + init_exp = default_function_array_read_conversion (init_loc, + init_exp); + init = build_modify_expr (init_loc, decl, decl_exp.original_type, + NOP_EXPR, init_loc, init_exp.value, + init_exp.original_type); + init = c_process_expr_stmt (init_loc, init); + + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + } + else + { + error_init: + c_parser_error (parser, "expected induction variable initialization"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return; + } + + /* Parse the loop condition. */ + tree cond = NULL_TREE; + if (c_parser_next_token_is_not (parser, CPP_SEMICOLON)) + { + location_t cond_loc = c_parser_peek_token (parser)->location; + struct c_expr cond_expr = c_parser_binary_expression (parser, NULL, NULL); + + cond = cond_expr.value; + cond = c_objc_common_truthvalue_conversion (cond_loc, cond); + cond = c_fully_fold (cond, false, NULL); + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + + /* Parse the increment expression. */ + tree incr = NULL_TREE; + if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) + { + location_t incr_loc = c_parser_peek_token (parser)->location; + incr = c_process_expr_stmt (incr_loc, + c_parser_expression (parser).value); + } + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (decl == NULL || decl == error_mark_node || init == error_mark_node) + fail = true; + + tree save_break = c_break_label; + /* Magic number to inform c_finish_bc_stmt() that we are within a + Cilk for construct. */ + c_break_label = build_int_cst (size_type_node, 2); + + tree save_cont = c_cont_label; + c_cont_label = NULL_TREE; + body = c_parser_c99_block_statement (parser); + c_break_label = save_break; + c_cont_label = save_cont; + + if (!fail) + c_finish_cilk_for_loop (loc, decl, init, cond, incr, body, grain, false, + false); + + stmt = c_end_compound_stmt (loc, block, true); + add_stmt (stmt); + c_break_label = save_break; + c_cont_label = save_cont; +} + +/* This function helps parse the grainsize pragma for a _Cilk_for statement. + Here is the correct syntax of this pragma: + #pragma cilk grainsize = + */ + +static void +c_parser_cilk_grainsize (c_parser *parser) +{ + extern tree convert_to_integer (tree, tree); + + c_parser_consume_pragma (parser); + + if (c_parser_require (parser, CPP_EQ, "expected %<=%>") != 0) + { + struct c_expr g_expr = c_parser_binary_expression (parser, NULL, NULL); + if (g_expr.value && TREE_CODE (g_expr.value) == C_MAYBE_CONST_EXPR) + { + error_at (input_location, "cannot convert grain to long integer.\n"); + c_parser_skip_to_pragma_eol (parser); + } + else if (g_expr.value && g_expr.value != error_mark_node) + { + c_parser_skip_to_pragma_eol (parser); + c_token *token = c_parser_peek_token (parser); + if (token && token->type == CPP_KEYWORD + && token->keyword == RID_CILK_FOR) + { + tree grain = convert_to_integer (long_integer_type_node, + g_expr.value); + if (grain && grain != error_mark_node) + c_parser_cilk_for_statement (parser, grain); + } + else + warning (0, "grainsize pragma is not followed by %<_Cilk_for%>"); + } + else + c_parser_skip_to_pragma_eol (parser); + } + else + c_parser_skip_to_pragma_eol (parser); +} + /* Main entry point for parsing Cilk Plus <#pragma simd> for loops. */ diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index c4dfc3b..55f2a7a 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -684,4 +684,7 @@ extern tree c_check_omp_declare_reduction_r (tree *, int *, void *); extern void pedwarn_c90 (location_t, int opt, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4); extern void pedwarn_c99 (location_t, int opt, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4); +/* In c-cilk.c */ +extern int c_gimplify_cilk_for (tree *, gimple_seq *, gimple_seq *); + #endif /* ! GCC_C_TREE_H */ diff --git a/gcc/cilk-builtins.def b/gcc/cilk-builtins.def index 8634194..a279a93 100644 --- a/gcc/cilk-builtins.def +++ b/gcc/cilk-builtins.def @@ -31,3 +31,5 @@ DEF_CILK_BUILTIN_STUB (BUILT_IN_CILK_SYNC, "__cilkrts_sync") DEF_CILK_BUILTIN_STUB (BUILT_IN_CILK_LEAVE_FRAME, "__cilkrts_leave_frame") DEF_CILK_BUILTIN_STUB (BUILT_IN_CILK_POP_FRAME, "__cilkrts_pop_frame") DEF_CILK_BUILTIN_STUB (BUILT_IN_CILK_SAVE_FP, "__cilkrts_save_fp_ctrl_state") +DEF_CILK_BUILTIN_STUB (BUILT_IN_CILK_FOR_32, "__cilkrts_cilk_for_32") +DEF_CILK_BUILTIN_STUB (BUILT_IN_CILK_FOR_64, "__cilkrts_cilk_for_64") \ No newline at end of file diff --git a/gcc/cilk-common.c b/gcc/cilk-common.c index 8e070a3..c5308f4 100644 --- a/gcc/cilk-common.c +++ b/gcc/cilk-common.c @@ -70,7 +70,6 @@ cilk_arrow (tree frame_ptr, int field_number, bool volatil) field_number, volatil); } - /* This function will add FIELD of type TYPE to a defined built-in structure. *NAME is the name of the field to be added. */ @@ -105,6 +104,27 @@ install_builtin (const char *name, tree fntype, enum built_in_function code, return fndecl; } +/* Returns a FUNCTION_DECL of type TYPE whose name is *NAME. */ + +static tree +cilk_declare_looper (const char *name, tree type, enum built_in_function code) +{ + tree cb, ft, fn; + + cb = build_function_type_list (void_type_node, + ptr_type_node, type, type, + NULL_TREE); + cb = build_pointer_type (cb); + ft = build_function_type_list (void_type_node, + cb, ptr_type_node, type, + integer_type_node, NULL_TREE); + fn = install_builtin (name, ft, code, false); + TREE_NOTHROW (fn) = 0; + + return fn; +} + + /* Creates and initializes all the built-in Cilk keywords functions and three structures: __cilkrts_stack_frame, __cilkrts_pedigree and __cilkrts_worker. Detailed information about __cilkrts_stack_frame and @@ -268,6 +288,17 @@ cilk_init_builtins (void) cilk_save_fp_fndecl = install_builtin ("__cilkrts_save_fp_ctrl_state", fptr_fun, BUILT_IN_CILK_SAVE_FP, false); + + /* __cilkrts_cilk_for_32 (...); */ + cilk_for_32_fndecl = cilk_declare_looper ("__cilkrts_cilk_for_32", + unsigned_intSI_type_node, + BUILT_IN_CILK_FOR_32); + + + /* __cilkrts_cilk_for_64 (...); */ + cilk_for_64_fndecl = cilk_declare_looper ("__cilkrts_cilk_for_64", + unsigned_intDI_type_node, + BUILT_IN_CILK_FOR_64); } /* Get the appropriate frame arguments for CALL that is of type CALL_EXPR. */ diff --git a/gcc/cilk.h b/gcc/cilk.h index 99b4d78..acdfb9c 100644 --- a/gcc/cilk.h +++ b/gcc/cilk.h @@ -40,6 +40,8 @@ enum cilk_tree_index { CILK_TI_F_POP, /* __cilkrts_pop_frame (...). */ CILK_TI_F_RETHROW, /* __cilkrts_rethrow (...). */ CILK_TI_F_SAVE_FP, /* __cilkrts_save_fp_ctrl_state (...). */ + CILK_TI_F_LOOP_32, /* __cilkrts_cilk_for_32 (...). */ + CILK_TI_F_LOOP_64, /* __cilkrts_cilk_for_64 (...). */ /* __cilkrts_stack_frame struct fields. */ CILK_TI_FRAME_FLAGS, /* stack_frame->flags. */ CILK_TI_FRAME_PARENT, /* stack_frame->parent. */ @@ -65,6 +67,140 @@ enum cilk_tree_index { CILK_TI_MAX }; +enum add_variable_type { + /* Reference to previously-defined variable. */ + ADD_READ, + /* Definition of a new variable in inner-scope. */ + ADD_BIND, + /* Write to possibly previously-defined variable. */ + ADD_WRITE +}; + +enum cilk_block_type { + /* Indicates a _Cilk_spawn block. 30 was an arbitary number picked for + ease of debugging. */ + CILK_BLOCK_SPAWN = 30, + /* Indicates _Cilk_for statement block. */ + CILK_BLOCK_FOR +}; + +struct wrapper_data +{ + /* Kind of function to be created. */ + enum cilk_block_type type; + /* Signature of helper function. */ + tree fntype; + /* Containing function. */ + tree context; + /* Disposition of all variables in the inner statement. */ + struct pointer_map_t *decl_map; + /* True if this function needs a static chain. */ + bool nested; + /* Arguments to be passed to wrapper function, currently a list. */ + tree arglist; + /* Argument types, a list. */ + tree argtypes; + /* Incoming parameters. */ + tree parms; + /* Outer BLOCK object. */ + tree block; +}; + +/* This structure holds all the important information necessary for decomposing + a cilk_for statement. */ + +struct cilk_for_desc +{ + /* Location of the _Cilk_for statement. */ + location_t loc; + + /* Information about the wrapper/nested function for _Cilk_for. */ + struct wrapper_data wd; + + /* Does the loop body trigger undefined behavior at runtime? */ + bool invalid; + + /* Indicates if the parent function is a nested function (C++ only). */ + bool nested_ok; + + /* Is the loop control variable a RECORD_TYPE? */ + bool iterator; + + /* Does the loop range include its upper bound? */ + bool inclusive; + + /* Does the loop control variable, after converting pointer to + machine address and taking into account sizeof pointed to + type, increment or decrement by (plus or minus) one? */ + bool exactly_one; + + /* Is the increment stored in this structure to be added (+1) + or subtracted (-1)? */ + signed char incr_sign; + + /* Direction is +/-1 if the increment is known to be exactly one + in the user-visible units, +/-2 if the sign is known but the + value is not known to be one, and zero if the sign is not known + at compile time. */ + signed char direction; + + /* Loop upper bound. END_EXPR is the tree for the loop bound. + END_VAR is either END_EXPR or a VAR_DECL holding the stabilized + value, if computation of the value has side effects. */ + tree end_expr, end_var; + + /* The originally-declared loop control variable. */ + tree var; + + /* Lower bound of the loop if it is constant enough. + With a constant lower bound the loop body may not + need to use the static chain to compute the iterator + value. */ + tree lower_bound; + + /* Several types: + + The declared type of the loop control variable, + T1 in the cilk_for spec. + + The type of the loop count and argument to loop body, currently + always unsigned long. (If pointers are wider, we will need a + pointer-sized type.) + + The static type of end, T2 in the cilk_for spec. + + The difference type T3 of T1-T1, which is the same as T1 for + integral types. The difference type may not be wider than the + count type. For integers subtraction is done in count_type + in case difference_type can't hold the range. + + If integral, the type of the increment is known to be no wider + than var_type otherwise the truncation in + VAR = (shorter)((longer)VAR + INCR) + would have been rejected. */ + tree var_type, count_type, difference_type; + tree incr; + tree cond; + /* The originally-declared body of the loop. */ + tree body; + + /* Grainsize set by the user. */ + tree grain; + + /* Context argument to generated function, if not (fdesc fn 1). */ + tree ctx_arg; + + /* The number of loop iterations, in case the generated function + needs to know. */ + tree count; + + /* Variables of the generated function. */ + tree ctx_parm, min_parm, max_parm; + + /* Copy of the induction variable, but at different function context. */ + tree var2; +}; + extern GTY (()) tree cilk_trees[CILK_TI_MAX]; #define cilk_worker_fndecl cilk_trees[CILK_TI_F_WORKER] @@ -77,6 +213,8 @@ extern GTY (()) tree cilk_trees[CILK_TI_MAX]; #define cilk_rethrow_fndecl cilk_trees[CILK_TI_F_RETHROW] #define cilk_pop_fndecl cilk_trees[CILK_TI_F_POP] #define cilk_save_fp_fndecl cilk_trees[CILK_TI_F_SAVE_FP] +#define cilk_for_32_fndecl cilk_trees[CILK_TI_F_LOOP_32] +#define cilk_for_64_fndecl cilk_trees[CILK_TI_F_LOOP_64] #define cilk_worker_type_fndecl cilk_trees[CILK_TI_WORKER_TYPE] #define cilk_frame_type_decl cilk_trees[CILK_TI_FRAME_TYPE] @@ -90,6 +228,7 @@ extern tree cilk_dot (tree, int, bool); extern void cilk_init_builtins (void); extern void gimplify_cilk_sync (tree *, gimple_seq *); extern tree cilk_call_setjmp (tree); + /* Returns true if Cilk Plus is enabled and if F->cilk_frame_decl is not NULL_TREE. */ diff --git a/gcc/gimplify.c b/gcc/gimplify.c index bb50e25..f8b2b9b 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -7246,6 +7246,11 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, } break; + case CILK_FOR_STMT: + ret = (enum gimplify_status) + lang_hooks.cilkplus.gimplify_cilk_for (expr_p, pre_p, post_p); + break; + case CILK_SPAWN_STMT: gcc_assert (fn_contains_cilk_spawn_p (cfun) diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h index 411cf74..e9c46b2 100644 --- a/gcc/langhooks-def.h +++ b/gcc/langhooks-def.h @@ -219,11 +219,13 @@ extern bool lhd_cilk_detect_spawn (tree *); #define LANG_HOOKS_CILKPLUS_DETECT_SPAWN_AND_UNWRAP lhd_cilk_detect_spawn #define LANG_HOOKS_CILKPLUS_FRAME_CLEANUP lhd_install_body_with_frame_cleanup #define LANG_HOOKS_CILKPLUS_GIMPLIFY_SPAWN lhd_gimplify_expr +#define LANG_HOOKS_CILKPLUS_GIMPLIFY_CILK_FOR lhd_gimplify_expr #define LANG_HOOKS_CILKPLUS { \ LANG_HOOKS_CILKPLUS_DETECT_SPAWN_AND_UNWRAP, \ LANG_HOOKS_CILKPLUS_FRAME_CLEANUP, \ - LANG_HOOKS_CILKPLUS_GIMPLIFY_SPAWN \ + LANG_HOOKS_CILKPLUS_GIMPLIFY_SPAWN, \ + LANG_HOOKS_CILKPLUS_GIMPLIFY_CILK_FOR \ } #define LANG_HOOKS_DECLS { \ diff --git a/gcc/langhooks.h b/gcc/langhooks.h index 9539e7d..fe8e440 100644 --- a/gcc/langhooks.h +++ b/gcc/langhooks.h @@ -154,6 +154,11 @@ struct lang_hooks_for_cilkplus status, but as mentioned in a previous comment, we can't see that type here, so just return an int. */ int (*gimplify_cilk_spawn) (tree *, gimple_seq *, gimple_seq *); + + /* Function to gimplify a _Cilk_for statement. Returns enum gimplify + status, but as mentioned in a previous comment, we can't see that type + here, so just return an int. */ + int (*gimplify_cilk_for) (tree *, gimple_seq *, gimple_seq *); }; /* Language hooks related to decls and the symbol table. */ diff --git a/gcc/testsuite/gcc.dg/cilk-plus/CK/cilk-for.c b/gcc/testsuite/gcc.dg/cilk-plus/CK/cilk-for.c new file mode 100644 index 0000000..caab055 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/CK/cilk-for.c @@ -0,0 +1,34 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + +int main(int argc, char **argv) +{ + char Array1[26], Array2[26]; + char Array1_Serial[26], Array2_Serial[26]; + + int ii = 0, error = 0; + for (ii = 0; ii < 26; ii++) + { + Array1[ii] = 'A'+ii; + Array1_Serial[ii] = 'A'+ii; + } + for (ii = 0; ii < 26; ii++) + { + Array2[ii] = 'a'+ii; + Array2_Serial[ii] = 'a'+ii; + } + ii = 0; + _Cilk_for (ii = 0 ; ii < 26; ii++) + Array1[ii] = Array2[ii]; + + for (ii = 0; ii < 26; ii++) + Array1_Serial[ii] = Array2_Serial[ii]; + + for (ii = 0; ii < 26; ii++) { + if (Array1_Serial[ii] != Array1[ii]) { + error = 1; + } + } + return error; +} diff --git a/gcc/testsuite/gcc.dg/cilk-plus/CK/cilk_for_decr.c b/gcc/testsuite/gcc.dg/cilk-plus/CK/cilk_for_decr.c new file mode 100644 index 0000000..e45b557 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/CK/cilk_for_decr.c @@ -0,0 +1,44 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus -w" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + +#define ARRAY_SIZE 1000 + +int a[ARRAY_SIZE]; + +int main(void) +{ + int i= 0; + + for (i = 0; i < ARRAY_SIZE; i++) + a[i] = 0; + + _Cilk_for (i = (ARRAY_SIZE-1); i >= 0; i--) + a[i] = i; + + for (i = 0; i < ARRAY_SIZE; i++) + if (a[i] != i) + return 1; + + for (i = 0; i < ARRAY_SIZE; i++) + a[i] = 0; + + _Cilk_for (i = (ARRAY_SIZE-1); i >= 0; i -= 1) + a[i] = i; + + for (i = 0; i < ARRAY_SIZE; i++) + if (a[i] != i) + return 1; + + for (i = 0; i < ARRAY_SIZE; i++) + a[i] = 0; + + _Cilk_for (i = (ARRAY_SIZE-1); i >= 0; --i) + a[i] = i; + + for (i = 0; i < ARRAY_SIZE; i++) + if (a[i] != i) + return 1; + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/cilk-plus/CK/cilk_for_errors.c b/gcc/testsuite/gcc.dg/cilk-plus/CK/cilk_for_errors.c new file mode 100644 index 0000000..c6d6656 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/CK/cilk_for_errors.c @@ -0,0 +1,61 @@ +struct foo +{ + int x,y,z; + char q; +}; + +int main (void) +{ + int q = 0, ii = 0, jj = 0; + volatile int vii = 0; + static int sii = 0; + register int rii = 0; + extern int eii; + struct foo something, nothing; + float fii = 0; + _Cilk_for (ii; ii < 10; ii++) /* { dg-error " expected induction variable initialization" } */ + q = 5; + + _Cilk_for (; ii < 10; ii++) /* { dg-error "expected induction variable initialization" } */ + q = 2; + + _Cilk_for (ii = 0; ; ii++) /* { dg-error "missing condition" } */ + q = 2; + + _Cilk_for (ii = 0; ii < 10, jj < 10; ii++) /* { dg-error "expected ';' before ',' token" } */ + q = 5; + + _Cilk_for (ii = 0; ii < 10; ) /* { dg-error "missing increment" } */ + q = 5; + + _Cilk_for (ii = 0, jj = 0; ii < 10; ii++) /* { dg-error "expected ';' before ',' token" } */ + q = 5; + + _Cilk_for (vii = 0; vii < 10; vii++) /* { dg-error "iteration variable cannot be volatile" } */ + q = 5; + + _Cilk_for (sii = 0; sii < 10; sii++) /* { dg-error "induction variable cannot be static" } */ + q = 5; + + _Cilk_for (rii = 0; rii < 10; rii++) /* { dg-error "induction variable cannot be declared register" } */ + q = 5; + + _Cilk_for (something = nothing; ii < 10; ii++) /* { dg-error "induction variable must be of integral or" } */ + q = 5; + + _Cilk_for (fii = 3.47; fii < 5.23; ii++) /* { dg-error "induction variable must be of integral or pointer type" } */ + q = 5; + + _Cilk_for (ii = 0; 10 > jj; ii++) /* { dg-error "invalid controlling predicate" } */ + q = 5; + + _Cilk_for (ii = 0; ii < 10; ii >> 1) /* { dg-error "invalid increment expression" } */ + q = 5; + + _Cilk_for (ii = 10; ii >= 0; ii--) /* This is OK! */ + q = 5; + + _Cilk_for (ii; ii < 10; ii++) /* { dg-error "expected induction variable initialization" } */ + q = 5; + return 0; +} diff --git a/gcc/testsuite/gcc.dg/cilk-plus/CK/cilk_for_grain.c b/gcc/testsuite/gcc.dg/cilk-plus/CK/cilk_for_grain.c new file mode 100644 index 0000000..4c86bf6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/CK/cilk_for_grain.c @@ -0,0 +1,34 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus -w" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + +int grain_value = 2; +int main (void) +{ + int Array1[200], Array1_Serial[200]; + int ii = 0; + + for (ii = 0; ii < 200; ii++) + { + Array1_Serial[ii] = 2; + Array1[ii] = 1; + } + +#pragma cilk grainsize = 2 + _Cilk_for (ii = 0; ii < 200; ii++) + Array1[ii] = 2; + + for (ii = 0; ii < 200; ii++) + if (Array1[ii] != Array1_Serial[ii]) + return (ii+1); + +#pragma cilk grainsize = grain_value + _Cilk_for (ii = 0; ii < 200; ii++) + Array1[ii] = 2; + + for (ii = 0; ii < 200; ii++) + if (Array1[ii] != Array1_Serial[ii]) + return (ii+1); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/cilk-plus/CK/cilk_for_grain_errors.c b/gcc/testsuite/gcc.dg/cilk-plus/CK/cilk_for_grain_errors.c new file mode 100644 index 0000000..36d75df --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/CK/cilk_for_grain_errors.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-options "-Wall -fcilkplus" } */ +char Array1[26]; + +#pragma cilk grainsize = 2 /* { dg-error "must be inside a function" } */ + +int main(int argc, char **argv) +{ + int ii = 0; + +/* This is OK. */ +#pragma cilk grainsize = 2 + _Cilk_for (ii = 0; ii < 10; ii++) + Array1[ii] = 0; + +#pragma cilk grainsize 2 /* { dg-error "expected '=' before numeric constant" } */ + _Cilk_for (ii = 0; ii < 10; ii++) + Array1[ii] = 0; + +#pragma cilk grainsiz = 2 /* { dg-warning "ignoring #pragma cilk grainsiz" } */ + _Cilk_for (ii = 0; ii < 10; ii++) + Array1[ii] = 0; + + +/* This is OK, it will do a type conversion to long int. */ +#pragma cilk grainsize = 0.5 + _Cilk_for (ii = 0; ii < 10; ii++) + Array1[ii] = 0; + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/cilk-plus/CK/cilk_for_ptr_iter.c b/gcc/testsuite/gcc.dg/cilk-plus/CK/cilk_for_ptr_iter.c new file mode 100644 index 0000000..8eec6be --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/CK/cilk_for_ptr_iter.c @@ -0,0 +1,28 @@ +/* { dg-do run { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-options "-fcilkplus -w" } */ +/* { dg-options "-lcilkrts" { target { i?86-*-* x86_64-*-* } } } */ + +/* loop control variable must have integer, pointer or class type + +*/ + +#define ARRAY_SIZE 10000 +int a[ARRAY_SIZE]; + +int main(void) +{ + int *aa = 0; + int ii = 0; + + for (ii =0; ii < ARRAY_SIZE; ii++) + a[ii] = 5; + + _Cilk_for(aa = a; aa < a + ARRAY_SIZE; aa++) + *aa = 0; + + for (ii = 0; ii < ARRAY_SIZE; ii++) + if (a[ii] != 0) + return 1; + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/cilk-plus/CK/cilk_for_warning.c b/gcc/testsuite/gcc.dg/cilk-plus/CK/cilk_for_warning.c new file mode 100644 index 0000000..f39eb7b --- /dev/null +++ b/gcc/testsuite/gcc.dg/cilk-plus/CK/cilk_for_warning.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +int main (void) +{ + int ii = 0, q = 2; + _Cilk_for (ii = 0; ii < 10; ii++) /* { dg-warning "loop body modifies control variable" } */ + ii += q; + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp b/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp index 7407e8e..edab8eb 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp +++ b/gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp @@ -60,5 +60,12 @@ if { [check_effective_target_lto] } { dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O3 -flto -g -fcilkplus $ALWAYS_CFLAGS" " " } - +dg-runtest [lsort [glob -nocomplain $srcdir/gcc.dg/cilk-plus/CK/*.c]] " -g -fcilkplus $ALWAYS_CFLAGS " " " +dg-runtest [lsort [glob -nocomplain $srcdir/gcc.dg/cilk-plus/CK/*.c]] " -O1 -fcilkplus $ALWAYS_CFLAGS" " " +dg-runtest [lsort [glob -nocomplain $srcdir/gcc.dg/cilk-plus/CK/*.c]] " -O2 -std=c99 -fcilkplus $ALWAYS_CFLAGS" " " +dg-runtest [lsort [glob -nocomplain $srcdir/gcc.dg/cilk-plus/CK/*.c]] " -O2 -ftree-vectorize -fcilkplus $ALWAYS_CFLAGS" " " +dg-runtest [lsort [glob -nocomplain $srcdir/gcc.dg/cilk-plus/CK/*.c]] " -O3 -g -fcilkplus $ALWAYS_CFLAGS" " " +if { [check_effective_target_lto] } { +dg-runtest [lsort [glob -nocomplain $srcdir/gcc.dg/cilk-plus/CK/*.c]] " -O3 -flto -g -fcilkplus $ALWAYS_CFLAGS" " " +} dg-finish diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 7fe849d..de2a24b 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -2661,6 +2661,29 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, pp_string (buffer, "_Cilk_sync"); break; + case CILK_FOR_STMT: + if (CILK_FOR_GRAIN (node)) + { + pp_string (buffer, "#pragma cilk grainsize = "); + dump_generic_node (buffer, CILK_FOR_GRAIN (node), spc, flags, false); + newline_and_indent (buffer, spc); + } + pp_string (buffer, "_Cilk_for ("); + dump_generic_node (buffer, CILK_FOR_INIT (node), spc, flags, false); + pp_string (buffer, "; "); + dump_generic_node (buffer, CILK_FOR_COND (node), spc, flags, false); + pp_string (buffer, "; "); + dump_generic_node (buffer, CILK_FOR_EXPR (node), spc, flags, false); + pp_string (buffer, ")"); + newline_and_indent (buffer, spc + 2); + pp_left_brace (buffer); + newline_and_indent (buffer, spc + 4); + dump_generic_node (buffer, CILK_FOR_BODY (node), spc + 4, flags, false); + newline_and_indent (buffer, spc + 2); + pp_right_brace (buffer); + is_expr = false; + break; + default: NIY; } diff --git a/gcc/tree.def b/gcc/tree.def index 8eecba7..9c0bfe2 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -1285,6 +1285,16 @@ DEFTREECODE (CILK_SPAWN_STMT, "cilk_spawn_stmt", tcc_statement, 1) /* Cilk Sync statement: Does not have any operands. */ DEFTREECODE (CILK_SYNC_STMT, "cilk_sync_stmt", tcc_statement, 0) +/* Cilk for statement + Operand 0 is the initializer. + Operand 1 is the loop terminating condition. + Operand 2 is the increment/decrement expression. + Operand 3 is the loop-body. + Operand 4 is the scope. + Operand 5 is the induction variable. + Operand 6 is the grain that is passed in through a pragma. */ +DEFTREECODE (CILK_FOR_STMT, "cilk_for_stmt", tcc_statement, 7) + /* Local variables: mode:c diff --git a/gcc/tree.h b/gcc/tree.h index e58b3a5..000a448 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -804,6 +804,15 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, /* Cilk keywords accessors. */ #define CILK_SPAWN_FN(NODE) TREE_OPERAND (CILK_SPAWN_STMT_CHECK (NODE), 0) +/* CILK_FOR_STMT accessors. */ +#define CILK_FOR_INIT(NODE) TREE_OPERAND (CILK_FOR_STMT_CHECK (NODE), 0) +#define CILK_FOR_COND(NODE) TREE_OPERAND (CILK_FOR_STMT_CHECK (NODE), 1) +#define CILK_FOR_EXPR(NODE) TREE_OPERAND (CILK_FOR_STMT_CHECK (NODE), 2) +#define CILK_FOR_BODY(NODE) TREE_OPERAND (CILK_FOR_STMT_CHECK (NODE), 3) +#define CILK_FOR_SCOPE(NODE) TREE_OPERAND (CILK_FOR_STMT_CHECK (NODE), 4) +#define CILK_FOR_VAR(NODE) TREE_OPERAND (CILK_FOR_STMT_CHECK (NODE), 5) +#define CILK_FOR_GRAIN(NODE) TREE_OPERAND (CILK_FOR_STMT_CHECK (NODE), 6) + /* In a RESULT_DECL, PARM_DECL and VAR_DECL, means that it is passed by invisible reference (and the TREE_TYPE is a pointer to the true type). */