Hello Everyone, Attached, please find a patch that will implement SIMD enabled functions for C targeting the gomp-4_0-branch. Here are the ChangeLog entries. Is this OK to install?
gcc/c/ChangeLog 2013-11-18 Balaji V. Iyer <balaji.v.i...@intel.com> * c-parser.c (c_parser_declaration_or_fndef): Added a check for attribute keyword before the function name. If so, call the function to parse attributes. Added a NULL parameter for c_parser_attributes. (c_parser_declspecs): Added a NULL parameter for c_parser_attributes. (c_parser_enum_specifier): Likewise. (c_parser_struct_or_union_specifier): Likewise. (c_parser_struct_declaration): Likewise. (c_parser_direct_declarator): Likewise. (c_parser_direct_declarator_inner): Likewise. (c_parser_parms_list_declarator): Likewise. (c_parser_parameter_declaration): Likewise. (c_parser_label): Likewise. (c_parser_objc_maybe_method_attributes): Likewise. (c_parser_objc_method_decl): Likewise. (c_parser_transaction_attributes): Likewise. (c_parser_elem_fn_vectorlength): New function. (c_parser_elem_fn_expr_list): Likewise. (c_finish_elem_fn_tokens): Likewise. (c_parser_elem_fn_attributes): Added a elem_fn_tokens parameter. Added a check for vector attribute and if so call c_parser_elem_fn_expr_list. Also, called c_finish_elem_fn_tokens when Cilk Plus is enabled. testsuite/ChangeLog 2013-11-18 Balaji V. Iyer <balaji.v.i...@intel.com> * c-c++-common/cilk-plus/EF/ef_test.c: New test. * c-c++-common/cilk-plus/EF/vlength_errors.c: Likewise. * gcc.dg/cilk-plus/cilk-plus.exp: Added calls for the above tests. Thanks, Balaji V. Iyer.
Index: gcc/c/c-parser.c =================================================================== --- gcc/c/c-parser.c (revision 204981) +++ gcc/c/c-parser.c (working copy) @@ -1148,7 +1148,7 @@ tree); static struct c_parm *c_parser_parameter_declaration (c_parser *, tree); static tree c_parser_simple_asm_expr (c_parser *); -static tree c_parser_attributes (c_parser *); +static tree c_parser_attributes (c_parser *, vec <c_token> *); static struct c_type_name *c_parser_type_name (c_parser *); static struct c_expr c_parser_initializer (c_parser *); static struct c_expr c_parser_braced_init (c_parser *, tree, bool); @@ -1502,9 +1502,17 @@ c_parser_peek_token (parser)->value = error_mark_node; fndef_ok = !nested; } + /* In Cilk Plus SIMD-enabled functions (formerly known as Elemental + Functions), attributes are used right above the functoin declaration or + the function itself. */ + tree attrs = NULL_TREE; + if (flag_enable_cilkplus + && c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) + attrs = c_parser_attributes (parser, &omp_declare_simd_clauses); c_parser_declspecs (parser, specs, true, true, start_attr_ok, true, true, cla_nonabstract_decl); + specs->attrs = chainon (attrs, specs->attrs); if (parser->error) { c_parser_skip_to_end_of_block_or_statement (parser); @@ -1676,7 +1684,7 @@ if (c_parser_next_token_is_keyword (parser, RID_ASM)) asm_name = c_parser_simple_asm_expr (parser); if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) - postfix_attrs = c_parser_attributes (parser); + postfix_attrs = c_parser_attributes (parser, NULL); if (c_parser_next_token_is (parser, CPP_EQ)) { tree d; @@ -1815,7 +1823,7 @@ } c_parser_consume_token (parser); if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) - all_prefix_attrs = chainon (c_parser_attributes (parser), + all_prefix_attrs = chainon (c_parser_attributes (parser, NULL), prefix_attrs); else all_prefix_attrs = prefix_attrs; @@ -2403,7 +2411,7 @@ case RID_ATTRIBUTE: if (!attrs_ok) goto out; - attrs = c_parser_attributes (parser); + attrs = c_parser_attributes (parser, NULL); declspecs_add_attrs (loc, specs, attrs); break; case RID_ALIGNAS: @@ -2452,7 +2460,7 @@ gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM)); enum_loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); - attrs = c_parser_attributes (parser); + attrs = c_parser_attributes (parser, NULL); enum_loc = c_parser_peek_token (parser)->location; /* Set the location in case we create a decl now. */ c_parser_set_source_position_from_token (c_parser_peek_token (parser)); @@ -2532,7 +2540,7 @@ break; } } - postfix_attrs = c_parser_attributes (parser); + postfix_attrs = c_parser_attributes (parser, NULL); ret.spec = finish_enum (type, nreverse (values), chainon (attrs, postfix_attrs)); ret.kind = ctsk_tagdef; @@ -2623,7 +2631,7 @@ } struct_loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); - attrs = c_parser_attributes (parser); + attrs = c_parser_attributes (parser, NULL); /* Set the location in case we create a decl now. */ c_parser_set_source_position_from_token (c_parser_peek_token (parser)); @@ -2735,7 +2743,7 @@ recovered already. Go on with the next field. */ } } - postfix_attrs = c_parser_attributes (parser); + postfix_attrs = c_parser_attributes (parser, NULL); ret.spec = finish_struct (struct_loc, type, nreverse (contents), chainon (attrs, postfix_attrs), struct_info); ret.kind = ctsk_tagdef; @@ -2904,7 +2912,7 @@ width = c_parser_expr_no_commas (parser, NULL).value; } if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) - postfix_attrs = c_parser_attributes (parser); + postfix_attrs = c_parser_attributes (parser, NULL); d = grokfield (c_parser_peek_token (parser)->location, declarator, specs, width, &all_prefix_attrs); decl_attributes (&d, chainon (postfix_attrs, @@ -2912,7 +2920,7 @@ DECL_CHAIN (d) = decls; decls = d; if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) - all_prefix_attrs = chainon (c_parser_attributes (parser), + all_prefix_attrs = chainon (c_parser_attributes (parser, NULL), prefix_attrs); else all_prefix_attrs = prefix_attrs; @@ -3226,7 +3234,7 @@ tree attrs; struct c_declarator *inner; c_parser_consume_token (parser); - attrs = c_parser_attributes (parser); + attrs = c_parser_attributes (parser, NULL); if (kind != C_DTR_NORMAL && (c_parser_next_token_starts_declspecs (parser) || c_parser_next_token_is (parser, CPP_CLOSE_PAREN))) @@ -3382,7 +3390,7 @@ tree attrs; struct c_arg_info *args; c_parser_consume_token (parser); - attrs = c_parser_attributes (parser); + attrs = c_parser_attributes (parser, NULL); args = c_parser_parms_declarator (parser, id_present, attrs); if (args == NULL) return NULL; @@ -3529,7 +3537,7 @@ tree new_attrs; c_parser_consume_token (parser); mark_forward_parm_decls (); - new_attrs = c_parser_attributes (parser); + new_attrs = c_parser_attributes (parser, NULL); return c_parser_parms_list_declarator (parser, new_attrs, expr); } if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) @@ -3623,7 +3631,7 @@ return NULL; } if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) - postfix_attrs = c_parser_attributes (parser); + postfix_attrs = c_parser_attributes (parser, NULL); return build_c_parm (specs, chainon (postfix_attrs, prefix_attrs), declarator); } @@ -3760,6 +3768,148 @@ return attr_name; } +/* Parses the vectorlength vector attribute for the SIMD Enabled functions + in Cilk Plus. + Syntax: + vectorlength (<integer constant expression>) */ + +static bool +c_parser_elem_fn_vectorlength (c_parser *parser, vec <c_token> *token_list) +{ + c_token *token = c_parser_peek_token (parser); + gcc_assert (simple_cst_equal (token->value, + get_identifier ("vectorlength")) == 1); + token->value = get_identifier ("simdlen"); + token_list->safe_push (*token); + + c_parser_consume_token (parser); + + token = c_parser_peek_token (parser); + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return false; + + token_list->safe_push (*token); + + token = c_parser_peek_token (parser); + tree value = token->value; + if (!value) + { + error_at (token->location, "expected vectorlength value"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return false; + } + c_parser_consume_token (parser); + if (TREE_CODE (value) != INTEGER_CST) + { + error_at (token->location, "vectorlength must be a constant integer"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return false; + } + if (!integer_pow2p (value)) + { + error_at (token->location, "vectorlength must be a power of 2"); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return false; + } + token_list->safe_push (*token); + + token = c_parser_peek_token (parser); + if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + return false; + token_list->safe_push (*token); + return true; +} + +/* Parses the vector attribute of SIMD enabled functions in Cilk Plus. + Syntax: + vector + vector (<vector attributes>). */ + +static void +c_parser_elem_fn_expr_list (c_parser *parser, c_token vec_token, + vec <c_token> *elem_fn_tokens) +{ + gcc_assert (simple_cst_equal (vec_token.value, + get_identifier ("vector")) == 1); + int paren_scope = 0; + /* Replace the vector keyword with SIMD. */ + vec_token.value = get_identifier ("simd"); + elem_fn_tokens->safe_push (vec_token); + + /* Consume the "vector" token. */ + c_parser_consume_token (parser); + + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + c_parser_consume_token (parser); + paren_scope++; + } + while (paren_scope > 0) + { + c_token *token = c_parser_peek_token (parser); + if (token->type == CPP_OPEN_PAREN) + paren_scope++; + else if (token->type == CPP_CLOSE_PAREN) + paren_scope--; + if (token->type == CPP_NAME + && TREE_CODE (token->value) == IDENTIFIER_NODE) + { + tree value = token->value; + if (simple_cst_equal (value, get_identifier ("mask")) == 1) + token->value = get_identifier ("inbranch"); + else if (simple_cst_equal (value, get_identifier ("nomask")) == 1) + token->value = get_identifier ("notinbranch"); + else if (simple_cst_equal (value, + get_identifier ("vectorlength")) == 1) + { + if (!c_parser_elem_fn_vectorlength (parser, elem_fn_tokens)) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + /* No reason to keep any of these tokens if the + vectorlength is messed up. */ + elem_fn_tokens->release (); + return; + } + else + continue; + } + /* linear and uniform are the same between SIMD + enabled functions and #pragma omp declare simd. */ + } + /* Do not push the last ')' */ + if (!(token->type == CPP_CLOSE_PAREN && paren_scope == 0)) + elem_fn_tokens->safe_push (*token); + c_parser_consume_token (parser); + } + c_token eol_token; + memset (&eol_token, 0, sizeof (eol_token)); + eol_token.type = CPP_PRAGMA_EOL; + elem_fn_tokens->safe_push (eol_token); + return; +} + +/* Add 2 CPP_EOF at the end of ELEM_FN_TOKENS vector. */ + +static void +c_finish_elem_fn_tokens (vec <c_token> *elem_fn_tokens) +{ + /* If the token is a CPP_EOF, then there is no reason to stuff it again + with 2 EOF. If it is NULL, then we didn't find any vector keywords. */ + if (!elem_fn_tokens || *elem_fn_tokens == vNULL + || (*elem_fn_tokens)[0].type == CPP_EOF) + return; + /* Since we are converting an attribute to a pragma, we need to end the + attribute with PRAGMA_EOL. OpenMP guys would like to have 2 CPP_EOF + at the end, and so we insert that also. */ + c_token eof_token; + memset (&eof_token, 0, sizeof (eof_token)); + eof_token.type = CPP_PRAGMA_EOL; + elem_fn_tokens->safe_push (eof_token); + eof_token.type = CPP_EOF; + elem_fn_tokens->safe_push (eof_token); + elem_fn_tokens->safe_push (eof_token); +} + /* Parse (possibly empty) attributes. This is a GNU extension. attributes: @@ -3788,7 +3938,7 @@ allow identifiers declared as types to start the arguments? */ static tree -c_parser_attributes (c_parser *parser) +c_parser_attributes (c_parser *parser, vec <c_token> *elem_fn_tokens) { tree attrs = NULL_TREE; while (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) @@ -3824,6 +3974,13 @@ attr_name = c_parser_attribute_any_word (parser); if (attr_name == NULL) break; + if (flag_enable_cilkplus + && simple_cst_equal (attr_name, get_identifier ("vector")) == 1) + { + c_token *v_token = c_parser_peek_token (parser); + c_parser_elem_fn_expr_list (parser, *v_token, elem_fn_tokens); + continue; + } c_parser_consume_token (parser); if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN)) { @@ -3904,6 +4061,9 @@ } parser->lex_untranslated_string = false; } + + if (flag_enable_cilkplus) + c_finish_elem_fn_tokens (elem_fn_tokens); return attrs; } @@ -4588,7 +4748,7 @@ c_parser_consume_token (parser); gcc_assert (c_parser_next_token_is (parser, CPP_COLON)); c_parser_consume_token (parser); - attrs = c_parser_attributes (parser); + attrs = c_parser_attributes (parser, NULL); tlab = define_label (loc2, name); if (tlab) { @@ -8386,7 +8546,7 @@ } if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) - *attributes = c_parser_attributes (parser); + *attributes = c_parser_attributes (parser, NULL); /* If there were no attributes here, just report any earlier error. */ if (*attributes == NULL_TREE || bad) @@ -8475,7 +8635,7 @@ } /* New ObjC allows attributes on method parameters. */ if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) - param_attr = c_parser_attributes (parser); + param_attr = c_parser_attributes (parser, NULL); if (c_parser_next_token_is_not (parser, CPP_NAME)) { c_parser_error (parser, "expected identifier"); @@ -13630,7 +13790,7 @@ tree attr_name, attr = NULL; if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) - return c_parser_attributes (parser); + return c_parser_attributes (parser, NULL); if (!c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) return NULL_TREE; Index: gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp =================================================================== --- gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp (revision 204981) +++ gcc/testsuite/gcc.dg/cilk-plus/cilk-plus.exp (working copy) @@ -59,6 +59,12 @@ dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/CK/*.c]] " -O3 -flto -g -fcilkplus" " " } +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/EF/*.c]] " -g" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/EF/*.c]] " -O1" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/EF/*.c]] " -O2 -std=c99" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/EF/*.c]] " -O2 -ftree-vectorize" " " +dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/EF/*.c]] " -O3 -g" " " + dg-finish unset TEST_EXTRA_LIBS Index: gcc/testsuite/c-c++-common/cilk-plus/EF/vlength_errors.c =================================================================== --- gcc/testsuite/c-c++-common/cilk-plus/EF/vlength_errors.c (revision 0) +++ gcc/testsuite/c-c++-common/cilk-plus/EF/vlength_errors.c (revision 0) @@ -0,0 +1,49 @@ +/* { dg-do compile } */ +/* { dg-options "-fcilkplus -Wunknown-pragmas" } */ + +#define Q 4 + +int z = Q; + +__attribute__ ((vector (uniform(x), vectorlength (), linear (y:1) ))) /* { dg-error "expected vectorlength value" } */ +int func2 (int x, int y) +{ + int zq = 5; + return x + (y*zq); +} + +__attribute__ ((vector (uniform(x), linear (y:1), vectorlength (4.5) ))) /* { dg-error "vectorlength must be a constant integer" } */ +int func3 (int x, int y) +{ + int zq = 5; + return x + (y*zq); +} + +__attribute__ ((vector (uniform(x), linear (y:1), vectorlength (z) ))) /* { dg-error "vectorlength must be a constant integer" } */ +int func4 (int x, int y) +{ + int zq = 5; + return x + (y*zq); +} + +__attribute__ ((vector (uniform(x), linear (y:1), vectorlength (Q) ))) /* This is OK! */ +int func5 (int x, int y) +{ + int zq = 5; + return x + (y*zq); +} + +__attribute__ ((vector (uniform(x), vectorlength (z), linear (y:1)))) /* { dg-error "vectorlength must be a constant integer" } */ +int func6 (int x, int y) +{ + int zq = 5; + return x + (y*zq); +} + +int main (void) +{ + int ii = 0, q = 5; + for (ii = 0; ii < 10; ii++) + q += func2 (z, ii); + return q; +} Index: gcc/testsuite/c-c++-common/cilk-plus/EF/ef_test.c =================================================================== --- gcc/testsuite/c-c++-common/cilk-plus/EF/ef_test.c (revision 0) +++ gcc/testsuite/c-c++-common/cilk-plus/EF/ef_test.c (revision 0) @@ -0,0 +1,78 @@ +/* { dg-do compile } */ +/* { dg-options "-fcilkplus -Wunknown-pragmas" } */ + +/* Tests the clauses in several combinations put in different locations. */ +/* This is mostly a parser test. */ +#define Q 4 + +int z = Q; + + __attribute__ ((vector (uniform(x), linear (y:1), vectorlength (4) ))) +int func (int x, int y) +{ + int zq = 5; + return x + (y*zq); +} + __attribute__ ((vector (uniform(x), vectorlength (2), linear (y:1) ))) +int func2 (int x, int y) +{ + int zq = 5; + return x + (y*zq); +} + +__attribute__ ((vector (uniform(y), linear (x), vectorlength (4) ))) +int func3 (int x, int y) +{ + int zq = 5; + return x + (y*zq); +} + +__attribute__ ((vector (uniform(x), linear (y:1), mask))) +int func4 (int x, int y) +{ + int zq = 5; + return x + (y*zq); +} + +__attribute__ ((vector (uniform(x), linear (y:1), nomask))) +int func5 (int x, int y) +{ + int zq = 5; + return x + (y*zq); +} + +__attribute__ ((vector (uniform(x), mask, linear (y:1)))) +int func6 (int x, int y) +{ + int zq = 5; + return x + (y*zq); +} + +__attribute__ ((vector (uniform (x), mask, linear (y:1)), vector)) +int func7 (int x, int y) +{ + int zq = 5; + return x + (y*zq); +} + +__attribute__ ((vector (uniform (x), mask, linear (y:1)), vector (uniform (y), mask))) +int func8 (int x, int y) +{ + int zq = 5; + return x + (y*zq); +} + +__attribute__ ((vector, vector (uniform (y), mask))) +int func9 (int x, int y) +{ + int zq = 5; + return x + (y*zq); +} + +int main (int argc, char *argv[]) +{ + int ii = 0, q = 5; + for (ii = 0; ii < 10; ii++) + q += func (argc, ii); + return q; +}