From patchwork Mon Jun 10 20:21:02 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: 250350 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 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "localhost", Issuer "www.qmailtoaster.com" (not verified)) by ozlabs.org (Postfix) with ESMTPS id 7A8D72C0095 for ; Tue, 11 Jun 2013 06:21:48 +1000 (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:content-type:mime-version; q=dns; s=default; b=RLsDYzXHZSzYSwgyipMSUgcQWO3STisWRmmccwvMKpxth/eADT 2J8uRoy9cUppw2z2T7Uk+WlQfHC04v4QABH7hSbWTtVXY+HZJzVY5j03Xi8TjwQW u+8PWkKRguQguXe0qLmg9Lf96Xtdxx2su/ZSJXIJXM0izWEJoYi77ivVQ= 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:content-type:mime-version; s= default; bh=23W58aQ3n5qqyYf2m7zkSZ6372c=; b=ZnXknNybaBOFJoiZSiAn F4MTuW8vGJ8o+62tJfJMdv11bkN0tJ86/PLWz9bHedPLHtl1+YeJUQvXrhRTV29M xFEl3B2M6VDrWQnDDp0I1a38SsKzMYsGS+HrNDvHNe0UUiTZJowWcEFcf9lWLPmy nI3N0B4NEI57WsERERGAz7Y= Received: (qmail 11757 invoked by alias); 10 Jun 2013 20:21:38 -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 11703 invoked by uid 89); 10 Jun 2013 20:21:31 -0000 X-Spam-SWARE-Status: No, score=-4.9 required=5.0 tests=AWL, BAYES_50, RCVD_IN_HOSTKARMA_W, RCVD_IN_HOSTKARMA_WL, RP_MATCHES_RCVD, SPF_PASS, TW_BJ, TW_FN, TW_JC, TW_TM autolearn=no version=3.3.1 Received: from mga01.intel.com (HELO mga01.intel.com) (192.55.52.88) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Mon, 10 Jun 2013 20:21:22 +0000 Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga101.fm.intel.com with ESMTP; 10 Jun 2013 13:21:04 -0700 X-ExtLoop1: 1 Received: from fmsmsx106.amr.corp.intel.com ([10.19.9.37]) by fmsmga002.fm.intel.com with ESMTP; 10 Jun 2013 13:21:03 -0700 Received: from fmsmsx101.amr.corp.intel.com ([169.254.1.135]) by FMSMSX106.amr.corp.intel.com ([169.254.6.10]) with mapi id 14.03.0123.003; Mon, 10 Jun 2013 13:21:03 -0700 From: "Iyer, Balaji V" To: "gcc-patches@gcc.gnu.org" CC: "Jason Merrill (jason@redhat.com)" , "rth@redhat.com" , "Aldy Hernandez (aldyh@redhat.com)" Subject: [PATCH] Cilk Plus Array Notation for C++ Date: Mon, 10 Jun 2013 20:21:02 +0000 Message-ID: MIME-Version: 1.0 Hello Everyone, Attached, please find a patch that will implement Cilk Plus Array Notation for C++. This patch is a follow-up of the Array notation for C patch (i.e. there are several helper functions that are shared between the two). I have tested this on x86 and x86_64 and it seem to work OK and pass all the regression tests. The patch does not affect the status (i.e. PASS or FAIL) of any other tests. Here are the ChangeLog entries: gcc/cp/ChangeLog 2013-06-10 Balaji V. Iyer * call.c (convert_like_real): Added a check if array notation is present in expression. If so, then no conversion of arguments is necessary. (build_over_call): Likewise. * typeck.c (cp_build_function_call_vec): Likewise. (convert_for_assignment): Likewise. (cp_build_array_ref): Reject array notations with a rank greater than 1 as an array's index. (cp_build_binary_op): If array notations are preent in op, then call find_correct_array_notation_type. (cp_build_addr_expr_1): Handle ARRAY_NOTATION_REF similar to ARRAY_REF. * cp-array-notation.c: New file. * cp-objcp-common.c (cp_common_init_ts): Marked ARRAY_NOTATION_REF tree as typed. * cp-tree.h (fix_array_notation_exprs): New prototype. * semantics.c (finish_return_stmt): Reject array notations as return value. (cxx_eval_constant_expression): Added ARRAY_NOTATION_REF case. (potential_constant_expression_1): Likewise. * tree.c (lvalue_kind): Likewise. * error.c (dump_decl): Likewise. (dump_expr): Likewise. * pt.c (ARRAY_NOTATION_REF): Likewise. (type_unification_real): Do not unify any arguments if array notations are found in arg. (instantiate_decl): Added a check for array notaitons inside the function body. If so, then expand them. * parser.c (cp_parser_array_notation): New function. (cp_parser_postfix_open_square_expression): Added a check for colons inside square braces. If found, then handle the array access as an array notation access. Also, disable auto-correction from a single colon to scope when Cilk Plus is enabled. (cp_parser_compound_statement): Added a check for array notations inside the statement. If found, then expand them. (cp_parser_ctor_initializer_opt_and_function_body): Likewise. (cp_parser_function_definition_after_declarator): Likewise. (cp_parser_selection_statement): Searched for array notations inside condition. If so, then emit an error. (cp_parser_iteration_statement): Likewise. (cp_parser_direct_declarator): Reject array notations inside a variable or array declaration. * Make-lang.in (CXX_AND_OBJCXX_OBJS): Added cp/cp-array-notation.o. gcc/testsuite/ChangeLog 2013-06-10 Balaji V. Iyer * c-c++-common/cilk-plus/AN/array_test1.c: Make this an execution test. Also changed the returns from error as distinct values so that debugging can get easier. * c-c++-common/cilk-plus/AN/if_test_errors.c (main): Made certain errors specific to C, if necessary. Also added new error hooks for C++. * c-c++-common/cilk-plus/AN/misc.c (main): Likewise. * c-c++-common/cilk-plus/AN/parser_errors.c (main): Likewise. * c-c++-common/cilk-plus/AN/parser_errors2.c (main): Likewise. * c-c++-common/cilk-plus/AN/parser_errors3.c (main): Likewise. * c-c++-common/cilk-plus/AN/pr57541.c (main): Likewise. * c-c++-common/cilk-plus/AN/parser_errors4.c (main): In addition to the same changes as parser_errors3.c, spaces were added between colons to not confuse C++ compiler with 2 colons as scope. * c-c++-common/cilk-plus/AN/sec_implicit_ex.c (main): Removed the usage of abort and exit and replaced them with return 1 and return 0. * c-c++-common/cilk-plus/AN/vla.c: Make this test C specific. * g++.dg/cilk-plus/AN/array_test1_tplt.cc: New test. * g++.dg/cilk-plus/AN/array_test2_tplt.cc: Likewise. * g++.dg/cilk-plus/AN/array_test_ND_tplt.cc: Likewise. * g++.dg/cilk-plus/AN/braced_list.cc: Likewise. * g++.dg/cilk-plus/AN/builtin_fn_custom_tplt.cc: Likewise. * g++.dg/cilk-plus/AN/builtin_fn_mutating_tplt.cc: Likewise. * g++.dg/cilk-plus/AN/fp_triplet_values_tplt.c: Likewise. * g++.dg/cilk-plus/cilk-plus.exp: New script. * g++.dg/dg.exp: Included Cilk Plus C++ tests in the list. Thanks, Balaji V. Iyer. diff --git gcc/cp/ChangeLog gcc/cp/ChangeLog old mode 100644 new mode 100755 index c0977c3d..4ecae05 Binary files gcc/cp/ChangeLog and gcc/cp/ChangeLog differ diff --git gcc/cp/Make-lang.in gcc/cp/Make-lang.in index df8ed3e..6e80bcf 100644 --- gcc/cp/Make-lang.in +++ gcc/cp/Make-lang.in @@ -80,7 +80,7 @@ CXX_AND_OBJCXX_OBJS = cp/call.o cp/decl.o cp/expr.o cp/pt.o cp/typeck2.o \ cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o \ cp/search.o cp/semantics.o cp/tree.o cp/repo.o cp/dump.o cp/optimize.o \ cp/mangle.o cp/cp-objcp-common.o cp/name-lookup.o cp/cxx-pretty-print.o \ - cp/cp-gimplify.o $(CXX_C_OBJS) + cp/cp-gimplify.o cp/cp-array-notation.o $(CXX_C_OBJS) # Language-specific object files for C++. CXX_OBJS = cp/cp-lang.o c-family/stub-objc.o $(CXX_AND_OBJCXX_OBJS) @@ -266,6 +266,9 @@ CXX_PRETTY_PRINT_H = cp/cxx-pretty-print.h $(C_PRETTY_PRINT_H) cp/lex.o: cp/lex.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) \ $(C_PRAGMA_H) input.h cp/operators.def $(TM_P_H) \ c-family/c-objc.h +cp/cp-array-notation.o: cp/cp-array-notation.c $(CONFIG_H) $(SYSTEM_H) \ + coretypes.h $(TREE_H) $(CXX_TREE_H) $(DIAGNOSTIC_H) tree-iterator.h vec.h \ + $(GIMPLE_H) c-family/array-notation-common.o $(C_COMMON_H) cp/cp-lang.o: cp/cp-lang.c $(CXX_TREE_H) $(TM_H) debug.h langhooks.h \ $(LANGHOOKS_DEF_H) $(C_COMMON_H) gtype-cp.h gt-cp-cp-lang.h \ cp/cp-objcp-common.h $(EXPR_H) $(TARGET_H) $(CXX_PARSER_H) diff --git gcc/cp/call.c gcc/cp/call.c index dfd061a..a3d7d2d 100644 --- gcc/cp/call.c +++ gcc/cp/call.c @@ -5858,9 +5858,15 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, break; } - if (permerror (loc, "invalid conversion from %qT to %qT", - TREE_TYPE (expr), totype) - && fn) + if (flag_enable_cilkplus + && (contains_array_notation_expr (expr) + || contains_array_notation_expr (fn))) + /* If we are using array notations, we fix them up at a later stage + and we will do these checks then. */ + ; + else if (permerror (loc, "invalid conversion from %qT to %qT", + TREE_TYPE (expr), totype) + && fn) inform (DECL_SOURCE_LOCATION (fn), "initializing argument %P of %qD", argnum, fn); @@ -6890,12 +6896,21 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) } } - val = convert_like_with_context (conv, arg, fn, i-is_method, - conversion_warning - ? complain - : complain & (~tf_warning)); + /* If the function call is builtin array notation function then we do not + need to do any type conversion. */ + if (flag_enable_cilkplus && fn && TREE_CODE (fn) == FUNCTION_DECL + && DECL_NAME (fn) && IDENTIFIER_POINTER (DECL_NAME (fn)) + && !strncmp (IDENTIFIER_POINTER (DECL_NAME (fn)), "__sec_reduce", 12)) + val = arg; + else + { + val = convert_like_with_context (conv, arg, fn, i-is_method, + conversion_warning + ? complain + : complain & (~tf_warning)); - val = convert_for_arg_passing (type, val, complain); + val = convert_for_arg_passing (type, val, complain); + } if (val == error_mark_node) return error_mark_node; else diff --git gcc/cp/cp-array-notation.c gcc/cp/cp-array-notation.c new file mode 100755 index 0000000..e8a5a51 --- /dev/null +++ gcc/cp/cp-array-notation.c @@ -0,0 +1,2844 @@ +/* This file is part of the Intel(R) Cilk(TM) Plus support + It contains routines to handle Array Notation expression + handling routines in the C++ Compiler. + 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 + . */ + +/* The Array Notation Transformation Technique: + + An array notation expression has 4 major components: + 1. The array name + 2. Start Index + 3. Number of elements we need to acess (we call it length) + 4. Stride + + So, if we have something like A[0:5:2], we are accessing A[0], A[2], A[4], + A[6] and A[8]. The user is responsible to make sure the access length does + not step outside the array's size. + + In this section, I highlight the overall method on how array notations are + broken up into C/C++ code. Almost all the functions follows this step: + + Let's say the user has used the array notation in a statement like this: + + A[St1:Ln:Str1] = B[St2:Ln:Str2] + + + where St{1,2} = Starting index, Ln = Number of elements we need to access, + and Str{1,2} = the stride. + Note: The length of both the array notation expressions must be the same. + + The above expression is broken into the following: + + for (Tmp_Var = 0; Tmp_Var < Ln; Tmp_Var++) + A[St1 + Tmp_Var * Str1] = B[St1 + Tmp_Var * Str2] + ; +*/ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "cp-tree.h" +#include "c-family/c-common.h" +#include "diagnostic.h" +#include "tree-iterator.h" +#include "vec.h" +#include "gimple.h" + + +/* Creates a FOR_STMT with INIT, COND, INCR and BODY as the initializer, + condition, increment expression and the loop-body, respectively. */ + +static void +create_an_loop (tree init, tree cond, tree incr, tree body) +{ + tree for_stmt; + + finish_expr_stmt (init); + for_stmt = begin_for_stmt (NULL_TREE, NULL_TREE); + finish_for_init_stmt (for_stmt); + finish_for_cond (cond, for_stmt); + finish_for_expr (incr, for_stmt); + finish_expr_stmt (body); + finish_for_stmt (for_stmt); +} + +/* Replaces all the scalar expressions in *NODE. Returns a STATEMENT LIST that + holds the NODE along with the variables that hold the results of the + invariant expressions. */ + +static tree +replace_invariant_exprs (tree *node) +{ + size_t ix = 0; + tree node_list = NULL_TREE; + tree t = NULL_TREE, new_var = NULL_TREE, new_node; + struct inv_list data; + + data.list_values = NULL; + data.replacement = NULL; + data.additional_tcodes = NULL; + cp_walk_tree (node, find_inv_trees, (void *) &data, NULL); + + if (vec_safe_length (data.list_values)) + { + node_list = push_stmt_list (); + for (ix = 0; vec_safe_iterate (data.list_values, ix, &t); ix++) + { + if (processing_template_decl || !TREE_TYPE (t)) + new_var = build_min_nt_loc (EXPR_LOCATION (t), VAR_DECL, NULL_TREE, + NULL_TREE); + else + new_var = build_decl (EXPR_LOCATION (t), VAR_DECL, NULL_TREE, + TREE_TYPE (t)); + gcc_assert (new_var != NULL_TREE && new_var != error_mark_node); + new_node = build_x_modify_expr (EXPR_LOCATION (t), new_var, NOP_EXPR, + t, tf_warning_or_error); + finish_expr_stmt (new_node); + vec_safe_push (data.replacement, new_var); + } + cp_walk_tree (node, replace_inv_trees, (void *) &data, NULL); + node_list = pop_stmt_list (node_list); + } + return node_list; +} + +/* Returns true of NODE has a call_expression with ARRAY_NOTATION_REF tree. */ + +static bool +has_call_expr_with_array_notation (tree node) +{ + int ii = 0; + + if (!contains_array_notation_expr (node)) + return false; + + if (TREE_CODE (node) == ARRAY_NOTATION_REF) + return false; + else if (TREE_CODE (node) == DECL_EXPR) + { + tree x = DECL_EXPR_DECL (node); + if (x && TREE_CODE (x) != FUNCTION_DECL) + if (DECL_INITIAL (x)) + return has_call_expr_with_array_notation (DECL_INITIAL (x)); + + } + else if (TREE_CODE (node) == STATEMENT_LIST) + { + tree_stmt_iterator ii_tsi; + for (ii_tsi = tsi_start (node); !tsi_end_p (ii_tsi); tsi_next (&ii_tsi)) + return has_call_expr_with_array_notation (*tsi_stmt_ptr (ii_tsi)); + } + else if (TREE_CODE (node) == CALL_EXPR) + { + if (is_cilkplus_reduce_builtin (CALL_EXPR_FN (node)) != BUILT_IN_NONE) + return true; + + if (is_sec_implicit_index_fn (CALL_EXPR_FN (node))) + return true; + + if (TREE_CODE (TREE_OPERAND (node, 0)) == INTEGER_CST) + { + int length = TREE_INT_CST_LOW (TREE_OPERAND (node, 0)); + bool x = false; + for (ii = 0; ii < length; ii++) + x |= contains_array_notation_expr (TREE_OPERAND (node, ii)); + return x; + } + else + gcc_unreachable (); + } + else + { + bool x = false; + for (ii = 0; ii < TREE_CODE_LENGTH (TREE_CODE (node)); ii++) + x |= has_call_expr_with_array_notation (TREE_OPERAND (node, ii)); + return x; + } + return false; +} + +/* Replace array notation's built-in function passed in AN_BUILTIN_FN with + the appropriate loop and computation (all stored in variable LOOP of type + tree node). The output of the function function is always a scalar and that + result is returned in *NEW_VAR. *NEW_VAR is NULL_TREE if the function is + __sec_reduce_mutating. */ + +static tree +fix_builtin_array_notation_fn (tree an_builtin_fn, tree *new_var) +{ + tree new_var_type = NULL_TREE, func_parm, new_expr, new_yes_expr, new_no_expr; + tree array_ind_value = NULL_TREE, new_no_ind, new_yes_ind, new_no_list; + tree new_yes_list, new_cond_expr; + tree new_var_init = NULL_TREE, new_exp_init = NULL_TREE; + vec *array_list = NULL, *array_operand = NULL; + int s_jj = 0; + size_t list_size = 0, rank = 0, ii = 0, jj = 0; + tree **array_ops, *array_var, jj_tree; + tree **array_value, **array_stride, **array_length, **array_start; + tree body, an_init, loop_with_init = alloc_stmt_list (); + tree *compare_expr, array_op0, *expr_incr, *ind_init, comp_node; + tree call_fn = NULL_TREE, identity_value = NULL_TREE, new_call_expr; + bool **count_down, **array_vector; + tree begin_var, lngth_var, strde_var; + location_t location = UNKNOWN_LOCATION; + tsubst_flags_t complain = tf_warning_or_error; + + enum built_in_function an_type = + is_cilkplus_reduce_builtin (CALL_EXPR_FN (an_builtin_fn)); + + if (an_type == BUILT_IN_NONE) + return NULL_TREE; + + if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE + && an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING) + func_parm = CALL_EXPR_ARG (an_builtin_fn, 0); + else + { + call_fn = CALL_EXPR_ARG (an_builtin_fn, 2); + + /* We need to do this because we are "faking" the builtin function types, + so the compiler does a bunch of typecasts and this will get rid of + all that! */ + while (TREE_CODE (call_fn) == CONVERT_EXPR + || TREE_CODE (call_fn) == NOP_EXPR) + call_fn = TREE_OPERAND (call_fn, 0); + + if (TREE_CODE (call_fn) != OVERLOAD + && TREE_CODE (call_fn) != FUNCTION_DECL) + call_fn = TREE_OPERAND (call_fn, 0); + identity_value = CALL_EXPR_ARG (an_builtin_fn, 0); + func_parm = CALL_EXPR_ARG (an_builtin_fn, 1); + + /* We need to do this because we are "faking" the builtin function types + so the compiler does a bunch of typecasts and this will get rid of + all that! */ + while (TREE_CODE (identity_value) == CONVERT_EXPR + || TREE_CODE (identity_value) == NOP_EXPR) + identity_value = TREE_OPERAND (identity_value, 0); + } + + while (TREE_CODE (func_parm) == CONVERT_EXPR + || TREE_CODE (func_parm) == NOP_EXPR) + func_parm = TREE_OPERAND (func_parm, 0); + + location = EXPR_LOCATION (an_builtin_fn); + if (!find_rank (location, an_builtin_fn, an_builtin_fn, true, &rank)) + return error_mark_node; + if (rank == 0) + return an_builtin_fn; + else if (rank > 1 + && (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND + || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)) + { + error_at (location, "__sec_reduce_min_ind or __sec_reduce_max_ind cannot " + "have arrays with dimension greater than 1"); + return error_mark_node; + } + + extract_array_notation_exprs (func_parm, true, &array_list); + list_size = vec_safe_length (array_list); + switch (an_type) + { + case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD: + case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL: + case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX: + case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN: + new_var_type = TREE_TYPE ((*array_list)[0]); + break; + case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO: + case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO: + case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO: + case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO: + new_var_type = integer_type_node; + break; + case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND: + case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND: + new_var_type = size_type_node; + break; + case BUILT_IN_CILKPLUS_SEC_REDUCE: + if (call_fn && identity_value) + new_var_type = TREE_TYPE ((*array_list)[0]); + break; + case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING: + new_var_type = NULL_TREE; + break; + default: + gcc_unreachable (); + } + + if (new_var_type && TREE_CODE (new_var_type) == ARRAY_TYPE) + new_var_type = TREE_TYPE (new_var_type); + + array_ops = XNEWVEC (tree *, list_size); + for (ii = 0; ii < list_size; ii++) + array_ops[ii] = XNEWVEC (tree, rank); + + array_vector = XNEWVEC (bool *, list_size); + for (ii = 0; ii < list_size; ii++) + array_vector[ii] = XNEWVEC (bool, rank); + + array_value = XNEWVEC (tree *, list_size); + array_stride = XNEWVEC (tree *, list_size); + array_length = XNEWVEC (tree *, list_size); + array_start = XNEWVEC (tree *, list_size); + + for (ii = 0; ii < list_size; ii++) + { + array_value[ii] = XNEWVEC (tree, rank); + array_stride[ii] = XNEWVEC (tree, rank); + array_length[ii] = XNEWVEC (tree, rank); + array_start[ii] = XNEWVEC (tree, rank); + } + + compare_expr = XNEWVEC (tree, rank); + expr_incr = XNEWVEC (tree, rank); + ind_init = XNEWVEC (tree, rank); + + count_down = XNEWVEC (bool *, list_size); + for (ii = 0; ii < list_size; ii++) + count_down[ii] = XNEWVEC (bool, rank); + + array_var = XNEWVEC (tree, rank); + an_init = push_stmt_list (); + + /* Assign the array notation components to variable so that they can satisfy + the exec-once rule. */ + for (ii = 0; ii < list_size; ii++) + { + tree array_node = (*array_list)[ii]; + tree array_begin = ARRAY_NOTATION_START (array_node); + tree array_lngth = ARRAY_NOTATION_LENGTH (array_node); + tree array_strde = ARRAY_NOTATION_STRIDE (array_node); + if (array_node && TREE_CODE (array_node) == ARRAY_NOTATION_REF) + { + if (TREE_CODE (array_begin) != INTEGER_CST) + { + begin_var = build_decl (location, VAR_DECL, NULL_TREE, + integer_type_node); + finish_expr_stmt (build_x_modify_expr (location, begin_var, + NOP_EXPR, array_begin, + complain)); + ARRAY_NOTATION_START (array_node) = begin_var; + } + if (TREE_CODE (array_lngth) != INTEGER_CST) + { + lngth_var = build_decl (location, VAR_DECL, NULL_TREE, + integer_type_node); + finish_expr_stmt (build_x_modify_expr (location, lngth_var, + NOP_EXPR, array_lngth, + complain)); + ARRAY_NOTATION_LENGTH (array_node) = lngth_var; + } + if (TREE_CODE (array_strde) != INTEGER_CST) + { + strde_var = build_decl (location, VAR_DECL, NULL_TREE, + integer_type_node); + finish_expr_stmt (build_x_modify_expr (location, strde_var, + NOP_EXPR, array_strde, + complain)); + ARRAY_NOTATION_STRIDE (array_node) = strde_var; + } + } + } + for (ii = 0; ii < list_size; ii++) + { + jj = 0; + jj_tree = (*array_list)[ii]; + while (jj_tree) + { + if (TREE_CODE (jj_tree) == ARRAY_NOTATION_REF) + { + array_ops[ii][jj] = jj_tree; + jj++; + jj_tree = ARRAY_NOTATION_ARRAY (jj_tree); + } + else if (TREE_CODE (jj_tree) == ARRAY_REF) + jj_tree = TREE_OPERAND (jj_tree, 0); + else if (TREE_CODE (jj_tree) == VAR_DECL + || TREE_CODE (jj_tree) == PARM_DECL) + break; + } + } + + for (ii = 0; ii < list_size; ii++) + { + if (TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF) + for (jj = 0; jj < rank; jj++) + { + if (TREE_CODE (array_ops[ii][jj]) == ARRAY_NOTATION_REF) + { + array_value[ii][jj] = + ARRAY_NOTATION_ARRAY (array_ops[ii][jj]); + array_start[ii][jj] = + ARRAY_NOTATION_START (array_ops[ii][jj]); + array_length[ii][jj] = + fold_build1 (CONVERT_EXPR, integer_type_node, + ARRAY_NOTATION_LENGTH (array_ops[ii][jj])); + array_stride[ii][jj] = + ARRAY_NOTATION_STRIDE (array_ops[ii][jj]); + array_vector[ii][jj] = true; + + if (!TREE_CONSTANT (array_length[ii][jj]) + || TREE_CODE (array_length[ii][jj]) != INTEGER_TYPE) + count_down[ii][jj] = false; + else if (tree_int_cst_sgn (array_length[ii][jj]) == -1) + count_down[ii][jj] = true; + else + count_down[ii][jj] = false; + } + else + array_vector[ii][jj] = false; + } + } + + for (ii = 0; ii < rank; ii++) + { + array_var[ii] = build_decl (location, VAR_DECL, NULL_TREE, + TREE_TYPE (array_start[0][ii])); + ind_init[ii] = build_x_modify_expr + (location, array_var[ii], NOP_EXPR, + build_zero_cst (TREE_TYPE (array_var[ii])), tf_warning_or_error); + } + for (ii = 0; ii < list_size; ii++) + if (array_vector[ii][0]) + { + tree array_opr = array_value[ii][rank - 1]; + for (s_jj = rank - 1; s_jj >= 0; s_jj--) + { + tree stride = NULL_TREE, var = NULL_TREE, start = NULL_TREE; + + /* If stride and start are of same type and the induction var + is not, we convert induction variable to stride's type. */ + if ((TREE_TYPE (array_start[ii][s_jj]) == + TREE_TYPE (array_stride[ii][s_jj])) + && (TREE_TYPE (array_stride[ii][s_jj]) != + TREE_TYPE (array_var[s_jj]))) + { + start = array_start[ii][s_jj]; + stride = array_stride[ii][s_jj]; + var = + build_c_cast (location, TREE_TYPE (array_stride[ii][s_jj]), + array_var[s_jj]); + } + else if (TREE_TYPE (array_start[ii][s_jj]) != + TREE_TYPE (array_stride[ii][s_jj])) + { + /* If we reach here, then the stride and start are of + different types, and so it doesn't really matter what + the induction variable type is, we stay safe and convert + everything to integer. The reason why we pick integer + instead of something like size_t is because the stride + and length can be + or -. */ + start = build_c_cast (location, integer_type_node, + array_start[ii][s_jj]); + stride = build_c_cast (location, integer_type_node, + array_stride[ii][s_jj]); + var = build_c_cast (location, integer_type_node, + array_var[s_jj]); + } + else + { + start = array_start[ii][s_jj]; + stride = array_stride[ii][s_jj]; + var = array_var[s_jj]; + } + if (count_down[ii][s_jj]) + /* Array[start_index - (induction_var * stride)]. */ + array_opr = grok_array_decl + (location, array_opr, + build2 (MINUS_EXPR, TREE_TYPE (var), start, + build2 (MULT_EXPR, TREE_TYPE (var), var, stride)), + false); + else + /* Array[start_index + (induction_var * stride)]. */ + array_opr = grok_array_decl + (location, array_opr, + build2 (PLUS_EXPR, TREE_TYPE (var), start, + build2 (MULT_EXPR, TREE_TYPE (var), var, stride)), + false); + } + vec_safe_push (array_operand, array_opr); + } + else + vec_safe_push (array_operand, integer_one_node); + + replace_array_notations (&func_parm, true, array_list, array_operand); + + if (!TREE_TYPE (func_parm)) + TREE_TYPE (func_parm) = TREE_TYPE ((*array_list)[0]); + + for (ii = 0; ii < rank; ii++) + if (count_down[0][ii]) + expr_incr[ii] = build_x_unary_op (location, POSTDECREMENT_EXPR, + array_var[ii], tf_warning_or_error); + else + expr_incr[ii] = build_x_unary_op (location, POSTINCREMENT_EXPR, + array_var[ii], tf_warning_or_error); + + for (jj = 0; jj < rank; jj++) + if (rank && expr_incr[jj]) + { + if (count_down[0][jj]) + compare_expr[jj] = build_x_binary_op + (location, GT_EXPR, array_var[jj], TREE_CODE (array_var[jj]), + array_length[0][jj], TREE_CODE (array_length[0][jj]), NULL, + tf_warning_or_error); + else + compare_expr[jj] = build_x_binary_op + (location, LT_EXPR, array_var[jj], TREE_CODE (array_var[jj]), + array_length[0][jj], TREE_CODE (array_length[0][jj]), NULL, + tf_warning_or_error); + } + if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING) + { + if (processing_template_decl) + *new_var = build_decl (location, VAR_DECL, NULL_TREE, new_var_type); + else + *new_var = create_tmp_var (new_var_type, NULL); + } + else + /* We do not require a new variable for mutating. The "identity value" + itself is a variable. */ + *new_var = NULL_TREE; + + if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND + || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND) + { + array_ind_value = create_tmp_var (TREE_TYPE (func_parm), NULL); + gcc_assert (array_ind_value && (array_ind_value != error_mark_node)); + DECL_INITIAL (array_ind_value) = NULL_TREE; + pushdecl (array_ind_value); + } + array_op0 = (*array_operand)[0]; + if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_ADD) + { + if (ARITHMETIC_TYPE_P (new_var_type)) + new_var_init = build_x_modify_expr (location, *new_var, + NOP_EXPR, + build_zero_cst (new_var_type), 1); + else + new_var_init = build_x_modify_expr (location, *new_var, + NOP_EXPR, + integer_zero_node, 1); + new_expr = build_x_modify_expr (location, *new_var, PLUS_EXPR, + func_parm, 1); + } + else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MUL) + { + if (ARITHMETIC_TYPE_P (new_var_type)) + new_var_init = build_x_modify_expr (location, *new_var, + NOP_EXPR, + build_one_cst (new_var_type), 1); + else + new_var_init = build_x_modify_expr (location, *new_var, + NOP_EXPR, + integer_one_node, 1); + new_expr = build_x_modify_expr (location, *new_var, MULT_EXPR, + func_parm, 1); + } + else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO) + { + new_var_init = build_x_modify_expr (location, *new_var, NOP_EXPR, + build_one_cst (new_var_type), 1); + /* Initially you assume everything is zero, now if we find a case where + it is NOT true, then we set the result to false. Otherwise we just + keep the previous value. */ + new_yes_expr = build_x_modify_expr (location, *new_var, NOP_EXPR, + build_zero_cst (new_var_type), 1); + new_no_expr = build_x_modify_expr (location, *new_var, NOP_EXPR, + *new_var, 1); + if (ARITHMETIC_TYPE_P (TREE_TYPE (func_parm))) + comp_node = build_zero_cst (TREE_TYPE (func_parm)); + else + comp_node = integer_zero_node; + new_cond_expr = build_x_binary_op + (location, NE_EXPR, func_parm, TREE_CODE (func_parm), comp_node, + TREE_CODE (comp_node), NULL, tf_warning_or_error); + new_expr = build_x_conditional_expr (location, new_cond_expr, + new_yes_expr, new_no_expr, + tf_warning_or_error); + } + else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO) + { + new_var_init = build_x_modify_expr + (location, *new_var, NOP_EXPR, build_one_cst (new_var_type), 1); + /* Initially you assume everything is non-zero, now if we find a case + where it is NOT true, then we set the result to false. Otherwise we + just keep the previous value. */ + new_yes_expr = build_x_modify_expr + (location, *new_var, NOP_EXPR, + build_zero_cst (TREE_TYPE (*new_var)), 1); + new_no_expr = build_x_modify_expr (location, *new_var, NOP_EXPR, + *new_var, 1); + if (ARITHMETIC_TYPE_P (TREE_TYPE (func_parm))) + comp_node = build_zero_cst (TREE_TYPE (func_parm)); + else + comp_node = integer_zero_node; + new_cond_expr = build_x_binary_op + (location, EQ_EXPR, func_parm, TREE_CODE (func_parm), comp_node, + TREE_CODE (comp_node), NULL, tf_warning_or_error); + new_expr = build_x_conditional_expr (location, new_cond_expr, + new_yes_expr, new_no_expr, + tf_warning_or_error); + } + else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO) + { + new_var_init = build_x_modify_expr + (location, *new_var, NOP_EXPR, + build_zero_cst (new_var_type), 1); + /* Initially we assume there are NO zeros in the list. When we find a + non-zero, we keep the previous value. If we find a zero, we set the + value to true. */ + new_no_expr = build_x_modify_expr + (location, *new_var, NOP_EXPR, + build_one_cst (TREE_TYPE (*new_var)), 1); + new_yes_expr = build_x_modify_expr (location, *new_var, NOP_EXPR, + *new_var, 1); + if (ARITHMETIC_TYPE_P (TREE_TYPE (func_parm))) + comp_node = build_zero_cst (TREE_TYPE (func_parm)); + else + comp_node = integer_zero_node; + new_cond_expr = build_x_binary_op + (location, EQ_EXPR, func_parm, TREE_CODE (func_parm), comp_node, + TREE_CODE (comp_node), NULL, tf_warning_or_error); + new_expr = build_x_conditional_expr (location, new_cond_expr, + new_yes_expr, new_no_expr, + tf_warning_or_error); + } + else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO) + { + new_var_init = build_x_modify_expr (location, *new_var, NOP_EXPR, + build_zero_cst (new_var_type), 1); + /* Initially we assume there are NO non-zeros in the list. When we find a + zero, we keep the previous value. If we find a zero, we set the value + to true. */ + new_no_expr = build_x_modify_expr + (location, *new_var, NOP_EXPR, + build_one_cst (TREE_TYPE (*new_var)), 1); + new_yes_expr = build_x_modify_expr (location, *new_var, NOP_EXPR, + *new_var, 1); + if (ARITHMETIC_TYPE_P (TREE_TYPE (func_parm))) + comp_node = build_zero_cst (TREE_TYPE (func_parm)); + else + comp_node = integer_zero_node; + new_cond_expr = build_x_binary_op + (location, NE_EXPR, func_parm, TREE_CODE (func_parm), comp_node, + TREE_CODE (comp_node), NULL, tf_warning_or_error); + new_expr = build_x_conditional_expr (location, new_cond_expr, + new_yes_expr, new_no_expr, + tf_warning_or_error); + } + else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX) + { + /* If the TYPE_MIN_VALUE is available for the new_var_type, then + set that as the initial value. */ + if (TYPE_MIN_VALUE (new_var_type)) + new_var_init = build_x_modify_expr (location, *new_var, NOP_EXPR, + TYPE_MIN_VALUE (new_var_type), 1); + else + /* ... otherwise set initial value as the first element of array. */ + new_var_init = build_x_modify_expr (location, *new_var, NOP_EXPR, + func_parm, 1); + new_no_expr = build_x_modify_expr (location, *new_var, NOP_EXPR, + *new_var, 1); + new_yes_expr = build_x_modify_expr (location, *new_var, NOP_EXPR, + func_parm, 1); + new_cond_expr = build_x_binary_op (location, LT_EXPR, *new_var, + TREE_CODE (*new_var), func_parm, + TREE_CODE (func_parm), NULL, + tf_warning_or_error); + new_expr = build_x_conditional_expr (location, new_cond_expr, + new_yes_expr, new_no_expr, + tf_warning_or_error); + } + else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN) + { + /* If the TYPE_MAX_VALUE is available for the new_var_type, then + set that as the initial value. */ + if (TYPE_MAX_VALUE (new_var_type)) + new_var_init = build_x_modify_expr (location, *new_var, NOP_EXPR, + TYPE_MAX_VALUE (new_var_type), 1); + else + /* ... otherwise set initial value as the first element of array. */ + new_var_init = build_x_modify_expr (location, *new_var, NOP_EXPR, + func_parm, 1); + new_no_expr = build_x_modify_expr (location, *new_var, NOP_EXPR, + *new_var, 1); + new_yes_expr = build_x_modify_expr (location, *new_var, NOP_EXPR, + func_parm, 1); + new_cond_expr = build_x_binary_op (location, GT_EXPR, *new_var, + TREE_CODE (*new_var), func_parm, + TREE_CODE (func_parm), NULL, + tf_warning_or_error); + new_expr = build_x_conditional_expr (location, new_cond_expr, + new_yes_expr, new_no_expr, + tf_warning_or_error); + } + else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND) + { + new_var_init = build_x_modify_expr (location, *new_var, NOP_EXPR, + array_var[0], tf_warning_or_error); + new_exp_init = build_x_modify_expr (location, array_ind_value, + NOP_EXPR, func_parm, + tf_warning_or_error); + new_no_ind = build_x_modify_expr (location, *new_var, NOP_EXPR, + *new_var, tf_warning_or_error); + new_no_expr = build_x_modify_expr (location, array_ind_value, + NOP_EXPR, + array_ind_value, tf_warning_or_error); + if (list_size > 1) + new_yes_ind = build_x_modify_expr (location, *new_var, + NOP_EXPR, array_var[0], + tf_warning_or_error); + else + new_yes_ind = build_x_modify_expr + (location, *new_var, NOP_EXPR, + TREE_OPERAND (array_op0, 1), tf_warning_or_error); + new_yes_expr = build_x_modify_expr (location, array_ind_value, + NOP_EXPR, func_parm, + tf_warning_or_error); + new_yes_list = alloc_stmt_list (); + append_to_statement_list (new_yes_ind, &new_yes_list); + append_to_statement_list (new_yes_expr, &new_yes_list); + + new_no_list = alloc_stmt_list (); + append_to_statement_list (new_no_ind, &new_no_list); + append_to_statement_list (new_no_expr, &new_no_list); + + new_cond_expr = build_x_binary_op + (location, LT_EXPR, array_ind_value, + TREE_CODE (array_ind_value), + func_parm, TREE_CODE (func_parm), NULL, tf_warning_or_error); + new_expr = build_x_conditional_expr (location, new_cond_expr, + new_yes_list, new_no_list, + tf_warning_or_error); + } + else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND) + { + new_var_init = build_x_modify_expr (location, *new_var, NOP_EXPR, + array_var[0], 1); + new_exp_init = build_x_modify_expr (location, array_ind_value, + NOP_EXPR, func_parm, 1); + new_no_ind = build_x_modify_expr (location, *new_var, NOP_EXPR, + *new_var, 1); + new_no_expr = build_x_modify_expr (location, array_ind_value, + NOP_EXPR, array_ind_value, 1); + if (list_size > 1) + new_yes_ind = build_x_modify_expr (location, *new_var, + NOP_EXPR, array_var[0], 1); + else + new_yes_ind = build_x_modify_expr + (location, *new_var, NOP_EXPR, TREE_OPERAND (array_op0, 1), 1); + new_yes_expr = build_x_modify_expr (location, array_ind_value, + NOP_EXPR, func_parm, 1); + new_yes_list = alloc_stmt_list (); + append_to_statement_list (new_yes_ind, &new_yes_list); + append_to_statement_list (new_yes_expr, &new_yes_list); + + new_no_list = alloc_stmt_list (); + append_to_statement_list (new_no_ind, &new_no_list); + append_to_statement_list (new_no_expr, &new_no_list); + new_cond_expr = + build_x_binary_op (location, GT_EXPR, array_ind_value, + TREE_CODE (array_ind_value), func_parm, + TREE_CODE (func_parm), NULL, tf_warning_or_error); + new_expr = build_x_conditional_expr (location, new_cond_expr, + new_yes_list, new_no_list, + tf_warning_or_error); + } + else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE) + { + vec *func_args; + func_args = make_tree_vector (); + vec_safe_push (func_args, *new_var); + vec_safe_push (func_args, func_parm); + + new_var_init = build_x_modify_expr (location, *new_var, NOP_EXPR, + identity_value, tf_warning_or_error); + new_call_expr = finish_call_expr (call_fn, &func_args, false, true, + tf_warning_or_error); + new_expr = build_x_modify_expr (location, *new_var, NOP_EXPR, + new_call_expr, tf_warning_or_error); + } + else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING) + { + vec *func_args; + + func_args = make_tree_vector (); + vec_safe_push (func_args, identity_value); + vec_safe_push (func_args, func_parm); + new_expr = finish_call_expr (call_fn, &func_args, false, true, + tf_warning_or_error); + } + else + gcc_unreachable (); + + /* The reason we are putting initial variable twice is because the + new exp init below depends on this value being initialized. */ + for (ii = 0; ii < rank; ii++) + finish_expr_stmt (ind_init[ii]); + + if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING) + finish_expr_stmt (new_var_init); + + if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND + || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND) + finish_expr_stmt (new_exp_init); + + an_init = pop_stmt_list (an_init); + append_to_statement_list_force (an_init, &loop_with_init); + body = new_expr; + + for (ii = 0; ii < rank; ii++) + { + tree new_loop = push_stmt_list (); + create_an_loop (ind_init[ii], compare_expr[ii], expr_incr[ii], body); + body = pop_stmt_list (new_loop); + } + append_to_statement_list_force (body, &loop_with_init); + + XDELETEVEC (compare_expr); + XDELETEVEC (expr_incr); + XDELETEVEC (ind_init); + XDELETEVEC (array_var); + + for (ii = 0; ii < list_size; ii++) + { + XDELETEVEC (count_down[ii]); + XDELETEVEC (array_value[ii]); + XDELETEVEC (array_stride[ii]); + XDELETEVEC (array_length[ii]); + XDELETEVEC (array_start[ii]); + XDELETEVEC (array_ops[ii]); + XDELETEVEC (array_vector[ii]); + } + XDELETEVEC (count_down); + XDELETEVEC (array_value); + XDELETEVEC (array_stride); + XDELETEVEC (array_length); + XDELETEVEC (array_start); + XDELETEVEC (array_ops); + XDELETEVEC (array_vector); + + return loop_with_init; +} + +/* Returns a loop with ARRAY_REF inside it with an appropriate modify expr. + The LHS and/or RHS will be array notation expressions that have a + MODIFYCODE. The location of the variable is specified by LOCATION. */ + +static tree +build_x_array_notation_expr (location_t location, tree lhs, + enum tree_code modifycode, tree rhs, + tsubst_flags_t complain) +{ + bool **lhs_vector = NULL, **rhs_vector = NULL; + tree **lhs_array = NULL, **rhs_array = NULL; + tree array_expr_lhs = NULL_TREE, array_expr_rhs = NULL_TREE; + tree array_expr = NULL_TREE; + tree **lhs_value = NULL, **rhs_value = NULL; + tree **lhs_stride = NULL, **lhs_length = NULL, **lhs_start = NULL; + tree **rhs_stride = NULL, **rhs_length = NULL, **rhs_start = NULL; + tree body = NULL_TREE, *lhs_var = NULL, *rhs_var = NULL; + tree *cond_expr = NULL; + tree *lhs_expr_incr = NULL, *rhs_expr_incr = NULL; + tree *lhs_ind_init = NULL, *rhs_ind_init = NULL; + bool **lhs_count_down = NULL, **rhs_count_down = NULL; + tree *lhs_compare = NULL, *rhs_compare = NULL; + vec *lhs_array_operand = NULL, *rhs_array_operand = NULL; + size_t lhs_rank = 0, rhs_rank = 0, ii = 0, jj = 0; + tree ii_tree = NULL_TREE; + vec *rhs_list = NULL, *lhs_list = NULL; + size_t rhs_list_size = 0, lhs_list_size = 0; + tree new_modify_expr, new_var = NULL_TREE, builtin_loop, scalar_mods; + bool found_builtin_fn = false; + int s_jj = 0; + tree lhs_begin_var, lhs_lngth_var, lhs_strde_var, rhs_begin_var; + tree rhs_lngth_var, rhs_strde_var; + tree an_init, loop_with_init = alloc_stmt_list (); + + /* Note about using find_rank (): If find_rank returns false, then it must + have already reported an error, thus we just return an error_mark_node + without any doing any error emission. */ + if (!find_rank (location, rhs, rhs, false, &rhs_rank)) + return error_mark_node; + + extract_array_notation_exprs (rhs, false, &rhs_list); + rhs_list_size = vec_safe_length (rhs_list); + an_init = push_stmt_list (); + if (rhs_rank) + { + scalar_mods = replace_invariant_exprs (&rhs); + if (scalar_mods) + finish_expr_stmt (scalar_mods); + } + for (ii = 0; ii < rhs_list_size; ii++) + { + tree rhs_node = (*rhs_list)[ii]; + if (TREE_CODE (rhs_node) == CALL_EXPR) + { + builtin_loop = fix_builtin_array_notation_fn (rhs_node, &new_var); + if (builtin_loop == error_mark_node) + return error_mark_node; + else if (builtin_loop) + { + finish_expr_stmt (builtin_loop); + found_builtin_fn = true; + if (new_var) + { + vec *rhs_sub_list = NULL, *new_var_list = NULL; + vec_safe_push (rhs_sub_list, rhs_node); + vec_safe_push (new_var_list, new_var); + replace_array_notations (&rhs, false, rhs_sub_list, + new_var_list); + } + } + } + } + + lhs_rank = 0; + rhs_rank = 0; + if (!find_rank (location, lhs, lhs, true, &lhs_rank) + || !find_rank (location, rhs, rhs, true, &rhs_rank)) + { + pop_stmt_list (an_init); + return error_mark_node; + } + + /* If both are scalar, then the only reason why we will get this far is if + there is some array notations inside it and was using a builtin array + notation functions. If so, we have already broken those guys up and now + a simple build_x_modify_expr would do. */ + if (lhs_rank == 0 && rhs_rank == 0) + { + if (found_builtin_fn) + { + new_modify_expr = build_x_modify_expr (location, lhs, + modifycode, rhs, complain); + finish_expr_stmt (new_modify_expr); + pop_stmt_list (an_init); + return an_init; + } + else + { + pop_stmt_list (an_init); + return NULL_TREE; + } + } + + /* If for some reason location is not set, then find if LHS or RHS has + location info. If so, then use that so we atleast have an idea. */ + if (location == UNKNOWN_LOCATION) + { + if (EXPR_LOCATION (lhs) != UNKNOWN_LOCATION) + location = EXPR_LOCATION (lhs); + else if (EXPR_LOCATION (rhs) != UNKNOWN_LOCATION) + location = EXPR_LOCATION (rhs); + } + + + /* We need this when we have a scatter issue. */ + extract_array_notation_exprs (lhs, true, &lhs_list); + rhs_list = NULL; + extract_array_notation_exprs (rhs, true, &rhs_list); + rhs_list_size = vec_safe_length (rhs_list); + lhs_list_size = vec_safe_length (lhs_list); + + if (lhs_rank == 0 && rhs_rank != 0) + { + tree rhs_base = rhs; + if (TREE_CODE (rhs_base) == COMPOUND_EXPR) + rhs_base = TREE_OPERAND (rhs_base, 0); + if (TREE_CODE (rhs_base) == TARGET_EXPR) + rhs_base = TARGET_EXPR_INITIAL (rhs_base); + + if (TREE_CODE (rhs) != CALL_EXPR + && !has_call_expr_with_array_notation (rhs)) + { + for (ii = 0; ii < rhs_rank; ii++) + rhs_base = ARRAY_NOTATION_ARRAY (rhs); + + if (location == UNKNOWN_LOCATION && EXPR_HAS_LOCATION (rhs)) + location = EXPR_LOCATION (rhs); + error_at (location, "%qD cannot be scalar when %qD is not", lhs, + rhs_base); + return error_mark_node; + } + } + if (lhs_rank != 0 && rhs_rank != 0 && lhs_rank != rhs_rank) + { + tree lhs_base = lhs; + tree rhs_base = rhs; + + for (ii = 0; ii < lhs_rank; ii++) + lhs_base = ARRAY_NOTATION_ARRAY (lhs_base); + + while (rhs_base && TREE_CODE (rhs_base) != ARRAY_NOTATION_REF) + rhs_base = TREE_OPERAND (rhs_base, 0); + for (ii = 0; ii < rhs_rank; ii++) + rhs_base = ARRAY_NOTATION_ARRAY (rhs_base); + + if (location == UNKNOWN_LOCATION && EXPR_HAS_LOCATION (lhs)) + location = EXPR_LOCATION (lhs); + error_at (location, "rank mismatch between %qD and %qD", lhs_base, + rhs_base); + return error_mark_node; + } + + /* Assign the array notation components to variable so that they can satisfy + the exec-once rule. */ + for (ii = 0; ii < lhs_list_size; ii++) + { + tree array_node = (*lhs_list)[ii]; + tree array_begin = ARRAY_NOTATION_START (array_node); + tree array_lngth = ARRAY_NOTATION_LENGTH (array_node); + tree array_strde = ARRAY_NOTATION_STRIDE (array_node); + + if (TREE_CODE (array_begin) != INTEGER_CST) + { + lhs_begin_var = build_decl (location, VAR_DECL, NULL_TREE, + integer_type_node); + finish_expr_stmt (build_x_modify_expr (location, lhs_begin_var, + NOP_EXPR, array_begin, + complain)); + ARRAY_NOTATION_START (array_node) = lhs_begin_var; + } + if (TREE_CODE (array_lngth) != INTEGER_CST) + { + lhs_lngth_var = build_decl (location, VAR_DECL, NULL_TREE, + integer_type_node); + finish_expr_stmt (build_x_modify_expr (location, lhs_lngth_var, + NOP_EXPR, array_lngth, + complain)); + ARRAY_NOTATION_LENGTH (array_node) = lhs_lngth_var; + } + if (TREE_CODE (array_strde) != INTEGER_CST) + { + lhs_strde_var = build_decl (location, VAR_DECL, NULL_TREE, + integer_type_node); + finish_expr_stmt (build_x_modify_expr (location, lhs_strde_var, + NOP_EXPR, array_strde, + complain)); + ARRAY_NOTATION_STRIDE (array_node) = lhs_strde_var; + } + } + for (ii = 0; ii < rhs_list_size; ii++) + { + tree array_node = (*rhs_list)[ii]; + if (array_node && TREE_CODE (array_node) == ARRAY_NOTATION_REF) + { + tree array_begin = ARRAY_NOTATION_START (array_node); + tree array_lngth = ARRAY_NOTATION_LENGTH (array_node); + tree array_strde = ARRAY_NOTATION_STRIDE (array_node); + + if (TREE_CODE (array_begin) != INTEGER_CST) + { + rhs_begin_var = build_decl (location, VAR_DECL, NULL_TREE, + integer_type_node); + finish_expr_stmt (build_x_modify_expr (location, rhs_begin_var, + NOP_EXPR, array_begin, + complain)); + ARRAY_NOTATION_START (array_node) = rhs_begin_var; + } + if (TREE_CODE (array_lngth) != INTEGER_CST) + { + rhs_lngth_var = build_decl (location, VAR_DECL, NULL_TREE, + integer_type_node); + finish_expr_stmt (build_x_modify_expr (location, rhs_lngth_var, + NOP_EXPR, array_lngth, + complain)); + ARRAY_NOTATION_LENGTH (array_node) = rhs_lngth_var; + } + if (TREE_CODE (array_strde) != INTEGER_CST) + { + rhs_strde_var = build_decl (location, VAR_DECL, NULL_TREE, + integer_type_node); + finish_expr_stmt (build_x_modify_expr (location, rhs_strde_var, + NOP_EXPR, array_strde, + complain)); + ARRAY_NOTATION_STRIDE (array_node) = rhs_strde_var; + } + } + } + lhs_vector = XNEWVEC (bool *, lhs_list_size); + for (ii = 0; ii < lhs_list_size; ii++) + lhs_vector[ii] = XNEWVEC (bool, lhs_rank); + + rhs_vector = XNEWVEC (bool *, rhs_list_size); + for (ii = 0; ii < rhs_list_size; ii++) + rhs_vector[ii] = XNEWVEC (bool, rhs_rank); + + lhs_array = XNEWVEC (tree *, lhs_list_size); + for (ii = 0; ii < lhs_list_size; ii++) + lhs_array[ii] = XNEWVEC (tree, lhs_rank); + + rhs_array = XNEWVEC (tree *, rhs_list_size); + for (ii = 0; ii < rhs_list_size; ii++) + rhs_array[ii] = XNEWVEC (tree, rhs_rank); + + lhs_value = XNEWVEC (tree *, lhs_list_size); + for (ii = 0; ii < lhs_list_size; ii++) + lhs_value[ii] = XNEWVEC (tree, lhs_rank); + + rhs_value = XNEWVEC (tree *, rhs_list_size); + for (ii = 0; ii < rhs_list_size; ii++) + rhs_value[ii] = XNEWVEC (tree, rhs_rank); + + lhs_stride = XNEWVEC (tree *, lhs_list_size); + for (ii = 0; ii < lhs_list_size; ii++) + lhs_stride[ii] = XNEWVEC (tree, lhs_rank); + + rhs_stride = XNEWVEC (tree *, rhs_list_size); + for (ii = 0; ii < rhs_list_size; ii++) + rhs_stride[ii] = XNEWVEC (tree, rhs_rank); + + lhs_length = XNEWVEC (tree *, lhs_list_size); + for (ii = 0; ii < lhs_list_size; ii++) + lhs_length[ii] = XNEWVEC (tree, lhs_rank); + + rhs_length = XNEWVEC (tree *, rhs_list_size); + for (ii = 0; ii < rhs_list_size; ii++) + rhs_length[ii] = XNEWVEC (tree, rhs_rank); + + lhs_start = XNEWVEC (tree *, lhs_list_size); + for (ii = 0; ii < lhs_list_size; ii++) + lhs_start[ii] = XNEWVEC (tree, lhs_rank); + + rhs_start = XNEWVEC (tree *, rhs_list_size); + for (ii = 0; ii < rhs_list_size; ii++) + rhs_start[ii] = XNEWVEC (tree, rhs_rank); + + lhs_var = XNEWVEC (tree, lhs_rank); + rhs_var = XNEWVEC (tree, rhs_rank); + + + /* The reason why we are just using lhs_rank for this is because we have then + following scenarios: + 1. LHS_RANK == RHS_RANK + 2. LHS_RANK != RHS_RANK && RHS_RANK = 0 + + In both the scenarios, just checking the LHS_RANK is OK. */ + + cond_expr = XNEWVEC (tree, MAX (lhs_rank, rhs_rank)); + lhs_expr_incr = XNEWVEC (tree, lhs_rank); + rhs_expr_incr = XNEWVEC (tree, rhs_rank); + + lhs_ind_init = XNEWVEC (tree, lhs_rank); + rhs_ind_init = XNEWVEC (tree, rhs_rank); + + lhs_count_down = XNEWVEC (bool *, lhs_list_size); + for (ii = 0; ii < lhs_list_size; ii++) + lhs_count_down[ii] = XNEWVEC (bool, lhs_rank); + + rhs_count_down = XNEWVEC (bool *, rhs_list_size); + for (ii = 0; ii < rhs_list_size; ii++) + rhs_count_down[ii] = XNEWVEC (bool, rhs_rank); + + lhs_compare = XNEWVEC (tree, lhs_rank); + rhs_compare = XNEWVEC (tree, rhs_rank); + + if (lhs_rank) + { + for (ii = 0; ii < lhs_list_size; ii++) + { + jj = 0; + ii_tree = (*lhs_list)[ii]; + while (ii_tree) + { + if (TREE_CODE (ii_tree) == ARRAY_NOTATION_REF) + { + lhs_array[ii][jj] = ii_tree; + jj++; + ii_tree = ARRAY_NOTATION_ARRAY (ii_tree); + } + else if (TREE_CODE (ii_tree) == ARRAY_REF) + ii_tree = TREE_OPERAND (ii_tree, 0); + else if (TREE_CODE (ii_tree) == VAR_DECL + || TREE_CODE (ii_tree) == PARM_DECL) + break; + } + } + } + else + lhs_array[0][0] = NULL_TREE; + + if (rhs_rank) + { + for (ii = 0; ii < rhs_list_size; ii++) + { + jj = 0; + ii_tree = (*rhs_list)[ii]; + while (ii_tree) + { + if (TREE_CODE (ii_tree) == ARRAY_NOTATION_REF) + { + rhs_array[ii][jj] = ii_tree; + jj++; + ii_tree = ARRAY_NOTATION_ARRAY (ii_tree); + } + else if (TREE_CODE (ii_tree) == ARRAY_REF) + ii_tree = TREE_OPERAND (ii_tree, 0); + else if (TREE_CODE (ii_tree) == VAR_DECL + || TREE_CODE (ii_tree) == PARM_DECL + || TREE_CODE (ii_tree) == CALL_EXPR) + break; + } + } + } + for (ii = 0; ii < lhs_list_size; ii++) + { + if (TREE_CODE ((*lhs_list)[ii]) == ARRAY_NOTATION_REF) + { + for (jj = 0; jj < lhs_rank; jj++) + { + if (TREE_CODE (lhs_array[ii][jj]) == ARRAY_NOTATION_REF) + { + lhs_value[ii][jj] = ARRAY_NOTATION_ARRAY (lhs_array[ii][jj]); + lhs_start[ii][jj] = ARRAY_NOTATION_START (lhs_array[ii][jj]); + lhs_length[ii][jj] = + fold_build1 (CONVERT_EXPR, integer_type_node, + ARRAY_NOTATION_LENGTH (lhs_array[ii][jj])); + lhs_stride[ii][jj] = + fold_build1 (CONVERT_EXPR, integer_type_node, + ARRAY_NOTATION_STRIDE (lhs_array[ii][jj])); + lhs_vector[ii][jj] = true; + + /* If the stride value is variable (i.e. not constant) then + assume that the length is positive. */ + if (!TREE_CONSTANT (lhs_length[ii][jj])) + lhs_count_down[ii][jj] = false; + else if (tree_int_cst_lt + (lhs_length[ii][jj], + build_zero_cst (TREE_TYPE (lhs_length[ii][jj])))) + lhs_count_down[ii][jj] = true; + else + lhs_count_down[ii][jj] = false; + } + else + lhs_vector[ii][jj] = false; + } + } + } + for (ii = 0; ii < rhs_list_size; ii++) + { + if (TREE_CODE ((*rhs_list)[ii]) == ARRAY_NOTATION_REF) + { + for (jj = 0; jj < rhs_rank; jj++) + { + if (TREE_CODE (rhs_array[ii][jj]) == ARRAY_NOTATION_REF) + { + rhs_value[ii][jj] = ARRAY_NOTATION_ARRAY (rhs_array[ii][jj]); + rhs_start[ii][jj] = ARRAY_NOTATION_START (rhs_array[ii][jj]); + rhs_length[ii][jj] = + ARRAY_NOTATION_LENGTH (rhs_array[ii][jj]); + rhs_stride[ii][jj] = + ARRAY_NOTATION_STRIDE (rhs_array[ii][jj]); + rhs_vector[ii][jj] = true; + /* If the stride value is variable (i.e. not constant) then + assume that the length is positive. */ + if (!TREE_CONSTANT (rhs_length[ii][jj])) + rhs_count_down[ii][jj] = false; + else if (tree_int_cst_lt + (rhs_length[ii][jj], + build_zero_cst (TREE_TYPE (rhs_length[ii][jj])))) + rhs_count_down[ii][jj] = true; + else + rhs_count_down[ii][jj] = false; + } + else + rhs_vector[ii][jj] = false; + } + } + else + for (jj = 0; jj < rhs_rank; jj++) + { + rhs_vector[ii][jj] = false; + rhs_length[ii][jj] = NULL_TREE; + } + } + + if (length_mismatch_in_expr_p (EXPR_LOCATION (lhs), lhs_length, + lhs_list_size, lhs_rank) + || length_mismatch_in_expr_p (EXPR_LOCATION (rhs), rhs_length, + rhs_list_size, rhs_rank)) + { + pop_stmt_list (an_init); + return error_mark_node; + } + + if (lhs_list_size > 0 && rhs_list_size > 0 && lhs_rank > 0 && rhs_rank > 0 + && TREE_CODE (lhs_length[0][0]) == INTEGER_CST + && rhs_length[0][0] && TREE_CODE (rhs_length[0][0]) == INTEGER_CST) + { + HOST_WIDE_INT l_length = int_cst_value (lhs_length[0][0]); + HOST_WIDE_INT r_length = int_cst_value (rhs_length[0][0]); + if (absu_hwi (l_length) != absu_hwi (r_length)) + { + error_at (location, "length mismatch between LHS and RHS"); + pop_stmt_list (an_init); + return error_mark_node; + } + } + for (ii = 0; ii < lhs_rank; ii++) + if (lhs_start[0][ii] && TREE_TYPE (lhs_start[0][ii])) + lhs_var[ii] = build_decl (location, VAR_DECL, NULL_TREE, + TREE_TYPE (lhs_start[0][ii])); + else + lhs_var[ii] = build_decl (location, VAR_DECL, NULL_TREE, + integer_type_node); + + for (ii = 0; ii < rhs_list_size; ii++) + { + if (TREE_CODE ((*rhs_list)[ii]) == CALL_EXPR) + { + int idx_value = 0; + tree func_name = CALL_EXPR_FN ((*rhs_list)[ii]); + if (TREE_CODE (func_name) == ADDR_EXPR) + { + if (is_sec_implicit_index_fn (func_name)) + { + idx_value = + extract_sec_implicit_index_arg (location, (*rhs_list)[ii]); + if (idx_value < (int) lhs_rank && idx_value >= 0) + vec_safe_push (rhs_array_operand, lhs_var[idx_value]); + else if (idx_value == -1) + return error_mark_node; + else + { + size_t ee = 0; + tree lhs_base = (*lhs_list)[ii]; + for (ee = 0; ee < lhs_rank; ee++) + if (lhs_base + && TREE_CODE (lhs_base) == ARRAY_NOTATION_REF) + lhs_base = ARRAY_NOTATION_ARRAY (lhs_base); + + if (location == UNKNOWN_LOCATION + && EXPR_HAS_LOCATION (lhs)) + location = EXPR_LOCATION (lhs); + error_at (location, "__sec_implicit_index argument %d " + "must be less than the rank of %qD", idx_value, + lhs_base); + return error_mark_node; + } + } + else + vec_safe_push (rhs_array_operand, (*rhs_list)[ii]); + } + else + vec_safe_push (rhs_array_operand, (*rhs_list)[ii]); + } + else + vec_safe_push (rhs_array_operand, (*rhs_list)[ii]); + } + + replace_array_notations (&rhs, true, rhs_list, rhs_array_operand); + rhs_list_size = 0; + rhs_list = NULL; + extract_array_notation_exprs (rhs, true, &rhs_list); + rhs_list_size = vec_safe_length (rhs_list); + + for (ii = 0; ii < lhs_rank; ii++) + if (lhs_vector[0][ii]) + { + lhs_ind_init[ii] = build_x_modify_expr + (location, lhs_var[ii], NOP_EXPR, + build_zero_cst (TREE_TYPE (lhs_var[ii])), complain); + } + + + for (ii = 0; ii < rhs_rank; ii++) + { + /* When we have a polynomial, we assume that the indices are of type + integer. */ + rhs_var[ii] = build_decl (location, VAR_DECL, NULL_TREE, + TREE_TYPE (rhs_start[0][ii])); + rhs_ind_init[ii] = build_x_modify_expr + (location, rhs_var[ii], NOP_EXPR, + build_zero_cst (TREE_TYPE (rhs_var[ii])), complain); + } + + if (lhs_rank) + { + for (ii = 0; ii < lhs_list_size; ii++) + { + if (lhs_vector[ii][0]) + { + /* The last ARRAY_NOTATION element's ARRAY component should be + the array's base value. */ + tree lhs_array_opr = lhs_value[ii][lhs_rank - 1]; + for (s_jj = lhs_rank - 1; s_jj >= 0; s_jj--) + { + tree stride = NULL_TREE, var = NULL_TREE, start = NULL_TREE; + if ((TREE_TYPE (lhs_start[ii][s_jj]) == + TREE_TYPE (lhs_stride[ii][s_jj])) + && (TREE_TYPE (lhs_stride[ii][s_jj]) != + TREE_TYPE (lhs_var[s_jj]))) + { + /* If stride and start are of same type and the induction + var is not, we convert induction variable to stride's + type. */ + start = lhs_start[ii][s_jj]; + stride = lhs_stride[ii][s_jj]; + var = build_c_cast (location, + TREE_TYPE (lhs_stride[ii][s_jj]), + lhs_var[s_jj]); + } + else if (TREE_TYPE (lhs_start[ii][s_jj]) != + TREE_TYPE (lhs_stride[ii][s_jj])) + { + /* If we reach here, then the stride and start are of + different types, and so it doesn't really matter what + the induction variable type is, we stay safe and + convert everything to integer. The reason why we + pick integer instead of something like size_t is + because the stride and length can be + or -. */ + start = build_c_cast (location, integer_type_node, + lhs_start[ii][s_jj]); + stride = build_c_cast (location, integer_type_node, + lhs_stride[ii][s_jj]); + var = build_c_cast (location, integer_type_node, + lhs_var[s_jj]); + } + else + { + start = lhs_start[ii][s_jj]; + stride = lhs_stride[ii][s_jj]; + var = lhs_var[s_jj]; + } + if (lhs_count_down[ii][s_jj]) + /* Array[start_index - (induction_var * stride)]. */ + lhs_array_opr = grok_array_decl + (location, lhs_array_opr, + build2 (MINUS_EXPR, TREE_TYPE (var), start, + build2 (MULT_EXPR, TREE_TYPE (var), var, + stride)), false); + else + /* Array[start_index + (induction_var * stride)]. */ + lhs_array_opr = grok_array_decl + (location, lhs_array_opr, + build2 (PLUS_EXPR, TREE_TYPE (var), start, + build2 (MULT_EXPR, TREE_TYPE (var), var, + stride)), false); + } + vec_safe_push (lhs_array_operand, lhs_array_opr); + } + else + vec_safe_push (lhs_array_operand, integer_one_node); + } + replace_array_notations (&lhs, true, lhs_list, lhs_array_operand); + array_expr_lhs = lhs; + } + + if (rhs_array_operand) + vec_safe_truncate (rhs_array_operand, 0); + + if (rhs_rank) + { + for (ii = 0; ii < rhs_list_size; ii++) + { + if (rhs_vector[ii][0]) + { + tree rhs_array_opr = rhs_value[ii][rhs_rank - 1]; + for (s_jj = rhs_rank - 1; s_jj >= 0; s_jj--) + { + tree stride = NULL_TREE, var = NULL_TREE, start = NULL_TREE; + if ((TREE_TYPE (rhs_start[ii][s_jj]) == + TREE_TYPE (rhs_stride[ii][s_jj])) + && (TREE_TYPE (rhs_stride[ii][s_jj]) != + TREE_TYPE (rhs_var[s_jj]))) + { + /* If stride and start are of same type and the induction + var is not, we convert induction variable to stride's + type. */ + start = rhs_start[ii][s_jj]; + stride = rhs_stride[ii][s_jj]; + var = build_c_cast (location, + TREE_TYPE (rhs_stride[ii][s_jj]), + rhs_var[s_jj]); + } + else if (TREE_TYPE (rhs_start[ii][s_jj]) != + TREE_TYPE (rhs_stride[ii][s_jj])) + { + /* If we reach here, then the stride and start are of + different types, and so it doesn't really matter what + the induction variable type is, we stay safe and + convert everything to integer. The reason why we + pick integer instead of something like size_t is + because the stride and length can be + or -. */ + start = build_c_cast (location, integer_type_node, + rhs_start[ii][s_jj]); + stride = build_c_cast (location, integer_type_node, + rhs_stride[ii][s_jj]); + var = build_c_cast (location, integer_type_node, + rhs_var[s_jj]); + } + else + { + start = rhs_start[ii][s_jj]; + stride = rhs_stride[ii][s_jj]; + var = rhs_var[s_jj]; + } + if (rhs_count_down[ii][s_jj]) + /* Array[start_index - (induction_var * stride)]. */ + rhs_array_opr = grok_array_decl + (location, rhs_array_opr, + build2 (MINUS_EXPR, TREE_TYPE (var), start, + build2 (MULT_EXPR, TREE_TYPE (var), var, + stride)), false); + else + /* Array[start_index + (induction_var * stride)]. */ + rhs_array_opr = grok_array_decl + (location, rhs_array_opr, + build2 (PLUS_EXPR, TREE_TYPE (var), start, + build2 (MULT_EXPR, TREE_TYPE (var), var, + stride)), false); + } + vec_safe_push (rhs_array_operand, rhs_array_opr); + } + else + /* This is just a dummy node to make sure the list sizes for both + array list and array operand list are the same. */ + vec_safe_push (rhs_array_operand, integer_one_node); + } + for (ii = 0; ii < rhs_list_size; ii++) + { + tree rhs_node = (*rhs_list)[ii]; + if (TREE_CODE (rhs_node) == CALL_EXPR) + { + int idx_value = 0; + tree func_name = CALL_EXPR_FN (rhs_node); + if (TREE_CODE (func_name) == ADDR_EXPR) + if (is_sec_implicit_index_fn (func_name)) + { + idx_value = + extract_sec_implicit_index_arg (location, rhs_node); + if (idx_value < (int) lhs_rank && idx_value >= 0) + vec_safe_push (rhs_array_operand, rhs_var[idx_value]); + else + { + size_t ee = 0; + tree rhs_base = (*lhs_list)[ii]; + for (ee = 0; ee < rhs_rank; ee++) + if (rhs_base + && TREE_CODE (rhs_base) == ARRAY_NOTATION_REF) + rhs_base = ARRAY_NOTATION_ARRAY (rhs_base); + + error_at (location, "__sec_implicit_index argument %d " + "must be less than rank of %qD", idx_value, + rhs_base); + return error_mark_node; + } + } + } + } + replace_array_notations (&rhs, true, rhs_list, rhs_array_operand); + array_expr_rhs = rhs; + } + else + { + for (ii = 0; ii < rhs_list_size; ii++) + { + tree rhs_node = (*rhs_list)[ii]; + if (TREE_CODE (rhs_node) == CALL_EXPR) + { + int idx_value = 0; + tree func_name = CALL_EXPR_FN (rhs_node); + if (is_sec_implicit_index_fn (func_name)) + { + idx_value = extract_sec_implicit_index_arg (location, + rhs_node); + if (idx_value < (int) lhs_rank && idx_value >= 0) + vec_safe_push (rhs_array_operand, lhs_var[idx_value]); + else + { + size_t ee = 0; + tree lhs_base = (*lhs_list)[ii]; + for (ee = 0; ee < lhs_rank; ee++) + if (lhs_base + && TREE_CODE (lhs_base) == ARRAY_NOTATION_REF) + lhs_base = ARRAY_NOTATION_ARRAY (lhs_base); + error_at (location, "__sec_implicit_index argument %d " + "must be less than the rank of %qD", idx_value, + lhs_base); + return error_mark_node; + } + } + } + } + replace_array_notations (&rhs, true, rhs_list, rhs_array_operand); + array_expr_rhs = rhs; + rhs_expr_incr[0] = NULL_TREE; + } + + for (ii = 0; ii < rhs_rank; ii++) + if (rhs_count_down[0][ii]) + rhs_expr_incr[ii] = build_x_unary_op (location, POSTDECREMENT_EXPR, + rhs_var[ii], complain); + else + rhs_expr_incr[ii] = build_x_unary_op (location, POSTINCREMENT_EXPR, + rhs_var[ii], complain); + + for (ii = 0; ii < lhs_rank; ii++) + if (lhs_count_down[0][ii]) + lhs_expr_incr[ii] = build_x_unary_op (location, POSTDECREMENT_EXPR, + lhs_var[ii], complain); + else + lhs_expr_incr[ii] = build_x_unary_op (location, POSTINCREMENT_EXPR, + lhs_var[ii], complain); + if (!array_expr_lhs) + array_expr_lhs = lhs; + + array_expr = build_x_modify_expr (location, array_expr_lhs, modifycode, + array_expr_rhs, complain); + + for (jj = 0; jj < MAX (lhs_rank, rhs_rank); jj++) + { + if (rhs_rank && rhs_expr_incr[jj]) + { + size_t iii = 0; + if (lhs_rank) + { + if (lhs_count_down[0][jj]) + lhs_compare[jj] = build_x_binary_op + (location, GT_EXPR, lhs_var[jj], TREE_CODE (lhs_var[jj]), + lhs_length[0][jj], TREE_CODE (lhs_length[0][jj]), NULL, + complain); + else + lhs_compare[jj] = build_x_binary_op + (location, LT_EXPR, lhs_var[jj], TREE_CODE (lhs_var[jj]), + lhs_length[0][jj], TREE_CODE (lhs_length[0][jj]), NULL, + complain); + } + else + lhs_compare[jj] = NULL_TREE; + + for (iii = 0; iii < rhs_list_size; iii++) + if (rhs_vector[iii][jj]) + break; + + /* What we are doing here is this: + We always count up, so: + if (length is negative ==> which means we count down) + we multiply length by -1 and count up => ii < -LENGTH + else + we just count up, so we compare for ii < LENGTH + */ + if (rhs_count_down[iii][jj]) + { + tree new_rhs = build_x_modify_expr + (location, rhs_length[iii][jj], MULT_EXPR, + build_int_cst (TREE_TYPE (rhs_length[iii][jj]), -1), complain); + rhs_compare[jj] = build_x_binary_op + (location, GT_EXPR, rhs_var[jj], TREE_CODE (rhs_var[jj]), + new_rhs, TREE_CODE (new_rhs), NULL, complain); + } + else + rhs_compare[jj] = build_x_binary_op + (location, LT_EXPR, rhs_var[jj], TREE_CODE (rhs_var[jj]), + rhs_length[iii][jj], TREE_CODE (rhs_length[0][jj]), NULL, + complain); + + if (lhs_rank) + cond_expr[jj] = build_x_binary_op + (location, TRUTH_ANDIF_EXPR, lhs_compare[jj], + TREE_CODE (lhs_compare[jj]), rhs_compare[jj], + TREE_CODE (rhs_compare[jj]), NULL, complain); + else + cond_expr[jj] = rhs_compare[jj]; + } + else + { + if (lhs_count_down[0][jj]) + cond_expr[jj] = build_x_binary_op + (location, GT_EXPR, lhs_var[jj], TREE_CODE (lhs_var[jj]), + lhs_length[0][jj], TREE_CODE (lhs_length[0][jj]), NULL, + complain); + else + cond_expr[jj] = build_x_binary_op + (location, LT_EXPR, lhs_var[jj], TREE_CODE (lhs_var[jj]), + lhs_length[0][jj], TREE_CODE (lhs_length[0][jj]), NULL, + complain); + } + } + + an_init = pop_stmt_list (an_init); + append_to_statement_list_force (an_init, &loop_with_init); + body = array_expr; + for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++) + { + tree incr_list = alloc_stmt_list (); + tree init_list = alloc_stmt_list (); + tree new_loop = push_stmt_list (); + + if (lhs_rank) + { + append_to_statement_list_force (lhs_ind_init[ii], &init_list); + append_to_statement_list_force (lhs_expr_incr[ii], &incr_list); + } + if (rhs_rank) + { + append_to_statement_list_force (rhs_ind_init[ii], &init_list); + append_to_statement_list_force (rhs_expr_incr[ii], &incr_list); + } + create_an_loop (init_list, cond_expr[ii], incr_list, body); + body = pop_stmt_list (new_loop); + } + append_to_statement_list (body, &loop_with_init); + for (ii = 0; ii < rhs_list_size; ii++) + { + XDELETEVEC (rhs_vector[ii]); + XDELETEVEC (rhs_array[ii]); + XDELETEVEC (rhs_value[ii]); + XDELETEVEC (rhs_length[ii]); + XDELETEVEC (rhs_stride[ii]); + XDELETEVEC (rhs_start[ii]); + } + for (ii = 0; ii < lhs_list_size; ii++) + { + XDELETEVEC (lhs_vector[ii]); + XDELETEVEC (lhs_array[ii]); + XDELETEVEC (lhs_value[ii]); + XDELETEVEC (lhs_length[ii]); + XDELETEVEC (lhs_stride[ii]); + XDELETEVEC (lhs_start[ii]); + } + if (rhs_vector) + XDELETEVEC (rhs_vector); + + if (rhs_array) + XDELETEVEC (rhs_array); + if (rhs_value) + XDELETEVEC (rhs_value); + if (rhs_length) + XDELETEVEC (rhs_length); + if (rhs_stride) + XDELETEVEC (rhs_stride); + if (rhs_start) + XDELETEVEC (rhs_start); + if (rhs_expr_incr) + XDELETEVEC (rhs_expr_incr); + if (rhs_ind_init) + XDELETEVEC (rhs_ind_init); + if (rhs_compare) + XDELETEVEC (rhs_compare); + if (lhs_compare) + XDELETEVEC (lhs_compare); + + return loop_with_init; +} + +/* Helper function for fix_conditonal_array_notations. Encloses the conditional + statement passed in ORIG_STMT with a loop around it and replaces the + condition in STMT with a ARRAY_REF tree-node to the array. The condition + must have a ARRAY_NOTATION_REF tree. */ + +static tree +cp_fix_cond_array_notations (tree orig_stmt) +{ + vec *array_list = NULL, *array_operand = NULL; + size_t list_size = 0; + size_t rank = 0, ii = 0, jj = 0; + tree **array_ops, *array_var, jj_tree, body, stmt = NULL_TREE; + tree **array_value, **array_stride, **array_length, **array_start; + tree *compare_expr, an_init, *expr_incr, *ind_init; + tree builtin_loop, new_var = NULL_TREE; + bool **count_down, **array_vector; + tree loop_with_init = alloc_stmt_list (); + int s_jj = 0; + tree begin_var, lngth_var, strde_var; + tsubst_flags_t complain = tf_warning_or_error; + location_t location = UNKNOWN_LOCATION; + + if (TREE_CODE (orig_stmt) == COND_EXPR) + { + size_t cond_rank = 0, yes_rank = 0, no_rank = 0; + tree yes_expr = COND_EXPR_THEN (orig_stmt); + tree no_expr = COND_EXPR_ELSE (orig_stmt); + tree cond = COND_EXPR_COND (orig_stmt); + if (!find_rank (EXPR_LOCATION (cond), cond, cond, true, &cond_rank) + || !find_rank (EXPR_LOCATION (yes_expr), yes_expr, yes_expr, true, + &yes_rank) + || find_rank (EXPR_LOCATION (no_expr), no_expr, no_expr, true, + &no_rank)) + return error_mark_node; + if (cond_rank != 0 && cond_rank != yes_rank && yes_rank != 0) + { + error_at (EXPR_LOCATION (yes_expr), "rank mismatch with controlling" + " expression of parent if-statement"); + return error_mark_node; + } + else if (cond_rank != 0 && cond_rank != no_rank && no_rank != 0) + { + error_at (EXPR_LOCATION (no_expr), "rank mismatch with controlling " + "expression of parent if-statement"); + return error_mark_node; + } + } + else if (TREE_CODE (orig_stmt) == IF_STMT) + { + size_t cond_rank = 0, yes_rank = 0, no_rank = 0; + tree yes_expr = THEN_CLAUSE (orig_stmt); + tree no_expr = ELSE_CLAUSE (orig_stmt); + tree cond = IF_COND (orig_stmt); + if (!find_rank (EXPR_LOCATION (cond), cond, cond, true, &cond_rank) + || (yes_expr + && !find_rank (EXPR_LOCATION (yes_expr), yes_expr, yes_expr, true, + &yes_rank)) + || (no_expr + && !find_rank (EXPR_LOCATION (no_expr), no_expr, no_expr, true, + &no_rank))) + return error_mark_node; + if (cond_rank != 0 && cond_rank != yes_rank && yes_rank != 0) + { + error_at (EXPR_LOCATION (yes_expr), "rank mismatch with controlling" + " expression of parent if-statement"); + return error_mark_node; + } + else if (cond_rank != 0 && cond_rank != no_rank && no_rank != 0) + { + error_at (EXPR_LOCATION (no_expr), "rank mismatch with controlling " + "expression of parent if-statement"); + return error_mark_node; + } + } + + if (!find_rank (EXPR_LOCATION (orig_stmt), orig_stmt, orig_stmt, true, + &rank)) + return error_mark_node; + if (rank == 0) + return orig_stmt; + + extract_array_notation_exprs (orig_stmt, false, &array_list); + stmt = alloc_stmt_list (); + for (ii = 0; ii < vec_safe_length (array_list); ii++) + { + tree array_node = (*array_list)[ii]; + if (TREE_CODE (array_node) == CALL_EXPR + || TREE_CODE (array_node) == AGGR_INIT_EXPR) + { + builtin_loop = fix_builtin_array_notation_fn (array_node, &new_var); + if (builtin_loop == error_mark_node) + finish_expr_stmt (error_mark_node); + else if (new_var) + { + vec *sub_list = NULL, *new_var_list = NULL; + vec_safe_push (sub_list, array_node); + vec_safe_push (new_var_list, new_var); + replace_array_notations (&orig_stmt, false, sub_list, + new_var_list); + append_to_statement_list_force (builtin_loop, &stmt); + } + } + } + append_to_statement_list_force (orig_stmt, &stmt); + rank = 0; + array_list = NULL; + if (!find_rank (EXPR_LOCATION (stmt), stmt, stmt, true, &rank)) + return error_mark_node; + if (rank == 0) + return stmt; + + extract_array_notation_exprs (stmt, true, &array_list); + list_size = vec_safe_length (array_list); + if (list_size == 0) + return stmt; + + location = EXPR_LOCATION (orig_stmt); + array_ops = XNEWVEC (tree *, list_size); + for (ii = 0; ii < list_size; ii++) + array_ops[ii] = XNEWVEC (tree, rank); + + array_vector = XNEWVEC (bool *, list_size); + for (ii = 0; ii < list_size; ii++) + array_vector[ii] = XNEWVEC (bool, rank); + + array_value = XNEWVEC (tree *, list_size); + array_stride = XNEWVEC (tree *, list_size); + array_length = XNEWVEC (tree *, list_size); + array_start = XNEWVEC (tree *, list_size); + + for (ii = 0; ii < list_size; ii++) + { + array_value[ii] = XNEWVEC (tree, rank); + array_stride[ii] = XNEWVEC (tree, rank); + array_length[ii] = XNEWVEC (tree, rank); + array_start[ii] = XNEWVEC (tree, rank); + } + + compare_expr = XNEWVEC (tree, rank); + expr_incr = XNEWVEC (tree, rank); + ind_init = XNEWVEC (tree, rank); + + list_size = vec_safe_length (array_list); + count_down = XNEWVEC (bool *, list_size); + for (ii = 0; ii < list_size; ii++) + count_down[ii] = XNEWVEC (bool, rank); + + array_var = XNEWVEC (tree, rank); + an_init = push_stmt_list (); + + /* Assign the array notation components to variable so that they can satisfy + the exec-once rule. */ + for (ii = 0; ii < list_size; ii++) + { + tree array_node = (*array_list)[ii]; + if (array_node && TREE_CODE (array_node) == ARRAY_NOTATION_REF) + { + tree array_begin = ARRAY_NOTATION_START (array_node); + tree array_lngth = ARRAY_NOTATION_LENGTH (array_node); + tree array_strde = ARRAY_NOTATION_STRIDE (array_node); + + if (TREE_CODE (array_begin) != INTEGER_CST) + { + begin_var = build_decl (location, VAR_DECL, NULL_TREE, + integer_type_node); + finish_expr_stmt (build_x_modify_expr (location, begin_var, + NOP_EXPR, array_begin, + complain)); + ARRAY_NOTATION_START (array_node) = begin_var; + } + if (TREE_CODE (array_lngth) != INTEGER_CST) + { + lngth_var = build_decl (location, VAR_DECL, NULL_TREE, + integer_type_node); + finish_expr_stmt (build_x_modify_expr (location, lngth_var, + NOP_EXPR, array_lngth, + complain)); + ARRAY_NOTATION_LENGTH (array_node) = lngth_var; + } + if (TREE_CODE (array_strde) != INTEGER_CST) + { + strde_var = build_decl (location, VAR_DECL, NULL_TREE, + integer_type_node); + finish_expr_stmt (build_x_modify_expr (location, strde_var, + NOP_EXPR, array_strde, + complain)); + ARRAY_NOTATION_STRIDE (array_node) = strde_var; + } + } + } + + for (ii = 0; ii < list_size; ii++) + { + jj = 0; + jj_tree = (*array_list)[ii]; + while (jj_tree) + { + if (TREE_CODE (jj_tree) == ARRAY_NOTATION_REF) + { + array_ops[ii][jj] = jj_tree; + jj++; + jj_tree = ARRAY_NOTATION_ARRAY (jj_tree); + } + else if (TREE_CODE (jj_tree) == ARRAY_REF) + jj_tree = TREE_OPERAND (jj_tree, 0); + else if (TREE_CODE (jj_tree) == VAR_DECL + || TREE_CODE (jj_tree) == PARM_DECL) + break; + } + } + + for (ii = 0; ii < list_size; ii++) + { + if (TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF) + { + for (jj = 0; jj < rank; jj++) + { + if (TREE_CODE (array_ops[ii][jj]) == ARRAY_NOTATION_REF) + { + array_value[ii][jj] = + ARRAY_NOTATION_ARRAY (array_ops[ii][jj]); + array_start[ii][jj] = + ARRAY_NOTATION_START (array_ops[ii][jj]); + array_length[ii][jj] = + ARRAY_NOTATION_LENGTH (array_ops[ii][jj]); + array_stride[ii][jj] = + ARRAY_NOTATION_STRIDE (array_ops[ii][jj]); + array_vector[ii][jj] = true; + + if (!integer_zerop (array_length[ii][jj]) + && !integer_nonzerop (array_length[ii][jj])) + count_down[ii][jj] = false; + else if (tree_int_cst_lt + (array_length[ii][jj], + build_zero_cst (TREE_TYPE (array_length[ii][jj])))) + count_down[ii][jj] = true; + else + count_down[ii][jj] = false; + } + else + array_vector[ii][jj] = false; + } + } + } + for (ii = 0; ii < rank; ii++) + { + if (TREE_TYPE (array_start[0][ii]) + && TREE_CODE (TREE_TYPE (array_start[0][ii])) != TEMPLATE_TYPE_PARM) + { + array_var[ii] = build_decl (location, VAR_DECL, NULL_TREE, + TREE_TYPE (array_start[0][ii])); + ind_init[ii] = build_x_modify_expr + (location, array_var[ii], NOP_EXPR, + build_zero_cst (TREE_TYPE (array_var[ii])), tf_warning_or_error); + } + else + { + array_var[ii] = build_min_nt_loc (location, VAR_DECL, + NULL_TREE, NULL_TREE); + ind_init[ii] = build_x_modify_expr (location, array_var[ii], + NOP_EXPR, + integer_zero_node, 1); + } + } + for (ii = 0; ii < list_size; ii++) + { + if (array_vector[ii][0]) + { + tree array_opr = array_value[ii][rank - 1]; + for (s_jj = rank - 1; s_jj >= 0; s_jj--) + { + tree stride = NULL_TREE, var = NULL_TREE, start = NULL_TREE; + + /* If stride and start are of same type and the induction var + is not, we convert induction variable to stride's type. */ + if ((TREE_TYPE (array_start[ii][s_jj]) == + TREE_TYPE (array_stride[ii][s_jj])) + && (TREE_TYPE (array_stride[ii][s_jj]) != + TREE_TYPE (array_var[s_jj]))) + { + start = array_start[ii][s_jj]; + stride = array_stride[ii][s_jj]; + var = + build_c_cast (location, TREE_TYPE (array_stride[ii][s_jj]), + array_var[s_jj]); + } + else if (TREE_TYPE (array_start[ii][s_jj]) != + TREE_TYPE (array_stride[ii][s_jj])) + { + /* If we reach here, then the stride and start are of + different types, and so it doesn't really matter what + the induction variable type is, we stay safe and convert + everything to integer. The reason why we pick integer + instead of something like size_t is because the stride + and length can be + or -. */ + start = build_c_cast (location, integer_type_node, + array_start[ii][s_jj]); + stride = build_c_cast (location, integer_type_node, + array_stride[ii][s_jj]); + var = build_c_cast (location, integer_type_node, + array_var[s_jj]); + } + else + { + start = array_start[ii][s_jj]; + stride = array_stride[ii][s_jj]; + var = array_var[s_jj]; + } + if (count_down[ii][s_jj]) + /* Array[start_index - (induction_var * stride)]. */ + array_opr = grok_array_decl + (location, array_opr, + build2 (MINUS_EXPR, TREE_TYPE (var), start, + build2 (MULT_EXPR, TREE_TYPE (var), var, stride)), + false); + else + /* Array[start_index + (induction_var * stride)]. */ + array_opr = grok_array_decl + (location, array_opr, + build2 (PLUS_EXPR, TREE_TYPE (var), start, + build2 (MULT_EXPR, TREE_TYPE (var), var, stride)), + false); + + } + vec_safe_push (array_operand, array_opr); + } + else + vec_safe_push (array_operand, integer_one_node); + } + replace_array_notations (&stmt, true, array_list, array_operand); + + for (ii = 0; ii < rank; ii++) + if (count_down[0][ii]) + expr_incr[ii] = build_x_unary_op (location, POSTDECREMENT_EXPR, + array_var[ii], tf_warning_or_error); + else + expr_incr[ii] = build_x_unary_op (location, POSTINCREMENT_EXPR, + array_var[ii], tf_warning_or_error); + + for (jj = 0; jj < rank; jj++) + { + if (rank && expr_incr[jj]) + { + if (count_down[0][jj]) + compare_expr[jj] = build_x_binary_op + (location, GT_EXPR, array_var[jj], TREE_CODE (array_var[jj]), + array_length[0][jj], TREE_CODE (array_length[0][jj]), NULL, + tf_warning_or_error); + else + compare_expr[jj] = build_x_binary_op + (location, LT_EXPR, array_var[jj], TREE_CODE (array_var[jj]), + array_length[0][jj], TREE_CODE (array_length[0][jj]), NULL, + tf_warning_or_error); + } + } + + an_init = pop_stmt_list (an_init); + append_to_statement_list_force (an_init, &loop_with_init); + body = stmt; + + for (ii = 0; ii < rank; ii++) + { + tree new_loop = push_stmt_list (); + create_an_loop (ind_init[ii], compare_expr[ii], expr_incr[ii], body); + body = pop_stmt_list (new_loop); + } + append_to_statement_list_force (body, &loop_with_init); + + XDELETEVEC (compare_expr); + XDELETEVEC (expr_incr); + XDELETEVEC (ind_init); + XDELETEVEC (array_var); + + for (ii = 0; ii < list_size; ii++) + { + XDELETEVEC (count_down[ii]); + XDELETEVEC (array_value[ii]); + XDELETEVEC (array_stride[ii]); + XDELETEVEC (array_length[ii]); + XDELETEVEC (array_start[ii]); + XDELETEVEC (array_ops[ii]); + XDELETEVEC (array_vector[ii]); + } + + XDELETEVEC (count_down); + XDELETEVEC (array_value); + XDELETEVEC (array_stride); + XDELETEVEC (array_length); + XDELETEVEC (array_start); + XDELETEVEC (array_ops); + XDELETEVEC (array_vector); + + return loop_with_init; +} + +/* Transforms array notations inside unary expression ORIG_STMT with an + appropriate loop and ARRAY_REF (and returns all this as a super-tree called + LOOP). */ + +static tree +fix_unary_array_notation_exprs (tree orig_stmt) +{ + vec *array_list = NULL, *array_operand = NULL; + int s_jj = 0; + size_t list_size = 0, rank = 0, ii = 0, jj = 0; + tree **array_ops, *array_var, jj_tree, body, array_opr; + tree **array_value, **array_stride, **array_length, **array_start; + tree *compare_expr, *expr_incr, *ind_init; + bool **count_down, **array_vector; + tree builtin_loop, stmt = NULL_TREE, new_var = NULL_TREE; + tree begin_var, lngth_var, strde_var; + location_t location = EXPR_LOCATION (orig_stmt); + tree an_init, loop_with_init = alloc_stmt_list (); + + if (!find_rank (location, orig_stmt, orig_stmt, true, &rank)) + return error_mark_node; + if (rank == 0) + return orig_stmt; + + extract_array_notation_exprs (orig_stmt, false, &array_list); + list_size = vec_safe_length (array_list); + location = EXPR_LOCATION (orig_stmt); + stmt = NULL_TREE; + for (ii = 0; ii < list_size; ii++) + { + tree list_node = (*array_list)[ii]; + if (TREE_CODE (list_node) == CALL_EXPR + || TREE_CODE (list_node) == AGGR_INIT_EXPR) + { + builtin_loop = + fix_builtin_array_notation_fn (list_node, &new_var); + if (builtin_loop == error_mark_node) + return error_mark_node; + else if (builtin_loop) + { + vec *sub_list = NULL, *new_var_list = NULL; + stmt = alloc_stmt_list (); + append_to_statement_list_force (builtin_loop, &stmt); + vec_safe_push (sub_list, list_node); + vec_safe_push (new_var_list, new_var); + replace_array_notations (&orig_stmt, false, sub_list, + new_var_list); + } + } + } + if (stmt != NULL_TREE) + append_to_statement_list_force (finish_expr_stmt (orig_stmt), &stmt); + else + stmt = orig_stmt; + rank = 0; + list_size = 0; + array_list = NULL; + extract_array_notation_exprs (stmt, true, &array_list); + list_size = vec_safe_length (array_list); + + if (!find_rank (EXPR_LOCATION (stmt), stmt, stmt, true, &rank)) + return error_mark_node; + if (rank == 0) + return stmt; + + if (list_size == 0) + return stmt; + + array_ops = XNEWVEC (tree *, list_size); + for (ii = 0; ii < list_size; ii++) + array_ops[ii] = XNEWVEC (tree, rank); + + array_vector = XNEWVEC (bool *, list_size); + for (ii = 0; ii < list_size; ii++) + array_vector[ii] = XNEWVEC (bool, rank); + + array_value = XNEWVEC (tree *, list_size); + array_stride = XNEWVEC (tree *, list_size); + array_length = XNEWVEC (tree *, list_size); + array_start = XNEWVEC (tree *, list_size); + + for (ii = 0; ii < list_size; ii++) + { + array_value[ii] = XNEWVEC (tree, rank); + array_stride[ii] = XNEWVEC (tree, rank); + array_length[ii] = XNEWVEC (tree, rank); + array_start[ii] = XNEWVEC (tree, rank); + } + + compare_expr = XNEWVEC (tree, rank); + expr_incr = XNEWVEC (tree, rank); + ind_init = XNEWVEC (tree, rank); + array_var = XNEWVEC (tree, rank); + + count_down = XNEWVEC (bool *, list_size); + for (ii = 0; ii < list_size; ii++) + count_down[ii] = XNEWVEC (bool, rank); + + /* Assign the array notation components to variable so that they can satisfy + the exec-once rule. */ + for (ii = 0; ii < list_size; ii++) + { + tree array_node = (*array_list)[ii]; + tree array_begin = ARRAY_NOTATION_START (array_node); + tree array_lngth = ARRAY_NOTATION_LENGTH (array_node); + tree array_strde = ARRAY_NOTATION_STRIDE (array_node); + tsubst_flags_t complain = tf_warning_or_error; + if (array_node && TREE_CODE (array_node) == ARRAY_NOTATION_REF) + { + if (TREE_CODE (array_begin) != INTEGER_CST) + { + begin_var = build_decl (location, VAR_DECL, NULL_TREE, + integer_type_node); + finish_expr_stmt (build_x_modify_expr (location, begin_var, + NOP_EXPR, array_begin, + complain)); + ARRAY_NOTATION_START (array_node) = begin_var; + } + if (TREE_CODE (array_lngth) != INTEGER_CST) + { + lngth_var = build_decl (location, VAR_DECL, NULL_TREE, + integer_type_node); + finish_expr_stmt (build_x_modify_expr (location, lngth_var, + NOP_EXPR, array_lngth, + complain)); + ARRAY_NOTATION_LENGTH (array_node) = lngth_var; + } + if (TREE_CODE (array_strde) != INTEGER_CST) + { + strde_var = build_decl (location, VAR_DECL, NULL_TREE, + integer_type_node); + finish_expr_stmt (build_x_modify_expr (location, strde_var, + NOP_EXPR, array_strde, + complain)); + ARRAY_NOTATION_STRIDE (array_node) = strde_var; + } + } + } + for (ii = 0; ii < list_size; ii++) + { + jj = 0; + jj_tree = (*array_list)[ii]; + while (jj_tree) + { + if (TREE_CODE (jj_tree) == ARRAY_NOTATION_REF) + { + array_ops[ii][jj] = jj_tree; + jj++; + jj_tree = ARRAY_NOTATION_ARRAY (jj_tree); + } + else if (TREE_CODE (jj_tree) == VAR_DECL + || TREE_CODE (jj_tree) == PARM_DECL) + break; + else + jj_tree = TREE_OPERAND (jj_tree, 0); + } + } + for (ii = 0; ii < list_size; ii++) + { + if (TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF) + { + for (jj = 0; jj < rank; jj++) + { + if (TREE_CODE (array_ops[ii][jj]) == ARRAY_NOTATION_REF) + { + array_value[ii][jj] = + ARRAY_NOTATION_ARRAY (array_ops[ii][jj]); + array_start[ii][jj] = + ARRAY_NOTATION_START (array_ops[ii][jj]); + array_length[ii][jj] = + ARRAY_NOTATION_LENGTH (array_ops[ii][jj]); + array_stride[ii][jj] = + ARRAY_NOTATION_STRIDE (array_ops[ii][jj]); + array_vector[ii][jj] = true; + + if (!TREE_CONSTANT (array_length[ii][jj]) + || TREE_CODE (array_length[ii][jj]) == VAR_DECL) + count_down[ii][jj] = false; + else if (!integer_zerop (array_length[ii][jj]) + && !integer_nonzerop (array_length[ii][jj])) + count_down[ii][jj] = false; + else if (tree_int_cst_lt + (array_length[ii][jj], + build_zero_cst (TREE_TYPE (array_length[ii][jj])))) + count_down[ii][jj] = true; + else + count_down[ii][jj] = false; + } + else + array_vector[ii][jj] = false; + } + } + } + + an_init = push_stmt_list (); + for (ii = 0; ii < rank; ii++) + { + array_var[ii] = build_decl (location, VAR_DECL, NULL_TREE, + TREE_TYPE (array_start[0][ii])); + ind_init[ii] = build_x_modify_expr + (location, array_var[ii], NOP_EXPR, + build_zero_cst (TREE_TYPE (array_var[ii])), tf_warning_or_error); + } + for (ii = 0; ii < list_size; ii++) + { + if (array_vector[ii][0]) + { + array_opr = array_value[ii][rank - 1]; + for (s_jj = rank - 1; s_jj >= 0; s_jj--) + { + tree stride = NULL_TREE, var = NULL_TREE, start = NULL_TREE; + if ((TREE_TYPE (array_start[ii][s_jj]) == + TREE_TYPE (array_stride[ii][s_jj])) + && (TREE_TYPE (array_stride[ii][s_jj]) != + TREE_TYPE (array_var[s_jj]))) + { + /* If stride and start are of same type and the induction var + is not, we convert induction variable to stride's + type. */ + start = array_start[ii][s_jj]; + stride = array_stride[ii][s_jj]; + var = + build_c_cast (location, TREE_TYPE (array_stride[ii][s_jj]), + array_var[s_jj]); + } + else if (TREE_TYPE (array_start[ii][s_jj]) != + TREE_TYPE (array_stride[ii][s_jj])) + { + /* If we reach here, then the stride and start are of + different types, and so it doesn't really matter what + the induction variable type is, we stay safe and convert + everything to integer. The reason why we pick integer + instead of something like size_t is because the stride + and length can be + or -. */ + start = build_c_cast (location, integer_type_node, + array_start[ii][s_jj]); + stride = build_c_cast (location, integer_type_node, + array_stride[ii][s_jj]); + var = build_c_cast (location, integer_type_node, + array_var[s_jj]); + } + else + { + start = array_start[ii][s_jj]; + stride = array_stride[ii][s_jj]; + var = array_var[s_jj]; + } + if (count_down[ii][s_jj]) + /* Array[start_index - (induction_var * stride)]. */ + array_opr = grok_array_decl + (location, array_opr, + build2 (MINUS_EXPR, TREE_TYPE (var), start, + build2 (MULT_EXPR, TREE_TYPE (var), var, stride)), + false); + else + /* Array[start_index + (induction_var * stride)]. */ + array_opr = grok_array_decl + (location, array_opr, + build2 (PLUS_EXPR, TREE_TYPE (var), start, + build2 (MULT_EXPR, TREE_TYPE (var), var, stride)), + false); + } + vec_safe_push (array_operand, array_opr); + } + else + vec_safe_push (array_operand, integer_one_node); + } + replace_array_notations (&stmt, true, array_list, array_operand); + + for (ii = 0; ii < rank; ii++) + if (count_down[0][ii]) + expr_incr[ii] = build_x_unary_op (location, POSTDECREMENT_EXPR, + array_var[ii], tf_warning_or_error); + else + expr_incr[ii] = build_x_unary_op (location, POSTINCREMENT_EXPR, + array_var[ii], tf_warning_or_error); + + for (jj = 0; jj < rank; jj++) + { + if (rank && expr_incr[jj]) + { + if (count_down[0][jj]) + compare_expr[jj] = build_x_binary_op + (location, GT_EXPR, array_var[jj], TREE_CODE (array_var[jj]), + array_length[0][jj], TREE_CODE (array_length[0][jj]), NULL, + tf_warning_or_error); + else + compare_expr[jj] = build_x_binary_op + (location, LT_EXPR, array_var[jj], TREE_CODE (array_var[jj]), + array_length[0][jj], TREE_CODE (array_length[0][jj]), NULL, + tf_warning_or_error); + } + } + + an_init = pop_stmt_list (an_init); + append_to_statement_list_force (an_init, &loop_with_init); + body = stmt; + + for (ii = 0; ii < rank; ii++) + { + tree new_loop = push_stmt_list (); + create_an_loop (ind_init[ii], compare_expr[ii], expr_incr[ii], body); + body = pop_stmt_list (new_loop); + } + append_to_statement_list_force (body, &loop_with_init); + + XDELETEVEC (compare_expr); + XDELETEVEC (expr_incr); + XDELETEVEC (ind_init); + XDELETEVEC (array_var); + + for (ii = 0; ii < list_size; ii++) + { + XDELETEVEC (count_down[ii]); + XDELETEVEC (array_value[ii]); + XDELETEVEC (array_stride[ii]); + XDELETEVEC (array_length[ii]); + XDELETEVEC (array_start[ii]); + XDELETEVEC (array_ops[ii]); + XDELETEVEC (array_vector[ii]); + } + + XDELETEVEC (count_down); + XDELETEVEC (array_value); + XDELETEVEC (array_stride); + XDELETEVEC (array_length); + XDELETEVEC (array_start); + XDELETEVEC (array_ops); + XDELETEVEC (array_vector); + + return loop_with_init; +} + +/* Expands the array notation's builtin reduction function in EXPR + (of type RETURN_EXPR) and returns a STATEMENT_LIST that contains a loop + with the builtin function expansion and a return statement at the end. */ + +static tree +fix_return_expr (tree expr) +{ + tree new_mod_list, new_var, new_mod, retval_expr; + location_t loc = EXPR_LOCATION (expr); + + if (TREE_CODE (expr) != RETURN_EXPR) + return expr; + + new_mod_list = alloc_stmt_list (); + retval_expr = TREE_OPERAND (expr, 0); + new_var = build_decl (loc, VAR_DECL, NULL_TREE, TREE_TYPE (retval_expr)); + new_mod = build_x_array_notation_expr (loc, new_var, NOP_EXPR, + TREE_OPERAND (retval_expr, 1), + tf_warning_or_error); + TREE_OPERAND (retval_expr, 1) = new_var; + TREE_OPERAND (expr, 0) = retval_expr; + append_to_statement_list_force (new_mod, &new_mod_list); + append_to_statement_list_force (expr, &new_mod_list); + return new_mod_list; +} + +/* Expands ARRAY_NOTATION_REF and builtin functions in a compound statement, + STMT. Returns the STMT with expanded array notations. */ + +tree +fix_array_notation_exprs (tree t) +{ + enum tree_code code; + bool is_expr; + location_t loc = UNKNOWN_LOCATION; + + /* Skip empty subtrees. */ + if (!t) + return t; + + loc = EXPR_LOCATION (t); + + code = TREE_CODE (t); + is_expr = IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)); + switch (code) + { + case ERROR_MARK: + case IDENTIFIER_NODE: + case INTEGER_CST: + case REAL_CST: + case FIXED_CST: + case STRING_CST: + case BLOCK: + case PLACEHOLDER_EXPR: + case FIELD_DECL: + case VOID_TYPE: + case REAL_TYPE: + case SSA_NAME: + case LABEL_DECL: + case RESULT_DECL: + case VAR_DECL: + case PARM_DECL: + case NON_LVALUE_EXPR: + case NOP_EXPR: + case INIT_EXPR: + case ADDR_EXPR: + case ARRAY_REF: + case BIT_FIELD_REF: + case VECTOR_CST: + case COMPLEX_CST: + return t; + case MODIFY_EXPR: + if (contains_array_notation_expr (t)) + t = build_x_array_notation_expr (loc, TREE_OPERAND (t, 0), NOP_EXPR, + TREE_OPERAND (t, 1), + tf_warning_or_error); + return t; + case MODOP_EXPR: + if (contains_array_notation_expr (t) && !processing_template_decl) + t = build_x_array_notation_expr + (loc, TREE_OPERAND (t, 0), TREE_CODE (TREE_OPERAND (t, 1)), + TREE_OPERAND (t, 2), tf_warning_or_error); + return t; + case CONSTRUCTOR: + return t; + case BIND_EXPR: + { + BIND_EXPR_BODY (t) = + fix_array_notation_exprs (BIND_EXPR_BODY (t)); + return t; + } + case DECL_EXPR: + { + tree x = DECL_EXPR_DECL (t); + if (t && TREE_CODE (x) != FUNCTION_DECL) + if (DECL_INITIAL (x)) + t = fix_unary_array_notation_exprs (t); + return t; + } + case STATEMENT_LIST: + { + tree_stmt_iterator i; + for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) + *tsi_stmt_ptr (i) = + fix_array_notation_exprs (*tsi_stmt_ptr (i)); + return t; + } + + case OMP_PARALLEL: + case OMP_TASK: + case OMP_FOR: + case OMP_SINGLE: + case OMP_SECTION: + case OMP_SECTIONS: + case OMP_MASTER: + case OMP_ORDERED: + case OMP_CRITICAL: + case OMP_ATOMIC: + case OMP_CLAUSE: + case TARGET_EXPR: + case INTEGER_TYPE: + case ENUMERAL_TYPE: + case BOOLEAN_TYPE: + case POINTER_TYPE: + case ARRAY_TYPE: + case RECORD_TYPE: + case METHOD_TYPE: + return t; + case RETURN_EXPR: + if (contains_array_notation_expr (t)) + t = fix_return_expr (t); + return t; + case PREDECREMENT_EXPR: + case PREINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + case AGGR_INIT_EXPR: + case CALL_EXPR: + t = fix_unary_array_notation_exprs (t); + return t; + case CONVERT_EXPR: + case CLEANUP_POINT_EXPR: + case EXPR_STMT: + TREE_OPERAND (t, 0) = fix_array_notation_exprs (TREE_OPERAND (t, 0)); + /* It is not necessary to wrap error_mark_node in EXPR_STMT. */ + if (TREE_OPERAND (t, 0) == error_mark_node) + return TREE_OPERAND (t, 0); + return t; + case COND_EXPR: + t = cp_fix_cond_array_notations (t); + if (TREE_CODE (t) == COND_EXPR) + { + COND_EXPR_THEN (t) = + fix_array_notation_exprs (COND_EXPR_THEN (t)); + COND_EXPR_ELSE (t) = + fix_array_notation_exprs (COND_EXPR_ELSE (t)); + } + else + t = fix_array_notation_exprs (t); + return t; + + case SWITCH_EXPR: + t = cp_fix_cond_array_notations (t); + if (TREE_CODE (t) == SWITCH_EXPR) + SWITCH_BODY (t) = fix_array_notation_exprs (SWITCH_BODY (t)); + else + t = fix_array_notation_exprs (t); + return t; + + case FOR_STMT: + + /* FIXME: Add a check for CILK_FOR_STMT here when we add Cilk tasking + keywords. */ + if (TREE_CODE (t) == FOR_STMT) + FOR_BODY (t) = fix_array_notation_exprs (FOR_BODY (t)); + else + t = fix_array_notation_exprs (t); + return t; + + case IF_STMT: + t = cp_fix_cond_array_notations (t); + /* If the above function added some extra instructions above the original + if statement, then we can't assume it is still IF_STMT so we have to + check again. */ + if (TREE_CODE (t) == IF_STMT) + { + if (THEN_CLAUSE (t)) + THEN_CLAUSE (t) = fix_array_notation_exprs (THEN_CLAUSE (t)); + if (ELSE_CLAUSE (t)) + ELSE_CLAUSE (t) = fix_array_notation_exprs (ELSE_CLAUSE (t)); + } + else + t = fix_array_notation_exprs (t); + return t; + + case SWITCH_STMT: + t = cp_fix_cond_array_notations (t); + /* If the above function added some extra instructions above the original + switch statement, then we can't assume it is still SWITCH_STMT so we + have to check again. */ + if (TREE_CODE (t) == SWITCH_STMT) + { + if (SWITCH_STMT_BODY (t)) + SWITCH_STMT_BODY (t) = + fix_array_notation_exprs (SWITCH_STMT_BODY (t)); + } + else + t = fix_array_notation_exprs (t); + return t; + + case WHILE_STMT: + t = cp_fix_cond_array_notations (t); + /* If the above function added some extra instructions above the original + while statement, then we can't assume it is still WHILE_STMTso we + have to check again. */ + if (TREE_CODE (t) == WHILE_STMT) + { + if (WHILE_BODY (t)) + WHILE_BODY (t) = fix_array_notation_exprs (WHILE_BODY (t)); + } + else + t = fix_array_notation_exprs (t); + return t; + + case DO_STMT: + t = cp_fix_cond_array_notations (t); + /* If the above function added some extra instructions above the original + do-while statement, then we can't assume it is still DO_STMT so we + have to check again. */ + if (TREE_CODE (t) == DO_STMT) + { + if (DO_BODY (t)) + DO_BODY (t) = fix_array_notation_exprs (DO_BODY (t)); + } + else + t = fix_array_notation_exprs (t); + return t; + + default: + if (is_expr) + { + int i, len; + + /* Walk over all the sub-trees of this operand. */ + len = TREE_CODE_LENGTH (code); + + /* 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) + TREE_OPERAND (t, i) = + fix_array_notation_exprs (TREE_OPERAND (t, i)); + } + return t; + } + return t; +} + +/* Handles expression of the form "a[i:j:k]" or "a[:]" or "a[i:j]," which + denotes an array notation expression. If a is a variable or a member, then + we generate a ARRAY_NOTATION_REF front-end tree and return it. + This tree is broken down to ARRAY_REF toward the end of parsing. + ARRAY_NOTATION_REF tree holds the START_INDEX, LENGTH, STRIDE and the TYPE + of ARRAY_REF. Restrictions on START_INDEX, LENGTH and STRIDE is same as that + of the index field passed into ARRAY_REF. The only additional restriction + is that, unlike index in ARRAY_REF, stride, length and start_index cannot + contain ARRAY_NOTATIONS. */ + +tree +build_array_notation_ref (location_t loc, tree array, tree start_index, + tree length, tree stride, tree type) +{ + tree array_ntn_expr = NULL_TREE; + size_t stride_rank = 0, length_rank = 0, start_rank = 0; + tree subtype = type; + + /* If we are dealing with templates, then we will resolve the type checking + at a later time. */ + if (processing_template_decl || !type) + { + if (!type && TREE_TYPE (array)) + type = TREE_TYPE (array); + array_ntn_expr = build_min_nt_loc (loc, ARRAY_NOTATION_REF, array, + start_index, length, stride, type, + NULL_TREE); + TREE_TYPE (array_ntn_expr) = type; + } + if (!TREE_TYPE (start_index) || !INTEGRAL_TYPE_P (TREE_TYPE (start_index))) + { + error_at (loc, + "start-index of array notation triplet is not an integer"); + return error_mark_node; + } + if (!TREE_TYPE (length) || !INTEGRAL_TYPE_P (TREE_TYPE (length))) + { + error_at (loc, "length of array notation triplet is not an integer"); + return error_mark_node; + } + if (!TREE_TYPE (stride) || !INTEGRAL_TYPE_P (TREE_TYPE (stride))) + { + error_at (loc, "stride of array notation triplet is not an integer"); + return error_mark_node; + } + if (TREE_CODE (type) == FUNCTION_TYPE) + { + error_at (loc, "array notations cannot be used with function type"); + return error_mark_node; + } + + while (subtype && (TREE_CODE (subtype) == POINTER_TYPE + || TREE_CODE (subtype) == ARRAY_TYPE)) + { + subtype = TREE_TYPE (subtype); + if (subtype && TREE_CODE (subtype) == FUNCTION_TYPE) + { + error_at (loc, "array notations cannot be used with function pointer " + "arrays"); + return error_mark_node; + } + } + + if (!stride) + { + if (TREE_CONSTANT (start_index) && TREE_CONSTANT (length) + && TREE_CODE (start_index) != VAR_DECL + && TREE_CODE (length) != VAR_DECL + && tree_int_cst_lt (length, start_index)) + stride = build_int_cst (TREE_TYPE (start_index), -1); + else + stride = build_int_cst (TREE_TYPE (start_index), 1); + } + + if (!find_rank (loc, start_index, start_index, false, &start_rank) + || !find_rank (loc, length, length, false, &length_rank) + || !find_rank (loc, stride, stride, false, &stride_rank)) + return error_mark_node; + + if (start_rank != 0) + { + error_at (loc, "rank of an array notation triplet's start-index is not " + "zero"); + return error_mark_node; + } + if (length_rank != 0) + { + error_at (loc, "rank of array notation triplet's length is not zero"); + return error_mark_node; + } + if (stride_rank != 0) + { + error_at (loc, "rank of array notation triplet's stride is not zero"); + return error_mark_node; + } + if (!processing_template_decl) + { + array_ntn_expr = build4 (ARRAY_NOTATION_REF, NULL_TREE, NULL_TREE, + NULL_TREE, NULL_TREE, NULL_TREE); + ARRAY_NOTATION_ARRAY (array_ntn_expr) = array; + ARRAY_NOTATION_START (array_ntn_expr) = start_index; + ARRAY_NOTATION_LENGTH (array_ntn_expr) = length; + ARRAY_NOTATION_STRIDE (array_ntn_expr) = stride; + if (type && (TREE_CODE (type) == ARRAY_TYPE + || TREE_CODE (type) == POINTER_TYPE)) + TREE_TYPE (array_ntn_expr) = TREE_TYPE (type); + else + TREE_TYPE (array_ntn_expr) = type; + } + SET_EXPR_LOCATION (array_ntn_expr, loc); + + return array_ntn_expr; +} diff --git gcc/cp/cp-objcp-common.c gcc/cp/cp-objcp-common.c index bccd884..d301db0 100644 --- gcc/cp/cp-objcp-common.c +++ gcc/cp/cp-objcp-common.c @@ -321,6 +321,7 @@ cp_common_init_ts (void) MARK_TS_TYPED (USING_STMT); MARK_TS_TYPED (LAMBDA_EXPR); MARK_TS_TYPED (CTOR_INITIALIZER); + MARK_TS_TYPED (ARRAY_NOTATION_REF); } #include "gt-cp-cp-objcp-common.h" diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h index 9421822..94037a3 100644 --- gcc/cp/cp-tree.h +++ gcc/cp/cp-tree.h @@ -6135,6 +6135,8 @@ extern bool cxx_omp_privatize_by_reference (const_tree); extern void suggest_alternatives_for (location_t, tree); extern tree strip_using_decl (tree); +/* In cp/cp-array-notations.c */ +extern tree fix_array_notation_exprs (tree); /* -- end of C++ */ #endif /* ! GCC_CP_TREE_H */ diff --git gcc/cp/error.c gcc/cp/error.c old mode 100644 new mode 100755 index a75fc4e..a8f52cd --- gcc/cp/error.c +++ gcc/cp/error.c @@ -1071,6 +1071,17 @@ dump_decl (tree t, int flags) pp_cxx_right_bracket (cxx_pp); break; + case ARRAY_NOTATION_REF: + dump_decl (ARRAY_NOTATION_ARRAY (t), flags | TFF_EXPR_IN_PARENS); + pp_cxx_left_bracket (cxx_pp); + dump_decl (ARRAY_NOTATION_START (t), flags | TFF_EXPR_IN_PARENS); + pp_string (cxx_pp, ":"); + dump_decl (ARRAY_NOTATION_LENGTH (t), flags | TFF_EXPR_IN_PARENS); + pp_string (cxx_pp, ":"); + dump_decl (ARRAY_NOTATION_STRIDE (t), flags | TFF_EXPR_IN_PARENS); + pp_cxx_right_bracket (cxx_pp); + break; + /* So that we can do dump_decl on an aggr type. */ case RECORD_TYPE: case UNION_TYPE: @@ -2057,6 +2068,17 @@ dump_expr (tree t, int flags) pp_cxx_right_bracket (cxx_pp); break; + case ARRAY_NOTATION_REF: + dump_expr (ARRAY_NOTATION_ARRAY (t), flags | TFF_EXPR_IN_PARENS); + pp_cxx_left_bracket (cxx_pp); + dump_expr (ARRAY_NOTATION_START (t), flags | TFF_EXPR_IN_PARENS); + pp_string (cxx_pp, ":"); + dump_expr (ARRAY_NOTATION_LENGTH (t), flags | TFF_EXPR_IN_PARENS); + pp_string (cxx_pp, ":"); + dump_expr (ARRAY_NOTATION_STRIDE (t), flags | TFF_EXPR_IN_PARENS); + pp_cxx_right_bracket (cxx_pp); + break; + case UNARY_PLUS_EXPR: dump_unary_op ("+", t, flags); break; diff --git gcc/cp/parser.c gcc/cp/parser.c old mode 100644 new mode 100755 index 319da21..05cb9a5 --- gcc/cp/parser.c +++ gcc/cp/parser.c @@ -6054,6 +6054,168 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, return error_mark_node; } +/* This function parses Cilk Plus array notations. The starting index is + passed in INIT_INDEX and the array name is passed in ARRAY_VALUE. The + return value of this function is a tree node called VALUE_TREE of type + ARRAY_NOTATION_REF. If some error occurred it returns error_mark_node. */ + +static tree +cp_parser_array_notation (location_t loc, cp_parser *parser, tree init_index, + tree array_value) +{ + cp_token *token = NULL; + tree start_index = NULL_TREE, length_index = NULL_TREE, stride = NULL_TREE; + tree value_tree, type, array_type, array_type_domain; + double_int x; + bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p; + + if (!array_value || array_value == error_mark_node) + { + cp_parser_skip_to_end_of_statement (parser); + return error_mark_node; + } + + if (processing_template_decl) + { + array_type = TREE_TYPE (array_value); + type = TREE_TYPE (array_type); + } + else + { + array_type = TREE_TYPE (array_value); + gcc_assert (array_type); + type = array_type; + } + token = cp_lexer_peek_token (parser->lexer); + if (!token) + { + cp_parser_error (parser, "expected %<:%> or numeral"); + return error_mark_node; + } + else if (token->type == CPP_COLON) + { + if (!init_index) + { + /* If we are here, then we have a case like this A[:]. */ + cp_lexer_consume_token (parser->lexer); + + if (cp_lexer_peek_token (parser->lexer)->type != CPP_CLOSE_SQUARE) + { + cp_parser_error (parser, "expected %<]%>"); + cp_parser_skip_to_end_of_statement (parser); + return error_mark_node; + } + if (TREE_CODE (array_type) == RECORD_TYPE + || TREE_CODE (array_type) == POINTER_TYPE) + { + error_at (loc, "start-index and length fields necessary for " + "using array notations in pointers or records"); + cp_parser_skip_to_end_of_statement (parser); + return error_mark_node; + } + if (TREE_CODE (array_type) == ARRAY_TYPE) + { + tree subtype = TREE_TYPE (array_type); + while (subtype && TREE_CODE (subtype) == POINTER_TYPE) + { + /* This could be a function ptr. If so, then emit error. */ + subtype = TREE_TYPE (subtype); + if (subtype && TREE_CODE (subtype) == FUNCTION_TYPE) + { + error_at (loc, "array notations cannot be used with" + " function pointer arrays"); + cp_parser_skip_to_end_of_statement (parser); + return error_mark_node; + } + } + } + array_type_domain = TYPE_DOMAIN (array_type); + if (!array_type_domain) + { + error_at (loc, "start-index and length fields necessary for " + "using array notations in dimensionless arrays"); + cp_parser_skip_to_end_of_statement (parser); + return error_mark_node; + } + start_index = TYPE_MINVAL (array_type_domain); + start_index = fold_build1 (CONVERT_EXPR, ptrdiff_type_node, + start_index); + x = TREE_INT_CST (TYPE_MAXVAL (array_type_domain)); + x.low++; + length_index = double_int_to_tree (integer_type_node, x); + length_index = fold_build1 (CONVERT_EXPR, ptrdiff_type_node, + length_index); + stride = build_int_cst (integer_type_node, 1); + stride = fold_build1 (CONVERT_EXPR, ptrdiff_type_node, stride); + } + else if (init_index != error_mark_node) + { + /* If we hare here, then there are 2 possibilities: + 1. Array [ EXPR : EXPR ] + 2. Array [ EXPR : EXPR : EXPR ] + */ + start_index = init_index; + cp_lexer_consume_token (parser->lexer); + + saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p; + /* The ':' is used in array notation. Thus compiler cannot do scope + correction automatically. */ + parser->colon_corrects_to_scope_p = false; + length_index = cp_parser_expression (parser, false, NULL); + parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; + if (!length_index || length_index == error_mark_node) + cp_parser_skip_to_end_of_statement (parser); + + if (cp_lexer_peek_token (parser->lexer)->type == CPP_COLON) + { + cp_lexer_consume_token (parser->lexer); + saved_colon_corrects_to_scope_p = + parser->colon_corrects_to_scope_p; + /* Disable correcting single colon correcting to scope. */ + parser->colon_corrects_to_scope_p = false; + stride = cp_parser_expression (parser, false, NULL); + parser->colon_corrects_to_scope_p = + saved_colon_corrects_to_scope_p; + if (!stride || stride == error_mark_node) + { + cp_parser_skip_to_end_of_statement (parser); + if (cp_lexer_peek_token (parser->lexer)->type + == CPP_CLOSE_SQUARE) + cp_lexer_consume_token (parser->lexer); + } + } + else + stride = build_one_cst (integer_type_node); + } + else + { + cp_parser_skip_to_end_of_statement (parser); + return error_mark_node; + } + } + + if (start_index == error_mark_node || length_index == error_mark_node + || stride == error_mark_node || !start_index || !length_index + || !stride) + { + if (cp_lexer_peek_token (parser->lexer)->type == CPP_CLOSE_SQUARE) + cp_lexer_consume_token (parser->lexer); + return error_mark_node; + } + cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE); + + /* We fold all 3 of the values to make things easier when we transform + them later. */ + start_index = fold (start_index); + length_index = fold (length_index); + stride = fold (stride); + + value_tree = build_array_notation_ref (input_location, array_value, + start_index, length_index, stride, + type); + return value_tree; +} + /* A subroutine of cp_parser_postfix_expression that also gets hijacked by cp_parser_builtin_offsetof. We're looking for @@ -6075,41 +6237,78 @@ cp_parser_postfix_open_square_expression (cp_parser *parser, /* Consume the `[' token. */ cp_lexer_consume_token (parser->lexer); - /* Parse the index expression. */ - /* ??? For offsetof, there is a question of what to allow here. If - offsetof is not being used in an integral constant expression context, - then we *could* get the right answer by computing the value at runtime. - If we are in an integral constant expression context, then we might - could accept any constant expression; hard to say without analysis. - Rather than open the barn door too wide right away, allow only integer - constant expressions here. */ - if (for_offsetof) - index = cp_parser_constant_expression (parser, false, NULL); + if (flag_enable_cilkplus + && cp_lexer_peek_token (parser->lexer)->type == CPP_COLON) + /* If we are here, then we have something like this: + ARRAY[:] + */ + postfix_expression = cp_parser_array_notation (loc, parser, NULL_TREE, + postfix_expression); else { - if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + /* Here are have these options: + 1. ARRAY[EXPR] -- This is the normal array call. + 2. ARRAY[EXPR : EXPR] -- Array notation expr with default stride + of 1. + 3. ARRAY[EXPR : EXPR : EXPR] -- Array Notation with userdefined stride. + 4. Array[Braced List] -- This is handled by braced list. + */ + + /* Parse the index expression. */ + /* ??? For offsetof, there is a question of what to allow here. If + offsetof is not being used in an integral constant expression context, + then we *could* get the right answer by computing the value at runtime. + If we are in an integral constant expression context, then we might + could accept any constant expression; hard to say without analysis. + Rather than open the barn door too wide right away, allow only integer + constant expressions here. */ + if (for_offsetof) + index = cp_parser_constant_expression (parser, false, NULL); + else { - bool expr_nonconst_p; - maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS); - index = cp_parser_braced_list (parser, &expr_nonconst_p); + bool saved_colon_corrects_to_scope_p = + parser->colon_corrects_to_scope_p; + if (flag_enable_cilkplus) + parser->colon_corrects_to_scope_p = false; + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + bool expr_nonconst_p; + maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS); + index = cp_parser_braced_list (parser, &expr_nonconst_p); + if (flag_enable_cilkplus + && cp_lexer_peek_token (parser->lexer)->type == CPP_COLON) + { + error_at (cp_lexer_peek_token (parser->lexer)->location, + "braced list index is not allowed with array " + "notations"); + index = error_mark_node; + } + } + else + index = cp_parser_expression (parser, /*cast_p=*/false, NULL); + parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; } + if (flag_enable_cilkplus + && cp_lexer_peek_token (parser->lexer)->type == CPP_COLON) + postfix_expression = cp_parser_array_notation (loc, parser, index, + postfix_expression); else - index = cp_parser_expression (parser, /*cast_p=*/false, NULL); - } - - /* Look for the closing `]'. */ - cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE); - - /* Build the ARRAY_REF. */ - postfix_expression = grok_array_decl (loc, postfix_expression, - index, decltype_p); + { + /* Look for the closing `]'. */ + cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE); - /* When not doing offsetof, array references are not permitted in - constant-expressions. */ - if (!for_offsetof - && (cp_parser_non_integral_constant_expression (parser, NIC_ARRAY_REF))) - postfix_expression = error_mark_node; + /* Build the ARRAY_REF. */ + postfix_expression = grok_array_decl (loc, postfix_expression, + index, decltype_p); + /* When not doing offsetof, array references are not permitted in + constant-expressions. */ + if (!for_offsetof + && (cp_parser_non_integral_constant_expression (parser, + NIC_ARRAY_REF))) + postfix_expression = error_mark_node; + } + } return postfix_expression; } @@ -9336,6 +9535,8 @@ cp_parser_compound_statement (cp_parser *parser, tree in_statement_expr, /* Consume the `}'. */ cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); + if (flag_enable_cilkplus && contains_array_notation_expr (compound_stmt)) + compound_stmt = fix_array_notation_exprs (compound_stmt); return compound_stmt; } @@ -9528,6 +9729,14 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p) /* Now we're all done with the switch-statement. */ finish_switch_stmt (statement); + if (flag_enable_cilkplus + && contains_array_notation_expr (condition)) + { + error_at (EXPR_LOCATION (condition), + "array notations cannot be used as a condition for " + "switch statement"); + statement = error_mark_node; + } } return statement; @@ -10088,6 +10297,12 @@ cp_parser_iteration_statement (cp_parser* parser) parser->in_statement = in_statement; /* We're done with the while-statement. */ finish_while_stmt (statement); + if (flag_enable_cilkplus && contains_array_notation_expr (condition)) + { + error_at (EXPR_LOCATION (condition), "array notations cannot be " + "used as a condition for while statement"); + statement = error_mark_node; + } } break; @@ -10114,6 +10329,15 @@ cp_parser_iteration_statement (cp_parser* parser) cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); /* Look for the `;'. */ cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); + if (flag_enable_cilkplus + && contains_array_notation_expr (DO_COND (statement))) + { + error_at (EXPR_LOCATION (DO_COND (statement)), + "array notations cannot be used as a condition for a " + "do-while statement"); + statement = error_mark_node; + } + } break; @@ -10132,8 +10356,17 @@ cp_parser_iteration_statement (cp_parser* parser) cp_parser_already_scoped_statement (parser); parser->in_statement = in_statement; - /* We're done with the for-statement. */ - finish_for_stmt (statement); + if (flag_enable_cilkplus + && contains_array_notation_expr (FOR_COND (statement))) + { + error_at (EXPR_LOCATION (FOR_COND (statement)), + "array notations cannot be used in a condition for a " + "for-loop"); + statement = error_mark_node; + } + else + /* We're done with the for-statement. */ + finish_for_stmt (statement); } break; @@ -16708,30 +16941,53 @@ cp_parser_direct_declarator (cp_parser* parser, { bool non_constant_p; - bounds - = cp_parser_constant_expression (parser, - /*allow_non_constant=*/true, - &non_constant_p); - if (!non_constant_p) - /* OK */; - else if (error_operand_p (bounds)) - /* Already gave an error. */; - else if (!parser->in_function_body - || current_binding_level->kind == sk_function_parms) + if (flag_enable_cilkplus + && cp_lexer_next_token_is (parser->lexer, CPP_COLON)) { - /* Normally, the array bound must be an integral constant - expression. However, as an extension, we allow VLAs - in function scopes as long as they aren't part of a - parameter declaration. */ - cp_parser_error (parser, - "array bound is not an integer constant"); bounds = error_mark_node; + error_at (cp_lexer_peek_token (parser->lexer)->location, + "array notations cannot be used in declaration"); + cp_lexer_consume_token (parser->lexer); } - else if (processing_template_decl) + else { - /* Remember this wasn't a constant-expression. */ - bounds = build_nop (TREE_TYPE (bounds), bounds); - TREE_SIDE_EFFECTS (bounds) = 1; + bounds + = cp_parser_constant_expression (parser, + /*allow_non_constant=*/true, + &non_constant_p); + if (!non_constant_p) + /* OK */; + else if (error_operand_p (bounds)) + /* Already gave an error. */; + else if (!parser->in_function_body + || current_binding_level->kind == sk_function_parms) + { + /* Normally, the array bound must be an integral constant + expression. However, as an extension, we allow VLAs + in function scopes as long as they aren't part of a + parameter declaration. */ + cp_parser_error (parser, + "array bound is not an integer constant"); + bounds = error_mark_node; + } + else if (processing_template_decl) + { + /* Remember this wasn't a constant-expression. */ + bounds = build_nop (TREE_TYPE (bounds), bounds); + TREE_SIDE_EFFECTS (bounds) = 1; + } + if (flag_enable_cilkplus + && cp_lexer_next_token_is (parser->lexer, CPP_COLON)) + { + location_t loc = + cp_lexer_peek_token (parser->lexer)->location; + while (cp_lexer_next_token_is_not (parser->lexer, + CPP_CLOSE_SQUARE)) + cp_lexer_consume_token (parser->lexer); + error_at (loc, "array notations cannot be used in " + "declaration"); + bounds = error_mark_node; + } } } else @@ -18102,6 +18358,11 @@ cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser, cp_parser_function_body (parser, in_function_try_block); if (check_body_p) check_constexpr_ctor_body (last, list); + + /* Transform all array notations to the equivalent array refs and loop. */ + if (flag_enable_cilkplus && contains_array_notation_expr (body)) + body = fix_array_notation_exprs (body); + /* Finish the function body. */ finish_function_body (body); @@ -22081,6 +22342,12 @@ cp_parser_function_definition_after_declarator (cp_parser* parser, finish_lambda_scope (); + /* Expand all array notation expressions here. */ + if (flag_enable_cilkplus && current_function_decl + && contains_array_notation_expr (DECL_SAVED_TREE (current_function_decl))) + DECL_SAVED_TREE (current_function_decl) = + fix_array_notation_exprs (DECL_SAVED_TREE (current_function_decl)); + /* Finish the function. */ fn = finish_function ((ctor_initializer_p ? 1 : 0) | (inline_p ? 2 : 0)); diff --git gcc/cp/pt.c gcc/cp/pt.c old mode 100644 new mode 100755 index 5d83cc6..485b718 --- gcc/cp/pt.c +++ gcc/cp/pt.c @@ -13740,6 +13740,43 @@ tsubst_copy_and_build (tree t, RECUR (TREE_OPERAND (t, 1)), complain|decltype_flag)); + case ARRAY_NOTATION_REF: + { + tree start_index, length, stride; + op1 = tsubst_non_call_postfix_expression (ARRAY_NOTATION_ARRAY (t), + args, complain, in_decl); + start_index = RECUR (ARRAY_NOTATION_START (t)); + length = RECUR (ARRAY_NOTATION_LENGTH (t)); + stride = RECUR (ARRAY_NOTATION_STRIDE (t)); + + /* We do type-checking here for templatized array notation triplets. */ + if (!TREE_TYPE (start_index) + || !INTEGRAL_TYPE_P (TREE_TYPE (start_index))) + { + error_at (loc, "start-index of array notation triplet is not an " + "integer"); + RETURN (error_mark_node); + } + if (!TREE_TYPE (length) || !INTEGRAL_TYPE_P (TREE_TYPE (length))) + { + error_at (loc, "length of array notation triplet is not an " + "integer"); + RETURN (error_mark_node); + } + if (!TREE_TYPE (stride) || !INTEGRAL_TYPE_P (TREE_TYPE (stride))) + { + error_at (loc, "stride of array notation triplet is not an " + "integer"); + RETURN (error_mark_node); + } + if (TREE_CODE (TREE_TYPE (op1)) == FUNCTION_TYPE) + { + error_at (loc, "array notations cannot be used with function type"); + RETURN (error_mark_node); + } + RETURN (build_array_notation_ref (EXPR_LOCATION (t), op1, start_index, + length, stride, TREE_TYPE (op1))); + } case SIZEOF_EXPR: if (PACK_EXPANSION_P (TREE_OPERAND (t, 0))) RETURN (tsubst_copy (t, args, complain, in_decl)); @@ -15712,6 +15749,9 @@ type_unification_real (tree tparms, arg = args[ia]; ++ia; + if (flag_enable_cilkplus && TREE_CODE (arg) == ARRAY_NOTATION_REF) + return 1; + if (unify_one_argument (tparms, targs, parm, arg, subr, strict, flags, explain_p)) return 1; @@ -19112,6 +19152,11 @@ instantiate_decl (tree d, int defer_ok, pointer_map_destroy (local_specializations); local_specializations = saved_local_specializations; + /* We expand all the array notation expressions here. */ + if (flag_enable_cilkplus + && contains_array_notation_expr (DECL_SAVED_TREE (d))) + DECL_SAVED_TREE (d) = fix_array_notation_exprs (DECL_SAVED_TREE (d)); + /* Finish the function. */ d = finish_function (0); expand_or_defer_fn (d); diff --git gcc/cp/semantics.c gcc/cp/semantics.c index b5c3b0a..77467bf 100644 --- gcc/cp/semantics.c +++ gcc/cp/semantics.c @@ -779,6 +779,22 @@ finish_return_stmt (tree expr) tree r; bool no_warning; + if (flag_enable_cilkplus && contains_array_notation_expr (expr)) + { + size_t rank = 0; + + if (!find_rank (input_location, expr, expr, false, &rank)) + return error_mark_node; + + /* If the return expr. has a builtin array notation function, then its + OK. */ + if (rank >= 1) + { + error_at (input_location, "array notation expression cannot be " + "used as a return value"); + return error_mark_node; + } + } expr = check_return_expr (expr, &no_warning); if (flag_openmp && !check_omp_return ()) @@ -8066,6 +8082,7 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t, non_constant_p, overflow_p); break; + case ARRAY_NOTATION_REF: case ARRAY_REF: r = cxx_eval_array_reference (call, t, allow_non_constant, addr, non_constant_p, overflow_p); @@ -8877,6 +8894,7 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags) want_rval = true; /* Fall through. */ case ARRAY_REF: + case ARRAY_NOTATION_REF: case ARRAY_RANGE_REF: case MEMBER_REF: case DOTSTAR_EXPR: diff --git gcc/cp/tree.c gcc/cp/tree.c index 8524f6c..dd2fda4 100644 --- gcc/cp/tree.c +++ gcc/cp/tree.c @@ -141,6 +141,7 @@ lvalue_kind (const_tree ref) case INDIRECT_REF: case ARROW_EXPR: case ARRAY_REF: + case ARRAY_NOTATION_REF: case PARM_DECL: case RESULT_DECL: return clk_ordinary; diff --git gcc/cp/typeck.c gcc/cp/typeck.c old mode 100644 new mode 100755 index 11ac85b..06979f9 --- gcc/cp/typeck.c +++ gcc/cp/typeck.c @@ -3005,6 +3005,22 @@ cp_build_array_ref (location_t loc, tree array, tree idx, return error_mark_node; } + /* If an array's index is an array notation, then its rank cannot be + greater than one. */ + if (flag_enable_cilkplus && contains_array_notation_expr (idx)) + { + size_t rank = 0; + + /* If find_rank returns false, then it should have reported an error, + thus it is unnecessary for repetition. */ + if (!find_rank (loc, idx, idx, true, &rank)) + return error_mark_node; + if (rank > 1) + { + error_at (loc, "rank of the array%'s index is greater than 1"); + return error_mark_node; + } + } if (TREE_TYPE (array) == error_mark_node || TREE_TYPE (idx) == error_mark_node) return error_mark_node; @@ -3477,8 +3493,12 @@ cp_build_function_call_vec (tree function, vec **params, params = &allocated; } - nargs = convert_arguments (parm_types, params, fndecl, LOOKUP_NORMAL, - complain); + if (flag_enable_cilkplus + && fndecl && is_cilkplus_reduce_builtin (fndecl)) + nargs = (*params)->length (); + else + nargs = convert_arguments (parm_types, params, fndecl, LOOKUP_NORMAL, + complain); if (nargs < 0) return error_mark_node; @@ -3936,8 +3956,15 @@ cp_build_binary_op (location_t location, } } - type0 = TREE_TYPE (op0); - type1 = TREE_TYPE (op1); + if (flag_enable_cilkplus && contains_array_notation_expr (op0)) + type0 = find_correct_array_notation_type (op0); + else + type0 = TREE_TYPE (op0); + + if (flag_enable_cilkplus && contains_array_notation_expr (op1)) + type1 = find_correct_array_notation_type (op1); + else + type1 = TREE_TYPE (op1); /* The expression codes of the data types of the arguments tell us whether the arguments are integers, floating, pointers, etc. */ @@ -5140,6 +5167,13 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain) gcc_assert (!identifier_p (arg) || !IDENTIFIER_OPNAME_P (arg)); + if (flag_enable_cilkplus && TREE_CODE (arg) == ARRAY_NOTATION_REF) + { + val = build_address (arg); + if (TREE_CODE (arg) == OFFSET_REF) + PTRMEM_OK_P (val) = PTRMEM_OK_P (arg); + return val; + } if (TREE_CODE (arg) == COMPONENT_REF && type_unknown_p (arg) && !really_overloaded_fn (TREE_OPERAND (arg, 1))) { @@ -7818,6 +7852,13 @@ convert_for_assignment (tree type, tree rhs, tree rhstype; enum tree_code coder; + /* If we are dealing with built-in array notation function then we don't need + to convert them. They will be broken up into modify exprs in future, + during which all these checks will be done. */ + if (flag_enable_cilkplus + && is_cilkplus_reduce_builtin (fndecl) != BUILT_IN_NONE) + return rhs; + /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ if (TREE_CODE (rhs) == NON_LVALUE_EXPR) rhs = TREE_OPERAND (rhs, 0); diff --git gcc/testsuite/ChangeLog gcc/testsuite/ChangeLog old mode 100644 new mode 100755 diff --git gcc/testsuite/c-c++-common/cilk-plus/AN/array_test1.c gcc/testsuite/c-c++-common/cilk-plus/AN/array_test1.c index e4f1ea8..282a55d 100644 --- gcc/testsuite/c-c++-common/cilk-plus/AN/array_test1.c +++ gcc/testsuite/c-c++-common/cilk-plus/AN/array_test1.c @@ -1,4 +1,4 @@ -/* { dg-do compile } */ +/* { dg-do run } */ /* { dg-options "-fcilkplus" } */ #include @@ -47,7 +47,7 @@ int main2 (char **argv) array[x:y:z] = 505; for (ii = x; ii < 10; ii += z) if (array[ii] != 505) - return 2; + return 4; x = atoi(argv[1]); z = (10-atoi(argv[1]))/atoi(argv[1]); @@ -57,7 +57,7 @@ int main2 (char **argv) for (ii = x; ii < 10; ii += z) if (array[ii] != 25) - return 1; + return 5; x = atoi(argv[1]); z = (10-atoi(argv[1]))/atoi(argv[1]); y = 10-atoi(argv[1]); @@ -66,19 +66,19 @@ int main2 (char **argv) 1400; for (ii = x; ii < 10; ii += z) if (array[ii] != 1400) - return 1; + return 6; array[atoi("5"):5:1] = 5555; for (ii = atoi ("5"); ii < 10; ii++) if (array[ii] != 5555) - return 2; + return 7; array[atoi("5"):atoi("5"):atoi("1")] = 9999; for (ii = atoi ("5"); ii < (atoi ("5") + atoi ("5")); ii += atoi ("1")) if (array[ii] != 9999) - return 3; + return 8; return 0; } diff --git gcc/testsuite/c-c++-common/cilk-plus/AN/if_test_errors.c gcc/testsuite/c-c++-common/cilk-plus/AN/if_test_errors.c index d17d8cf..579d396 100644 --- gcc/testsuite/c-c++-common/cilk-plus/AN/if_test_errors.c +++ gcc/testsuite/c-c++-common/cilk-plus/AN/if_test_errors.c @@ -18,19 +18,19 @@ int main (void) array2[:] = 5; else array2[:] = 10; - if (!(array[0:10:1] + array[0:10:1])) /* { dg-error "condition and the then-block" } */ - array2d[:][:] = 5; + if (!(array[0:10:1] + array[0:10:1])) /* { dg-error "condition and the then-block" "" { target c } } */ + array2d[:][:] = 5; /* { dg-error "rank mismatch with controlling expression of parent" "" { target c++ } } */ else array2[:] = 10; - if (!(array[0:10:1] + array[0:10:1])) /* { dg-error "condition and the else-block" } */ + if (!(array[0:10:1] + array[0:10:1])) /* { dg-error "condition and the else-block" "" { target c } } */ array2[:] = 5; else - array2d[:][:] = 10; + array2d[:][:] = 10; /* { dg-error "rank mismatch with controlling expression of parent" "" { target c++ } } */ - if (TwodArray[:][:] != 10) /* { dg-error "condition and the then-block" } */ - array2[:] = 10; + if (TwodArray[:][:] != 10) /* { dg-error "condition and the then-block" "" { target c } } */ + array2[:] = 10; /* { dg-error "rank mismatch with controlling expression of parent" "" { target c++ } } */ else array2[:] = 5; @@ -40,8 +40,8 @@ int main (void) array4[32][:][:][:] = 5; /* atoi(argv[1]) == 10, so it will convert all 10's to 5's */ - if (FourDArray[42][0:10:1][9:10:-1][0:5:2] != 10) /* { dg-error "condition and the then-block" } */ - array4[0:10:1][0:5:2][9:10:-1][0:5:2] = 10; + if (FourDArray[42][0:10:1][9:10:-1][0:5:2] != 10) /* { dg-error "condition and the then-block" "" { target c } } */ + array4[0:10:1][0:5:2][9:10:-1][0:5:2] = 10; /* { dg-error "rank mismatch with controlling expression of parent" "" { target c++ } } */ else array4[0:10:1][0:5:2][9:10:-1][0:5:2] = 5; diff --git gcc/testsuite/c-c++-common/cilk-plus/AN/misc.c gcc/testsuite/c-c++-common/cilk-plus/AN/misc.c index 35eb115..14421d9 100644 --- gcc/testsuite/c-c++-common/cilk-plus/AN/misc.c +++ gcc/testsuite/c-c++-common/cilk-plus/AN/misc.c @@ -73,13 +73,13 @@ int main (void) while (ii != array2[1:x:3][1:2:1]) /* { dg-error "array notations cannot be used as a condition for while statement" } */ x = 2; - do { /* { dg-error "array notations cannot be used as a condition for a do-while statement" } */ + do { /* { dg-error "array notations cannot be used as a condition for a do-while statement" "" { target c } } */ x = 3; - } while (ii != array2[:][:]); + } while (ii != array2[:][:]); /* { dg-error "array notations cannot be used as a condition for a do-while statement" "" { target c++ } } */ - do { /* { dg-error "array notations cannot be used as a condition for a do-while statement" } */ + do { /* { dg-error "array notations cannot be used as a condition for a do-while statement" "" { target c } } */ x = 2; - } while (ii != (x + array2[:][1:x:2]) + 2); + } while (ii != (x + array2[:][1:x:2]) + 2); /* { dg-error "array notations cannot be used as a condition for a do-while statement" "" { target c++ } } */ do { x += 3; diff --git gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors.c gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors.c old mode 100644 new mode 100755 index a0a3742..18816e0 --- gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors.c +++ gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors.c @@ -8,4 +8,4 @@ int main (void) array2[:] = array2[: ; /* { dg-error "expected ']'" } */ return 0; -} /* { dg-error "expected ';' before" } */ +} /* { dg-error "expected ';' before" "" { target c } } */ diff --git gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors2.c gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors2.c index 2e86b4f..4314090 100644 --- gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors2.c +++ gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors2.c @@ -5,7 +5,8 @@ int main (void) { int array[10][10], array2[10]; - array2[:] = array2[1:2:] ; /* { dg-error "expected expression before" } */ + array2[:] = array2[1:2:] ; /* { dg-error "expected expression before" "" { target c } } */ + /* { dg-error "expected primary-expression before" "" { target c++ } 8 } */ - return 0; /* { dg-error "expected ';' before" } */ + return 0; /* { dg-error "expected ';' before" "" { target c } } */ } diff --git gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors3.c gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors3.c index 34dfa16..47b5979 100644 --- gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors3.c +++ gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors3.c @@ -5,7 +5,8 @@ int main (void) { int array[10][10], array2[10]; - array2[:] = array2[1::] ; /* { dg-error "expected expression before" } */ + array2[:] = array2[1: :] ; /* { dg-error "expected expression before" "" { target c } } */ + /* { dg-error "expected primary-expression before" "" { target c++ } 8 } */ - return 0; /* { dg-error "expected ';' before" } */ + return 0; /* { dg-error "expected ';' before" "" { target c } } */ } diff --git gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors4.c gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors4.c index eba28a8..a0efc04 100644 --- gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors4.c +++ gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors4.c @@ -5,7 +5,7 @@ int main (void) { int array[10][10], array2[10]; - array2[:] = array2[::] ; /* { dg-error " expected ']' before ':' token" } */ + array2[:] = array2[ : : ] ; /* { dg-error " expected ']' before ':' token" } */ return 0; } diff --git gcc/testsuite/c-c++-common/cilk-plus/AN/pr57541.c gcc/testsuite/c-c++-common/cilk-plus/AN/pr57541.c index cabdb23..793afb2 100755 --- gcc/testsuite/c-c++-common/cilk-plus/AN/pr57541.c +++ gcc/testsuite/c-c++-common/cilk-plus/AN/pr57541.c @@ -4,11 +4,11 @@ int A[10]; int main () { - char c = (char)N; /* { dg-error "undeclared" } */ + char c = (char)N; /* { dg-error "declared" } */ short s = (short)N; long l = (long)N; A[l:s:c]; } -/* { dg-message "note: each" "defined" { target *-*-* } 7 } */ +/* { dg-message "note: each" "defined" { target c } 7 } */ diff --git gcc/testsuite/c-c++-common/cilk-plus/AN/sec_implicit_ex.c gcc/testsuite/c-c++-common/cilk-plus/AN/sec_implicit_ex.c index c22b818..b863276 100644 --- gcc/testsuite/c-c++-common/cilk-plus/AN/sec_implicit_ex.c +++ gcc/testsuite/c-c++-common/cilk-plus/AN/sec_implicit_ex.c @@ -1,9 +1,6 @@ /* { dg-do run } */ /* { dg-options "-fcilkplus" } */ -void abort (void); -void exit (int); - int main(void) { @@ -24,10 +21,7 @@ int main(void) for (jj = 0; jj < 10; jj++) for (kk = 0; kk < 10; kk++) if (array_3[ii][jj][kk] != array_3C[ii][jj][kk]) - abort (); + return 1; - - exit (0); - return 0; } diff --git gcc/testsuite/c-c++-common/cilk-plus/AN/vla.c gcc/testsuite/c-c++-common/cilk-plus/AN/vla.c index 843745e..3b0777e 100644 --- gcc/testsuite/c-c++-common/cilk-plus/AN/vla.c +++ gcc/testsuite/c-c++-common/cilk-plus/AN/vla.c @@ -1,5 +1,5 @@ -/* { dg-do compile } */ -/* { dg-options "-fcilkplus -std=c99" } */ +/* { dg-do compile { target c } } */ +/* { dg-options "-fcilkplus -std=c99 -w" } */ int func (int x) { diff --git gcc/testsuite/g++.dg/cilk-plus/AN/array_test1_tplt.cc gcc/testsuite/g++.dg/cilk-plus/AN/array_test1_tplt.cc new file mode 100644 index 0000000..e9ee7ec --- /dev/null +++ gcc/testsuite/g++.dg/cilk-plus/AN/array_test1_tplt.cc @@ -0,0 +1,118 @@ +/* { dg-do run } */ +/* { dg-options "-fcilkplus" } */ + +#include +#include +#if HAVE_IO +#include +#endif +template int main2 (char **argv); + +int main (void) +{ + int x = 1, y = 1, z = 1; + char *array[2]; + array[0] = strdup ("a.out"); + array[1] = strdup ("5"); + x = main2 (array); + x += main2 (array); + y = main2 (array); + y += main2 (array); + y += main2 (array); + y += main2 (array); + z = main2 (array); + z += main2 (array); + y += main2 (array); + z += main2 (array); + + return x+y+z; +} +template +int main2 (char **argv) +{ + T array[10]; + int ii = 0, x = 2, z= 0 , y = 0; + + for (ii = 0; ii < 10; ii++) + array[ii] = 10; + + array[0:10:1] = (T)15; + + for (ii = 0; ii < 10; ii++) + if (array[ii] != (T)15) + return 1; + + + array[0:5:2] = (T)20; + + for (ii = 0; ii < 10; ii += 2) + if (array[ii] != (T)20) + return 2; + + + x = atoi(argv[1]); + z = (10-atoi(argv[1]))/atoi(argv[1]); + + array[x:5:z] = (T)50; + + for (ii = x; ii < 10; ii += z) + if (array[ii] != (T)50) + return 3; + + x = atoi(argv[1]); + z = (10-atoi(argv[1]))/atoi(argv[1]); /* (10 - 5) / 5 = 1 */ + y = 10-atoi(argv[1]); + + array[x:y:z] = (T)52; +#if HAVE_IO + for (ii = atoi ("5"); ii < (atoi ("5") + atoi ("5")); ii += atoi ("1")) + std::printf("%d\t", (int)array[ii]); + std::printf("\n"); +#endif + for (ii = x; ii < 10; ii += z) + if (array[ii] != (T)52) + return 4; + + + x = atoi(argv[1]); + z = (10-atoi(argv[1]))/atoi(argv[1]); + y = 10-atoi(argv[1]); + + array[x:y:((10-atoi(argv[1]))/atoi(argv[1]))] = (T)25; + + for (ii = x; ii < 10; ii += z) + if (array[ii] != (T)25) + return 5; + + x = atoi(argv[1]); + z = (10-atoi(argv[1]))/atoi(argv[1]); + y = 10-atoi(argv[1]); + + array[atoi(argv[1]):(10-atoi(argv[1])):((10-atoi(argv[1]))/atoi(argv[1]))] = + (T)14; + for (ii = x; ii < 10; ii += z) + if (array[ii] != (T)14) + return 6; + + + array[atoi("5"):5:1] = (T)65; + + for (ii = atoi ("5"); ii < 10; ii++) + if (array[ii] != (T)65) + return 7; + + + array[atoi("5"):atoi("5"):atoi("1")] = 99; + +#if HAVE_IO + for (ii = atoi ("5"); ii < (atoi ("5") + atoi ("5")); ii += atoi ("1")) + std::printf("%d\t", (int)array[ii]); + std::printf("\n"); +#endif + + for (ii = atoi ("5"); ii < (atoi ("5") + atoi ("5")); ii += atoi ("1")) + if (array[ii] != (T)99) + return 8; + + return 0; +} diff --git gcc/testsuite/g++.dg/cilk-plus/AN/array_test2_tplt.cc gcc/testsuite/g++.dg/cilk-plus/AN/array_test2_tplt.cc new file mode 100644 index 0000000..87c37e1 --- /dev/null +++ gcc/testsuite/g++.dg/cilk-plus/AN/array_test2_tplt.cc @@ -0,0 +1,141 @@ +/* { dg-do run } */ +/* { dg-options "-fcilkplus" } */ + +#include +#include +template int main2(char **argv); +int main(void) +{ + int x = 1, y = 1, z = 1, w = 1; + char *array[2]; + array[0] = strdup ("a.out"); + array[1] = strdup ("5"); + w = main2(array); + w += main2 (array); + x = main2 (array); + x += main2 (array); + y = main2 (array); + y += main2 (array); + z = main2 (array); + z += main2 (array); + z += main2 (array); + + return (w+x+y+z); +} + +template +int main2(char **argv) +{ + T array[10], array2[10]; + int ii = 0, x = 2, z= 0 , y = 0 ; + + for (ii = 0; ii < 10; ii++) + { + array[ii] = 10; + array2[ii] = 5000000; + } + + array2[0:10:1] = array[0:10:1]; + + for (ii = 0; ii < 10; ii++) + if (array2[ii] != array[ii]) + return 1; + + for (ii = 0; ii < 10; ii++) + { + array[ii] = 10; + array2[ii] = 5000000; + } + + array2[0:5:2] = array[0:5:2]; + + for (ii = 0; ii < 10; ii += 2) + if (array[ii] != array2[ii]) + return 2; + + for (ii = 0; ii < 10; ii++) + { + array[ii] = 10; + array2[ii] = 5000000; + } + x = atoi(argv[1]); + z = (10-atoi(argv[1]))/atoi(argv[1]); + + array2[x:5:z] = array[x:5:z]; + + for (ii = x; ii < 5; ii += z) + if (array2[ii] != array[ii]) + return 3; + + for (ii = 0; ii < 10; ii++) + { + array[ii] = 500; + array2[ii] = 1000000; + } + x = atoi(argv[1]); + z = (10-atoi(argv[1]))/atoi(argv[1]); + y = 10-atoi(argv[1]); + + array2[x:y:z] = array[x:y:z]; + for (ii = x; ii < 10; ii = ii + z) + if (array2[ii] != array[ii]) + return 4; + + for (ii = 0; ii < 10; ii++) + { + array[ii] = 500; + array2[ii] = 1000000; + } + x = atoi(argv[1]); + z = (10-atoi(argv[1]))/atoi(argv[1]); + y = 10-atoi(argv[1]); + + array[x:y:((10-atoi(argv[1]))/atoi(argv[1]))] = + array2[x:y:((10-atoi(argv[1]))/atoi(argv[1]))]; + + for (ii = x; ii < 10; ii += z) + if (array[ii] != array2[ii]) + return 6; + + + x = atoi(argv[1]); + z = (10-atoi(argv[1]))/atoi(argv[1]); + y = 10-atoi(argv[1]); + + for (ii = 0; ii < 10; ii++) + { + array[ii] = 500; + array2[ii] = 1000000; + } + + array[atoi(argv[1]):(10-atoi(argv[1])):((10-atoi(argv[1]))/atoi(argv[1]))] = + array2[atoi(argv[1]):(10-atoi(argv[1])):((10-atoi(argv[1]))/atoi(argv[1]))]; + for (ii = x; ii < 10; ii += z) + if (array[ii] != array2[ii]) + return 6; + + for (ii = 0; ii < 10; ii++) + { + array[ii] = 4; + array2[ii] = 2; + } + + array[atoi("5"):5:1] = array2[atoi("5"):5:1]; + + for (ii = atoi ("5"); ii < 10; ii++) + if (array[ii] != array2[ii]) + return 7; + + for (ii = 0; ii < 10; ii++) + { + array[ii] = 5; + array2[ii] = 1; + } + array[atoi("5"):atoi("5"):atoi("1")] = array2[atoi("5"):atoi("5"):atoi("1")]; + + for (ii = 5; ii < 10; ii++) + if (array2[ii] != array[ii]) + return 8; + + return 0; +} diff --git gcc/testsuite/g++.dg/cilk-plus/AN/array_test_ND_tplt.cc gcc/testsuite/g++.dg/cilk-plus/AN/array_test_ND_tplt.cc new file mode 100644 index 0000000..479ba13 --- /dev/null +++ gcc/testsuite/g++.dg/cilk-plus/AN/array_test_ND_tplt.cc @@ -0,0 +1,115 @@ +/* { dg-do run } */ +/* { dg-options "-fcilkplus" } */ + +#include +#include +template int main2(char **argv); + +int main(void) +{ + int x = 1, y=1, z=1, w = 1; + char *array[3]; + array[0] = strdup ("a.out"); + array[1] = strdup ("10"); + array[2] = strdup ("15"); + w = main2 (array); + w += main2 (array); + x = main2 (array); + x += main2 (array); + y = main2 (array); + y += main2 (array); + z = main2 (array); + z += main2 (array); + return x+y+z; +} + +template +int main2(char **argv) +{ + T array[10][15]; + T array_2[10][15]; + int ii = 0, jj = 0,x = 0, z= 1 , y = 10 ,argc = 3; + + + for (ii = 0; ii < 10; ii++) { + for (jj = 0; jj< 15; jj++) { + array[ii][jj] = ii+jj; + array_2[ii][jj] = 0; + } + } + array_2[0:5:2][0:5:3] = array[0:5:2][0:5:3] + 1 + 5 + array[0][5] + x; + + for (ii = 0; ii < 10; ii += 2) + { + for (jj = 0; jj < 15; jj += 3) + { + if (array_2[ii][jj] != array[ii][jj] + 1 + 5 + array[0][5] + x) + return 1; + } + } + + + for (ii = 0; ii < 10; ii++) { + for (jj = 0; jj< 15; jj++) { + array[ii][jj] = ii+jj; + array_2[ii][jj] = 0; + } + } + x = atoi(argv[1]); + y = atoi(argv[2]); + array_2[0:x:1][0:y:1] = array[0:x:1][0:y:1] + x + y + array[0:x:1][0:y:1]; + + for (ii = 0; ii < x; ii++) + { + for (jj = 0; jj < y; jj++) + { + if (array_2[ii][jj] != array[ii][jj] + x + y + array[ii][jj]) + return 2; + } + } + + for (ii = 0; ii < 10; ii++) { + for (jj = 0; jj< 15; jj++) { + array[ii][jj] = ii+jj; + array_2[ii][jj] = 0; + } + } + x = atoi(argv[1]); + y = atoi(argv[2]); + z = (20- atoi (argv[1]))/atoi(argv[1]); + /* (20-10)/10 evaluates to 1 all the time :-). */ + array_2[0:x:z][0:y:z] = array[0:x:z][0:y:z] + array[0:x:z][0:y:z] + y + z; + + for (ii = 0; ii < x; ii += z) + { + for (jj = 0; jj < y; jj += z) + { + if (array_2[ii][jj] != array[ii][jj] + array[ii][jj] + y + z) + return 3; + } + } + + + + for (ii = 0; ii < 10; ii++) { + for (jj = 0; jj< 15; jj++) { + array[ii][jj] = ii+jj; + array_2[ii][jj] = 0; + } + } + x = argc-3; + y = 20-atoi(argv[1]); + z = (20- atoi (argv[1]))/atoi(argv[1]); + /* (20-10)/10 evaluates to 1 all the time :-). */ + array_2[(argc-3):(20-atoi(argv[1])):(20-atoi(argv[1]))/atoi(argv[1])][(argc-3):(30-atoi(argv[2])): ((30-atoi(argv[2]))/atoi(argv[2]))] = array[(argc-3):20-atoi(argv[1]):(20-atoi(argv[1]))/atoi(argv[1])][(argc-3):(30-atoi(argv[2])): (30-atoi(argv[2]))/atoi(argv[2])] + array[(argc-3):20-atoi(argv[1]):(20-atoi(argv[1]))/atoi(argv[1])][(argc-3):(30-atoi(argv[2])): (30-atoi(argv[2]))/atoi(argv[2])] * array[(argc-3):20-atoi(argv[1]):(20-atoi(argv[1]))/atoi(argv[1])][(argc-3):(30-atoi(argv[2])): (30-atoi(argv[2]))/atoi(argv[2])]; + + for (ii = 0; ii < 10; ii++) + { + for (jj = 0; jj < 15; jj++) + { + if (array_2[ii][jj] != array[ii][jj] + array[ii][jj] * array[ii][jj]) + return 4; + } + } + return 0; +} diff --git gcc/testsuite/g++.dg/cilk-plus/AN/braced_list.cc gcc/testsuite/g++.dg/cilk-plus/AN/braced_list.cc new file mode 100755 index 0000000..b91de7a --- /dev/null +++ gcc/testsuite/g++.dg/cilk-plus/AN/braced_list.cc @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-fcilkplus -std=c++11 " } */ + +int main (void) +{ + int Array[100], Array2[100]; + + Array[{1,2}:2] = 5; /* { dg-error "braced list index is not allowed" } */ + Array[1:{1,2}:2] = 5; /* { dg-error "expected primary-expression before" } */ + Array[1:10:{1,2}] = 5; /* { dg-error "expected primary-expression before" } */ + + return 0; +} diff --git gcc/testsuite/g++.dg/cilk-plus/AN/builtin_fn_custom_tplt.cc gcc/testsuite/g++.dg/cilk-plus/AN/builtin_fn_custom_tplt.cc new file mode 100644 index 0000000..fd60063 --- /dev/null +++ gcc/testsuite/g++.dg/cilk-plus/AN/builtin_fn_custom_tplt.cc @@ -0,0 +1,128 @@ +/* { dg-do run } */ +/* { dg-options "-fcilkplus "} */ + +#if HAVE_IO +#include +#endif + +#include + +template +T my_func (T x, T y) +{ + if (x > y) + return x; + else + return y; +} + +template +T main_func (T *array, T *array2, T identity_val, int size) +{ + T result; + + result = __sec_reduce (identity_val, array[0:size:1] * array2[0:size:1], + my_func); // my_func (identity_val, array[5] * array2[5]); + return result; +} +int main (void) +{ + int i_index = 0, f_index = 0, d_index = 0, l_index = 0; + int iarray[10], iarray2[10], i_result, i_max; + long larray[10], larray2[10], l_result, l_max; + float farray[10], farray2[10], f_result, f_max; + double darray[10], darray2[10], d_result, d_max; +#if 1 + for (int ii = 0; ii < 10; ii++) + { + if (ii%2 && ii) + { + darray[ii] = (double)(1.0000/(double)ii); + farray[ii] = (float)(1.00/(float)ii); + } + else + { + darray[ii] = (double) ii + 0.10; + farray[ii] = (float) (1.00/((float)(ii+1.000))); + } + darray2[ii] = (double) (1.00000/ (double)(ii+1)); + farray2[ii] = (float) (1.00/ (float)(ii+1)); + } + + for (int ii = 0; ii < 10; ii++) + { + iarray[ii] = ii; + larray[ii] = (long)ii; + } + + for (int ii = 0; ii < 10; ii++) + { + iarray2[ii] = (ii-5); + larray2[ii] = long (ii-5); + } +#endif +#if HAVE_IO + printf("Int: "); + for (int ii=0; ii < 10; ii++) + { + printf("%2d ", iarray[ii] * iarray2[ii]); + } + printf("\nfloat: "); + for (int ii=0; ii < 10; ii++) + { + printf("%4.3f ", farray[ii] * farray2[ii]); + } + + printf("\nlong: "); + for (int ii=0; ii < 10; ii++) + { + printf("%2d ", larray[ii] * larray2[ii]); + } + + printf("\ndouble: "); + for (int ii=0; ii < 10; ii++) + { + printf("%4.3f ", (float) (darray[ii] * darray2[ii])); + } + printf("\n"); +#endif + + i_result = main_func (iarray, iarray2, iarray[0] * iarray2[0], 10); + f_result = main_func(farray, farray2, 0.00, 10); + d_result = main_func(darray, darray2, 0.0000, 10); + l_result = main_func(larray, larray2, 0, 10); + +#if HAVE_IO + printf("int result = %2d\n", i_result); + printf ("long result = %2d\n", l_result); + printf("float result = %4.3f\n", f_result); + printf("double result = %4.3lf\n", d_result); +#endif + + i_max = iarray[0] * iarray2[0]; + f_max = farray[0] * farray2[0]; + d_max = darray[0] * darray2[0]; + l_max = larray[0] * larray2[0]; + for (int ii = 0; ii < 10; ii++) + { + if (i_max < iarray[ii] * iarray2[ii]) + i_max = iarray[ii] * iarray2[ii]; + if (f_max < farray[ii] * farray2[ii]) + f_max = farray[ii] * farray2[ii]; + if (d_max < darray[ii] * darray2[ii]) + d_max = darray[ii] * darray2[ii]; + if (l_max < larray[ii] * larray2[ii]) + l_max = larray[ii] * larray2[ii]; + } + + if (i_max != i_result) + return 1; + if (f_max != f_result) + return 2; + if (d_max != d_result) + return 3; + if (l_max != l_result) + return 4; + return 0; +} + diff --git gcc/testsuite/g++.dg/cilk-plus/AN/builtin_fn_mutating_tplt.cc gcc/testsuite/g++.dg/cilk-plus/AN/builtin_fn_mutating_tplt.cc new file mode 100644 index 0000000..d4267c5 --- /dev/null +++ gcc/testsuite/g++.dg/cilk-plus/AN/builtin_fn_mutating_tplt.cc @@ -0,0 +1,136 @@ +/* { dg-do run } */ +/* { dg-options "-fcilkplus" } */ + +#if HAVE_IO +#include +#include +#endif + +#include + +template +T my_func (T *x, T y) +{ + if (*x < y) + *x = y; + else + *x = *x; +} + +template T my_func (T *x, T y); +template +T main_func (T *array, T *array2, T identity_val, int size) +{ + T result = identity_val; + + __sec_reduce_mutating (&result, array[0:size] * array2[0:size:1], my_func); + +#if HAVE_IO + std::cout << "Result = " << result << std::endl; +#endif + return result; +} + +int main (void) +{ + int iarray[10], iarray2[10], i_result = 0, i_max; +#if 1 + long larray[10], larray2[10], l_result = 0, l_max; + float farray[10], farray2[10], f_result = 0, f_max; + double darray[10], darray2[10], d_result = 0, d_max; + for (int ii = 0; ii < 10; ii++) + { + if (ii%2 && ii) + { + darray[ii] = (double)(1.0000/(double)(ii)); + farray[ii] = (float)(1.00/(float)(ii)); + } + else + { + darray[ii] = (double) ii + 0.10; + farray[ii] = (float) (1.00/((float)(ii) + 0.10)); + } + darray2[ii] = (double) (1.00000/ (double)(ii+1)); + farray2[ii] = (float) (1.00/ (float)(ii+1)); + } + + for (int ii = 0; ii < 10; ii++) + { + iarray[ii] = ii; + larray[ii] = (long)ii; + } + + for (int ii = 0; ii < 10; ii++) + { + iarray2[ii] = (ii-5); + larray2[ii] = (long)ii-5; + } +#endif +#if HAVE_IO + printf("\nInt: "); + for (int ii=0; ii < 10; ii++) + { + printf("%2d ", iarray[ii] * iarray2[ii]); + } + printf("\nfloat: "); + for (int ii=0; ii < 10; ii++) + { + printf("%3.2f ", farray[ii] * farray2[ii]); + } + + printf("\nlong: "); + for (int ii=0; ii < 10; ii++) + { + printf("%2d ", larray[ii] * larray2[ii]); + } + + printf("\ndouble: "); + for (int ii=0; ii < 10; ii++) + { + printf("%4.3lf ", (float) (darray[ii] * darray2[ii])); + } + printf("\n"); +#endif + + i_result = main_func (iarray, iarray2, 0, 10); + l_result = main_func(larray, larray2, 0, 10); + f_result = main_func(farray, farray2, 0.00, 10); + d_result = main_func(darray, darray2, 0.0000, 10); + + i_max = iarray[0] * iarray2[0]; + d_max = darray[0] * darray2[0]; + f_max = farray[0] * farray2[0]; + l_max = larray[0] * larray2[0]; + for (int ii = 0; ii < 10; ii++) + { + if (iarray[ii] * iarray2[ii] > i_max) + i_max = iarray[ii] * iarray2[ii]; + if (darray[ii] * darray2[ii] > d_max) + d_max = darray[ii] * darray2[ii]; + if (farray[ii] * farray2[ii] > f_max) + f_max = farray[ii] * farray2[ii]; + if (larray[ii] * larray2[ii] > l_max) + l_max = larray[ii] * larray2[ii]; + } +#if HAVE_IO + printf("int result = %2d\n", i_max); + printf("long result = %2d\n", l_max); + printf("float result = %4.3f\n", f_max); + printf("double result = %4.3lf\n", (float)d_max); +#endif + + if (i_max != i_result) + return 1; + + if (f_max != f_result) + return 2; + + if (l_max != l_result) + return 3; + + if (d_max != d_result) + return 4; + + return 0; +} + diff --git gcc/testsuite/g++.dg/cilk-plus/AN/fp_triplet_values_tplt.c gcc/testsuite/g++.dg/cilk-plus/AN/fp_triplet_values_tplt.c new file mode 100644 index 0000000..1387558 --- /dev/null +++ gcc/testsuite/g++.dg/cilk-plus/AN/fp_triplet_values_tplt.c @@ -0,0 +1,36 @@ +/* { dg-do compile } */ +/* { dg-options "-fcilkplus" } */ + +float q; + +void func (int *x) +{ + *x = 5; +} +template int main2 (T x, T y, T z); + +int main (void) +{ + main2 (1.5, 2.3, 3.443); + main2 (1.34393, 2.38383, 4.38383); + return 0; +} +template +int main2 (T x, T y, T z) +{ + int array[10], array2[10]; + array2[:] = array[x:2]; /* { dg-error "start-index of array notation triplet is not an integer" } */ + array2[:] = array[1:y]; /* { dg-error "length of array notation triplet is not an integer" } */ + array2[1:2:z] = array[:]; /* { dg-error "stride of array notation triplet is not an integer" } */ + func (&array2[1:x:3]); /* { dg-error "length of array notation triplet is not an integer" } */ + array2[y:9]++; /* { dg-error "start-index of array notation triplet is not an integer" } */ + array2[1:x]++; /* { dg-error "length of array notation triplet is not an integer" } */ + array2[1:9:x]++; /* { dg-error "stride of array notation triplet is not an integer" } */ + + ++array2[1:q:3]; /* { dg-error "length of array notation triplet is not an integer" } */ + array2[:] = array[q:1:3]; /* { dg-error "start-index of array notation triplet is not an integer" } */ + array2[:] = array[1:q:3]; /* { dg-error "length of array notation triplet is not an integer" } */ + array2[:] = array[1:3:q]; /* { dg-error "stride of array notation triplet is not an integer" } */ + func (&array2[1:q:3]); /* { dg-error "length of array notation triplet is not an integer" } */ + return 0; +} diff --git gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp new file mode 100644 index 0000000..a153529 --- /dev/null +++ gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp @@ -0,0 +1,48 @@ +# Copyright (C) 2013 Free Software Foundation, Inc. + +# This program 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 of the License, or +# (at your option) any later version. +# +# This program 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 +# . + +# Written by Balaji V. Iyer + + +load_lib g++-dg.exp + +dg-init +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O0 -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O1 -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O2 -ftree-vectorize -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O3 -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -g -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -g -O0 -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -g -O1 -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -g -O2 -ftree-vectorize -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -g -O3 -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O3 -ftree-vectorize -fcilkplus -g" " " +dg-finish + +dg-init +dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -O0 -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -O1 -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -O2 -ftree-vectorize -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -O3 -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -g -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -g -O0 -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -g -O1 -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -g -O2 -ftree-vectorize -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -g -O3 -fcilkplus" " " +dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -O3 -ftree-vectorize -fcilkplus -g" " " +dg-finish diff --git gcc/testsuite/g++.dg/dg.exp gcc/testsuite/g++.dg/dg.exp old mode 100644 new mode 100755 index 7201359..710218e --- gcc/testsuite/g++.dg/dg.exp +++ gcc/testsuite/g++.dg/dg.exp @@ -33,6 +33,7 @@ dg-init set tests [lsort [find $srcdir/$subdir *.C]] set tests [prune $tests $srcdir/$subdir/bprob/*] set tests [prune $tests $srcdir/$subdir/charset/*] +set tests [prune $tests $srcdir/$subdir/cilk-plus/AN/*] set tests [prune $tests $srcdir/$subdir/compat/*] set tests [prune $tests $srcdir/$subdir/debug/*] set tests [prune $tests $srcdir/$subdir/dfp/*]