This patch gets the gimple FE to parse calls to internal functions. The only non-obvious thing was how the functions should be written to avoid clashes with real function names. One option would be to go the magic number of underscores route, but we already do that for built-in functions, and it would be good to keep them visually distinct. In the end I borrowed the local/internal label convention from asm and used:
x = .SQRT (y); I don't think even C++ has found a meaning for a leading dot yet. Tested on aarch64-linux-gnu (with and without SVE), aarch64_be-elf and x86_64-linux-gnu. OK to install? Richard 2018-05-17 Richard Sandiford <richard.sandif...@linaro.org> gcc/ * internal-fn.h (lookup_internal_fn): Declare * internal-fn.c (lookup_internal_fn): New function. * gimple.c (gimple_build_call_from_tree): Handle calls to internal functions. * gimple-pretty-print.c (dump_gimple_call): Print "." before internal function names. * tree-pretty-print.c (dump_generic_node): Likewise. * tree-ssa-scopedtables.c (expr_hash_elt::print): Likewise. gcc/c/ * gimple-parser.c: Include internal-fn.h. (c_parser_gimple_statement): Treat a leading CPP_DOT as a call. (c_parser_gimple_call_internal): New function. (c_parser_gimple_postfix_expression): Use it to handle CPP_DOT. Fix typos in comment. gcc/testsuite/ * gcc.dg/gimplefe-28.c: New test. * gcc.dg/asan/use-after-scope-9.c: Adjust expected output for internal function calls. * gcc.dg/goacc/loop-processing-1.c: Likewise. Index: gcc/internal-fn.h =================================================================== --- gcc/internal-fn.h 2018-05-16 12:48:59.194282896 +0100 +++ gcc/internal-fn.h 2018-05-17 09:17:58.757608747 +0100 @@ -107,6 +107,8 @@ internal_fn_name (enum internal_fn fn) return internal_fn_name_array[(int) fn]; } +extern internal_fn lookup_internal_fn (const char *); + /* Return the ECF_* flags for function FN. */ extern const int internal_fn_flags_array[]; Index: gcc/internal-fn.c =================================================================== --- gcc/internal-fn.c 2018-05-16 12:48:59.410941892 +0100 +++ gcc/internal-fn.c 2018-05-17 09:22:49.808912358 +0100 @@ -64,6 +64,26 @@ #define DEF_INTERNAL_FN(CODE, FLAGS, FNS 0 }; +/* Return the internal function called NAME, or IFN_LAST if there's + no such function. */ + +internal_fn +lookup_internal_fn (const char *name) +{ + typedef hash_map<nofree_string_hash, internal_fn> name_to_fn_map_type; + static name_to_fn_map_type *name_to_fn_map; + + if (!name_to_fn_map) + { + name_to_fn_map = new name_to_fn_map_type (IFN_LAST); + for (unsigned int i = 0; i < IFN_LAST; ++i) + name_to_fn_map->put (internal_fn_name (internal_fn (i)), + internal_fn (i)); + } + internal_fn *entry = name_to_fn_map->get (name); + return entry ? *entry : IFN_LAST; +} + /* Fnspec of each internal function, indexed by function number. */ const_tree internal_fn_fnspec_array[IFN_LAST + 1]; Index: gcc/gimple.c =================================================================== --- gcc/gimple.c 2018-05-16 12:48:59.410941892 +0100 +++ gcc/gimple.c 2018-05-17 09:22:49.808912358 +0100 @@ -350,12 +350,19 @@ gimple_build_call_from_tree (tree t, tre { unsigned i, nargs; gcall *call; - tree fndecl = get_callee_fndecl (t); gcc_assert (TREE_CODE (t) == CALL_EXPR); nargs = call_expr_nargs (t); - call = gimple_build_call_1 (fndecl ? fndecl : CALL_EXPR_FN (t), nargs); + + tree fndecl = NULL_TREE; + if (CALL_EXPR_FN (t) == NULL_TREE) + call = gimple_build_call_internal_1 (CALL_EXPR_IFN (t), nargs); + else + { + fndecl = get_callee_fndecl (t); + call = gimple_build_call_1 (fndecl ? fndecl : CALL_EXPR_FN (t), nargs); + } for (i = 0; i < nargs; i++) gimple_call_set_arg (call, i, CALL_EXPR_ARG (t, i)); Index: gcc/gimple-pretty-print.c =================================================================== --- gcc/gimple-pretty-print.c 2018-05-16 12:48:59.410941892 +0100 +++ gcc/gimple-pretty-print.c 2018-05-17 09:22:49.808912358 +0100 @@ -874,7 +874,7 @@ dump_gimple_call (pretty_printer *buffer if (flags & TDF_RAW) { if (gimple_call_internal_p (gs)) - dump_gimple_fmt (buffer, spc, flags, "%G <%s, %T", gs, + dump_gimple_fmt (buffer, spc, flags, "%G <.%s, %T", gs, internal_fn_name (gimple_call_internal_fn (gs)), lhs); else dump_gimple_fmt (buffer, spc, flags, "%G <%T, %T", gs, fn, lhs); @@ -898,7 +898,10 @@ dump_gimple_call (pretty_printer *buffer pp_space (buffer); } if (gimple_call_internal_p (gs)) - pp_string (buffer, internal_fn_name (gimple_call_internal_fn (gs))); + { + pp_dot (buffer); + pp_string (buffer, internal_fn_name (gimple_call_internal_fn (gs))); + } else print_call_name (buffer, fn, flags); pp_string (buffer, " ("); Index: gcc/tree-pretty-print.c =================================================================== --- gcc/tree-pretty-print.c 2018-05-16 12:48:59.410941892 +0100 +++ gcc/tree-pretty-print.c 2018-05-17 09:22:49.808912358 +0100 @@ -2262,7 +2262,10 @@ dump_generic_node (pretty_printer *pp, t if (CALL_EXPR_FN (node) != NULL_TREE) print_call_name (pp, CALL_EXPR_FN (node), flags); else - pp_string (pp, internal_fn_name (CALL_EXPR_IFN (node))); + { + pp_dot (pp); + pp_string (pp, internal_fn_name (CALL_EXPR_IFN (node))); + } /* Print parameters. */ pp_space (pp); Index: gcc/tree-ssa-scopedtables.c =================================================================== --- gcc/tree-ssa-scopedtables.c 2018-02-08 13:34:20.649280969 +0000 +++ gcc/tree-ssa-scopedtables.c 2018-05-17 09:17:58.758608713 +0100 @@ -906,8 +906,8 @@ expr_hash_elt::print (FILE *stream) fn_from = m_expr.ops.call.fn_from; if (gimple_call_internal_p (fn_from)) - fputs (internal_fn_name (gimple_call_internal_fn (fn_from)), - stream); + fprintf (stream, ".%s", + internal_fn_name (gimple_call_internal_fn (fn_from))); else print_generic_expr (stream, gimple_call_fn (fn_from)); fprintf (stream, " ("); Index: gcc/c/gimple-parser.c =================================================================== --- gcc/c/gimple-parser.c 2018-05-16 12:48:59.410941892 +0100 +++ gcc/c/gimple-parser.c 2018-05-17 09:22:49.808912358 +0100 @@ -53,6 +53,7 @@ Software Foundation; either version 3, o #include "tree-ssanames.h" #include "gimple-ssa.h" #include "tree-dfa.h" +#include "internal-fn.h" /* Gimple parsing functions. */ @@ -400,9 +401,10 @@ c_parser_gimple_statement (c_parser *par } /* GIMPLE call with lhs. */ - if (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN - && lookup_name (c_parser_peek_token (parser)->value)) + if (c_parser_next_token_is (parser, CPP_DOT) + || (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN + && lookup_name (c_parser_peek_token (parser)->value))) { rhs = c_parser_gimple_unary_expression (parser); if (rhs.value != error_mark_node) @@ -726,14 +728,57 @@ c_parser_parse_ssa_name (c_parser *parse return name; } +/* Parse a gimple call to an internal function. + + gimple-call-internal: + . identifier ( gimple-argument-expression-list[opt] ) */ + +static struct c_expr +c_parser_gimple_call_internal (c_parser *parser) +{ + struct c_expr expr; + expr.set_error (); + + gcc_assert (c_parser_next_token_is (parser, CPP_DOT)); + c_parser_consume_token (parser); + location_t loc = c_parser_peek_token (parser)->location; + if (!c_parser_next_token_is (parser, CPP_NAME) + || c_parser_peek_token (parser)->id_kind != C_ID_ID) + { + c_parser_error (parser, "expecting internal function name"); + return expr; + } + tree id = c_parser_peek_token (parser)->value; + internal_fn ifn = lookup_internal_fn (IDENTIFIER_POINTER (id)); + c_parser_consume_token (parser); + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + auto_vec<tree> exprlist; + if (!c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + c_parser_gimple_expr_list (parser, &exprlist); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + if (ifn == IFN_LAST) + error_at (loc, "unknown internal function %qE", id); + else + { + expr.value = build_call_expr_internal_loc_array + (loc, ifn, void_type_node, exprlist.length (), + exprlist.address ()); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + } + } + return expr; +} + /* Parse gimple postfix expression. gimple-postfix-expression: gimple-primary-expression - gimple-primary-xpression [ gimple-primary-expression ] + gimple-primary-expression [ gimple-primary-expression ] gimple-primary-expression ( gimple-argument-expression-list[opt] ) - postfix-expression . identifier - postfix-expression -> identifier + gimple-postfix-expression . identifier + gimple-postfix-expression -> identifier gimple-argument-expression-list: gimple-unary-expression @@ -743,6 +788,7 @@ c_parser_parse_ssa_name (c_parser *parse identifier constant string-literal + gimple-call-internal */ @@ -779,6 +825,9 @@ c_parser_gimple_postfix_expression (c_pa expr.original_code = STRING_CST; c_parser_consume_token (parser); break; + case CPP_DOT: + expr = c_parser_gimple_call_internal (parser); + break; case CPP_NAME: if (c_parser_peek_token (parser)->id_kind == C_ID_ID) { Index: gcc/testsuite/gcc.dg/gimplefe-28.c =================================================================== --- /dev/null 2018-04-20 16:19:46.369131350 +0100 +++ gcc/testsuite/gcc.dg/gimplefe-28.c 2018-05-17 09:17:58.757608747 +0100 @@ -0,0 +1,16 @@ +/* { dg-do compile { target sqrt_insn } } */ +/* { dg-options "-fgimple -O2" } */ + +double __GIMPLE +f1 (double x) +{ + double res; + res = .SQRT (x); + return res; +} + +void __GIMPLE +f2 (double x) +{ + .SQRT (x); // Dead code +} Index: gcc/testsuite/gcc.dg/asan/use-after-scope-9.c =================================================================== --- gcc/testsuite/gcc.dg/asan/use-after-scope-9.c 2017-02-23 19:54:08.000000000 +0000 +++ gcc/testsuite/gcc.dg/asan/use-after-scope-9.c 2018-05-17 09:17:58.757608747 +0100 @@ -17,7 +17,7 @@ main (int argc, char **argv) return *ptr; } -// { dg-final { scan-tree-dump-times "= ASAN_POISON \\(\\)" 1 "asan1" } } +// { dg-final { scan-tree-dump-times {= \.ASAN_POISON \(\)} 1 "asan1" } } // { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" } // { dg-output "READ of size .*" } // { dg-output ".*'a' <== Memory access at offset \[0-9\]* is inside this variable.*" } Index: gcc/testsuite/gcc.dg/goacc/loop-processing-1.c =================================================================== --- gcc/testsuite/gcc.dg/goacc/loop-processing-1.c 2017-02-23 19:54:08.000000000 +0000 +++ gcc/testsuite/gcc.dg/goacc/loop-processing-1.c 2018-05-17 09:17:58.757608747 +0100 @@ -15,4 +15,4 @@ void vector_1 (int *ary, int size) } } -/* { dg-final { scan-tree-dump {OpenACC loops.*Loop 0\(0\).*Loop 24\(1\).*\.data_dep\.[0-9_]+ = UNIQUE \(OACC_HEAD_MARK, 0, 1, 36\);.*Head-0:.*\.data_dep\.[0-9_]+ = UNIQUE \(OACC_HEAD_MARK, 0, 1, 36\);.*\.data_dep\.[0-9_]+ = UNIQUE \(OACC_FORK, \.data_dep\.[0-9_]+, 0\);.*Tail-0:.*\.data_dep\.[0-9_]+ = UNIQUE \(OACC_TAIL_MARK, \.data_dep\.[0-9_]+, 1\);.*\.data_dep\.[0-9_]+ = UNIQUE \(OACC_JOIN, \.data_dep\.[0-9_]+, 0\);.*Loop 6\(6\).*\.data_dep\.[0-9_]+ = UNIQUE \(OACC_HEAD_MARK, 0, 2, 6\);.*Head-0:.*\.data_dep\.[0-9_]+ = UNIQUE \(OACC_HEAD_MARK, 0, 2, 6\);.*\.data_dep\.[0-9_]+ = UNIQUE \(OACC_FORK, \.data_dep\.[0-9_]+, 1\);.*Head-1:.*\.data_dep\.[0-9_]+ = UNIQUE \(OACC_HEAD_MARK, \.data_dep\.[0-9_]+, 1\);.*\.data_dep\.[0-9_]+ = UNIQUE \(OACC_FORK, \.data_dep\.[0-9_]+, 2\);.*Tail-1:.*\.data_dep\.[0-9_]+ = UNIQUE \(OACC_TAIL_MARK, \.data_dep\.[0-9_]+, 2\);.*\.data_dep\.[0-9_]+ = UNIQUE \(OACC_JOIN, \.data_dep\.[0-9_]+, 2\);.*Tail-0:.*\.data_dep\.[0-9_]+ = UNIQUE \(OACC_TAIL_MARK, \.data_dep\.[0-9_]+, 1\);.*\.data_dep\.[0-9_]+ = UNIQUE \(OACC_JOIN, \.data_dep\.[0-9_]+, 1\);} "oaccdevlow" } } */ +/* { dg-final { scan-tree-dump {OpenACC loops.*Loop 0\(0\).*Loop 24\(1\).*\.data_dep\.[0-9_]+ = \.UNIQUE \(OACC_HEAD_MARK, 0, 1, 36\);.*Head-0:.*\.data_dep\.[0-9_]+ = \.UNIQUE \(OACC_HEAD_MARK, 0, 1, 36\);.*\.data_dep\.[0-9_]+ = \.UNIQUE \(OACC_FORK, \.data_dep\.[0-9_]+, 0\);.*Tail-0:.*\.data_dep\.[0-9_]+ = \.UNIQUE \(OACC_TAIL_MARK, \.data_dep\.[0-9_]+, 1\);.*\.data_dep\.[0-9_]+ = \.UNIQUE \(OACC_JOIN, \.data_dep\.[0-9_]+, 0\);.*Loop 6\(6\).*\.data_dep\.[0-9_]+ = \.UNIQUE \(OACC_HEAD_MARK, 0, 2, 6\);.*Head-0:.*\.data_dep\.[0-9_]+ = \.UNIQUE \(OACC_HEAD_MARK, 0, 2, 6\);.*\.data_dep\.[0-9_]+ = \.UNIQUE \(OACC_FORK, \.data_dep\.[0-9_]+, 1\);.*Head-1:.*\.data_dep\.[0-9_]+ = \.UNIQUE \(OACC_HEAD_MARK, \.data_dep\.[0-9_]+, 1\);.*\.data_dep\.[0-9_]+ = \.UNIQUE \(OACC_FORK, \.data_dep\.[0-9_]+, 2\);.*Tail-1:.*\.data_dep\.[0-9_]+ = \.UNIQUE \(OACC_TAIL_MARK, \.data_dep\.[0-9_]+, 2\);.*\.data_dep\.[0-9_]+ = \.UNIQUE \(OACC_JOIN, \.data_dep\.[0-9_]+, 2\);.*Tail-0:.*\.data_dep\.[0-9_]+ = \.UNIQUE \(OACC_TAIL_MARK, \.data_dep\.[0-9_]+, 1\);.*\.data_dep\.[0-9_]+ = \.UNIQUE \(OACC_JOIN, \.data_dep\.[0-9_]+, 1\);} "oaccdevlow" } } */