From patchwork Mon Nov 30 14:48:10 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathan Sidwell X-Patchwork-Id: 550139 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 583411400CB for ; Tue, 1 Dec 2015 01:48:25 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=QQURCyAG; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:to :from:subject:message-id:date:mime-version:content-type; q=dns; s=default; b=oLgZDf6Uiv7aFgc0b49mK2SSqnvidYhbvj1tvRaERP3jUTVvBr T0xtyACarAWxXrGQpBLuNc+ympCnRdFClNKEQRrNI/mr4LlsBSkjKZUqID5Nr9te 3/GOwq+KW73Cl90k/AuguOcXk8DiFraZWy/ldJtgjP7NnxEg4xH+1g4gs= 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:to :from:subject:message-id:date:mime-version:content-type; s= default; bh=xCGyFH9LEvImjPe5vie6ro9l22M=; b=QQURCyAGBL/Gy0lCH28r e2dPiMKZGSRgstdyJdDJLIRChpTEnNINUn3clqMChsBlaM5sxV23WdBsNhfP7XvS NhZJb0zT1A+DPUpMBeUKTigCJWgYh5fXUG6ODCUI4nr5MPRBiFmqiz4egCLolX4+ kXJVP0mjKBcFE7AWl/bVVRM= Received: (qmail 62819 invoked by alias); 30 Nov 2015 14:48: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 62804 invoked by uid 89); 30 Nov 2015 14:48:15 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.6 required=5.0 tests=BAYES_00, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, SPF_PASS, UNSUBSCRIBE_BODY autolearn=no version=3.3.2 X-HELO: mail-qg0-f53.google.com Received: from mail-qg0-f53.google.com (HELO mail-qg0-f53.google.com) (209.85.192.53) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Mon, 30 Nov 2015 14:48:13 +0000 Received: by qgec40 with SMTP id c40so118813858qge.2 for ; Mon, 30 Nov 2015 06:48:11 -0800 (PST) X-Received: by 10.140.152.150 with SMTP id 144mr80191774qhy.8.1448894891752; Mon, 30 Nov 2015 06:48:11 -0800 (PST) Received: from ?IPv6:2601:181:c000:c497:a2a8:cdff:fe3e:b48? ([2601:181:c000:c497:a2a8:cdff:fe3e:b48]) by smtp.googlemail.com with ESMTPSA id r67sm15076628qki.17.2015.11.30.06.48.10 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 30 Nov 2015 06:48:10 -0800 (PST) To: GCC Patches From: Nathan Sidwell Subject: [PTX] rework PTX prototype emission Message-ID: <565C61AA.1090008@acm.org> Date: Mon, 30 Nov 2015 09:48:10 -0500 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.3.0 MIME-Version: 1.0 This patch moves all PTX prototype emission from a DECL into the renamed 'write_fn_decl'. Thus we no longer need write_fn_decl_and_comment, nor does nvptx_declare_function_name need to emit the linker comment marker itself (which is nearly identical to the one that was emitted by write_fn_decl_and_comment). While there I made the handling of name replacement consistent between the two prototype emitters and tidied up the argument emission of write_fn_decl. nathan 2015-11-30 Nathan Sidwell * config/nvptx/nvptx.c (nvptx_name_replacement): Move earlier. (write_one_arg): Reorder parms, add 'sep' param. (nvptx_write_function_decl): Rename to ... (write_fn_proto): ... here. Do name replacement. Emit linaer comment marker. Deal with both decls and defns. Simplify argument formatting. (write_function_decl_and_comment): Delete. (write_func_decl_from_insn): Rename to ... (write_fn_proto_from_insn): ... here. Don't do name replacement. (nvptx_record_fndecl): Call write_fn_proto. (nvptx_record_libfunc): Call write_fn_proto_from_insn. (nvptx_declare_function_name): Adjust for write_fn_proto changes. (nvotx_output_call_insn): Call write_fn_prot_from_insn. Index: gcc/config/nvptx/nvptx.c =================================================================== --- gcc/config/nvptx/nvptx.c (revision 231072) +++ gcc/config/nvptx/nvptx.c (working copy) @@ -224,6 +224,24 @@ nvptx_addr_space_from_sym (rtx sym) return ADDR_SPACE_GLOBAL; } +/* Check NAME for special function names and redirect them by returning a + replacement. This applies to malloc, free and realloc, for which we + want to use libgcc wrappers, and call, which triggers a bug in ptxas. */ + +static const char * +nvptx_name_replacement (const char *name) +{ + if (strcmp (name, "call") == 0) + return "__nvptx_call"; + if (strcmp (name, "malloc") == 0) + return "__nvptx_malloc"; + if (strcmp (name, "free") == 0) + return "__nvptx_free"; + if (strcmp (name, "realloc") == 0) + return "__nvptx_realloc"; + return name; +} + /* If MODE should be treated as two registers of an inner mode, return that inner mode. Otherwise return VOIDmode. */ @@ -309,8 +327,8 @@ arg_promotion (machine_mode mode) a decl with zero TYPE_ARG_TYPES, i.e. an old-style C decl. */ static int -write_one_arg (std::stringstream &s, tree type, int i, machine_mode mode, - bool no_arg_types) +write_one_arg (std::stringstream &s, const char *sep, int i, + tree type, machine_mode mode, bool no_arg_types) { if (!PASS_IN_REG_P (mode, type)) mode = Pmode; @@ -318,9 +336,9 @@ write_one_arg (std::stringstream &s, tre machine_mode split = maybe_split_mode (mode); if (split != VOIDmode) { - i = write_one_arg (s, NULL_TREE, i, split, false); - i = write_one_arg (s, NULL_TREE, i, split, false); - return i; + i = write_one_arg (s, sep, i, TREE_TYPE (type), split, false); + sep = ", "; + mode = split; } if (no_arg_types && !AGGREGATE_TYPE_P (type)) @@ -330,8 +348,7 @@ write_one_arg (std::stringstream &s, tre mode = arg_promotion (mode); } - if (i) - s << ", "; + s << sep; s << ".param" << nvptx_ptx_type_from_mode (mode, false) << " %in_ar" << i << (mode == QImode || mode == HImode ? "[1]" : ""); if (mode == BLKmode) @@ -349,41 +366,41 @@ write_as_kernel (tree attrs) || lookup_attribute ("omp target entrypoint", attrs) != NULL_TREE); } -/* Write a function decl for DECL to S, where NAME is the name to be used. - This includes ptx .visible or .extern specifiers, .func or .kernel, and - argument and return types. */ +/* Write a .func or .kernel declaration or definition along with + a helper comment for use by ld. S is the stream to write to, DECL + the decl for the function with name NAME. For definitions, emit + a declaration too. */ -static void -nvptx_write_function_decl (std::stringstream &s, const char *name, const_tree decl) +static const char * +write_fn_proto (std::stringstream &s, bool is_defn, + const char *name, const_tree decl) { - tree fntype = TREE_TYPE (decl); - tree result_type = TREE_TYPE (fntype); - tree args = TYPE_ARG_TYPES (fntype); - tree attrs = DECL_ATTRIBUTES (decl); - bool kernel = write_as_kernel (attrs); - bool is_main = strcmp (name, "main") == 0; - bool args_from_decl = false; - - /* We get: - NULL in TYPE_ARG_TYPES, for old-style functions - NULL in DECL_ARGUMENTS, for builtin functions without another - declaration. - So we have to pick the best one we have. */ - if (args == 0) + if (is_defn) + /* Emit a declaration. The PTX assembler gets upset without it. */ + name = write_fn_proto (s, false, name, decl); + else { - args = DECL_ARGUMENTS (decl); - args_from_decl = true; + /* Avoid repeating the name replacement. */ + name = nvptx_name_replacement (name); + if (name[0] == '*') + name++; } + /* Emit the linker marker. */ + s << "\n// BEGIN"; + if (TREE_PUBLIC (decl)) + s << " GLOBAL"; + s << " FUNCTION " << (is_defn ? "DEF" : "DECL") << ": " << name << "\n"; + + /* PTX declaration. */ if (DECL_EXTERNAL (decl)) s << ".extern "; else if (TREE_PUBLIC (decl)) s << (DECL_WEAK (decl) ? ".weak " : ".visible "); + s << (write_as_kernel (DECL_ATTRIBUTES (decl)) ? ".entry " : ".func "); - if (kernel) - s << ".entry "; - else - s << ".func "; + tree fntype = TREE_TYPE (decl); + tree result_type = TREE_TYPE (fntype); /* Declare the result. */ bool return_in_mem = false; @@ -396,78 +413,74 @@ nvptx_write_function_decl (std::stringst { mode = arg_promotion (mode); s << "(.param" << nvptx_ptx_type_from_mode (mode, false) - << " %out_retval)"; + << " %out_retval) "; } } - if (name[0] == '*') - s << (name + 1); - else - s << name; + s << name; + + const char *sep = " ("; + int i = 0; - /* Declare argument types. */ - if ((args != NULL_TREE - && !(TREE_CODE (args) == TREE_LIST - && TREE_VALUE (args) == void_type_node)) - || is_main - || return_in_mem - || DECL_STATIC_CHAIN (decl)) + /* Emit argument list. */ + if (return_in_mem) { - s << "("; - int i = 0; + s << sep << ".param.u" << GET_MODE_BITSIZE (Pmode) << " %in_ar0"; + sep = ", "; + i++; + } - if (return_in_mem) - { - s << ".param.u" << GET_MODE_BITSIZE (Pmode) << " %in_ar0"; - i++; - } - while (args != NULL_TREE) - { - tree type = args_from_decl ? TREE_TYPE (args) : TREE_VALUE (args); - machine_mode mode = TYPE_MODE (type); + /* We get: + NULL in TYPE_ARG_TYPES, for old-style functions + NULL in DECL_ARGUMENTS, for builtin functions without another + declaration. + So we have to pick the best one we have. */ + tree args = TYPE_ARG_TYPES (fntype); + bool null_type_args = !args; + if (null_type_args) + args = DECL_ARGUMENTS (decl); - if (mode != VOIDmode) - i = write_one_arg (s, type, i, mode, - TYPE_ARG_TYPES (fntype) == 0); - args = TREE_CHAIN (args); - } - if (stdarg_p (fntype)) - { - gcc_assert (i > 0); - s << ", .param.u" << GET_MODE_BITSIZE (Pmode) << " %in_argp"; - } - if (DECL_STATIC_CHAIN (decl)) - { - if (i) - s << ", "; - s << ".reg.u" << GET_MODE_BITSIZE (Pmode) - << reg_names [STATIC_CHAIN_REGNUM]; - } - if (!i && is_main) - s << ".param.u32 %argc, .param.u" << GET_MODE_BITSIZE (Pmode) - << " %argv"; - s << ")"; + for (; args; args = TREE_CHAIN (args)) + { + tree type = null_type_args ? TREE_TYPE (args) : TREE_VALUE (args); + machine_mode mode = TYPE_MODE (type); + + if (mode == VOIDmode) + break; + i = write_one_arg (s, sep, i, type, mode, null_type_args); + sep = ", "; } -} -/* Write a .func or .kernel declaration (not a definition) along with - a helper comment for use by ld. S is the stream to write to, DECL - the decl for the function with name NAME. */ + if (stdarg_p (fntype)) + { + s << sep << ".param.u" << GET_MODE_BITSIZE (Pmode) << " %in_argp"; + i++; + sep = ", "; + } -static void -write_function_decl_and_comment (std::stringstream &s, const char *name, const_tree decl) -{ - s << "\n// BEGIN"; - if (TREE_PUBLIC (decl)) - s << " GLOBAL"; - s << " FUNCTION DECL: "; - if (name[0] == '*') - s << (name + 1); - else - s << name; - s << "\n"; - nvptx_write_function_decl (s, name, decl); - s << ";\n"; + if (DECL_STATIC_CHAIN (decl)) + { + s << sep << ".reg.u" << GET_MODE_BITSIZE (Pmode) + << reg_names [STATIC_CHAIN_REGNUM]; + i++; + sep = ", "; + } + + if (!i && strcmp (name, "main") == 0) + { + s << sep + << ".param.u32 %argc, .param.u" << GET_MODE_BITSIZE (Pmode) + << " %argv"; + i++; + sep = ", "; + } + + if (i) + s << ")"; + + s << (is_defn ? "\n" : ";\n"); + + return name; } /* Construct a function declaration from a call insn. This can be @@ -476,8 +489,8 @@ write_function_decl_and_comment (std::st generated by emit_library_call for which no decl exists. */ static void -write_func_decl_from_insn (std::stringstream &s, const char *name, - rtx result, rtx pat) +write_fn_proto_from_insn (std::stringstream &s, const char *name, + rtx result, rtx pat) { if (!name) { @@ -486,6 +499,7 @@ write_func_decl_from_insn (std::stringst } else { + name = nvptx_name_replacement (name); s << "\n// BEGIN GLOBAL FUNCTION DECL: " << name << "\n"; s << "\t.extern .func "; } @@ -519,24 +533,6 @@ write_func_decl_from_insn (std::stringst s << ";\n"; } -/* Check NAME for special function names and redirect them by returning a - replacement. This applies to malloc, free and realloc, for which we - want to use libgcc wrappers, and call, which triggers a bug in ptxas. */ - -static const char * -nvptx_name_replacement (const char *name) -{ - if (strcmp (name, "call") == 0) - return "__nvptx_call"; - if (strcmp (name, "malloc") == 0) - return "__nvptx_malloc"; - if (strcmp (name, "free") == 0) - return "__nvptx_free"; - if (strcmp (name, "realloc") == 0) - return "__nvptx_realloc"; - return name; -} - /* DECL is an external FUNCTION_DECL, make sure its in the fndecl hash table and and write a ptx prototype. These are emitted at end of compilation. */ @@ -549,8 +545,7 @@ nvptx_record_fndecl (tree decl) { *slot = decl; const char *name = get_fnname_from_decl (decl); - name = nvptx_name_replacement (name); - write_function_decl_and_comment (func_decls, name, decl); + write_fn_proto (func_decls, false, name, decl); } } @@ -567,8 +562,7 @@ nvptx_record_libfunc (rtx callee, rtx re *slot = callee; const char *name = XSTR (callee, 0); - name = nvptx_name_replacement (name); - write_func_decl_from_insn (func_decls, name, retval, pat); + write_fn_proto_from_insn (func_decls, name, retval, pat); } } @@ -625,29 +619,13 @@ nvptx_declare_function_name (FILE *file, tree result_type = TREE_TYPE (fntype); int argno = 0; - name = nvptx_name_replacement (name); - std::stringstream s; - write_function_decl_and_comment (s, name, decl); - s << "// BEGIN"; - if (TREE_PUBLIC (decl)) - s << " GLOBAL"; - s << " FUNCTION DEF: "; - - if (name[0] == '*') - s << (name + 1); - else - s << name; - s << "\n"; - - nvptx_write_function_decl (s, name, decl); + write_fn_proto (s, true, name, decl); fprintf (file, "%s", s.str().c_str()); + fprintf (file, "{\n"); bool return_in_mem = (TYPE_MODE (result_type) != VOIDmode && !RETURN_IN_REG_P (TYPE_MODE (result_type))); - - fprintf (file, "\n{\n"); - if (return_in_mem) { fprintf (file, "\t.reg.u%d %%ar%d;\n", GET_MODE_BITSIZE (Pmode), argno); @@ -1794,7 +1771,7 @@ nvptx_output_call_insn (rtx_insn *insn, labelno++; ASM_OUTPUT_LABEL (asm_out_file, buf); std::stringstream s; - write_func_decl_from_insn (s, NULL, result, pat); + write_fn_proto_from_insn (s, NULL, result, pat); fputs (s.str().c_str(), asm_out_file); }