From patchwork Thu Jan 25 12:18:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andi Kleen X-Patchwork-Id: 192050 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7300:2553:b0:103:945f:af90 with SMTP id p19csp1596707dyi; Thu, 25 Jan 2024 04:19:26 -0800 (PST) X-Google-Smtp-Source: AGHT+IGgYoCno+jZUwYRUxpfb9+cp1C3pghSrTc4FGm5jdPoopaDG6EdNXoK2I+hB5+arTm3+IGO X-Received: by 2002:ac8:5a11:0:b0:42a:168d:d3b0 with SMTP id n17-20020ac85a11000000b0042a168dd3b0mr1350422qta.32.1706185165818; Thu, 25 Jan 2024 04:19:25 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1706185165; cv=pass; d=google.com; s=arc-20160816; b=PKVVVEU/FYc32JLrZ/6Ug/b+AkqWL+A7UXPG1fmw1z/y5Cst72OxFmTQPaGVTrYKB7 YMMfPxOz4J05C83Et/pO4e+Agi0uLMiW5WWDXd1+/OAAetIm6Kd6ll+C79W6Adk7tPbx IdRNyJW0jYB4eHN5C+cFtDSpewKovKCDMRsgALpxbzJrCwb4Xafz0YW0x7HxeFUG6gId Flk0ipmeywTWX5CzvHn96N2QMa0zh6wGScqMpUhTiqq1YEZ43lH9OrhrzLxiIJ/T3AA5 NvtI9DJsoi+m+PHdJDIe7z9p70RHZP5qLOidZYKoz7Ixy4yapKt/Y6wqaFMcVQ8zqCmm d/rg== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:message-id:date:subject:cc:to:from:dkim-signature :arc-filter:dmarc-filter:delivered-to; bh=IH7hZBhk6a1DRgrjx8sXUVU05eTUILCwKUIBcwOKCJc=; fh=uXf1mgDAefpqDEGJDL9umcdF3eby/Gqhcj5QI8MxE/0=; b=UVRmX/Zyf/U1VBfAS9Pet+z3Cqvy0XcwPIIeRlbTYYyMv/c29dTK1ArAMayapddHzw wqeMXGXb++m+UyoJrUiOfW4XOsB9p3gEnvHU+pQJ56rfFp49/5S/Hu4c+D4LvqXwNulk ZJZaqK4129vqyUyMsH9cWDO7TAst0smId5qwDwmWUFs2kyTGlHbvY9YLLtU7BulraYSd jhxseEqaagqh21Zp5vBGAfoYsyd9lFeapOx5GiNo7fvBzhSSQsFOUQaSsWW/cRIZVMxA 5RMAInj4SL96gL8/lUr8gahkE93y86d3tpPiK4q2dB87lUNYlJzUmPH2dF5w7tUGP2i1 GBBg== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=kaxY3EeD; arc=pass (i=1); spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: from server2.sourceware.org (server2.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id u11-20020a05622a14cb00b00429bcc54cf1si12263331qtx.531.2024.01.25.04.19.25 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jan 2024 04:19:25 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=kaxY3EeD; arc=pass (i=1); spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 836DF3858414 for ; Thu, 25 Jan 2024 12:19:25 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from eggs.gnu.org (eggs.gnu.org [IPv6:2001:470:142:3::10]) by sourceware.org (Postfix) with ESMTPS id 9805F3858C60 for ; Thu, 25 Jan 2024 12:18:38 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 9805F3858C60 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=linux.intel.com Authentication-Results: sourceware.org; spf=none smtp.mailfrom=linux.intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 9805F3858C60 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2001:470:142:3::10 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1706185121; cv=none; b=w0K8wyC7n57nriVIwZg2VyTe4RYdC4MCclL2VViNt9ZtuITJnJ2DFHQg4MXsl63+TWfYXymqvMrMa+yoUHdHftqK/KOyy46d1DlMS7gg4mZCJ/FbXvqoXvFTn43X4s01WUkmqrGbVuqMzJkugwN91KIyxddWAtJtRRZho/bLyYM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1706185121; c=relaxed/simple; bh=EP69xU9IA0EY1MpWI+zt6d4vLY89NYJCCaP8mYNXtBU=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=xfHWkut5xfoBTUE6ljui5slB1V82HZJug9eYx+QNxjqnCKgDCQ1eOENjAFu6ed0D7whkNl2ttPI+jHkXMMXMUR0dkSOZ9klurDlitXJJzy7z+1fj87fxjawbBOq8rLUjKlFgmyR2WJUsGQnKfr/n2IYXVmPmWd5amgZb3nmIlXM= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from mgamail.intel.com ([198.175.65.13]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rSygl-0004sj-6U for gcc-patches@gnu.org; Thu, 25 Jan 2024 07:18:38 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706185116; x=1737721116; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=EP69xU9IA0EY1MpWI+zt6d4vLY89NYJCCaP8mYNXtBU=; b=kaxY3EeDcLi588BFMPP6ki1jOUVlJIxtNyRp+NBUKmY4zCRAuvPw2KF9 Xd2rpnH+KxMBldQWBwguj5SVsNC8mUaZmlOGcuVEbDBPDeJF5xd+UgKB3 KCBPUEcCrpV3hHJZMtKdVfLLXypJN8VF3dYM/mzkry4kABSykKt4Eq9ZQ 2NXN8O0B5I0j7Nqp55CGVnTblEdwN7/j2S9a6bda2rMQ5IIrRRK0+QbDf Q89u8fvIIYZSJYk37uB3BoO9uCt8ZoS2EQLq+IDqBv4yEjLwO5DRhdGnu Jv0QoY9u94tswYsBj2yeRsz7oJhyi7rQfRa3Bid0hPXKC1567J6SRgR7X Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10962"; a="9256245" X-IronPort-AV: E=Sophos;i="6.05,216,1701158400"; d="scan'208";a="9256245" Received: from orviesa002.jf.intel.com ([10.64.159.142]) by orvoesa105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 Jan 2024 04:18:32 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.05,216,1701158400"; d="scan'208";a="28464944" Received: from tassilo.jf.intel.com ([10.54.38.190]) by orviesa002-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 Jan 2024 04:18:31 -0800 From: Andi Kleen To: gcc-patches@gnu.org Cc: Andi Kleen Subject: [PATCH v1] C++: Support constexpr strings for asm statements Date: Thu, 25 Jan 2024 04:18:19 -0800 Message-ID: <20240125121819.2759991-1-ak@linux.intel.com> X-Mailer: git-send-email 2.43.0 MIME-Version: 1.0 Received-SPF: none client-ip=198.175.65.13; envelope-from=ak@linux.intel.com; helo=mgamail.intel.com X-Spam_score_int: -34 X-Spam_score: -3.5 X-Spam_bar: --- X-Spam_report: (-3.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.5, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_NONE=0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-Spam-Status: No, score=-12.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_EF, GIT_PATCH_0, SPF_HELO_PASS, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1789064815923753197 X-GMAIL-MSGID: 1789064815923753197 Some programing styles use a lot of inline assembler, and it is common to use very complex preprocessor macros to generate the assembler strings for the asm statements. In C++ there would be a typesafe alternative using templates and constexpr to generate the assembler strings, but unfortunately the asm statement requires plain string literals, so this doesn't work. This patch modifies the C++ parser to accept strings generated by constexpr instead of just plain strings. This requires new syntax because e.g. asm("..." : "r" (expr)) would be ambigious with a function call. I chose () to make it unique. For example now you can write constexpr const char *genasm() { return "insn"; } constexpr const char *genconstraint() { return "r"; } asm(genasm() :: (genconstraint()) (input)); The constexpr strings are allowed for the asm template, the constraints and the clobbers (every time current asm accepts a string) The drawback of this scheme is that the constexpr doesn't have full control over the input/output/clobber lists, but that can be usually handled with a switch statement. One could imagine more flexible ways to handle that, for example supporting constexpr vectors for the clobber list, or similar. But even without that it is already useful. Bootstrapped and full test on x86_64-linux. --- gcc/cp/parser.cc | 76 ++++++++++++++++++-------- gcc/doc/extend.texi | 17 +++++- gcc/testsuite/g++.dg/constexpr-asm-1.C | 30 ++++++++++ 3 files changed, 99 insertions(+), 24 deletions(-) create mode 100644 gcc/testsuite/g++.dg/constexpr-asm-1.C diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 3748ccd49ff3..cc323dc8557a 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -22654,6 +22654,43 @@ cp_parser_using_directive (cp_parser* parser) cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); } +/* Parse a string literal or constant expression yielding a string. + The constant expression uses extra parens to avoid ambiguity with "x" (expr). + + asm-string-expr: + string-literal + ( constant-expr ) */ + +static tree +cp_parser_asm_string_expression (cp_parser *parser) +{ + location_t sloc = cp_lexer_peek_token (parser->lexer)->location; + + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + { + matching_parens parens; + parens.consume_open (parser); + tree string = cp_parser_constant_expression (parser); + if (string != error_mark_node) + string = cxx_constant_value (string, tf_error); + if (TREE_CODE (string) == NOP_EXPR) + string = TREE_OPERAND (string, 0); + if (TREE_CODE (string) == ADDR_EXPR && TREE_CODE (TREE_OPERAND (string, 0)) == STRING_CST) + string = TREE_OPERAND (string, 0); + if (TREE_CODE (string) == VIEW_CONVERT_EXPR) + string = TREE_OPERAND (string, 0); + if (TREE_CODE (string) != STRING_CST && string != error_mark_node) + { + error_at (sloc, "Expected string valued constant expression for %, not type %qT", + TREE_TYPE (string)); + string = error_mark_node; + } + parens.require_close (parser); + return string; + } + return cp_parser_string_literal (parser, false, false); +} + /* Parse an asm-definition. asm-qualifier: @@ -22666,19 +22703,19 @@ cp_parser_using_directive (cp_parser* parser) asm-qualifier-list asm-qualifier asm-definition: - asm ( string-literal ) ; + asm ( constant-expr ) ; GNU Extension: asm-definition: - asm asm-qualifier-list [opt] ( string-literal ) ; - asm asm-qualifier-list [opt] ( string-literal : asm-operand-list [opt] ) ; - asm asm-qualifier-list [opt] ( string-literal : asm-operand-list [opt] + asm asm-qualifier-list [opt] ( asm-string-expr ) ; + asm asm-qualifier-list [opt] ( asm-string-expr : asm-operand-list [opt] ) ; + asm asm-qualifier-list [opt] ( asm-string-expr : asm-operand-list [opt] : asm-operand-list [opt] ) ; - asm asm-qualifier-list [opt] ( string-literal : asm-operand-list [opt] + asm asm-qualifier-list [opt] ( asm-string-expr : asm-operand-list [opt] : asm-operand-list [opt] : asm-clobber-list [opt] ) ; - asm asm-qualifier-list [opt] ( string-literal : : asm-operand-list [opt] + asm asm-qualifier-list [opt] ( asm-string-expr : : asm-operand-list [opt] : asm-clobber-list [opt] : asm-goto-list ) ; @@ -22797,8 +22834,7 @@ cp_parser_asm_definition (cp_parser* parser) if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) return; /* Look for the string. */ - tree string = cp_parser_string_literal (parser, /*translate=*/false, - /*wide_ok=*/false); + tree string = cp_parser_asm_string_expression (parser); if (string == error_mark_node) { cp_parser_skip_to_closing_parenthesis (parser, true, false, @@ -29352,7 +29388,7 @@ cp_parser_yield_expression (cp_parser* parser) /* Parse an (optional) asm-specification. asm-specification: - asm ( string-literal ) + asm ( asm-string-expr ) If the asm-specification is present, returns a STRING_CST corresponding to the string-literal. Otherwise, returns @@ -29375,9 +29411,7 @@ cp_parser_asm_specification_opt (cp_parser* parser) parens.require_open (parser); /* Look for the string-literal. */ - tree asm_specification = cp_parser_string_literal (parser, - /*translate=*/false, - /*wide_ok=*/false); + tree asm_specification = cp_parser_asm_string_expression (parser); /* Look for the `)'. */ parens.require_close (parser); @@ -29392,8 +29426,8 @@ cp_parser_asm_specification_opt (cp_parser* parser) asm-operand-list , asm-operand asm-operand: - string-literal ( expression ) - [ string-literal ] string-literal ( expression ) + asm-string-expr ( expression ) + [ asm-string-expr ] asm-string-expr ( expression ) Returns a TREE_LIST representing the operands. The TREE_VALUE of each node is the expression. The TREE_PURPOSE is itself a @@ -29426,10 +29460,8 @@ cp_parser_asm_operand_list (cp_parser* parser) } else name = NULL_TREE; - /* Look for the string-literal. */ - tree string_literal = cp_parser_string_literal (parser, - /*translate=*/false, - /*wide_ok=*/false); + /* Look for the string. */ + tree string_literal = cp_parser_asm_string_expression (parser); /* Look for the `('. */ matching_parens parens; @@ -29462,8 +29494,8 @@ cp_parser_asm_operand_list (cp_parser* parser) /* Parse an asm-clobber-list. asm-clobber-list: - string-literal - asm-clobber-list , string-literal + const-expression + asm-clobber-list , const-expression Returns a TREE_LIST, indicating the clobbers in the order that they appeared. The TREE_VALUE of each node is a STRING_CST. */ @@ -29476,9 +29508,7 @@ cp_parser_asm_clobber_list (cp_parser* parser) while (true) { /* Look for the string literal. */ - tree string_literal = cp_parser_string_literal (parser, - /*translate=*/false, - /*wide_ok=*/false); + tree string_literal = cp_parser_asm_string_expression (parser); /* Add it to the list. */ clobbers = tree_cons (NULL_TREE, string_literal, clobbers); /* If the next token is not a `,', then the list is diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 0bc586d120e7..230b46fc6c75 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -10589,6 +10589,17 @@ contain any instructions recognized by the assembler, including directives. GCC does not parse the assembler instructions themselves and does not know what they mean or even whether they are valid assembler input. +With gnu++11 or later it can also be a compile time constant expression inside parens. + +@example +constexpr const char *genfoo() @{ return "foo"; @} + +void function() +@{ + asm((genfoo())); +@} +@end example + You may place multiple assembler instructions together in a single @code{asm} string, separated by the characters normally used in assembly code for the system. A combination that works in most places is a newline to break the @@ -10739,20 +10750,24 @@ perform a jump to one of the labels listed in the @var{GotoLabels}. @item AssemblerTemplate This is a literal string that is the template for the assembler code. It is a combination of fixed text and tokens that refer to the input, output, -and goto parameters. @xref{AssemblerTemplate}. +and goto parameters. @xref{AssemblerTemplate}. With gnu++11 or later it can +also be a constant expression inside parens. @item OutputOperands A comma-separated list of the C variables modified by the instructions in the @var{AssemblerTemplate}. An empty list is permitted. @xref{OutputOperands}. +With gnu++11 or later the strings can also be constant expressions inside parens. @item InputOperands A comma-separated list of C expressions read by the instructions in the @var{AssemblerTemplate}. An empty list is permitted. @xref{InputOperands}. +With gnu++11 or later the strings can also be constant expressions inside parens. @item Clobbers A comma-separated list of registers or other values changed by the @var{AssemblerTemplate}, beyond those listed as outputs. An empty list is permitted. @xref{Clobbers and Scratch Registers}. +With gnu++11 or later the strings can also be constant expressions inside parens. @item GotoLabels When you are using the @code{goto} form of @code{asm}, this section contains diff --git a/gcc/testsuite/g++.dg/constexpr-asm-1.C b/gcc/testsuite/g++.dg/constexpr-asm-1.C new file mode 100644 index 000000000000..b1305571a2c1 --- /dev/null +++ b/gcc/testsuite/g++.dg/constexpr-asm-1.C @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-std=gnu++11" } */ + +constexpr const char *genfoo() +{ + return "foo %1,%0"; +} + +constexpr const char *genoutput() +{ + return "=r"; +} + +constexpr const char *geninput() +{ + return "r"; +} + +constexpr const char *genclobber() +{ + return "memory"; +} + +void f() +{ + int a; + asm((genfoo()) : (genoutput()) (a) : (geninput()) (1) : (genclobber())); +} + +/* { dg-final { scan-assembler "foo" } } */