From patchwork Wed Jun 12 20:49:48 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: 250879 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 EC7842C008A for ; Thu, 13 Jun 2013 06:50:26 +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:references:in-reply-to :content-type:mime-version; q=dns; s=default; b=ZNfH2T3W88pFP4On dFz3WzOy1FGDchKK7XkdlxRqSDGr5W70CrgIyVd8pOPEOTg5YfDin/ln70rJKAJk zlUcxi6d8aq0xWp/9AgSNwsw9GkIoDK9AxeNCLZY78yjl0RSgpgwVT6gIh8G8l6U okjkShorRMOEhbm7EMTRD3MtUlA= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:references:in-reply-to :content-type:mime-version; s=default; bh=XCzaC7ZD/FYwxoAdYnudfE RgWxM=; b=D4TxNJU0hVHUd34Macu1ypt7v6aXlZcO1HV6WTH4FH/yFcDOFMKUxe uM1pKdQu+hci2OQroh9OYJHQK9/v0qyZmNlHF/Lx6yxxJ5a+cETkLvtAdSRlCiN1 5zJllUM9sgb8d2yoG1H4otnK8yBxsUIyYMmpQUzEBgtd2ti1H3ymM= Received: (qmail 11999 invoked by alias); 12 Jun 2013 20:50:16 -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 11988 invoked by uid 89); 12 Jun 2013 20:50:15 -0000 X-Spam-SWARE-Status: No, score=-5.6 required=5.0 tests=AWL, BAYES_50, KHOP_THREADED, RCVD_IN_HOSTKARMA_W, RCVD_IN_HOSTKARMA_WL, RP_MATCHES_RCVD, SPF_PASS, TW_BJ, TW_JC, TW_TM autolearn=ham version=3.3.1 Received: from mga11.intel.com (HELO mga11.intel.com) (192.55.52.93) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Wed, 12 Jun 2013 20:50:07 +0000 Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga102.fm.intel.com with ESMTP; 12 Jun 2013 13:50:37 -0700 X-ExtLoop1: 1 Received: from fmsmsx106.amr.corp.intel.com ([10.19.9.37]) by fmsmga002.fm.intel.com with ESMTP; 12 Jun 2013 13:49:49 -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; Wed, 12 Jun 2013 13:49:49 -0700 From: "Iyer, Balaji V" To: Aldy Hernandez CC: "gcc-patches@gcc.gnu.org" , "Jason Merrill (jason@redhat.com)" , "rth@redhat.com" Subject: RE: [PATCH] Cilk Plus Array Notation for C++ Date: Wed, 12 Jun 2013 20:49:48 +0000 Message-ID: References: <51B8A2FA.2020404@redhat.com> In-Reply-To: <51B8A2FA.2020404@redhat.com> MIME-Version: 1.0 Hi Aldy, Please see my comments below with the fixed patch. Thanks, Balaji V. Iyer. > -----Original Message----- > From: Aldy Hernandez [mailto:aldyh@redhat.com] > Sent: Wednesday, June 12, 2013 12:34 PM > To: Iyer, Balaji V > Cc: gcc-patches@gcc.gnu.org; Jason Merrill (jason@redhat.com); > rth@redhat.com > Subject: Re: [PATCH] Cilk Plus Array Notation for C++ > > [Jason/Richard: there are some things below I could use your feedback on.] > > Hi Balaji. > > Overall, a lot of the stuff in cp-array-notation.c looks familiar from the C front- > end changes. Can't you reuse a lot of it? > > Otherwise, here are some minor nits... > > > + /* 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; > > Don't we have BUILT_IN_CILKPLUS_SEC_REDUCE* now? So you shouldn't need > to poke at the actual identifier. And even so, won't the above strncmp match > __sec_reducegarbage? FIXED! > > > +/* 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. */ > > + > > It looks like a NULL in INIT_INDEX is a specially handled case. Perhaps you > should document that INIT_INDEX can be null and what it means. > Also, you don't need to document what internal variable name you are using as > a return value (VALUE_TREE). Perhaps instead of "The return value..." you could > write "This function returns the ARRAY_NOTATION_REF node." or something > like it. It is documented inside the function, right before checking for !init_index. Is that enough? > > > + 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))); > > + } > > > You do all this type checking here, but aren't you doing the same type checking > in build_array_notation_ref() which you're going to call anyway? It looks like > there is some code duplication going on. > > Also, I see you have a build_array_notation_ref() in cp/cp-array-notation.c and > also in c/c-array-notation.c. Can you not implement one function that handles > both C and C++, or at the very least reuse some of the common things? As we discussed in the previous email-exchange, I have created a new function called cilkplus_an_triplet_types_ok_p (). The reason why I prefixed "cilkplus_an" is because it is not a static function and I want to make sure this is unique and descriptive and does not cause any interference with anything present or future. > > You are missing a ChangeLog entry for the above snippet. I have put it in now. > > > + /* 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; > > + } > > The comment doesn't seem to match the code, or am I missing something? > > > + /* If find_rank returns false, then it should have reported an > > + error, FIXED > > Extra whitespace. > > > + if (rank > 1) > > + { > > + error_at (loc, "rank of the array%'s index is greater than 1"); > > + return error_mark_node; > > + } > > No corresponding test. This is being tested in the file "testsuite/c-c++-common/cilk-plus/AN/gather-scatter-errors.c" > > > + /* 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. */ > > Line too long, please wrap. > > There are various lines throughout your patch that are pretty long (both in code > and in ChangeLog entries). I don't know what the official GNU guidelines say, > but what I usually see as prior art in the GCC code base is something along the > lines of wrapping around column 72. Perhaps someone can pontificate on this, > but lines reaching the 78-80 columns look pretty darn long to me. The line length is specified to be at most 80 characters (http://gcc.gnu.org/codingconventions.html#Line). I have followed it everywhere except in the cases of dg-error since I can't fit them all in one line. > > > 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; > > Changes to existing tests should be submitted as a separate patch, since this > doesn't seem to be C++ specific. And BTW, this particular test change can be > committed as obvious. OK will do. What about adding {target c} and {target c++} for test cases. Can that be submitted with the patch? > > > + 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) > > Remove this redundant #if 1/#endif pair. Similarly in other tests. FIXED! > > > + 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"); > > No corresponding test, or is this handled by the existing > c-c++-common/cilk-plus tests? Please see c-c++-common/cilk-plus/AN/misc.c > > > + /* 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"); > > No need to document the obvious. The error message can be used in lieu of the > comment :). Also, no corresponding test. I didn't see one matching in c-c++- > common/cilkplus either. OK. This testcase (testsuite/c-c++-common/cilk-plus/AN/fn_ptr.c) checks this error. > > > + /* Disable correcting single colon correcting to scope. */ > > + parser->colon_corrects_to_scope_p = false; > > No need to document the obvious. FIXED! > > I suggest a different name for fix_array_notation_exprs() to avoid confusion > with the C function fix_array_notation_expr() (no final "s"). > Perhaps cpp_fix_array_notation_expr, or something similar? > > > +/* 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 > > Do you mean "ARRAY" instead of "a"? > > > + we generate a ARRAY_NOTATION_REF front-end tree and return it. > > s/a ARRAY/an ARRAY/ > > > + 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) > > Overall this function comment needs to be reworded. From reading the > comment, I still don't know what the function actually does and what it returns. > "Handles expression..." is rather ambiguous. Perhaps something like "Given a > blah blah blah in ARRAY, construct an ARRAY_NOTATION_REF and return it. > START_INDEX is blah, LENGTH is blah, etc etc". Reworded it. Please let me know if it is OK. > > Again, you can probably reuse a lot of the C counterpart. It looks like a lot of > the same code. > > > + 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); > > I see a lot of this business going on. Perhaps one of the core maintainers can > comment, but I would rather use an obstack, and avoid having to keep track of > all these little buckets-- which seems rather error prone, and then free the > obstack all in one swoop. But I'll defer to Richard or Jason. > > > > + is not, we convert induction variable to stride's > > Rephrase as "is not, convert the induction variable to the stride's" > Similarly in a few other places. It looks like you used the same comment. FIXED! > > > + /* 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 > > s/type is, we stay safe/type is. We stay safe/. > Similarly in a few other places. It looks like you used the same comment. FIXED! > > > + everything to integer. The reason why we pick integer > > s/pick integer/pick an integer > Similarly in a few other places. FIXED! > > > +/* 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) > > This is called "build_x_array_notation_expr", but it doesn't look like we build any > ARRAY_NOTATION_EXPRs in here. Perhaps a better name would be > "expand_array_notation_expr" (or something to that effect)? I renamed this function to "expand_an_in_modify_expr" to indicate that we are expanding array notations in modify expr. > > > +static tree > > +fix_builtin_array_notation_fn (tree an_builtin_fn, tree *new_var) > > It looks like this function expands the __sec_reduce* builtins. Perhaps it would > be cleaner to rename it as such? Maybe... > "expand_sec_reduce_builtin" or something? FIXED! > > The fact that you are sometimes using "build_*" and sometimes "fix_*" to > denote expansion is confusing. Replaced all the "fix" with "expand" > > > +/* Returns true of NODE has a call_expression with ARRAY_NOTATION_REF > > +tree. */ > > + > > +static bool > > +has_call_expr_with_array_notation (tree node) > > s/of NODE/if NODE FIXED! > > Thanks. > Aldy diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog old mode 100644 new mode 100755 index 2c93982..362f0bc Binary files a/gcc/cp/ChangeLog and b/gcc/cp/ChangeLog differ diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index df8ed3e..6e80bcf 100644 --- a/gcc/cp/Make-lang.in +++ b/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 a/gcc/cp/call.c b/gcc/cp/call.c index dfd061a..64be41f 100644 --- a/gcc/cp/call.c +++ b/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,20 @@ 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 no need + to do any type conversion. */ + if (flag_enable_cilkplus + && is_cilkplus_reduce_builtin (fn) != BUILT_IN_NONE) + 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 a/gcc/cp/cp-array-notation.c b/gcc/cp/cp-array-notation.c new file mode 100755 index 0000000..34c73f3 --- /dev/null +++ b/gcc/cp/cp-array-notation.c @@ -0,0 +1,2850 @@ +/* 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 if 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 +expand_sec_reduce_builtin (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, 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, convert everything to + integer. The reason why we pick an 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 +expand_an_in_modify_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 = expand_sec_reduce_builtin (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, 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, convert everything to + integer. The reason why we pick an 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, 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, convert everything to + integer. The reason why we pick an 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 expand_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_expand_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 = expand_sec_reduce_builtin (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, 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 an 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 +expand_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 = expand_sec_reduce_builtin (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, 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, convert everything to + integer. The reason why we pick an 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 +expand_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 = expand_an_in_modify_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 +expand_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 = expand_an_in_modify_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 = expand_an_in_modify_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) = + expand_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 = expand_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) = + expand_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 = expand_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 = expand_unary_array_notation_exprs (t); + return t; + case CONVERT_EXPR: + case CLEANUP_POINT_EXPR: + case EXPR_STMT: + TREE_OPERAND (t, 0) = expand_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_expand_cond_array_notations (t); + if (TREE_CODE (t) == COND_EXPR) + { + COND_EXPR_THEN (t) = + expand_array_notation_exprs (COND_EXPR_THEN (t)); + COND_EXPR_ELSE (t) = + expand_array_notation_exprs (COND_EXPR_ELSE (t)); + } + else + t = expand_array_notation_exprs (t); + return t; + + case SWITCH_EXPR: + t = cp_expand_cond_array_notations (t); + if (TREE_CODE (t) == SWITCH_EXPR) + SWITCH_BODY (t) = expand_array_notation_exprs (SWITCH_BODY (t)); + else + t = expand_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) = expand_array_notation_exprs (FOR_BODY (t)); + else + t = expand_array_notation_exprs (t); + return t; + + case IF_STMT: + t = cp_expand_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) = expand_array_notation_exprs (THEN_CLAUSE (t)); + if (ELSE_CLAUSE (t)) + ELSE_CLAUSE (t) = expand_array_notation_exprs (ELSE_CLAUSE (t)); + } + else + t = expand_array_notation_exprs (t); + return t; + + case SWITCH_STMT: + t = cp_expand_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) = + expand_array_notation_exprs (SWITCH_STMT_BODY (t)); + } + else + t = expand_array_notation_exprs (t); + return t; + + case WHILE_STMT: + t = cp_expand_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) = expand_array_notation_exprs (WHILE_BODY (t)); + } + else + t = expand_array_notation_exprs (t); + return t; + + case DO_STMT: + t = cp_expand_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) = expand_array_notation_exprs (DO_BODY (t)); + } + else + t = expand_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) = + expand_array_notation_exprs (TREE_OPERAND (t, i)); + } + return t; + } + return t; +} + +/* Given the base of an array (ARRAY), the START_INDEX, the number of elements + to be accessed (LENGTH) and the STRIDE, construct an ARRAY_NOTATION_REF tree + of type TYPE and return it. Restrictions on START_INDEX, LENGTH and STRIDE + are the same as that of 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; + + /* When dealing with templates, do 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 (!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 (!cilkplus_an_triplet_types_ok_p (loc, start_index, length, stride, type)) + 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; +} + + +/* Returns false if any of the Array notation triplet values: START_INDEX, + LENGTH and STRIDE, are not of integral type and have a rank greater than + zero. */ + +bool +cilkplus_an_triplet_types_ok_p (location_t loc, tree start_index, tree length, + tree stride, tree type) +{ + size_t stride_rank = 0, length_rank = 0, start_rank = 0; + 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 false; + } + if (!TREE_TYPE (length) || !INTEGRAL_TYPE_P (TREE_TYPE (length))) + { + error_at (loc, "length of array notation triplet is not an integer"); + return false; + } + if (!TREE_TYPE (stride) || !INTEGRAL_TYPE_P (TREE_TYPE (stride))) + { + error_at (loc, "stride of array notation triplet is not an integer"); + return false; + } + if (!TREE_CODE (type) == FUNCTION_TYPE) + { + error_at (loc, "array notations cannot be used with function type"); + return false; + } + + while (type && (TREE_CODE (type) == POINTER_TYPE + || TREE_CODE (type) == ARRAY_TYPE)) + { + type = TREE_TYPE (type); + if (type && TREE_CODE (type) == FUNCTION_TYPE) + { + error_at (loc, "array notations cannot be used with function pointer" + " arrays"); + return false; + } + } + 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 false; + + if (start_rank != 0) + { + error_at (loc, "rank of an array notation triplet%'s start-index is not " + "zero"); + return false; + } + if (length_rank != 0) + { + error_at (loc, "rank of an array notation triplet%'s length is not zero"); + return false; + } + if (stride_rank != 0) + { + error_at (loc, "rank of array notation triplet%'s stride is not zero"); + return false; + } + return true; +} diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index bccd884..d301db0 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/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 a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 9421822..4791a32 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6135,6 +6135,10 @@ 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 expand_array_notation_exprs (tree); +bool cilkplus_an_triplet_types_ok_p (location_t, tree, tree, tree, + tree); /* -- end of C++ */ #endif /* ! GCC_CP_TREE_H */ diff --git a/gcc/cp/error.c b/gcc/cp/error.c old mode 100644 new mode 100755 index a75fc4e..a8f52cd --- a/gcc/cp/error.c +++ b/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 a/gcc/cp/parser.c b/gcc/cp/parser.c old mode 100644 new mode 100755 index a581e88..523dcf7 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -6060,6 +6060,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 @@ -6081,41 +6243,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; } @@ -9342,6 +9541,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 = expand_array_notation_exprs (compound_stmt); return compound_stmt; } @@ -9534,6 +9735,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; @@ -10094,6 +10303,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; @@ -10120,6 +10335,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; @@ -10138,8 +10362,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; @@ -16714,30 +16947,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 @@ -18108,6 +18364,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 = expand_array_notation_exprs (body); + /* Finish the function body. */ finish_function_body (body); @@ -22087,6 +22348,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) = + expand_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 a/gcc/cp/pt.c b/gcc/cp/pt.c old mode 100644 new mode 100755 index 3602fcd..0a7d523 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13740,6 +13740,20 @@ 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)); + if (!cilkplus_an_triplet_types_ok_p (loc, start_index, length, stride, + TREE_TYPE (op1))) + 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 +15726,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; @@ -19119,6 +19136,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) = expand_array_notation_exprs (DECL_SAVED_TREE (d)); + /* Finish the function. */ d = finish_function (0); expand_or_defer_fn (d); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index b5c3b0a..656962b 100644 --- a/gcc/cp/semantics.c +++ b/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 expression contains array notatinos, then flag it as + error. */ + 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 a/gcc/cp/tree.c b/gcc/cp/tree.c index 8524f6c..dd2fda4 100644 --- a/gcc/cp/tree.c +++ b/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 a/gcc/cp/typeck.c b/gcc/cp/typeck.c old mode 100644 new mode 100755 index 11ac85b..17f19c7 --- a/gcc/cp/typeck.c +++ b/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 + && is_cilkplus_reduce_builtin (fndecl) != BUILT_IN_NONE) + 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 a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog old mode 100644 new mode 100755 diff --git a/gcc/testsuite/c-c++-common/cilk-plus/AN/array_test1.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/array_test1.c index e4f1ea8..282a55d 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/AN/array_test1.c +++ b/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 a/gcc/testsuite/c-c++-common/cilk-plus/AN/if_test_errors.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/if_test_errors.c index d17d8cf..579d396 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/AN/if_test_errors.c +++ b/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 a/gcc/testsuite/c-c++-common/cilk-plus/AN/misc.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/misc.c index 35eb115..14421d9 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/AN/misc.c +++ b/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 a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors.c old mode 100644 new mode 100755 index a0a3742..18816e0 --- a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors.c +++ b/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 a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors2.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors2.c index 2e86b4f..4314090 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors2.c +++ b/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 a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors3.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors3.c index 34dfa16..47b5979 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors3.c +++ b/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 a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors4.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors4.c index eba28a8..a0efc04 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors4.c +++ b/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 a/gcc/testsuite/c-c++-common/cilk-plus/AN/pr57541.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/pr57541.c index cabdb23..793afb2 100755 --- a/gcc/testsuite/c-c++-common/cilk-plus/AN/pr57541.c +++ b/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 a/gcc/testsuite/c-c++-common/cilk-plus/AN/vla.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/vla.c index 843745e..3b0777e 100644 --- a/gcc/testsuite/c-c++-common/cilk-plus/AN/vla.c +++ b/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 a/gcc/testsuite/g++.dg/cilk-plus/AN/array_test1_tplt.cc b/gcc/testsuite/g++.dg/cilk-plus/AN/array_test1_tplt.cc new file mode 100644 index 0000000..e9ee7ec --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cilk-plus/AN/array_test2_tplt.cc b/gcc/testsuite/g++.dg/cilk-plus/AN/array_test2_tplt.cc new file mode 100644 index 0000000..87c37e1 --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cilk-plus/AN/array_test_ND_tplt.cc b/gcc/testsuite/g++.dg/cilk-plus/AN/array_test_ND_tplt.cc new file mode 100644 index 0000000..479ba13 --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cilk-plus/AN/braced_list.cc b/gcc/testsuite/g++.dg/cilk-plus/AN/braced_list.cc new file mode 100755 index 0000000..b91de7a --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cilk-plus/AN/builtin_fn_custom_tplt.cc b/gcc/testsuite/g++.dg/cilk-plus/AN/builtin_fn_custom_tplt.cc new file mode 100644 index 0000000..94ffe6e --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/AN/builtin_fn_custom_tplt.cc @@ -0,0 +1,126 @@ +/* { 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; + 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); + } +#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 a/gcc/testsuite/g++.dg/cilk-plus/AN/builtin_fn_mutating_tplt.cc b/gcc/testsuite/g++.dg/cilk-plus/AN/builtin_fn_mutating_tplt.cc new file mode 100644 index 0000000..db81912 --- /dev/null +++ b/gcc/testsuite/g++.dg/cilk-plus/AN/builtin_fn_mutating_tplt.cc @@ -0,0 +1,134 @@ +/* { 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; + 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; + } +#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 a/gcc/testsuite/g++.dg/cilk-plus/AN/fp_triplet_values_tplt.c b/gcc/testsuite/g++.dg/cilk-plus/AN/fp_triplet_values_tplt.c new file mode 100644 index 0000000..1387558 --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp b/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp new file mode 100644 index 0000000..a153529 --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/dg.exp b/gcc/testsuite/g++.dg/dg.exp old mode 100644 new mode 100755 index 7201359..710218e --- a/gcc/testsuite/g++.dg/dg.exp +++ b/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/*]