From patchwork Tue May 5 22:30:44 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: feedable X-Patchwork-Id: 134515 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 2A5AB4BA23EB for ; Tue, 5 May 2026 22:32:02 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2A5AB4BA23EB Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20251104 header.b=WMnSKdT5 X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wm1-x336.google.com (mail-wm1-x336.google.com [IPv6:2a00:1450:4864:20::336]) by sourceware.org (Postfix) with ESMTPS id 854E94BA2E09 for ; Tue, 5 May 2026 22:31:10 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 854E94BA2E09 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 854E94BA2E09 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2a00:1450:4864:20::336 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778020270; cv=none; b=i6NulD0XnRL1eh90sMEzfmxKkXVhIcze9mCxbyEGxRf/1MwFfEWlRt8dJX8ycJ6mfueuG2vsnSw62Hh0mD8nYPr7MpdFroXYFEnpxzsF6sLn56qdJscUC8PHalVdqbA1ha4rhwzy2u82DBNPS1XQxy/9OG4vhT4rv+gxXz4j7OA= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778020270; c=relaxed/simple; bh=dMOEK9ROcgynPbQCaE7jhepBKPQz9OBPWOVD1U6l+5g=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Beb7xDFKcFkgiz1148Kfi1BiMo5YP03o5Le8qlL+473Q8Td083dxO5wfMFdHAaB6zqEqT4/y9hJntgkqzZ5T8SdTC/8/1bzue4lkeCusdGj0nf9nDkX+vgBCMHsmEhuCn3m6cQVfxb7Cl3HkKQqLQSAH7e48YYKDl6tP9s7P3zo= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 854E94BA2E09 Received: by mail-wm1-x336.google.com with SMTP id 5b1f17b1804b1-48374014a77so68144855e9.3 for ; Tue, 05 May 2026 15:31:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778020269; x=1778625069; darn=gcc.gnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=NzBurjs+9H7fUsUrdIRVFxshmTp4DLlFth46UEx6zK0=; b=WMnSKdT5NDfvD+i4uA8rOlrCvQHmH1cO/CCTLFlUTaUja4t8PswLcMT6asMZx9Jdbz lZtzFbVOoaDxkdcd5AtaOBTCD0OthVAtebQLyuVNrFjo/0LIflaSumyyDkTllP0jrcsW Fl0ckgr75h/7rYeuyg4PWDAixirLCLz9KmxnNHHOKQTgkRwPKkT3qQEersGHI8sQR7Qt kG7nUbhuqsQaOolZBZX4ouzbJP71UKz89YTR+ZJFkA4qSKj7InsoK+sr4y0AL66jN5XU xnEOdg56uJyFIsip5F+doYy/iu/aaRqNFWcmumqv992xdpRd6GLLFZm85ojuUciuxito c1bg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778020269; x=1778625069; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=NzBurjs+9H7fUsUrdIRVFxshmTp4DLlFth46UEx6zK0=; b=cDVsSwla4hJTm4Mdmlit5KPAXjQswxwSbrUYsHqgXZXC/7tyNP3Fet9Uj0dp32fJXk dJ9fqI79pkHS1uszX3ZcENUJjeoYyucMhaSQ8yTr1kyAJhRQxFknsSg0scYtklpCQvEV 3BxPf0j5lYwBAxpzk/awYBADR9jc4cAVP+uvu+AzQs0xNDAn4lzqOBnM8Bsi3eh+I6rz 0fsyU57NgoxlFUvVRFevjldu4CmNYLFrwIT5LL9bqK2DX1oQNEjCtdf2ovSfvNkjksJW cU1p53nUZBR8n3g9pLxB2Fk9bVhF/fhsEYHnqsR43fueN0UPCBxBH6agxopFqbqL71gn YCjA== X-Gm-Message-State: AOJu0YxTP+bvlevSTwXBpth9HyxDJ6LfTaq0OWrqOiZ82DWqKNV6BFb+ kO9Ijdkdfgo7uEaqXF54xnnDcdn4fWqFDFauFzw3rIRmjZJaz6ygD8TPBRjGNw== X-Gm-Gg: AeBDieufJbx/29jLRGKt5+f3Wa/ZMURoTd50HWQcjNW2UxOIHKGqxaoxMb9xBbIo0V7 XrWG+BXxicdkRxot4foTz/b+gKZmUWeRyD7YSMKOMD02nkq3tmVMmw6uraDmCyrT6Hx66CruR86 3ZTO0HK1V/q7FzVAw0gU/kh0eB6PBhYcXZYqS7De+0rOD0dVmF7XFiBdGqIlgoQcpxpNyrjsjE7 w1BwtAXMhnPqORjq0R+YWW8tJwIGL+sahyeQaXbHG1VTKdjsx8GWbXc366Ifr9Xsxl1INolU7jk 6RlZH/W7owaEdJmKNmA2BQXwV5GFh7Th3lMeZU6dn5mkitF1Q+eF/D0DnavsuNFdyDhOLrWwDjL /CqbLYM84Q6FTMxKH6AfzoXfYjd36ZDTkygnetnCSA3S7KsuvL+e6GZMh4LL/5T51ImypN0kxb3 mVKzDKTFkAR8vKgofFN7gIs2qKMgAcmON9r0cHTq79Zs6mkq3l X-Received: by 2002:a05:600c:3548:b0:489:1c1f:35f1 with SMTP id 5b1f17b1804b1-48e51e09706mr16778185e9.4.1778020269308; Tue, 05 May 2026 15:31:09 -0700 (PDT) Received: from 7a38.moduleworks.com ([2a02:8308:900b:fc00:1c70:a43b:cde8:2b29]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-48e53559d8esm79055e9.9.2026.05.05.15.31.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 May 2026 15:31:08 -0700 (PDT) From: feedable To: gcc-patches@gcc.gnu.org Cc: feedable Subject: [RFC PATCH 1/3] df: Add support for pseudos in function arguments Date: Wed, 6 May 2026 01:30:44 +0300 Message-ID: <20260505223045.347444-3-feedabl3@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505223045.347444-2-feedabl3@gmail.com> References: <20260505223045.347444-2-feedabl3@gmail.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_ENVFROM_END_DIGIT, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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~patchwork=sourceware.org@gcc.gnu.org Targets with vitual registers would like to use virtual registers as arguments same way usual targets use hard registers. This patch relaxes assertions that prevent that from happening. It also introduces a new hook, TARGET_MARK_ARG_REGNOS, which is supposed to tell df which pseudos are args. gcc/ChangeLog: * df-problems.cc (df_word_lr_bb_local_compute): Patch assert to accept pseudo registers as args. * expr.cc (use_regs): Likewise. * df-scan.cc (df_get_entry_block_def_set): Inboke the hook to mark arg pseudos. * target.def: Introduce a hook to mark vreg args. * doc/tm.texi.in: Document the new hook. * doc/tm.texi: Likewise. --- gcc/df-problems.cc | 6 ++++-- gcc/df-scan.cc | 4 ++++ gcc/doc/tm.texi | 5 +++++ gcc/doc/tm.texi.in | 2 ++ gcc/expr.cc | 3 ++- gcc/target.def | 7 +++++++ 6 files changed, 24 insertions(+), 3 deletions(-) diff --git a/gcc/df-problems.cc b/gcc/df-problems.cc index 710f3c12032..70b44c546d4 100644 --- a/gcc/df-problems.cc +++ b/gcc/df-problems.cc @@ -2954,9 +2954,11 @@ df_word_lr_bb_local_compute (unsigned int bb_index) rtx_insn *insn; df_ref def, use; - /* Ensure that artificial refs don't contain references to pseudos. */ + /* Ensure that artificial refs don't contain references to pseudos. + Do allow pseudos as args, though. */ FOR_EACH_ARTIFICIAL_DEF (def, bb_index) - gcc_assert (DF_REF_REGNO (def) < FIRST_PSEUDO_REGISTER); + gcc_assert (DF_REF_REGNO (def) < FIRST_PSEUDO_REGISTER + || bitmap_bit_p (df->entry_block_defs, DF_REF_REGNO (def))); FOR_EACH_ARTIFICIAL_USE (use, bb_index) gcc_assert (DF_REF_REGNO (use) < FIRST_PSEUDO_REGISTER); diff --git a/gcc/df-scan.cc b/gcc/df-scan.cc index c6a5053ddbb..5cc8f2e1a46 100644 --- a/gcc/df-scan.cc +++ b/gcc/df-scan.cc @@ -3500,6 +3500,10 @@ df_get_entry_block_def_set (bitmap entry_block_defs) bitmap_set_bit (entry_block_defs, INCOMING_REGNO (i)); } + /* Whatever the target considers to be an argument */ + if (targetm.calls.mark_arg_regnos) + targetm.calls.mark_arg_regnos (entry_block_defs); + /* The always important stack pointer. */ bitmap_set_bit (entry_block_defs, STACK_POINTER_REGNUM); diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 2832a447e3e..692794087dd 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -4507,6 +4507,11 @@ return a different value if an argument size must be rounded to a larger value. @end deftypefn +@deftypefn {Target Hook} void TARGET_MARK_ARG_REGNOS (bitmap @var{regs}) +Useful for TARGET_NO_REGISTER_ALLOCATION targets, define this to mark all + the pseudos that hold the current function arguments. +@end deftypefn + @defmac FUNCTION_ARG_REGNO_P (@var{regno}) A C expression that is nonzero if @var{regno} is the number of a hard register in which function arguments are sometimes passed. This does diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 274bb899d0c..afdd9f2bf8d 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -3465,6 +3465,8 @@ required. @hook TARGET_FUNCTION_ARG_ROUND_BOUNDARY +@hook TARGET_MARK_ARG_REGNOS + @defmac FUNCTION_ARG_REGNO_P (@var{regno}) A C expression that is nonzero if @var{regno} is the number of a hard register in which function arguments are sometimes passed. This does diff --git a/gcc/expr.cc b/gcc/expr.cc index 7ca5dd84ce9..78a3f68440d 100644 --- a/gcc/expr.cc +++ b/gcc/expr.cc @@ -3789,7 +3789,8 @@ use_regs (rtx *call_fusage, int regno, int nregs) { int i; - gcc_assert (regno + nregs <= FIRST_PSEUDO_REGISTER); + gcc_assert (regno + nregs <= FIRST_PSEUDO_REGISTER + || targetm.no_register_allocation); for (i = 0; i < nregs; i++) use_reg (call_fusage, regno_reg_rtx[regno + i]); diff --git a/gcc/target.def b/gcc/target.def index 11b358f4160..71e45c6c3a2 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -5378,6 +5378,13 @@ value.", unsigned int, (machine_mode mode, const_tree type), default_function_arg_round_boundary) +DEFHOOK +(mark_arg_regnos, + "Useful for TARGET_NO_REGISTER_ALLOCATION targets, define this to mark all\n\ + the pseudos that hold the current function arguments.", + void, (bitmap regs), + NULL) + /* Return the diagnostic message string if function without a prototype is not allowed for this 'val' argument; NULL otherwise. */ DEFHOOK From patchwork Tue May 5 22:30:45 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: feedable X-Patchwork-Id: 134516 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id AF6C04BA9008 for ; Tue, 5 May 2026 22:32:23 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org AF6C04BA9008 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20251104 header.b=XrH6drT/ X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wm1-x332.google.com (mail-wm1-x332.google.com [IPv6:2a00:1450:4864:20::332]) by sourceware.org (Postfix) with ESMTPS id B188E4BA2E0B for ; Tue, 5 May 2026 22:31:14 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org B188E4BA2E0B Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org B188E4BA2E0B Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2a00:1450:4864:20::332 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778020275; cv=none; b=UxmKUQXOS3YXPgnF0nBjUKKd7AfqKyPPCxWhc4oVXort3ibbynHlMjnzvdjTZ4OmOnHnOYHN4XkMLh1Hk9uxUeA09ZObAVoYtFz0rYNpkHpOpIgq9pI4ij/k/K6twvrtnT1ziZDEnoN4IG0vpCk/468UF+p+IdoMVNMk5DG3Cw8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778020275; c=relaxed/simple; bh=JgKXPP4fU332g85dnBKu4CxtRI+MHCrBa71GVxKv0Lo=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=wJM6aotmCfjyBLkBcgynzM/GHM8GrZQbi1cMHDYue/8s8fKU2M7TpresSrQLSDMPZbCKh2XlFAnB0wzDGFUu1RcEBIzSnmuiX72g1xsSApArVxRToOsVRcd6/foOOgzro1ZdXBk4iNk7cbd37KgCRoiGFJCMcnQKG5cEQQf8pEM= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B188E4BA2E0B Received: by mail-wm1-x332.google.com with SMTP id 5b1f17b1804b1-48374014a77so68145385e9.3 for ; Tue, 05 May 2026 15:31:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778020274; x=1778625074; darn=gcc.gnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=W3QSTVW1UGuUKD3F7Lu9UQBQNB46kPkQR2OrFYI4TMM=; b=XrH6drT/z4FdA8871XNdhz4AhnxkyQx5Qqp5Irt/sjMrrSAu0/6OJnZWANM8vT+vIb hYJ+b+Lfg6jacMRsQumLY3PCNlW3HfwIRShTgOEsOkb6KZik/kgHZick02sJvk5SxTPt nQxoCEkKfJst/z57kGMhNdnb472n2KNeHtb5QH7TH5P5zLrsTJiOvlfzDXzn/eHI8ssy NXoaXmFh/e+IWBhjwYiGn/JJFvvx+r6efr/YVwmnDXH/UpkR496uf7a9CKJnwv77T+Fk cX32Aeq8wZ+S3ZzhzWwcpOA1gsgngPT8YNEE60VJA9SK6WlocCesUxIYDX4xmsVOJq3p Un3g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778020274; x=1778625074; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=W3QSTVW1UGuUKD3F7Lu9UQBQNB46kPkQR2OrFYI4TMM=; b=YBhGwhVqOdeawiQ5LobATkde1Pxi16/PfWpzxeQQet6rg6DxcQKn3f1PkAcAeqBH1s 7pWDsBVcHiG4dtKFDViK/7Z19PWn2Tbq0q/YQkKkaw2kXcMRVXOIQuZCiYbYXwym1t9c 1yXNXFfuB/EJamdjQelhCH6ULPaHgUikqUCFGkOYTeGPZhkWKLIu/6Kv+00jKqyCccP+ 5wBY5V6N5CbB8tL4MQ4i5+Z7Dg28VNS/II2GzmFzhSoGyzfVVkRxDWcnhMwaHcQlVRA2 LWFzHsqpSOWU0nT5tQ/JFQDf+LV+17lt2hpLLfH/9DInsWlgmhax1rgkwKxzJ3mRT8LM dvIA== X-Gm-Message-State: AOJu0YzPG1VhJdil/M/O8ZX+IqfP3rZxZk1GXQYmyAjR9WhI4TixMx0d Sl0v6Q+6HUHURDPT7QsVdbVvsDzNXJn/X1SnEIQ2Pm6L5YpyWtiKzjF0B2xqZA== X-Gm-Gg: AeBDiesq7wZ2i3F9+HUwoHvMaw+MVZg2X5zdDavdEST3SCAH3sdu4pI+3ACoziHDZON viM+P3StXalBrEwmqYjbowBw0AG6rtSiNZTRtMemR0nSHonfA7SuyKV2Gtm4arXQCAumV8UkJRg iECrTwjy+Tg5QIJo+p9diJns2gMDFRyyfjznQUQG90HRmGxlcGvzMIBOfZms1b1GDEZVAaHg9nu GoTO9hdM4/MMh6tDnHS0xi/g4ADpvbCSKWwZb9U3/CjT38FZzI+z9HjkFnR01ZeVXnSaLaKhrtO fcWFru+jleS4n9o/dn1u9x0Pchxz39y+yTZG6rDrWIBY7SPbpC7uyYvBEzsIrpuFIHtSVmHpgs4 PMTmjuRsTFXOEf6Qq4v4dlhEN0xZbLOj9LHdupRh5PlwxIAVlyAYQtPIbHCZZkZxcdPcjobVFEr 9Beqf6Wf9I5HJhvywgWKZXlzbwwBuyU8aMvtNgzGbTIYQt5hd3/QgMW7iyPxk= X-Received: by 2002:a05:600c:3b17:b0:48a:568f:ae6d with SMTP id 5b1f17b1804b1-48e51e15c37mr15996545e9.8.1778020273153; Tue, 05 May 2026 15:31:13 -0700 (PDT) Received: from 7a38.moduleworks.com ([2a02:8308:900b:fc00:1c70:a43b:cde8:2b29]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-48e53559d8esm79055e9.9.2026.05.05.15.31.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 May 2026 15:31:12 -0700 (PDT) From: feedable To: gcc-patches@gcc.gnu.org Cc: feedable Subject: [RFC PATCH 2/3] wasm: New backend Date: Wed, 6 May 2026 01:30:45 +0300 Message-ID: <20260505223045.347444-4-feedabl3@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505223045.347444-2-feedabl3@gmail.com> References: <20260505223045.347444-2-feedabl3@gmail.com> MIME-Version: 1.0 X-Spam-Status: No, score=-9.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_ENVFROM_END_DIGIT, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, KAM_STOCKGEN, POISEN_SPAM_PILL, POISEN_SPAM_PILL_2, POISEN_SPAM_PILL_4, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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~patchwork=sourceware.org@gcc.gnu.org I don't really know what kind of a description is expected for a new backend implementation, so I'm leaving this empty for now as a placeholder. -- 8< -- gcc/ChangeLog: * config.gcc: Adjust for new backend. * config/wasm/attrs.md: New file. * config/wasm/t-wasm: New file. * config/wasm/wasm-asm.cc: New file. * config/wasm/wasm-cg.cc: New file. * config/wasm/wasm-modes.def: New file. * config/wasm/wasm-passes.cc: New file. * config/wasm/wasm-passes.def: New file. * config/wasm/wasm-protos.h: New file. * config/wasm/wasm.cc: New file. * config/wasm/wasm.h: New file. * config/wasm/wasm.md: New file. libgcc/ChangeLog: * config.host: Adjust for new backend. * config/wasm/t-wasm: New file. --- gcc/config.gcc | 7 + gcc/config/wasm/attrs.md | 84 +++ gcc/config/wasm/t-wasm | 13 + gcc/config/wasm/wasm-asm.cc | 945 ++++++++++++++++++++++++++++++++ gcc/config/wasm/wasm-cg.cc | 621 +++++++++++++++++++++ gcc/config/wasm/wasm-modes.def | 0 gcc/config/wasm/wasm-passes.cc | 153 ++++++ gcc/config/wasm/wasm-passes.def | 27 + gcc/config/wasm/wasm-protos.h | 12 + gcc/config/wasm/wasm.cc | 128 +++++ gcc/config/wasm/wasm.h | 307 +++++++++++ gcc/config/wasm/wasm.md | 495 +++++++++++++++++ libgcc/config.host | 5 + libgcc/config/wasm/t-wasm | 4 + 14 files changed, 2801 insertions(+) create mode 100644 gcc/config/wasm/attrs.md create mode 100644 gcc/config/wasm/t-wasm create mode 100644 gcc/config/wasm/wasm-asm.cc create mode 100644 gcc/config/wasm/wasm-cg.cc create mode 100644 gcc/config/wasm/wasm-modes.def create mode 100644 gcc/config/wasm/wasm-passes.cc create mode 100644 gcc/config/wasm/wasm-passes.def create mode 100644 gcc/config/wasm/wasm-protos.h create mode 100644 gcc/config/wasm/wasm.cc create mode 100644 gcc/config/wasm/wasm.h create mode 100644 gcc/config/wasm/wasm.md create mode 100644 libgcc/config/wasm/t-wasm diff --git a/gcc/config.gcc b/gcc/config.gcc index d1595a1d85e..822515c127e 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -614,6 +614,10 @@ tic6x-*-*) extra_headers="c6x_intrinsics.h" extra_options="${extra_options} c6x/c6x-tables.opt" ;; +wasm*-*-*) + cpu_type=wasm + extra_objs="wasm-cg.o wasm-asm.o wasm-passes.o" + ;; xtensa*-*-*) extra_options="${extra_options} fused-madd.opt" extra_objs="xtensa-dynconfig.o" @@ -3677,6 +3681,9 @@ visium-*-elf*) tm_file="elfos.h ${tm_file} visium/elf.h newlib-stdint.h" tmake_file="visium/t-visium visium/t-crtstuff" ;; +wasm*-*-*) + target_has_targetm_common=no + ;; xstormy16-*-elf) # For historical reasons, the target files omit the 'x'. tm_file="elfos.h newlib-stdint.h stormy16/stormy16.h" diff --git a/gcc/config/wasm/attrs.md b/gcc/config/wasm/attrs.md new file mode 100644 index 00000000000..6fbe39e5ce7 --- /dev/null +++ b/gcc/config/wasm/attrs.md @@ -0,0 +1,84 @@ +(define_c_enum "unspecv" [ + UNSPECV_CALL_ADDRESS_BARRIER +]) + +(define_mode_iterator QHSDI [QI HI SI DI]) +(define_mode_iterator QHSDI2 [QI HI SI DI]) +(define_mode_iterator QHSDISDF [QI HI SI DI SF DF]) +(define_mode_iterator F [SF DF]) +(define_mode_iterator REG [SI DI]) +(define_mode_iterator REGF [SI DI SF DF]) +(define_mode_attr REG2F [(SI "SF") (DI "DF") (SF "SI") (DF "DI")]) +(define_mode_attr reg2f [(SI "sf") (DI "df") (SF "si") (DF "di")]) +(define_mode_attr reg2f_types [ + (SF "i32") (DF "i64") + (SI "f32") (DI "f64")]) +(define_mode_attr types [ + (QI "i8") (HI "i16") + (SI "i32") (DI "i64") + (SF "f32") (DF "f64")]) +(define_mode_attr size [ + (QI "8") (HI "16") + (SI "32") (DI "64") + (SF "32") (DF "64")]) +(define_mode_attr promote_type [ + (QI "i32") (HI "i32") + (SI "i32") (DI "i64") + (SF "f32") (DF "f32")]) +(define_mode_attr promote_mode [ + (QI "SI") (HI "SI") + (SI "SI") (DI "DI") + (SF "SF") (DF "DF")]) +(define_mode_iterator SUBREGSI [QI HI]) +(define_mode_iterator SUBREGDI [QI HI SI]) +(define_mode_iterator P [(SI "Pmode == SImode") (DI "Pmode == DImode")]) + +(define_code_iterator irelop [le ge lt gt leu geu ltu gtu eq ne]) +(define_code_iterator frelop [le ge lt gt eq ne]) + +(define_code_iterator iunop [clz ctz popcount]) + +(define_code_iterator iconvop [sign_extend truncate]) + +(define_code_iterator ibinop [ + and ior xor + plus minus mult + div udiv mod umod + ashift ashiftrt lshiftrt + rotate rotatert]) + +(define_code_iterator fbinop [plus minus mult div smin smax copysign]) + +(define_code_iterator funop [abs neg sqrt]) + +(define_code_attr opname [ + (eq "eq") (ne "ne") + (le "le_s") (ge "ge_s") (lt "lt_s") (gt "gt_s") + (leu "le_u") (geu "ge_u") (ltu "lt_u") (gtu "gt_u") + (clz "clz") (ctz "ctz") (popcount "popcnt") + (and "and") (ior "or") (xor "xor") + (plus "add") (minus "sub") (mult "mul") + (div "div_s") (udiv "div_u") (mod "rem_s") (umod "rem_u") + (ashift "shl") (ashiftrt "shr_s") (lshiftrt "shr_u") + (rotate "rotl") (rotatert "rotr") + (sign_extend "extend") (zero_extend "zero_extend") + (truncate "trunc") + (abs "abs") (neg "neg") (sqrt "sqrt")]) +(define_code_attr opnamef [ + (eq "eq") (ne "ne") (le "le") (ge "ge") (lt "lt") (gt "gt") + (plus "add") (minus "sub") (mult "mul") (div "div") (smin "min") (smax "max") + (abs "abs") (neg "neg") (sqrt "sqrt") (copysign "copysign")]) +(define_code_attr opname_rt [ + (eq "eq") (ne "ne") + (le "le") (ge "ge") (lt "lt") (gt "gt") + (leu "leu") (geu "geu") (ltu "ltu") (gtu "gtu") + (clz "clz") (ctz "ctz") (popcount "popcount") + (and "and") (ior "ior") (xor "xor") + (plus "add") (minus "sub") (mult "mul") + (div "div") (udiv "udiv") (mod "mod") (umod "umod") + (ashift "ashl") (ashiftrt "ashr") (lshiftrt "lshr") + (rotate "rotl") (rotatert "rotr") + (sign_extend "extend") (zero_extend "zero_extend") + (truncate "ftrunc") + (smax "smax") (smin "smin") (copysign "copysign") + (abs "abs") (neg "neg") (sqrt "sqrt")]) diff --git a/gcc/config/wasm/t-wasm b/gcc/config/wasm/t-wasm new file mode 100644 index 00000000000..6d5846a8822 --- /dev/null +++ b/gcc/config/wasm/t-wasm @@ -0,0 +1,13 @@ +wasm-cg.o: $(srcdir)/config/wasm/wasm-cg.cc \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(INPUT_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< + +wasm-asm.o: $(srcdir)/config/wasm/wasm-asm.cc \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(INPUT_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< + +wasm-passes.o: $(srcdir)/config/wasm/wasm-passes.cc \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(INPUT_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< + +PASSES_EXTRA += $(srcdir)/config/wasm/wasm-passes.def \ No newline at end of file diff --git a/gcc/config/wasm/wasm-asm.cc b/gcc/config/wasm/wasm-asm.cc new file mode 100644 index 00000000000..17306a82851 --- /dev/null +++ b/gcc/config/wasm/wasm-asm.cc @@ -0,0 +1,945 @@ +/* WebAssembly assembly output utilities. + Copyright (C) 2025-2025 Free Software Foundation, Inc. + Contributed by feedable. + + 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 + . */ + +#define IN_TARGET_CODE 1 + +#include +#include + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "target.h" +#include "rtl.h" +#include "tree.h" +#include "regs.h" +#include "stringpool.h" +#include "attribs.h" +#include "gimple.h" +#include "df.h" +#include "memmodel.h" +#include "tm_p.h" +#include "stringpool.h" +#include "optabs.h" +#include "emit-rtl.h" +#include "recog.h" +#include "diagnostic-core.h" +#include "output.h" +#include "fold-const.h" +#include "stor-layout.h" +#include "varasm.h" +#include "calls.h" +#include "explow.h" +#include "expr.h" +#include "langhooks.h" +#include "cfgrtl.h" +#include "gimplify.h" +#include "reload.h" +#include "builtins.h" +#include "tree-pass.h" + +void wasm_print_operand (FILE *stream, rtx value, int mode); + +extern hash_map external_libcalls; + +namespace +{ + +int indent; +void output_indent(FILE *stream) +{ + fprintf (stream, "%*s", indent * 2, ""); +} +void output_indent() +{ + output_indent (asm_out_file); +} + +char *fake_out_file_data; +size_t fake_out_file_length; +FILE *saved_asm_out_file; + +hash_map> import_map; +hash_set external_libcall_set; + +bool +global_p (rtx reg) +{ + if (GET_CODE (reg) == SUBREG) + reg = SUBREG_REG (reg); + gcc_assert (GET_CODE (reg) == REG); + return REGNO (reg) == STACK_POINTER_REGNUM; +} + +bool +is_escape (char x) +{ + const char *escapes = "\"\'\\\t\n\r"; + while (*escapes and x != *escapes) + ++escapes; + return *escapes; +} + +void +assemble_string (FILE *stream, const char *string, int size, bool hex_only) +{ + fprintf (stream, " \""); + for (int i = 0; i != size; ++i) + { + char c[] = {'\\', string[i], '\0'}; + if (c[1] < 32 || c[1] > 127 || hex_only) + fprintf (stream, "\\%0.2hhx", c[1]); + else + fprintf (stream, "%s", c + !is_escape(c[1])); + } + fprintf (stream, "\""); +} + +void +assemble_zeroes (FILE *stream, unsigned HOST_WIDE_INT size) +{ + fputs (" \"", stream); + for (unsigned HOST_WIDE_INT i = 0; i != size; ++i) + fputs ("\\00", stream); + fputs ("\"", stream); +} + +void +assemble_const_int (FILE *stream, HOST_WIDE_INT value, unsigned size) +{ + char val[sizeof (HOST_WIDE_INT)]; + for (int i = 0; i != sizeof (HOST_WIDE_INT); ++i) + val[i] = value >> (i * 8); + assemble_string (stream, val, size, true); +} + +/* Can handle following shapes: + (const_int x) + (symbol_ref x) + (const (plus (symbol_ref x) (const_int y)) + (const (minus (symbol_ref x) (const_int y)) + (const (plus (const_int x) (const_int y)) + (const (minus (const_int x) (const_int y)) */ +bool +assemble_integer (FILE *stream, rtx x, unsigned size, int) +{ + HOST_WIDE_INT addend = 0; + + if (GET_CODE (x) == CONST) + { + x = XEXP (x, 0); + switch (GET_CODE (x)) + { + default: + return false; + case PLUS: + if (GET_CODE (XEXP (x, 1)) != CONST_INT) + return false; + addend = INTVAL (XEXP (x, 1)); + x = XEXP (x, 0); + break; + case MINUS: + if (GET_CODE (XEXP (x, 1)) != CONST_INT) + return false; + addend = -INTVAL (XEXP (x, 1)); + x = XEXP (x, 0); + break; + } + } + switch (GET_CODE (x)) + { + default: + return false; + case CONST_INT: + assemble_const_int (stream, INTVAL (x) + addend, size); + return true; + case SYMBOL_REF: + tree decl = SYMBOL_REF_DECL (x); + bool func_p = TREE_CODE (decl) == FUNCTION_DECL; + const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + + assemble_zeroes (stream, size); + fprintf (stream, " (@reloc i%d %s ", size * 8, + func_p ? "functable" : "data"); + wasm_print_operand (stream, x, 'l'); + if (addend) + fprintf(stream, " %+ld", addend); + fprintf (stream, ")"); + return true; + } +} + + +void +print_type (FILE *stream, const_tree type, bool first = false) +{ + const char *delim = first ? "" : " "; + switch (TREE_CODE (type)) + { + default: + gcc_unreachable (); + case VOID_TYPE: + break; + case NULLPTR_TYPE: + case VECTOR_TYPE: + case COMPLEX_TYPE: + print_type (stream, ptr_type_node, first); + break; + case UNION_TYPE: + case RECORD_TYPE: + if (TYPE_EMPTY_P (type)) + break; + if (TYPE_TRANSPARENT_AGGR (type)) + print_type (stream, TREE_TYPE (first_field (type)), first); + else + print_type (stream, ptr_type_node, first); + break; + case POINTER_TYPE: + case REFERENCE_TYPE: + case OFFSET_TYPE: + case INTEGER_TYPE: + case BOOLEAN_TYPE: + case ENUMERAL_TYPE: + fprintf (stream, "%s%s", delim, + TYPE_PRECISION (type) > 32 ? "i64" : "i32"); + break; + case REAL_TYPE: + fprintf (stream, "%s%s", delim, + TYPE_PRECISION (type) > 32 ? "f64" : "f32"); + break; + case FUNCTION_TYPE: + case METHOD_TYPE: + function_args_iterator it; + tree *arg; + fprintf (stream, "%s(param", delim); + CUMULATIVE_ARGS args; + INIT_CUMULATIVE_ARGS(args, type, nullptr, false, 0); + FOREACH_FUNCTION_ARGS_PTR (type, arg, it) + { + function_arg_info info (*arg, stdarg_p (type)); + if (pass_by_reference(&args, info)) + print_type (stream, intSI_type_node); + else + print_type (stream, *arg); + } + fprintf (stream, ")"); + tree return_type = TREE_TYPE (type); + fprintf (stream, " (result"); + if (return_type != void_type_node) + { + print_type (stream, return_type); + } + fprintf (stream, ")"); + break; + } +} +void +print_local_decl (FILE *stream, rtx reg, bool param = false) +{ + output_indent (stream); + fprintf (stream, "(%s ", param ? "param" : "local"); + wasm_print_operand (stream, reg, 0); + tree param_type = lang_hooks.types.type_for_mode (GET_MODE (reg), 0); + print_type (stream, param_type); + fprintf (stream, ")\n"); +} + +void assemble_visibility (FILE *stream, const_tree decl) +{ + if (decl && DECL_VISIBILITY (decl) == VISIBILITY_HIDDEN) + fprintf (stream, " hidden"); +} + +void assemble_binding (FILE *stream, const_tree decl) +{ + if (!decl) + return; + if (DECL_WEAK (decl)) + fprintf (stream, " weak"); + if (!TREE_PUBLIC (decl)) + fprintf (stream, " local"); +} + +void assemble_init_prio (FILE *stream, const_tree decl) +{ + if (DECL_STATIC_CONSTRUCTOR (decl)) + { + int prio = decl_init_priority_lookup (const_cast (decl)); + fprintf (stream, " (init_prio %d)", prio); + } +} + +void assemble_sym_name (FILE *stream, const char *name) +{ + fprintf (stream, " (name \""); + assemble_name (stream, name); + fprintf (stream, "\")"); +} + + +void +assemble_data_import (FILE *stream, const_tree decl, const char *name) +{ + output_indent (stream); + fprintf (stream, "(@sym.import.data $"); + assemble_name (stream, name); + assemble_binding (stream, decl); + assemble_visibility (stream, decl); + assemble_sym_name (stream, name); + fprintf (stream, ")\n"); +} + +/* Given the type, guess where assign_params must've put it */ +void print_func_frame_related (FILE *stream, tree type) +{ + if (VOID_TYPE_P (type)) + return; + if (TREE_CODE (type) == COMPLEX_TYPE + && targetm.calls.split_complex_arg (type)) + { + print_func_frame_related (stream, TREE_TYPE (type)); + print_func_frame_related (stream, TREE_TYPE (type)); + return; + } + if (RECORD_OR_UNION_TYPE_P (type) + && TYPE_TRANSPARENT_AGGR (type)) + type = TREE_TYPE (first_field (type)); + + function_arg_info arg (type, true); + if (pass_by_reference (NULL, arg)) + print_type (stream, build_pointer_type (type)); + else + print_type (stream, type); +} + +void +print_func_type (FILE *stream, const_tree type, bool for_block = false) +{ + tree result = TREE_TYPE (type); + + /* Taken from assign_parms_augmented_arg_list, please keep in sync */ + bool return_by_ref = aggregate_value_p (result, type); + if (!for_block) + { + fprintf (stream, " (param"); + if (return_by_ref) + print_func_frame_related (stream, build_pointer_type (result)); + tree arg; + function_args_iterator it; + FOREACH_FUNCTION_ARGS (type, arg, it) + { + print_func_frame_related (stream, arg); + } + if (stdarg_p (type) || !TYPE_ARG_TYPES (type)) + print_func_frame_related (stream, ptr_type_node); + fprintf (stream, ")"); + } + + fprintf (stream, "%s(result", for_block ? "": " "); + if (!return_by_ref) + print_func_frame_related (stream, result); + fprintf (stream, ")"); +} + +void print_global_type (FILE *stream, const_tree type) +{ + if (!TYPE_READONLY (type)) + fprintf (stream, " (mut"); + print_type (stream, type); + if (!TYPE_READONLY (type)) + fprintf (stream, ")"); +} + +void +assemble_entity_import (FILE *stream, const char *name, const char *abi_name, + const_tree decl) +{ + const_tree type = DECL_P (decl) ? TREE_TYPE (decl) : decl; + + output_indent (stream); + fprintf (stream, "(import \"env\" \""); + assemble_name (stream, abi_name); + fprintf (stream, "\" " ); + switch (TREE_CODE (type)) + { + case INTEGER_TYPE: + case BOOLEAN_TYPE: + case ENUMERAL_TYPE: + case POINTER_TYPE: + case OFFSET_TYPE: + case RECORD_TYPE: + case UNION_TYPE: { + fprintf (stream, "(global $"); + assemble_name (stream, name); + print_global_type (stream, type); + break; + } + case FUNCTION_TYPE: + case METHOD_TYPE: { + fprintf (stream, "(func $"); + assemble_name (stream, name); + fprintf (stream, " (@sym"); + if (type != decl) { + assemble_init_prio (stream, decl); + assemble_binding (stream, decl); + assemble_visibility (stream, decl); + } + fprintf (stream, ")"); + + print_func_type (stream, type); + break; + } + default: + gcc_unreachable (); + } + fprintf (stream, "))\n"); +} + +void +decl_end (FILE *stream) +{ + fprintf (stream, ")\n"); +} + +void +assemble_import (FILE *stream, const char *name, const_tree decl) +{ + if (!FUNC_OR_METHOD_TYPE_P (TREE_TYPE (decl))) + return assemble_data_import (stream, decl, name); + assemble_entity_import (stream, name, name, decl); +} + +template +void +print_nan_payload (FILE *stream, const REAL_VALUE_TYPE *n) +{ + constexpr int ndata = sizeof (T) / 4; + long data[ndata]; + real_to_target (data, n, float_mode_for_size (sizeof (T) * 8).require ()); + int mantissa = std::numeric_limits::digits - 1; + int mantissa_words = ((mantissa - 1) / 32) + 1; + for (int i = mantissa_words; i != ndata; ++i) + data[i] = 0; + unsigned mask = (1 << (mantissa % 32)) - 1; + data[mantissa / 32] &= mask; + + bool start = true; + for (int i = ndata; i--;) + if (start && !data[i]) + ; + else if (start) + fprintf (stream, "%lx", data[i]), start = false; + else + fprintf (stream, "%0.8lx", data[i]); +} + +} + +// TARGET_ASM_INIT_SECTIONS +void +wasm_asm_init_sections () +{ + text_section = get_unnamed_section (SECTION_CODE, [](const char *){}, "T"); + data_section = get_unnamed_section (SECTION_WRITE, [](const char *){}, "D"); +} + +// TARGET_ASM_FILE_START +void +wasm_asm_file_start () +{ + output_indent(asm_out_file); + indent++; + fprintf (asm_out_file, "(module\n"); + saved_asm_out_file = asm_out_file; + asm_out_file = open_memstream (&fake_out_file_data, &fake_out_file_length); +} + +// TARGET_ASM_FILE_END +void +wasm_asm_file_end () +{ + /* ??? All wasm globals should become builtin decls */ + output_indent (saved_asm_out_file); + fprintf (saved_asm_out_file, "(import \"env\" \"__stack_pointer\"" + " (global $stack (mut i32)))\n"); + + output_indent (saved_asm_out_file); + fprintf (saved_asm_out_file, "(import \"env\" \"memory\" (memory 0))\n"); + output_indent (saved_asm_out_file); + fprintf (saved_asm_out_file, "(import \"env\" \"__indirect_function_table\" (table 0 funcref))\n"); + + for (auto [key, value]: import_map) + { + auto [name, decl] = value; + assemble_import (saved_asm_out_file, IDENTIFIER_POINTER (name), decl); + } + for (auto sym: external_libcall_set) + assemble_entity_import (saved_asm_out_file, XSTR (sym, 0), XSTR (sym, 0), + *external_libcalls.get (sym)); + + fflush (asm_out_file); + fwrite (fake_out_file_data, 1, fake_out_file_length, saved_asm_out_file); + + fprintf (saved_asm_out_file, ")\n"); +} + +// ASM_OUTPUT_FUNCTION_LABEL +void +wasm_asm_start_function (FILE *stream, tree decl, const char *name) +{ + output_indent(stream); + indent++; + fprintf (stream, "(func $"); + assemble_name (stream, name); + + bool override_args = false; + if (MAIN_NAME_P (DECL_NAME (decl))) + { + if (!cfun->machine->func_args) + name = "__main_void"; + else + name = "__main_argc_argv", override_args = true; + } + + fprintf (stream, " (@sym"); + if (TREE_CODE (decl) == FUNCTION_DECL) + { + assemble_init_prio (stream, decl); + assemble_binding (stream, decl); + assemble_visibility (stream, decl); + assemble_sym_name (stream, name); + } + fprintf (stream, ") "); + + tree type = TREE_TYPE (decl); + //print_func_type (stream, type); + fprintf (stream, "\n"); + int i; + rtx reg; + + if (override_args) + { + FOR_EACH_VEC_SAFE_ELT (cfun->machine->func_args, i, reg) + print_local_decl (stream, reg, i < 2); + if (i < 1) + { + output_indent (stream); + fprintf (stream, "(param i32)\n"); + } + if (i < 2) + { + output_indent (stream); + fprintf (stream, "(param i32)\n"); + } + } + else + { + FOR_EACH_VEC_SAFE_ELT (cfun->machine->func_args, i, reg) + print_local_decl (stream, reg, true); + if (stdarg_p (type)) + print_local_decl (stream, regno_reg_rtx[ARG_POINTER_REGNUM], true); + if (DECL_STATIC_CHAIN (decl)) + print_local_decl (stream, regno_reg_rtx[STATIC_CHAIN_REGNUM], true); + } + output_indent (stream); + print_func_type (stream, type, true); + fprintf (stream, "\n"); + + output_indent (stream); + fprintf (stream, ";; hard\n"); + if (cfun->machine->return_mode != VOIDmode) + print_local_decl (stream, gen_rtx_REG (cfun->machine->return_mode, + WASM_RETURN_REGNUM)); + + df_set_regs_ever_live(WASM_CONTROL_POINTER_REGNUM, true); + for (int r = 0; r < FIRST_PSEUDO_REGISTER; r++) + { + if (r == WASM_RETURN_REGNUM) + continue; + if (r == ARG_POINTER_REGNUM) + continue; + if (r == STATIC_CHAIN_REGNUM && DECL_STATIC_CHAIN (decl)) + continue; + reg = regno_reg_rtx[r]; + if (df_regs_ever_live_p (r)) + { + if (!global_p (reg)) + print_local_decl (stream, reg); + } + } + + output_indent (stream); + fprintf (stream, ";; locals\n"); + int max = max_reg_num(); + for (int r = FIRST_PSEUDO_REGISTER; r < max; r++) + { + reg = regno_reg_rtx[r]; + if (!reg) + continue; + if (reg == const0_rtx) + continue; + if (vec_safe_contains (cfun->machine->func_args, reg)) + continue; + if (!bitmap_bit_p (cfun->machine->regs_ever_live, r)) + continue; + print_local_decl (stream, reg); + } + output_indent (stream); + fprintf (stream, "(local.set $control (i32.const 0))\n"); + output_indent (stream); + fprintf (stream, "(loop $control "); + print_func_type (stream, type, true); + fprintf (stream, "\n"); + indent++; + int len = cfun->machine->labelno_to_labels->elements (); + for (i = len - 1; i >= 0; --i) + { + output_indent (stream); + indent++; + fprintf (stream, "(block $%d\n", i); + } + + output_indent (stream); + + fprintf (stream, "(br_table"); + for (i = 0; i < len; ++i) + fprintf (stream, " $%d", i); + fprintf (stream, " (local.get $control))\n"); +} + +// ASM_DECLARE_FUNCTION_SIZE +void +wasm_asm_end_function (FILE *stream, tree, const char *name) +{ + indent--; + output_indent (stream); + fprintf (stream, ") ;; loop $control\n"); + indent--; + output_indent (stream); + fprintf (stream, ") ;;%s\n", + IDENTIFIER_POINTER (targetm.asm_out.mangle_assembler_name (name))); +} + +// TARGET_ASM_ASSEMBLE_UNDEFINED_DECL +void +wasm_handle_import (FILE *, const char *name, const_tree decl) +{ + auto has_proto = [] (const_tree ty) + { + if (TREE_CODE (ty) != FUNCTION_DECL) + return true; + ty = TREE_TYPE (ty); + return TYPE_ARG_TYPES (ty) || TYPE_NO_NAMED_ARGS_STDARG_P (ty); + }; + bool existed = false; + tree key = targetm.asm_out.mangle_assembler_name (name); + auto &slot = import_map.get_or_insert (key, &existed); + if (!existed || (!has_proto (slot.second) && has_proto (decl))) + slot = {get_identifier (name), decl}; +} + +// TARGET_ASM_ASSEMBLE_EXTERNAL_LIBCALL +void +wasm_handle_libcall (rtx symbol) +{ + external_libcall_set.add (symbol); +} + +// TARGET_ASM_INTEGER +bool +wasm_assemble_integer (rtx x, unsigned size, int align) +{ + return assemble_integer (asm_out_file, x, size, align); +} + +// TARGET_ASM_END_DECL +void +wasm_assemble_decl_end () +{ + return decl_end(asm_out_file); +} + +// ASM_OUTPUT_ASCII +void +wasm_assemble_ascii (FILE *stream, const char *data, int len) +{ + return assemble_string (stream, data, len, false); +} + +// ASM_OUTPUT_SKIP +void +wasm_assemble_skip (FILE *stream, unsigned HOST_WIDE_INT len) +{ + return assemble_zeroes (stream, len); +} + +// ASM_DECLARE_OBJECT_NAME +// ASM_DECLARE_CONSTANT_NAME +void +wasm_assemble_data_begin (FILE *stream, tree decl, const char *name, + HOST_WIDE_INT size, HOST_WIDE_INT align, bool pub) +{ + if (!name) + name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + if (!size) + size = tree_to_uhwi (DECL_SIZE_UNIT (decl)); + output_indent(stream); + /* ??? This is a crutch. We should know the alignment of the constant we're + declaring, but ASM_DECLARE_CONSTANT_NAME doesn't supply it. Assume it's + huge and move on for now. */ + align = align ? align : 1024; + fprintf (stream, "(data (@sym (align %ld)) (i32.const 0) (@sym $", align); + assemble_name (stream, name); + if (decl) + { + assemble_binding (stream, decl); + } + else + { + if (!pub) + fprintf (stream, " local"); + } + assemble_visibility (stream, decl); + assemble_sym_name (stream, name); + fprintf (stream, " (size %ld)", size); + fprintf (stream, ")"); +} + +// ASM_OUTPUT_ALIGNED_DECL_COMMON +// ASM_OUTPUT_ALIGNED_DECL_LOCAL +void +wasm_assemble_data_zeros (FILE *stream, tree decl, const char *name, + HOST_WIDE_INT size, HOST_WIDE_INT align, bool pub) +{ + wasm_assemble_data_begin (stream, decl, name, size, align, pub); + wasm_assemble_skip (stream, size); + decl_end(stream); +} + +// TARGET_PRINT_OPERAND_PUNCT_VALID_P +bool +wasm_valid_punct_p (unsigned char code) +{ + return code == '#'; +} + +// TARGET_PRINT_OPERAND +void +wasm_print_operand (FILE *stream, rtx value, int mode) +{ + if (value && GET_CODE (value) == UNSPEC_VOLATILE) + return wasm_print_operand (stream, XVECEXP (value, 0, 0), mode); + + if (mode == '#') /* print return */ + { + if (TREE_TYPE (TREE_TYPE (cfun->decl)) != void_type_node) + fprintf (stream, " (local.get $return)"); + } + else if (mode == 'M') /* print local/global */ + if (global_p(value)) + fprintf (stream, "global"); + else + fprintf (stream, "local"); + else if (mode == 'A') /* print an arglist */ + { + gcc_assert (GET_CODE (value) == PARALLEL); + int len = XVECLEN (value, 0); + for (int i = 1; i < len; ++i) + { + rtx arg = XVECEXP (value, 0, i); + gcc_assert (GET_CODE (arg) == USE); + rtx reg = XEXP (arg, 0); + gcc_assert (GET_CODE (reg) == REG); + fprintf (stream, " "); + wasm_print_operand (stream, reg, 'i'); + } + } + else if (mode == 'T') /* print a type */ + { + if (GET_CODE (value) == PARALLEL) + { + int len = XVECLEN (value, 0); + for (int i = 1; i < len; ++i) + { + rtx arg = XVECEXP (value, 0, i); + gcc_assert (GET_CODE (arg) == USE); + rtx reg = XEXP (arg, 0); + gcc_assert (GET_CODE (reg) == REG); + wasm_print_operand (stream, reg, mode); + } + } + else if (REG_P (value)) + print_type (stream, lang_hooks.types.type_for_mode (GET_MODE (value), 0)); + else + gcc_unreachable(); + } + else switch (GET_CODE (value)) + { + case MEM: + { + rtx addr = XEXP (value, 0); + if (GET_CODE (addr) == PLUS) + { + fprintf (stream, "offset=%lu ", UINTVAL (XEXP (addr, 1))); + addr = XEXP (addr, 0); + } + + wasm_print_operand (stream, addr, 'i'); + break; + } + case CONST: + case SYMBOL_REF: + { + rtx op = GET_CODE (value) == CONST ? XEXP (value, 0) : value; + rtx offset = NULL_RTX; + if (GET_CODE (op) == PLUS) + offset = XEXP (op, 1), op = XEXP (op, 0); + tree decl = SYMBOL_REF_P (op) ? SYMBOL_REF_DECL (op) : NULL_TREE; + bool fndecl_p = decl && TREE_CODE (decl) == FUNCTION_DECL; + if (mode == 'i') + fprintf (stream, "(i32.const 0 (@reloc %s ", + fndecl_p ? "functable" : "data"); + + fprintf (stream, "$"); + output_addr_const (stream, op); + if (offset) + { + fprintf (stream, " %+" HOST_WIDE_INT_PRINT "d", + INTVAL (offset)); + } + if (mode == 'i') + fprintf (stream, "))"); + break; + } + case SUBREG: + gcc_assert (SUBREG_BYTE (value) == 0); + wasm_print_operand (stream, SUBREG_REG (value), mode); + break; + case REG: + { + int reg = REGNO (value); + if (mode == 'i' || mode == 'o') + fprintf (stream, "%s%s.%s ", mode == 'o' ? "" : "(", + global_p (value) ? "global" : "local", + mode == 'i' ? "get" : "set"); + if (reg < FIRST_PSEUDO_REGISTER) + fprintf (stream, "%s", reg_names[reg]); + else + { + reg -= FIRST_PSEUDO_REGISTER; + fprintf (stream, "$local_%d", reg); + } + if (mode == 'i') + fprintf (stream, ")"); + break; + } + case CONST_INT: + if (mode == 'i') + fprintf (stream, "(i32.const "); + fprintf (stream, "%ld", INTVAL (value)); + if (mode == 'i') + fprintf (stream, ")"); + break; + case CONST_DOUBLE: + { + if (mode == 'i') + fprintf (stream, "(f%d.const ", GET_MODE_PRECISION (GET_MODE (value))); + const REAL_VALUE_TYPE *n = CONST_DOUBLE_REAL_VALUE (value); + if (REAL_VALUE_ISINF (*n)) + fprintf (stream, "%cinf", REAL_VALUE_NEGATIVE (*n) ? '-' : '+'); + else if (REAL_VALUE_ISNAN (*n)) + { + fprintf (stream, "%cnan", REAL_VALUE_NEGATIVE (*n) ? '-' : '+'); + if (!n->canonical) + { + fprintf (stream, ":0x"); + switch (GET_MODE (value)) + { + case DFmode: + print_nan_payload (stream, n); + break; + case SFmode: + print_nan_payload (stream, n); + break; + default: + gcc_unreachable(); + } + } + } + else + { + /* There are always 32 bits in each long, no matter the size of + the hosts long. */ + long tmp[2]; + REAL_VALUE_TO_TARGET_DOUBLE (*n, tmp); + int32_t tmp2[2] = {(int32_t)tmp[0], (int32_t)tmp[1]}; + double r; + std::memcpy (&r, tmp2, sizeof r); + fprintf (stream, "%a", r); + } + if (mode == 'i') + fprintf (stream, ")"); + break; + } + default: + gcc_unreachable (); + } +} + +static int get_cf_label (size_t no) +{ + rtx_insn **l = cfun->machine->labelno_to_labels->get (no); + if (!l) + return -1; + int cf = *cfun->machine->labels_to_cfno->get (*l); + gcc_assert (cf >= 0); + return cf; +} + +void +wasm_generate_internal_label (char *buf, const char *pfx, size_t no) +{ + if (!strcmp (pfx, "L")) + sprint_ul (buf, get_cf_label (no)); + else + sprintf (buf, "%s" HOST_WIDE_INT_PRINT_DEC, pfx, no); +} + +void +wasm_output_internal_label (FILE *stream, const char *pfx, size_t no) +{ + if (!strcmp (pfx, "L")) + { + int l = get_cf_label (no); + if (l >= 0) + { + indent--; + output_indent (stream); + fprintf (stream, ") ;; $%d\n", l); + } + } + else if (!strcmp (pfx, "LFB")) + /* Function begin */; + else if (!strcmp (pfx, "LFE")) + /* Function end */; + else + /* unknown */; +} diff --git a/gcc/config/wasm/wasm-cg.cc b/gcc/config/wasm/wasm-cg.cc new file mode 100644 index 00000000000..c8d7f6812d1 --- /dev/null +++ b/gcc/config/wasm/wasm-cg.cc @@ -0,0 +1,621 @@ +/* WebAssembly code generation utilities. + Copyright (C) 2025-2025 Free Software Foundation, Inc. + Contributed by feedable. + + 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 + . */ + +#define IN_TARGET_CODE 1 + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "target.h" +#include "rtl.h" +#include "tree.h" +#include "regs.h" +#include "stringpool.h" +#include "attribs.h" +#include "gimple.h" +#include "df.h" +#include "memmodel.h" +#include "tm_p.h" +#include "stringpool.h" +#include "optabs.h" +#include "emit-rtl.h" +#include "recog.h" +#include "diagnostic-core.h" +#include "output.h" +#include "fold-const.h" +#include "stor-layout.h" +#include "varasm.h" +#include "calls.h" +#include "explow.h" +#include "expr.h" +#include "langhooks.h" +#include "cfgrtl.h" +#include "gimplify.h" +#include "reload.h" +#include "builtins.h" +#include "tree-pass.h" +#include "cfghooks.h" + +hash_map external_libcalls; + +namespace +{ + +rtx +unify_mem (rtx mem) +{ + HOST_WIDE_INT offset = 0; + machine_mode mode = GET_MODE (mem); + if (SUBREG_P (mem) && MEM_P(SUBREG_REG (mem))) + { + offset += SUBREG_BYTE (mem); + mem = SUBREG_REG (mem); + } + if (!MEM_P (mem)) + return mem; + rtx addr = XEXP (mem, 0); + if (GET_CODE (addr) == PLUS && CONST_INT_P (XEXP (addr, 1))) + { + rtx offset_rtx = XEXP (addr, 1); + addr = XEXP (addr, 0); + offset += INTVAL (offset_rtx); + } + addr = force_reg (Pmode, addr); + addr = gen_rtx_PLUS (Pmode, addr, gen_rtx_CONST_INT (Pmode, offset)); + if (offset < 0) + addr = gen_rtx_PLUS (Pmode, force_reg (Pmode, addr), const0_rtx); + mem = copy_rtx (mem); + XEXP (mem, 0) = addr; + return mem; +} + +bool symref_p (rtx expr) +{ + if (GET_CODE(expr) == CONST) + { + expr = XEXP (expr, 0); + if (GET_CODE (expr) == PLUS) + expr = XEXP (expr, 0); + } + return GET_CODE (expr) == SYMBOL_REF; +} + +void +record_libcall (const_rtx sym, tree ret) +{ + auto_vec args; + vec *args_rtx = cfun->machine->call->args; + int cnt = vec_safe_length (args_rtx); + args.safe_grow (cnt); + for (int i = 0; i != cnt; ++i) + args[i] = lang_hooks.types.type_for_mode (GET_MODE ((*args_rtx)[i]), false); + tree ty = build_function_type_array (ret, cnt, args.address ()); + bool existed; + tree &slot = external_libcalls.get_or_insert (sym, &existed); + if (existed) + gcc_assert (slot == ty); + else + slot = ty; +} + +} + +machine_mode +wasm_real_register_mode (rtx reg) +{ + if (SUBREG_P (reg)) + reg = SUBREG_REG (reg); + if (!REG_P (reg)) + return VOIDmode; + machine_mode m = GET_MODE (reg); + PROMOTE_MODE (m, 0, NULL_TREE); + return m; +} + +static bool +expand_const (rtx dest, rtx src, machine_mode mode) +{ + if (!const_int_operand (src, mode) && !const_double_operand (src, mode) && + GET_CODE (src) != LABEL_REF && !symref_p (src)) + return false; + if (symref_p (src)) + + if (GET_CODE(src) == CONST) + if (GET_CODE (XEXP (src, 0)) == PLUS) + if (GET_CODE (XEXP (XEXP (src, 0), 1)) == CONST_INT) + { + tree symref_dcl = SYMBOL_REF_DECL (XEXP (XEXP (src, 0), 0)); + if (INTVAL (XEXP (XEXP (src, 0), 1)) <= 0) + src = force_reg (Pmode, XEXP (src, 0)); + else if (symref_dcl && TREE_CODE (symref_dcl) == FUNCTION_DECL) + src = force_reg (Pmode, XEXP (src, 0)); + } + + emit_insn (gen_rtx_SET (dest, src)); + return true; +} + +bool +wasm_expand_mov (rtx dest, rtx src, machine_mode mode) +{ + temporary_volatile_ok g {1}; + dest = unify_mem (dest); + src = unify_mem (src); + if (register_operand (dest, mode) && immediate_operand (src, mode)) + return expand_const (dest, src, mode); + gcc_assert (REG_P (dest) || MEM_P (dest) || SUBREG_P (dest)); + if (register_operand (dest, mode) && memory_operand (src, mode)) + { + emit_insn (gen_rtx_SET (dest, src)); + return true; + } + if (!SUBREG_P (src)) + src = force_reg (mode, src); + emit_insn (gen_rtx_SET (dest, src)); + return true; +} + +void +wasm_expand_conv (rtx dest, rtx src, rtx_code code, bool strict) +{ + if (code == TRUNCATE) + code = LOAD_EXTEND_OP (VOIDmode); + + auto real_reg = [](rtx reg) + { + if (!SUBREG_P (reg)) + return reg; + gcc_assert (SUBREG_BYTE (reg) == 0); + return SUBREG_REG (reg); + }; + rtx r_src = real_reg (src), r_dest = real_reg (dest); + + /* This is an intra-reg conversion */ + bool src_di_p = (GET_MODE (r_src) == DImode); + bool dest_di_p = (GET_MODE (r_dest) == DImode); + bool do_conv = src_di_p != dest_di_p; + bool do_intra = (GET_MODE (src) != SImode && GET_MODE (src) != DImode) || (GET_MODE (src) != DImode && (dest_di_p && src_di_p)); + machine_mode mid_mode = src_di_p ? DImode : SImode; + + rtx mid = do_conv + ? do_intra + ? gen_reg_rtx (mid_mode) + : src + : simplify_gen_subreg (mid_mode, dest, GET_MODE (r_dest), 0); + if (do_intra) + { + if (GET_MODE_PRECISION (GET_MODE (src)) >= GET_MODE_PRECISION (GET_MODE (mid))) + src = simplify_gen_subreg (mid_mode, src, GET_MODE (r_src), 0); + rtx op = gen_rtx_fmt_e_stat (code, mid_mode, src); + rtx_insn *i = emit_insn (gen_rtx_SET (mid, op)); + extract_insn (i); + } + + if (do_conv) + { + if (mid_mode == DImode) + code = TRUNCATE; + rtx op = gen_rtx_fmt_e_stat (code, GET_MODE (r_dest), mid); + rtx_insn *i = emit_insn (gen_rtx_SET (r_dest, op)); + extract_insn (i); + } +} + +void +wasm_expand_call(rtx retval, rtx fn, rtx aux) +{ + bool vararg_p = false; + bool has_proto = true; + bool is_fn = true; + bool need_chain = false; + + if (tree type = cfun->machine->call->type) + { + vararg_p = stdarg_p (type); + has_proto = TYPE_ARG_TYPES (type) || vararg_p; + } + + if (GET_CODE (XEXP (fn, 0)) == SYMBOL_REF) + if (tree decl = SYMBOL_REF_DECL (XEXP (fn, 0))) + { + if (TREE_CODE (decl) != FUNCTION_DECL) + is_fn = false; + else if (DECL_STATIC_CHAIN (decl)) + need_chain = true; + } + + /* Pretend unprototyped fn calls dynamic. That way we can assert the function + type ourselves, and if they don't agree with whatever is actually supplied + by the linker, ANSI C 3.3.2.2 says it's undefied anyway */ + if (!has_proto || !is_fn) + { + rtvec ops = gen_rtvec (1, force_reg (Pmode, XEXP (fn, 0))); + XEXP (fn, 0) = gen_rtx_UNSPEC_VOLATILE (SImode, ops, + UNSPECV_CALL_ADDRESS_BARRIER); + } + + rtx call = gen_rtx_CALL(VOIDmode, fn, aux); + if (retval) + call = gen_rtx_SET (retval, call); + + auto *args_rtx = cfun->machine->call->args; + + /* ??? This should be handled by the call machinery, not me! */ + if (vararg_p) + { + rtx stdarg_reg = gen_reg_rtx (SImode); + /* Rely on args being pushed in reverse order, and on only varargs being + pushed, so that the beginning of the vararg buffer is stack_pointer_rtx. + This is a hack. */ + emit_move_insn (stdarg_reg, stack_pointer_rtx); + vec_safe_insert (args_rtx, 0, stdarg_reg); + } + if (need_chain) + { + rtx chain_reg = gen_reg_rtx (SImode); + emit_move_insn (chain_reg, regno_reg_rtx[STATIC_CHAIN_REGNUM]); + vec_safe_insert (args_rtx, 0, chain_reg); + } + + int argc = vec_safe_length (args_rtx); + rtx res = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (argc + 1)); + XVECEXP (res, 0, 0) = call; + for (int i = 0; i < argc; ++i) + XVECEXP (res, 0, argc - i) = gen_rtx_USE (VOIDmode, (*args_rtx)[i]); + emit_call_insn (res); +} + +void +wasm_expand_prologue () +{ + emit_move_insn (regno_reg_rtx[WASM_BASE_POINTER_REGNUM], + stack_pointer_rtx); + if (crtl->stack_realign_needed) + { + int align = ~(crtl->max_used_stack_slot_alignment / BITS_PER_UNIT - 1); + rtx align_mask = gen_rtx_CONST_INT (SImode, align); + rtx reg = gen_reg_rtx (SImode); + emit_move_insn (reg, align_mask); + emit_insn (gen_andsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); + } + + if (flag_stack_usage_info) + current_function_static_stack_size = 0; + if (poly_int64 stack_space = get_frame_size ()) + { + HOST_WIDE_INT unit_boundary = STACK_BOUNDARY / BITS_PER_UNIT; + poly_int64 aligned = aligned_upper_bound (stack_space, unit_boundary); + rtx aligned_space_rtx = gen_int_mode (aligned, Pmode); + emit_insn (gen_sub2_insn (stack_pointer_rtx, aligned_space_rtx)); + emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); + if (flag_stack_usage_info) + current_function_static_stack_size = aligned; + } + if (HOST_WIDE_INT stack_space = crtl->outgoing_args_size) + { + emit_insn (gen_sub2_insn (stack_pointer_rtx, + gen_int_mode (stack_space, Pmode))); + } +} + +void +wasm_expand_epilogue () +{ + emit_move_insn (stack_pointer_rtx, regno_reg_rtx[WASM_BASE_POINTER_REGNUM]); +} + +void +wasm_expand_compare (machine_mode m, rtx res, rtx op) +{ + rtx *left_p = &XEXP (op, 0), *right_p = &XEXP (op, 1); + + *left_p = force_reg (m, *left_p); + *right_p = force_reg (m, *right_p); + + rtx left = *left_p, right = *right_p; + + switch (GET_CODE (op)) + { + case ORDERED: + { + rtx eq = gen_reg_rtx (SImode), ne = gen_reg_rtx (SImode); + wasm_expand_compare (m, eq, gen_rtx_LE (SImode, left, right)); + wasm_expand_compare (m, ne, gen_rtx_GE (SImode, left, right)); + emit_insn (gen_iorsi3 (res, eq, ne)); + break; + } + case LTGT: + { + rtx eq = gen_reg_rtx (SImode), ne = gen_reg_rtx (SImode); + wasm_expand_compare (m, eq, gen_rtx_LT (SImode, left, right)); + wasm_expand_compare (m, ne, gen_rtx_GT (SImode, left, right)); + emit_insn (gen_iorsi3 (res, eq, ne)); + break; + } + case LTU: + case GTU: + case LEU: + case GEU: + case LT: + case GT: + case LE: + case GE: + case EQ: + case NE: + op = gen_rtx_fmt_ee (GET_CODE (op), SImode, left, right); + emit_insn (gen_rtx_SET (res, op)); + break; + case UNLT: + case UNGT: + case UNLE: + case UNGE: + case UNEQ: + case UNORDERED: + { + rtx_code cond_code = reverse_condition_maybe_unordered (GET_CODE (op)); + rtx cond = gen_rtx_fmt_ee (cond_code, SImode, left, right); + rtx mid = gen_reg_rtx (SImode); + wasm_expand_compare (m, mid, cond); + emit_insn (gen_xorsi3 (res, mid, gen_rtx_CONST_INT (SImode, STORE_FLAG_VALUE))); + break; + } + default: + gcc_unreachable (); + } +} + +bool +wasm_regno_mode_ok (unsigned regno, machine_mode mode) +{ + if (COMPLEX_MODE_P (mode)) + return false; + if (regno == WASM_CONTROL_POINTER_REGNUM) + return mode == SImode; + if (regno == ARG_POINTER_REGNUM + || regno == STACK_POINTER_REGNUM + || regno == FRAME_POINTER_REGNUM + || regno == STATIC_CHAIN_REGNUM + || regno == WASM_BASE_POINTER_REGNUM) + return mode == Pmode; + if (GET_MODE_CLASS (mode) == MODE_INT) + return mode < TImode; + if (GET_MODE_CLASS (mode) == MODE_FLOAT) + return mode == DFmode || mode == SFmode; + return false; +} + +bool +wasm_can_change_mode_class (machine_mode from, machine_mode to, reg_class_t) +{ + return QImode <= from && from <= SImode && QImode <= to && to <= SImode; +} + +// TARGET_LEGITIMATE_ADDRESS_P +bool +wasm_legitimate_address_p (machine_mode, rtx x, bool, code_helper) +{ + if (GET_CODE (x) == CONST) + x = XEXP (x, 0); + if (GET_CODE (x) == PLUS && CONST_INT_P (XEXP (x, 1)) && + INTVAL (XEXP (x, 1)) >= 0) + x = XEXP (x, 0); + switch (GET_CODE (x)) + { + case SYMBOL_REF: + case LABEL_REF: + case CONST_INT: + case REG: + return true; + default: + return false; + } +} + +// TARGET_MARK_ARG_REGNOS +void +wasm_mark_arg_regnos (bitmap regnos) +{ + for (rtx arg: cfun->machine->func_args) + bitmap_set_bit (regnos, REGNO(arg)); +} + +// TARGET_START_CALL_ARGS +void +wasm_start_call_args (cumulative_args_t args) +{ + cfun->machine->call = get_cumulative_args (args); +} + +// TARGET_CALL_ARGS +void +wasm_call_args (cumulative_args_t args, rtx arg, tree type) +{ + get_cumulative_args (args)->type = type; + if (arg == pc_rtx) + return; + +if (GET_CODE (arg) == PARALLEL) + { + rtvec elts = XVEC (arg, 0); + for (int i = 0; i != GET_NUM_ELEM (elts); ++i) + wasm_call_args (args, XEXP (RTVEC_ELT (elts, i), 0), type); + return; + } + gcc_assert (REG_P (arg)); + vec_safe_push (get_cumulative_args (args)->args, arg); +} + +// TARGET_END_CALL_ARGS +void +wasm_end_call_args (cumulative_args_t) +{ + cfun->machine->call = NULL; + cfun->machine->unproto_call_p = false; +} + +// TARGET_FUNCTION_ARG_ADVANCE +void +wasm_function_arg_advance (cumulative_args_t, const function_arg_info &) +{ +} + +// TARGET_FUNCTION_ARG_BOUNDARY +unsigned int wasm_vararg_align (machine_mode mode, const_tree type) +{ + unsigned align = 0; + + if (type) + align = TYPE_ALIGN (type); + if (align) + return MIN (MAX (align, BITS_PER_UNIT), BIGGEST_ALIGNMENT); + return get_mode_alignment (mode); +} + +// TARGET_FUNCTION_VALUE +rtx +wasm_function_value (const_tree type, const_tree ARG_UNUSED (func), + bool outgoing) +{ + machine_mode mode = TYPE_MODE (type); + if (!cfun) + /* fake return regnum since none is actually available */ + return gen_rtx_REG (mode, WASM_RETURN_REGNUM); + if (outgoing) + { + /* Where we actually put the actual return val */ + cfun->machine->return_mode = mode; + return gen_rtx_REG (mode, WASM_RETURN_REGNUM); + } + if (!cfun->machine->call) + /* fake return regnum again, not in a call */ + return gen_rtx_REG (mode, WASM_RETURN_REGNUM); + + /* Put the retval in a fresh reg, its mode may be different from actual + retval, and we can't have that */ + return gen_reg_rtx (mode); +} + + +// TARGET_FUNCTION_ARG +rtx +wasm_function_arg (cumulative_args_t cum_v, const function_arg_info &arg) +{ + CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); + + if (arg.end_marker_p ()) + return NULL_RTX; + + if (!arg.named) + return NULL_RTX; + + if (arg.mode == TImode) + { + rtx const8_rtx = gen_rtx_CONST_INT (VOIDmode, 8); + rtvec para = gen_rtvec(2, + gen_rtx_EXPR_LIST (DImode, gen_reg_rtx (DImode), const0_rtx), + gen_rtx_EXPR_LIST (DImode, gen_reg_rtx (DImode), const8_rtx)); + return gen_rtx_PARALLEL (TImode, para); + } + return gen_reg_rtx (arg.mode); +} + +// TARGET_FUNCTION_INCOMING_ARG +rtx +wasm_function_incoming_arg (cumulative_args_t cum_v, + const function_arg_info &arg) +{ + CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); + + auto maybe_push_arg = [cum](rtx arg) + { + if (cum->incoming) + vec_safe_push (cum->args, arg); + }; + + if (arg.end_marker_p ()) + { + gcc_assert (!cfun->machine->func_args); + if (cum->incoming) + cfun->machine->func_args = cum->args; + return gen_rtx_CONST_INT (SImode, 80); + } + if (!arg.named) + return NULL_RTX; + + /* Int128 is passed as 2xint64_t, in LE order */ + if (arg.mode == TImode) + { + rtx const8_rtx = gen_rtx_CONST_INT (VOIDmode, 8); + + rtx lsb = gen_rtx_EXPR_LIST (DImode, gen_reg_rtx (DImode), const0_rtx); + rtx msb = gen_rtx_EXPR_LIST (DImode, gen_reg_rtx (DImode), const8_rtx); + maybe_push_arg (lsb); + maybe_push_arg (msb); + rtvec para = gen_rtvec(2, lsb, msb); + return gen_rtx_PARALLEL (TImode, para); + } + rtx reg = gen_reg_rtx (arg.mode); + maybe_push_arg (reg); + return reg; +} + +// TARGET_LIBCALL_VALUE +rtx wasm_libcall_value (machine_mode m, const_rtx sym) +{ + tree rtype = lang_hooks.types.type_for_mode (m, false); + if (cfun && cfun->machine->call) + record_libcall (sym, rtype); + return wasm_function_value (rtype, NULL_TREE, false); +} + +// TARGET_PASS_BY_REFERENCE +bool +wasm_pass_by_reference (cumulative_args_t, const function_arg_info &arg) +{ + if (arg.type) + { + if (TREE_CODE (arg.type) == COMPLEX_TYPE) + return true; + if (TREE_CODE (arg.type) == VECTOR_TYPE) + return true; + } + if (COMPLEX_MODE_P (arg.mode)) + return true; + if (VECTOR_MODE_P (arg.mode)) + return true; + if (arg.aggregate_type_p ()) + return true; + return false; +} +// TARGET_RETURN_IN_MEMORY +bool +wasm_return_in_memory (const_tree type, const_tree ARG_UNUSED (fntype)) +{ + if (TREE_CODE (type) == COMPLEX_TYPE) + return true; + if (TREE_CODE (type) == VECTOR_TYPE) + return true; + if (VECTOR_MODE_P (TYPE_MODE (type))) + return true; + if (COMPLEX_MODE_P (TYPE_MODE (type))) + return true; + return false; +} diff --git a/gcc/config/wasm/wasm-modes.def b/gcc/config/wasm/wasm-modes.def new file mode 100644 index 00000000000..e69de29bb2d diff --git a/gcc/config/wasm/wasm-passes.cc b/gcc/config/wasm/wasm-passes.cc new file mode 100644 index 00000000000..fc28ef93030 --- /dev/null +++ b/gcc/config/wasm/wasm-passes.cc @@ -0,0 +1,153 @@ +/* WebAssembly passes for code generation. +Copyright (C) 2025-2025 Free Software Foundation, Inc. + Contributed by feedable. + + 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 + . */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "target.h" +#include "rtl.h" +#include "tree.h" +#include "regs.h" +#include "stringpool.h" +#include "attribs.h" +#include "gimple.h" +#include "df.h" +#include "memmodel.h" +#include "tm_p.h" +#include "stringpool.h" +#include "optabs.h" +#include "emit-rtl.h" +#include "recog.h" +#include "diagnostic-core.h" +#include "output.h" +#include "fold-const.h" +#include "stor-layout.h" +#include "varasm.h" +#include "calls.h" +#include "explow.h" +#include "expr.h" +#include "langhooks.h" +#include "cfgrtl.h" +#include "gimplify.h" +#include "reload.h" +#include "builtins.h" +#include "tree-pass.h" +#include "cfghooks.h" + +namespace { + +const pass_data pass_data_count_labels = +{ + RTL_PASS, /* type */ + "count_labels", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_MACH_DEP, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + +class pass_count_labels : public rtl_opt_pass +{ + static void put_label (function *fun, rtx_insn *l, int &idx) + { + gcc_assert (!fun->machine->labels_to_cfno->put (l, idx++)); + int n = CODE_LABEL_NUMBER (l); + gcc_assert (!fun->machine->labelno_to_labels->put (n, l)); + } + static void mark_live (bitmap regs) + { + + df_clear_flags (DF_LR_RUN_DCE); + df_set_flags (DF_NO_INSN_RESCAN | DF_NO_HARD_REGS); + df_live_add_problem (); + df_live_set_all_dirty (); + df_analyze (); + //regstat_init_n_sets_and_refs (); + for (int i = FIRST_PSEUDO_REGISTER; i < max_reg_num (); ++i) + if (DF_REG_DEF_COUNT (i) || DF_REG_USE_COUNT (i)) + bitmap_set_bit (regs, i); + } + static void inject_trap (function *fun, basic_block bb) + { + rtx_insn *insn = BB_END (bb); + if (INSN_P (insn) + && (recog_memoized (insn) == CODE_FOR_trap)) + return; + if (!vec_safe_length (bb->succs)) + make_edge (bb, fun->cfg->x_exit_block_ptr, EDGE_FALLTHRU); + edge_iterator ei; + edge e; + FOR_EACH_EDGE (e, ei, bb->succs) + if (e->flags & EDGE_FALLTHRU && cfun->machine->return_mode != VOIDmode) + if (e->dest == fun->cfg->x_exit_block_ptr) + { + basic_block new_bb = split_edge (e); + emit_insn_after (gen_trap(), BB_END (new_bb)); + } + } + static rtx_insn *find_label (basic_block bb) + { + rtx_insn *insn; + FOR_BB_INSNS (bb, insn) + { + if (LABEL_P (insn)) + return insn; + if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_DELETED_LABEL) + return insn; + } + return NULL; + } +public: + pass_count_labels(gcc::context *ctxt) + : rtl_opt_pass(pass_data_count_labels, ctxt) + {} + + /* opt_pass methods: */ + unsigned int execute (function *fun) override + { + basic_block bb; + FOR_EACH_BB_FN (bb, fun) + inject_trap (fun, bb); + + bb = fun->cfg->x_entry_block_ptr->next_bb; + int i = 0; + put_label (fun, block_label (bb), i); + mark_live (fun->machine->regs_ever_live); + + FOR_BB_BETWEEN (bb, bb->next_bb, fun->cfg->x_exit_block_ptr, next_bb) + { + if (rtx_insn *x = find_label (bb)) + put_label (fun, x, i); + } + return 0; + } + +}; + +} // anon namespace + +rtl_opt_pass *make_pass_count_labels (gcc::context *ctx) +{ + return new pass_count_labels (ctx); +} diff --git a/gcc/config/wasm/wasm-passes.def b/gcc/config/wasm/wasm-passes.def new file mode 100644 index 00000000000..7c69cad12f5 --- /dev/null +++ b/gcc/config/wasm/wasm-passes.def @@ -0,0 +1,27 @@ +/* Description of target passes for WebAssembly + Copyright (C) 2025-2025 Free Software Foundation, Inc. + +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 +. */ + +/* + Macros that can be used in this file: + INSERT_PASS_AFTER (PASS, INSTANCE, TGT_PASS) + INSERT_PASS_BEFORE (PASS, INSTANCE, TGT_PASS) + REPLACE_PASS (PASS, INSTANCE, TGT_PASS) + */ + + INSERT_PASS_BEFORE (pass_free_cfg, 1, pass_count_labels); \ No newline at end of file diff --git a/gcc/config/wasm/wasm-protos.h b/gcc/config/wasm/wasm-protos.h new file mode 100644 index 00000000000..9aa5f6c0fe5 --- /dev/null +++ b/gcc/config/wasm/wasm-protos.h @@ -0,0 +1,12 @@ + +#ifdef RTX_CODE +extern void wasm_expand_prologue (); +extern void wasm_expand_epilogue (); +extern void wasm_expand_call (rtx retval, rtx fn, rtx aux); +extern void wasm_emit_jump (rtx dest, rtx fn); +extern bool wasm_expand_mov (rtx dest, rtx src, machine_mode mode); +extern void wasm_expand_conv (rtx, rtx, rtx_code, bool = true); +extern void wasm_expand_compare (machine_mode m, rtx res, rtx cmp); +extern machine_mode wasm_real_register_mode (rtx reg); +rtl_opt_pass *make_pass_count_labels (gcc::context *ctx); +#endif diff --git a/gcc/config/wasm/wasm.cc b/gcc/config/wasm/wasm.cc new file mode 100644 index 00000000000..0a5e746d87c --- /dev/null +++ b/gcc/config/wasm/wasm.cc @@ -0,0 +1,128 @@ +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "target.h" +#include "rtl.h" +#include "tree.h" +#include "stringpool.h" +#include "attribs.h" +#include "df.h" +#include "memmodel.h" +#include "stringpool.h" +#include "optabs.h" +#include "emit-rtl.h" +#include "recog.h" +#include "diagnostic-core.h" +#include "output.h" +#include "varasm.h" +#include "calls.h" +#include "explow.h" +#include "expr.h" +#include "builtins.h" + +#include "target.h" +#include "common/common-target.h" + +static machine_function * +wasm_init_machine_status (void) +{ + machine_function *p = ggc_cleared_alloc (); + p->labels_to_cfno = hash_map::create_ggc (31); + p->labelno_to_labels = hash_map::create_ggc (31); + p->regs_ever_live = BITMAP_GGC_ALLOC (); + return p; +} + +#define TARGET_OPTION_OVERRIDE wasm_option_override +static void +wasm_option_override (void) +{ + init_machine_status = wasm_init_machine_status; +} + +void wasm_asm_init_sections (); +#define TARGET_ASM_INIT_SECTIONS wasm_asm_init_sections +bool wasm_assemble_integer (rtx x, unsigned size, int align); +#define TARGET_ASM_INTEGER wasm_assemble_integer +void wasm_assemble_decl_end (); +#define TARGET_ASM_DECL_END wasm_assemble_decl_end +void wasm_handle_import (FILE *stream, const char *name, const_tree decl); +#define TARGET_ASM_ASSEMBLE_UNDEFINED_DECL wasm_handle_import +void wasm_handle_libcall (rtx symbol); +#define TARGET_ASM_EXTERNAL_LIBCALL wasm_handle_libcall +void wasm_assemble_data_begin (FILE *stream, tree decl, const char *name, + HOST_WIDE_INT size, HOST_WIDE_INT align, + bool pub); +#define TARGET_ASM_DECLARE_CONSTANT_NAME \ + [] (FILE *stream, const char *name, const_tree, HOST_WIDE_INT size) \ + { return wasm_assemble_data_begin (stream, 0, name, size, 0, false); } + +#define TARGET_ASM_GLOBALIZE_LABEL [](FILE *, const char *) {} +#define TARGET_ASM_ASSEMBLE_VISIBILITY [](tree, int) {} +#define TARGET_ASM_CONSTRUCTOR [] (rtx, int) {} +#define TARGET_ASM_DESTRUCTOR [] (rtx, int) {} +#define TARGET_USE_LATE_PROLOGUE_EPILOGUE [] { return true; } + +#define TARGET_ASM_FILE_START wasm_asm_file_start +void wasm_asm_file_start (); +#define TARGET_ASM_FILE_END wasm_asm_file_end +void wasm_asm_file_end (); + +bool wasm_valid_punct_p (unsigned char code); +#define TARGET_PRINT_OPERAND_PUNCT_VALID_P wasm_valid_punct_p +void wasm_print_operand (FILE *stream, rtx value, int mode); +#define TARGET_PRINT_OPERAND wasm_print_operand +void wasm_output_internal_label (FILE *stream, const char *pfx, size_t no); +#define TARGET_ASM_INTERNAL_LABEL wasm_output_internal_label +#define TARGET_HAVE_NAMED_SECTIONS false + +bool wasm_regno_mode_ok (unsigned regno, machine_mode mode); +#define TARGET_HARD_REGNO_MODE_OK wasm_regno_mode_ok +bool wasm_can_change_mode_class (machine_mode from, machine_mode to, reg_class_t); +#define TARGET_CAN_CHANGE_MODE_CLASS wasm_can_change_mode_class +bool wasm_legitimate_address_p (machine_mode, rtx x, bool, code_helper); +#define TARGET_LEGITIMATE_ADDRESS_P wasm_legitimate_address_p +void wasm_mark_arg_regnos (bitmap regnos); +#define TARGET_MARK_ARG_REGNOS wasm_mark_arg_regnos + +void wasm_start_call_args (cumulative_args_t args); +#define TARGET_START_CALL_ARGS wasm_start_call_args +void wasm_call_args (cumulative_args_t args, rtx arg, tree fntype); +#define TARGET_CALL_ARGS wasm_call_args +void wasm_end_call_args (cumulative_args_t); +#define TARGET_END_CALL_ARGS wasm_end_call_args +bool wasm_pass_by_reference(cumulative_args_t, const function_arg_info &arg); +#define TARGET_PASS_BY_REFERENCE wasm_pass_by_reference +bool wasm_return_in_memory (const_tree type, const_tree fntype); +#define TARGET_RETURN_IN_MEMORY wasm_return_in_memory +#define TARGET_SPLIT_COMPLEX_ARG [] (auto ...) { return false; } + + +#define TARGET_SCALAR_MODE_SUPPORTED_P [](scalar_mode m) \ + { return default_scalar_mode_supported_p(m) && m != TImode; } + +#define TARGET_EXCEPT_UNWIND_INFO [](auto...) { return UI_NONE; } + +#define TARGET_HAVE_STRUB_SUPPORT_FOR hook_bool_tree_false +#define TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS hook_bool_void_false +#define TARGET_STRICT_ARGUMENT_NAMING [] (auto ...) { return true; } +unsigned int wasm_vararg_align (machine_mode mode, const_tree type); +#define TARGET_FUNCTION_ARG_BOUNDARY wasm_vararg_align +void wasm_function_arg_advance (cumulative_args_t, const function_arg_info &); +#define TARGET_FUNCTION_ARG_ADVANCE wasm_function_arg_advance +rtx wasm_function_value (const_tree type, const_tree ARG_UNUSED (func), bool); +#define TARGET_FUNCTION_VALUE wasm_function_value +rtx wasm_function_arg (cumulative_args_t cum_v, const function_arg_info &arg); +#define TARGET_FUNCTION_ARG wasm_function_arg +rtx wasm_function_incoming_arg (cumulative_args_t cum_v, + const function_arg_info &arg); +#define TARGET_FUNCTION_INCOMING_ARG wasm_function_incoming_arg +rtx wasm_libcall_value (machine_mode, const_rtx); +#define TARGET_LIBCALL_VALUE wasm_libcall_value + +#include "target-def.h" +gcc_target targetm = TARGET_INITIALIZER; + +#include "common/common-target-def.h" +struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER; diff --git a/gcc/config/wasm/wasm.h b/gcc/config/wasm/wasm.h new file mode 100644 index 00000000000..8adfb8d3fe4 --- /dev/null +++ b/gcc/config/wasm/wasm.h @@ -0,0 +1,307 @@ +/* WebAssembly cpu description. + Copyright (C) 1997-2025 Free Software Foundation, Inc. + Contributed by feedable. + + 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 + . */ + +#ifndef GCC_WASM_H +#define GCC_WASM_H + +#ifndef USED_FOR_TARGET +#include "statistics.h" +#include "vec.h" +#include "hash-table.h" +#include "hash-map.h" +#endif + +/* Debug */ +#define PREFERRED_DEBUGGING_TYPE NO_DEBUG +/* End debug */ + +#define CC1PLUS_SPEC "-stdlib=libc++" +#define ASM_SPEC "-r --enable-annotations %{v:-v} %{Wa,*:%*}" +#define STANDARD_STARTFILE_PREFIX_1 "/lib/wasm32-wasi/" +#define STARTFILE_SPEC "%R" STANDARD_STARTFILE_PREFIX_1 "crt1%O%s" +#define LIB_SPEC "%{!shared:%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}}" +#define LINK_SPEC "%{!o:-o a.out}" +//#define LIB_SPEC "%{!shared: -lm -lc}" + +/* Run-time target specifications. */ +#define TARGET_CPU_CPP_BUILTINS() \ + do \ + { \ + builtin_define_std ("wasm32"); \ + builtin_assert ("machine=wasm32"); \ + builtin_assert ("cpu=wasm32"); \ + cpp_define (parse_in, "__wasm32__");\ + cpp_define (parse_in, "__wasi__"); \ + } \ + while (0) + +/* End run-time target specifications. */ + +/* Regs */ +#define WASM_RETURN_REGNUM 0 +#define STACK_POINTER_REGNUM 1 +#define FRAME_POINTER_REGNUM 2 +#define ARG_POINTER_REGNUM 3 +#define STATIC_CHAIN_REGNUM 4 +#define WASM_CONTROL_POINTER_REGNUM 5 +#define WASM_BASE_POINTER_REGNUM 6 + +/* If this isn't defined, loads form $args will be performed with nested + functions */ +#define FRAME_POINTER_CFA_OFFSET(FNDECL) ((void)(FNDECL), 0) + +/* ??? IRA is a bit silly with on targets that don't do register allocation, + in that it still needs free hard regs to play with, give it some for now */ +#define REGISTER_NAMES \ + { \ + "$return", \ + "$stack", \ + "$frame", \ + "$args", \ + "$chain", \ + "$control", \ + "$base", \ + "general0", \ + "general1", \ + "general2", \ + "general3", \ + } + +#define TARGET_NO_REGISTER_ALLOCATION true +#define FIRST_PSEUDO_REGISTER 11 +#define FIXED_REGISTERS { 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 } +#define CALL_USED_REGISTERS { 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 } + +enum reg_class { NO_REGS, ALL_REGS, LIM_REG_CLASSES }; +#define REG_CLASS_NAMES { "NO_REGS", "ALL_REGS" } +#define REG_CLASS_CONTENTS { { 0x0000 }, { 0xFFFF } } +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +#define GENERAL_REGS ALL_REGS +#define REGNO_REG_CLASS(R) ALL_REGS +#define BASE_REG_CLASS ALL_REGS +#define INDEX_REG_CLASS NO_REGS + +#define REGNO_OK_FOR_BASE_P(X) true +#define REGNO_OK_FOR_INDEX_P(X) false + +#define CLASS_MAX_NREGS(class, mode) 1 + +#define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE) \ + if ((MODE) == QImode || (MODE) == HImode) \ + (MODE) = SImode; \ +/* End regs */ + +/* Calling convention */ +#define PARM_BOUNDARY 8 +#define STACK_BOUNDARY 128 +#define FUNCTION_BOUNDARY 16 +#define BIGGEST_ALIGNMENT 128 +#define STRICT_ALIGNMENT 0 + +/* Copied from elf.h and other places. We'd otherwise use + BIGGEST_ALIGNMENT and fail a number of testcases. */ +#define MAX_OFILE_ALIGNMENT (32768 * 8) + +#define FRAME_GROWS_DOWNWARD 0 +#define STACK_GROWS_DOWNWARD 1 + +#ifndef USED_FOR_TARGET +#define CUMULATIVE_ARGS wasm_cumulative_args +struct wasm_cumulative_args { + bool incoming; + vec *args = NULL; + tree type = NULL; +}; +#endif + +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \ + CUM = {false} +#define INIT_CUMULATIVE_INCOMING_ARGS(CUM, FNTYPE, LIBNAME) \ + CUM = {true} + +#define FUNCTION_ARG_REGNO_P(r) 0 +#define FUNCTION_VALUE_REGNO_P(r) 0 + +#define ELIMINABLE_REGS \ + { \ + {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM} \ + } + +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) (OFFSET) = 0 + +#define FIRST_PARM_OFFSET(FNDECL) 0 +/* We only use the stack for varargs, let's abuse that to achieve the proper + layout for the varargs buffer */ +#define ACCUMULATE_OUTGOING_ARGS 1 + +#define TRAMPOLINE_SIZE 64 +#define TRAMPOLINE_ALIGNMENT 32 +/* End calling convention */ + +/* Costs */ +#define NO_FUNCTION_CSE 1 +#define SLOW_BYTE_ACCESS 0 +#define BRANCH_COST(speed_p, predictable_p) 6 +/* End costs */ + +/* Data layout */ +#define STORE_FLAG_VALUE 1 + +#define BITS_BIG_ENDIAN 1 +#define BYTES_BIG_ENDIAN 0 +#define WORDS_BIG_ENDIAN 0 +#define UNITS_PER_WORD 8 +#define MIN_UNITS_PER_WORD 4 + +#define Pmode SImode +#define FUNCTION_MODE SImode +#define CASE_VECTOR_MODE SImode + +#define POINTER_SIZE 32 +#define INT_TYPE_SIZE 32 +#define CHAR_TYPE_SIZE 8 +#define SHORT_TYPE_SIZE 16 +#define LONG_TYPE_SIZE 32 +#define LONG_LONG_TYPE_SIZE 64 +#define DEFAULT_SIGNED_CHAR 0 +#define WCHAR_TYPE_SIZE 32 +/* ??? Need to figure out why do we have to set this in order for TI to not + appear */ +#define MAX_FIXED_MODE_SIZE 64 + +#define SIZE_TYPE "long unsigned int" +#define WCHAR_TYPE "long int" +#define PTRDIFF_TYPE "long int" +#define INTPTR_TYPE "long int" +#define UINTPTR_TYPE "long unsigned int" + +/* From bpf */ +#define INT8_TYPE "signed char" +#define INT16_TYPE "short int" +#define INT32_TYPE "int" +#define INT64_TYPE "long long int" +#define UINT8_TYPE "unsigned char" +#define UINT16_TYPE "short unsigned int" +#define UINT32_TYPE "unsigned int" +#define UINT64_TYPE "long long unsigned int" + +#define INT_LEAST8_TYPE INT8_TYPE +#define INT_LEAST16_TYPE INT16_TYPE +#define INT_LEAST32_TYPE INT32_TYPE +#define INT_LEAST64_TYPE INT64_TYPE +#define UINT_LEAST8_TYPE UINT8_TYPE +#define UINT_LEAST16_TYPE UINT16_TYPE +#define UINT_LEAST32_TYPE UINT32_TYPE +#define UINT_LEAST64_TYPE UINT64_TYPE + +#define INT_FAST8_TYPE INT8_TYPE +#define INT_FAST16_TYPE INT16_TYPE +#define INT_FAST32_TYPE INT32_TYPE +#define INT_FAST64_TYPE INT64_TYPE +#define UINT_FAST8_TYPE UINT8_TYPE +#define UINT_FAST16_TYPE UINT16_TYPE +#define UINT_FAST32_TYPE UINT32_TYPE +#define UINT_FAST64_TYPE UINT64_TYPE + +#define MOVE_MAX 8 +#define MAX_REGS_PER_ADDRESS 1 +#define LEGITIMATE_PIC_OPERAND_P(X) 1 + + +#define WORD_REGISTER_OPERATIONS 1 +#define LOAD_EXTEND_OP(M) SIGN_EXTEND +/* End data layout */ + +/* Asm */ +#define ASM_COMMENT_START ";;" +#define ASM_APP_ON "" +#define ASM_APP_OFF "" + +#define GLOBAL_ASM_OP "" + +#ifndef USED_FOR_TARGET +void wasm_generate_internal_label (char *buf, const char *pfx, size_t no); +#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM)\ + wasm_generate_internal_label (LABEL, PREFIX, NUM) +#define ASM_OUTPUT_LABEL(stream, name) \ + gcc_unreachable() + //fprintf (stream, ") ;;%s\n", name) +#define ASM_OUTPUT_ALIGN(...) + +void wasm_assemble_data_begin (FILE *stream, tree decl, const char *name, + HOST_WIDE_INT size, HOST_WIDE_INT align, + bool pub); +#define ASM_DECLARE_OBJECT_NAME(FILE, DECL, NAME) \ + wasm_assemble_data_begin (FILE, NAME, DECL, 0, 0, true); +void wasm_assemble_data_zeros (FILE *stream, tree decl, const char *name, + HOST_WIDE_INT size, HOST_WIDE_INT align, + bool pub); +#define ASM_OUTPUT_ALIGNED_DECL_COMMON(FILE, DECL, NAME, SIZE, ALIGN) \ + wasm_assemble_data_zeros (FILE, DECL, NAME, SIZE, ALIGN, true); +#define ASM_OUTPUT_ALIGNED_DECL_LOCAL(FILE, DECL, NAME, SIZE, ALIGN) \ + wasm_assemble_data_zeros (FILE, DECL, NAME, SIZE, ALIGN, 0); + +void wasm_asm_start_function (FILE *stream, tree decl, const char *name); +#define ASM_OUTPUT_FUNCTION_LABEL(stream, name, decl) \ + wasm_asm_start_function(stream, decl, name) +void wasm_asm_end_function (FILE *stream, tree decl, const char *name); +#define ASM_DECLARE_FUNCTION_SIZE(stream, name, decl) \ + wasm_asm_end_function(stream, decl, name) + +void wasm_handle_import (FILE *stream, const char *name, const_tree decl); +#define ASM_OUTPUT_EXTERNAL(stream, decl, name) \ + wasm_handle_import (stream, name, decl) + +void wasm_assemble_skip (FILE *stream, unsigned HOST_WIDE_INT len); +#define ASM_OUTPUT_SKIP(...) wasm_assemble_skip (__VA_ARGS__) +void wasm_assemble_ascii (FILE *stream, const char *data, int len); +#define ASM_OUTPUT_ASCII(...) wasm_assemble_ascii (__VA_ARGS__) +#endif + +#define HAS_INIT_SECTION +#define SUPPORTS_INIT_PRIORITY 1 +#define SUPPORTS_WEAK 1 +/* End asm */ + + +#define FUNCTION_PROFILER(file, labelno) \ + sorry_at (input_location, \ + "profiling is not yet implemented for this architecture") + +#ifndef USED_FOR_TARGET +struct cfl_hash: int_hash {}; + +struct GTY(()) machine_function +{ + vec *func_args; /* Arg list for the current function. */ + machine_mode return_mode; + bool stdarg_p; + + wasm_cumulative_args *call; + bool unproto_call_p; + hash_map *labels_to_cfno; + hash_map *labelno_to_labels; + bitmap regs_ever_live; + hash_map *saved_libcalls; +}; +#endif + +#endif /* GCC_WASM_H */ diff --git a/gcc/config/wasm/wasm.md b/gcc/config/wasm/wasm.md new file mode 100644 index 00000000000..a5f32f4228d --- /dev/null +++ b/gcc/config/wasm/wasm.md @@ -0,0 +1,495 @@ +(include "attrs.md") + +(define_insn "nop" + [(const_int 0)] + "" + "(nop)" + []) + +(define_predicate "symbol_operand" + (match_code "symbol_ref")) +(define_predicate "funcref_operand" + (match_code "symbol_ref") + { + gcc_assert (GET_CODE (op) == SYMBOL_REF); + return !SYMBOL_REF_DECL (op) || TREE_CODE (SYMBOL_REF_DECL (op)) == FUNCTION_DECL; + }) +(define_predicate "varref_operand" + (match_code "symbol_ref") + { + gcc_assert (GET_CODE (op) == SYMBOL_REF); + return TREE_CODE (SYMBOL_REF_DECL (op)) == VAR_DECL; + }) +(define_predicate "subregister_for_si_operand" + (ior (match_code "reg") (match_code "subreg")) + { + rtx x = op; + if (SUBREG_P (x)) + x = SUBREG_REG (x); + if (!REG_P (x)) + return false; + machine_mode m = GET_MODE (x); + int sign = 0; + PROMOTE_MODE (m, sign, NULL_TREE); + return m == SImode; + }) + +(define_predicate "subregister_for_di_operand" + (ior (match_code "reg") (match_code "subreg")) + { + rtx x = op; + if (SUBREG_P (x)) + x = SUBREG_REG (x); + if (!REG_P (x)) + return false; + machine_mode m = GET_MODE (x); + int sign = 0; + PROMOTE_MODE (m, sign, NULL_TREE); + return m == DImode; + }) +(define_predicate "wasm_register_operand" + (match_operand 0 "register_operand") + { + machine_mode m = GET_MODE (op); + PROMOTE_MODE (m, 0, NULL_RTX); + if (mode == TImode) + return false; + return m == wasm_real_register_mode (op); + }) +(define_predicate "wasm_call_register_operand" + (ior (match_operand 0 "wasm_register_operand") + (match_test "GET_CODE (op) == UNSPEC_VOLATILE && wasm_register_operand (XVECEXP (op, 0, 0), mode)"))) +(define_predicate "wasm_subregister_operand" + (match_operand 0 "register_operand") + { + machine_mode m = wasm_real_register_mode (op); + return mode != TImode; + }) + +(define_predicate "immediate_or_register_operand" + (ior (match_operand 0 "immediate_operand") + (match_operand 0 "register_operand"))) + +(define_predicate "wasm_offset_operand" + (match_operand 0 "const_int_operand") + { + return INTVAL (op) >= 0; + }) + + (define_expand "mov" + [(set (match_operand:QHSDISDF 0 "nonimmediate_operand" "") + (match_operand:QHSDISDF 1 "general_operand" ""))] + "" + { + if (wasm_expand_mov (operands[0], operands[1], mode)) + DONE; + else FAIL; + }) + +(define_expand "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" +{ +}) + +(define_predicate "call_operation" + (match_code "parallel") +{ + int arg_end = XVECLEN (op, 0); + + for (int i = 1; i < arg_end; i++) + { + rtx elt = XVECEXP (op, 0, i); + + if (GET_CODE (elt) != USE || !REG_P (XEXP (elt, 0))) + return false; + } + return true; +}) +(define_insn "speculation_barrier" [(const_int 0)] "" "") +(define_expand "prologue" + [(const_int 777)] + "" + { + wasm_expand_prologue (); + DONE; + }) +(define_expand "epilogue" + [(const_int 777)] + "" + { + wasm_expand_epilogue (); + emit_jump_insn (gen_return ()); + DONE; + }) + +;; Calls +(define_expand "call" + [(call (match_operand:SI 0 "memory_operand" "m") + (match_operand:SI 1 "" ""))] + "" + { + wasm_expand_call(NULL_RTX, operands[0], operands[1]); + DONE; + }) + +(define_expand "call_value" + [(set (match_operand 0 "register_operand" "=r") + (call (match_operand:SI 1 "memory_operand" "m") + (match_operand:SI 2 "" "")))] + "" + { + wasm_expand_call(operands[0], operands[1], operands[2]); + DONE; + }) + +(define_insn "*call_internal_indirect" + [(match_parallel 2 "call_operation" + [(call (mem:SI (match_operand:P 0 "wasm_call_register_operand")) + (match_operand 1))])] + "" + "(call_indirect (param%T2) (result)%A2 (%M0.get %0))") + +(define_insn "*call_value_internal_indirect" + [(match_parallel 3 "call_operation" + [(set (match_operand 0 "wasm_register_operand" "") + (call (mem:SI (match_operand:P 1 "wasm_call_register_operand")) + (match_operand 2)))])] + "" + "(%M0.set %0 (call_indirect (param%T3) (result%T0)%A3 (%M1.get %1)))") + +(define_insn "*call_internal" + [(match_parallel 2 "call_operation" + [(call (mem:SI (match_operand:P 0 "funcref_operand")) + (match_operand 1))])] + "" + "(call %0%A2)") + +(define_insn "*call_value_internal" + [(match_parallel 3 "call_operation" + [(set (match_operand 0 "wasm_register_operand" "") + (call (mem:SI (match_operand:P 1 "funcref_operand")) + (match_operand 2)))])] + "" + "(%M0.set %0 (call %1%A3))") + +;; Literals +(define_insn "*local_const" + [(set (match_operand:QHSDI 0 "register_operand") + (match_operand:QHSDI 1 "const_int_operand" ""))] + "" + "(%M0.set %0 (.const %1))") + +(define_insn "*local_const" + [(set (match_operand:F 0 "register_operand") + (match_operand:F 1 "immediate_operand" ""))] + "" + "(%M0.set %0 (.const %1))") + +;; Address taking +(define_insn "*local_const_addr" + [(set (match_operand:SI 0 "register_operand") + (match_operand:SI 1 "immediate_operand"))] + "" + "(%M0.set %0 %i1)") + +;; Moves +(define_insn "*local_move" + [(set (match_operand:QHSDISDF 0 "wasm_subregister_operand" "") + (match_operand:QHSDISDF 1 "wasm_subregister_operand" ""))] + "wasm_real_register_mode (operands[0]) == wasm_real_register_mode (operands[1])" + "(%M0.set %0 (%M1.get %1))") + +(define_insn "*local_move" + [(set (match_operand:QHSDI 0 "subregister_for_di_operand" "") + (match_operand:QHSDI 1 "subregister_for_si_operand" ""))] + "" + "(%M0.set %0 (i64.extend_i32_s (%M1.get %1)))") + +(define_insn "*local_move" + [(set (match_operand:QHSDI 0 "subregister_for_si_operand" "") + (match_operand:QHSDI 1 "subregister_for_di_operand" ""))] + "" + "(%M0.set %0 (i32.wrap_i64 (%M1.get %1)))") + +;; Comparisons +(define_expand "cstore4" + [(set (match_operand:SI 0 "register_operand" "") + (match_operator 1 "comparison_operator" + [(match_operand:REGF 2 "general_operand" "") + (match_operand:REGF 3 "general_operand" "")]))] + "" + { + wasm_expand_compare (mode, operands[0], operands[1]); + DONE; + }) + +(define_insn "*test_" + [(set (match_operand:SI 0 "wasm_register_operand") + (frelop:SI (match_operand:F 1 "wasm_register_operand") + (match_operand:F 2 "wasm_register_operand")))] + "" + "(%M0.set %0 (. (%M1.get %1) (%M2.get %2)))") + +(define_insn "*test_" + [(set (match_operand:SI 0 "wasm_register_operand") + (irelop:SI (match_operand:REG 1 "wasm_register_operand") + (match_operand:REG 2 "wasm_register_operand")))] + "" + "(%M0.set %0 (. (%M1.get %1) (%M2.get %2)))") + +;; Control flow +(define_insn "return" [(return)] "" "(return%#)") +(define_insn "trap" [(trap_if (const_int 1) (const_int 0))] "" "(unreachable)") + +(define_expand "cbranch4" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand:REGF 1 "general_operand" "") + (match_operand:REGF 2 "general_operand" "")]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "" + { + rtx cond = gen_reg_rtx (SImode); + emit_insn (gen_cstore4 (cond, operands[0], operands[1], operands[2])); + emit_jump_insn (gen_branch (operands[3], cond)); + DONE; + }) + +(define_insn "branch" + [(set (pc) + (if_then_else (ne (match_operand:SI 1 "wasm_register_operand" "") + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "(br_if $control (local.set $control (i32.const %l0)) (%M1.get %1))") + +(define_insn "*jump" + [(set (pc) (label_ref (match_operand 0 "" "")))] + "" + "(br $control (local.set $control (i32.const %l0)))") + +;; Int memops +(define_insn "*store" + [(set (match_operand:REGF 0 "memory_operand") + (match_operand:REGF 1 "wasm_register_operand"))] + "" + "(.store %m0 %i1)") + +(define_insn "*load" + [(set (match_operand:REGF 0 "wasm_register_operand") + (match_operand:REGF 1 "memory_operand"))] + "" + "(%o0 (.load %m1))") + +;; I64 subreg memops +(define_insn "*store" + [(set (match_operand:SUBREGDI 0 "memory_operand") + (match_operand:SUBREGDI 1 "subregister_for_di_operand"))] + "" + "(i64.store %m0 %i1)") + +(define_insn "*load" + [(set (match_operand:SUBREGDI 0 "subregister_for_di_operand") + (match_operand:SUBREGDI 1 "memory_operand"))] + "" + "(%o0 (i64.load_s %m1))") + +;; I32 subreg memops +(define_insn "*store" + [(set (match_operand:SUBREGSI 0 "memory_operand" "") + (match_operand:SUBREGSI 1 "subregister_for_si_operand" ""))] + "" + "(i32.store %m0 %i1)") + +(define_insn "*load" + [(set (match_operand:SUBREGSI 0 "subregister_for_si_operand") + (match_operand:SUBREGSI 1 "memory_operand"))] + "" + "(%o0 (i32.load_s %i1))") + +;; Binary integer +(define_expand "3" + [(set (match_operand:REG 0 "register_operand" "") + (ibinop:REG (match_operand:REG 1 "immediate_or_register_operand" "") + (match_operand:REG 2 "immediate_or_register_operand" "")))] + "" + { + if (!subregister_for__operand(operands[1], mode)) + operands[1] = force_reg (mode, operands[1]); + if (!subregister_for__operand(operands[2], mode)) + operands[2] = force_reg (mode, operands[2]); + }) + +(define_insn "*3" + [(set (match_operand:REG 0 "wasm_register_operand") + (ibinop:REG (match_operand:REG 1 "wasm_register_operand") + (match_operand:REG 2 "wasm_register_operand")))] + "" + "(%M0.set %0 (. (%M1.get %1) (%M2.get %2)))") + +;; Unary integer +(define_expand "2" + [(set (match_operand:REG 0 "register_operand") + (iunop:REG (match_operand:REG 1 "immediate_or_register_operand")))] + "" + { + if (!subregister_for__operand(operands[1], mode)) + operands[1] = force_reg (mode, operands[1]); + }) + +(define_insn "*2" + [(set (match_operand:REG 0 "wasm_register_operand") + (iunop:REG (match_operand:REG 1 "wasm_register_operand")))] + "" + "(%M0.set %0 (. (%M1.get %1)))") + +;; Binary float +(define_expand "3" + [(set (match_operand:F 0 "register_operand") + (fbinop:F (match_operand:F 1 "immediate_or_register_operand") + (match_operand:F 2 "immediate_or_register_operand")))] + "" + { + operands[1] = force_reg (mode, operands[1]); + operands[2] = force_reg (mode, operands[2]); + }) + +(define_insn "*3" + [(set (match_operand:F 0 "wasm_register_operand") + (fbinop:F (match_operand:F 1 "wasm_register_operand") + (match_operand:F 2 "wasm_register_operand")))] + "" + "(%M0.set %0 (. (%M1.get %1) (%M2.get %2)))") + +;; Unary float +(define_expand "2" + [(set (match_operand:F 0 "register_operand") + (funop:F (match_operand:F 1 "immediate_or_register_operand")))] + "" + { + operands[1] = force_reg (mode, operands[1]); + }) + +(define_insn "*2" + [(set (match_operand:F 0 "wasm_register_operand") + (funop:F (match_operand:F 1 "wasm_register_operand")))] + "" + "(%M0.set %0 (. (%M1.get %1)))") + +;; Integer conv +(define_expand "2" + [(set (match_operand:QHSDI 0 "wasm_subregister_operand") + (iconvop:QHSDI (match_operand:QHSDI2 1 "wasm_subregister_operand")))] + "" + { + wasm_expand_conv (operands[0], operands[1], , false); + DONE; + }) + +(define_insn "*extend_si_" + [(set (match_operand:QHSDI 0 "register_operand") + (sign_extend:QHSDI (match_operand:SUBREGSI 1 "register_operand")))] + "wasm_real_register_mode (operands[0]) == SImode && wasm_real_register_mode (operands[1]) == SImode" + "(%M0.set %0 (i32.extend_s (%M1.get %1)))") + +(define_insn "*extend_di_" + [(set (match_operand:QHSDI 0 "register_operand") + (sign_extend:QHSDI (match_operand:SUBREGDI 1 "register_operand")))] + "wasm_real_register_mode (operands[0]) == DImode && wasm_real_register_mode (operands[1]) == DImode" + "(%M0.set %0 (i64.extend_s (%M1.get %1)))") +(define_insn "*extend_sidi" + [(set (match_operand:DI 0 "register_operand") + (sign_extend:DI (match_operand:SI 1 "register_operand")))] + "REG_P (operands[0]) && REG_P (operands[1])" + "(%M0.set %0 (i64.extend_i32_s (%M1.get %1)))") +(define_insn "*uextend_sidi" + [(set (match_operand:DI 0 "register_operand") + (zero_extend:DI (match_operand:SI 1 "register_operand")))] + "REG_P (operands[0]) && REG_P (operands[1])" + "(%M0.set %0 (i64.extend_i32_u (%M1.get %1)))") +(define_insn "*truncate_disi" + [(set (match_operand:SI 0 "register_operand") + (truncate:SI (match_operand:DI 1 "register_operand")))] + "REG_P (operands[0]) && REG_P (operands[1])" + "(%M0.set %0 (i32.wrap_i64 (%M1.get %1)))") + +;; Float conv +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "wasm_register_operand") + (float_extend:DF (match_operand:SF 1 "wasm_register_operand")))] + "" + "(%M0.set %0 (f64.promote_f32 (%M1.get %1)))") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "wasm_register_operand") + (float_truncate:SF (match_operand:DF 1 "wasm_register_operand")))] + "" + "(%M0.set %0 (f32.demote_f64 (%M1.get %1)))") + +;; Float -> int conv +(define_insn "fix_trunc2" + [(set (match_operand:REG 0 "wasm_register_operand") + (fix:REG (match_operand:F 1 "wasm_register_operand")))] + "" + "(%M0.set %0 (.trunc_sat__s (%M1.get %1)))") + +(define_insn "fixuns_trunc2" + [(set (match_operand:REG 0 "wasm_register_operand") + (unsigned_fix:REG (match_operand:F 1 "wasm_register_operand")))] + "" + "(%M0.set %0 (.trunc_sat__u (%M1.get %1)))") + +;; Int -> float conv +(define_insn "float2" + [(set (match_operand:F 0 "wasm_register_operand") + (float:F (match_operand:REG 1 "wasm_register_operand")))] + "" + "(%M0.set %0 (.convert__s (%M1.get %1)))") + +;; Rectify int <-> float cast +;;(define_insn "floatuns2" +;; [(set (match_operand:F 0 "register_operand") +;; (unsigned_float:F (match_operand:REG 1 "register_operand")))] +;; "" +;; "(%M0.set %0 (.convert__u (%M1.get %1)))") +;; +;;(define_subst "swap_subreg_s_" +;; [(set (match_operand:REGF 0) +;; (subreg:REGF (match_operand: 1) 0))] +;; "" +;; [(set (subreg: (match_dup 0) 0) +;; (match_dup 1))]) +;;(define_subst_attr "swap_subregsi" "swap_subreg_s_si" "_from" "_to") +;;(define_subst_attr "swap_subregdi" "swap_subreg_s_di" "_from" "_to") +;;(define_subst_attr "swap_subregsf" "swap_subreg_s_sf" "_from" "_to") +;;(define_subst_attr "swap_subregdf" "swap_subreg_s_df" "_from" "_to") + +;; Float -> int cast +(define_insn "*cast" + [(set (match_operand:REG 0 "wasm_register_operand") + (subreg:REG (match_operand: 1 "wasm_register_operand") 0))] + "" + "(%M0.set %0 (.reinterpret_ (%M1.get %1)))") + +(define_insn "*cast" + [(set (subreg: (match_operand:REG 0 "wasm_register_operand") 0) + (match_operand: 1 "wasm_register_operand"))] + "" + "(%M0.set %0 (.reinterpret_ (%M1.get %1)))") + +;; Int -> float cast +(define_insn "*cast" + [(set (match_operand: 0 "wasm_register_operand") + (subreg: (match_operand:REG 1 "wasm_register_operand") 0))] + "" + "(%M0.set %0 (.reinterpret_ (%M1.get %1)))") + +(define_insn "*cast" + [(set (subreg:REG (match_operand: 0 "wasm_register_operand") 0) + (match_operand:REG 1 "wasm_register_operand"))] + "" + "(%M0.set %0 (.reinterpret_ (%M1.get %1)))") \ No newline at end of file diff --git a/libgcc/config.host b/libgcc/config.host index ac10ccc4340..61404f2a18d 100644 --- a/libgcc/config.host +++ b/libgcc/config.host @@ -1574,6 +1574,11 @@ nvptx-*) tmake_file="$tmake_file nvptx/t-nvptx" extra_parts="crt0.o" ;; +wasm*-*-*) + tmake_file="$tmake_file wasm/t-wasm" + # unwind_header=config/no-unwind.h + # extra_parts="crt0.o" + ;; *) echo "*** Configuration ${host} not supported" 1>&2 exit 1 diff --git a/libgcc/config/wasm/t-wasm b/libgcc/config/wasm/t-wasm new file mode 100644 index 00000000000..bd09d3c0dbf --- /dev/null +++ b/libgcc/config/wasm/t-wasm @@ -0,0 +1,4 @@ +LIB2ADDEH= + +# Debug information is not yet supported +LIBGCC2_DEBUG_CFLAGS = -g0 \ No newline at end of file From patchwork Tue May 5 22:30:46 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: feedable X-Patchwork-Id: 134517 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 906B44BA2E09 for ; Tue, 5 May 2026 22:34:27 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 906B44BA2E09 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20251104 header.b=FOZXJXA5 X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wm1-x32e.google.com (mail-wm1-x32e.google.com [IPv6:2a00:1450:4864:20::32e]) by sourceware.org (Postfix) with ESMTPS id 3C5664BA2E0D for ; Tue, 5 May 2026 22:31:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3C5664BA2E0D Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 3C5664BA2E0D Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2a00:1450:4864:20::32e ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778020277; cv=none; b=lW2YnFf8tyiLhMV/EgWyoayExy6IrUDwMi44zDTXV/tZx2AKtxwX8Zb71t39IQC2oCwJacmc7qo4W3pR6nQZHtmQ9CRcZW1nVBRzg0BcGFDF0S614gYLZs92voLngIiKuerad2rIl6ZMCo5c0YSVvG5XBqhpfYmldCR1groqQUY= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778020277; c=relaxed/simple; bh=5ihIGhcAYtXc2da7xDCcE5X541nEOF+UjkgF2bGhd4U=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=LGf3pQC4zgG4hm885QR9ERpqGtsEzKTKmrxnaGxwupbamIn3y4P8NFaAzmgTe4aiTGNEhbAWk84E41LceMg3c+bepZzl99iVvAmLryX9tTk4JtZZ79uV9LbTj8VOXfs6aDiMcJ2KVJAK80BVBDG/EqjQNOKDWsq/JS4TAUSzbhg= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3C5664BA2E0D Received: by mail-wm1-x32e.google.com with SMTP id 5b1f17b1804b1-48d102471a4so24847795e9.2 for ; Tue, 05 May 2026 15:31:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778020276; x=1778625076; darn=gcc.gnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=laxrzMkcNXhf8cbblkYZKjc0V2IWri6haJbLrud1ABg=; b=FOZXJXA5kjez27Nr/4sumgycCeV9cT2v1Vv1XlPzrgP1+nsgU6HWD82SaUvM7Qtwqm cbDrcF4IUzV0y0mTKeHLzOTYaL1aqlHLEQCejDb6Pk3Lihzwf3lqjWaVsRUAwmh6mwt3 W2pR9ViL7zanMOXP/8YBWJgsUawEhPTU1HxjXtfmXkYX+ySpEt4DtSuTClqYuI8X2MGP C8ONNA+VRKO1x8gBWoQC0gGQD8vhMvemF9ZTj4nF3wiDfGwIYsEjzEvkaN2amXIXB763 Vn3VX9QFIBhagovhrZR0dAGHsagOJUQMEzJwsHBDUldWc3jD/2zQdcUMlG7zrBFWWq1e OsAg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778020276; x=1778625076; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=laxrzMkcNXhf8cbblkYZKjc0V2IWri6haJbLrud1ABg=; b=Td4ewNUh2oU7QvEXSl6rRGExvr/rCi4DrzWt6Nj7wQFKESgKYv4UUfptzqccpyJzrz +wj3816IWVY6Ajfqd4VEqQ7p6edaDfkXoMctA2WBCeWwqGiPP0FX8K0MZnONoMxmdyHF 96BgqFLHSAmkulGIBSCZc8odIEKVbl7uFT51AVNH/dirRiHTuKfLq8i/z9Cmz8QufI6p mfmsR9dM0jYiu+tuC3HQwC+xIOhu1Tfecsrvq+mXi+BRtHowW3bX0mSJdkxul4asySbz NF/rnInBEB0uiEh4rVJmTt773ASRRjrBwmWsmQRp8cmtbs8dK1l2qS24ksILmHnyNZiS Td1Q== X-Gm-Message-State: AOJu0Ywt3v314tgI+NkhWAcMPla8fyQ7LH97axaV+zyxZssn8GTLf9dE 7YEC7v5NGTZKqxtsPNDVx5dW7tqilOde27gOwD64Zf7RrIh2VKeHqmLEGHSloA== X-Gm-Gg: AeBDietUfTb5u0jOCGQlaR2v8CnLYHHr9rPOTnpMM16RU/68jfVKA94JxlL+LNz67XS J44SIZIQiiXJb/vC2nov3fkwjuck4jRNdW60K4elhYVevQWIUfBDNU9+evX1zaGxHNllhp85Mld 5ewF3ehs38vwIevrFZ0B7Lmgqf/fcvpWhJqGMhKFT81ZCsFOr0vs8eRnpO8OAENbbziR7CkJ4Nn eNIDRkRiyxc3IV8GQ4zpA38ELh2F0ZSZsvBGcPkVQFvaAC2XTDaW3Jr2Uu/af2V/KU/rJ6n/1AY oXCye7a1mdUofxM8sDrsEZII9pf/x0USZTn5HlQQ7cTG3ErmLZK48g0GI1QHCDFmDcmwoZfbEwB DUo7DGESqbpqYcV+Icy4HOCTkguHv34EZn5vgNbiq3VqVEMZNgl+mjf3lrle6cbWs+65JmHWE7E BvdAgsLlEgqtcKWJ/cVLsHv9wj6Av+YMkOAyXUxPBMvDhgbZmAOPwlObzIuX4= X-Received: by 2002:a05:600c:4f53:b0:48a:5565:ec3d with SMTP id 5b1f17b1804b1-48e51f44577mr17173205e9.22.1778020275588; Tue, 05 May 2026 15:31:15 -0700 (PDT) Received: from 7a38.moduleworks.com ([2a02:8308:900b:fc00:1c70:a43b:cde8:2b29]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-48e53559d8esm79055e9.9.2026.05.05.15.31.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 May 2026 15:31:14 -0700 (PDT) From: feedable To: gcc-patches@gcc.gnu.org Cc: feedable Subject: [RFC PATCH 3/3] wasm: Adjust tests Date: Wed, 6 May 2026 01:30:46 +0300 Message-ID: <20260505223045.347444-5-feedabl3@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505223045.347444-2-feedabl3@gmail.com> References: <20260505223045.347444-2-feedabl3@gmail.com> MIME-Version: 1.0 X-Spam-Status: No, score=-10.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_ENVFROM_END_DIGIT, FREEMAIL_FROM, GIT_PATCH_0, POISEN_SPAM_PILL, POISEN_SPAM_PILL_1, POISEN_SPAM_PILL_3, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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~patchwork=sourceware.org@gcc.gnu.org This patch marks tests that are not supported by the new backend skipped. gcc/testsuite/ChangeLog: * c-c++-common/analyzer/errno-1.c: Mark skipped for wasm (wasi-libc). * c-c++-common/analyzer/isatty-1.c: Likewise. * gcc.dg/analyzer/fd-access-mode-target-headers.c: Likewise. * gcc.dg/analyzer/fd-mktemp-family.c: Likewise. * gcc.dg/analyzer/mkdtemp-1.c: Likewise. * gcc.dg/analyzer/mkostemp-1.c: Likewise. * gcc.dg/analyzer/mkostemps-1.c: Likewise. * gcc.dg/analyzer/mkstemp-1.c: Likewise. * gcc.dg/analyzer/mkstemps-1.c: Likewise. * gcc.dg/analyzer/mktemp-1.c: Likewise. * gcc.dg/builtin-alloc-size.c: Likewise. * gcc.dg/builtins-nonnull.c: Likewise. * gcc.c-torture/compile/20000804-1.c: Mark skipped for wasm (register alllocation). * gcc.c-torture/compile/pr55921.c: Likewise. * gcc.c-torture/execute/20030222-1.c: Likewise. * gcc.dg/lower-subreg-1.c: Likewise. * gcc.c-torture/compile/pr60655-1.c: Mark skipped for wasm (named sections). * gcc.dg/array-quals-1.c: Likewise. * gcc.dg/pr49551.c: Likewise. * gcc.dg/profile-info-section.c: Mark skipped for wasm (profiling). * gcc.misc-tests/gcov-23.c: Likewise. * gcc.misc-tests/gcov.exp: Likewise. * gcc.c-torture/execute/builtins/20010124-1.x: Mark skipped for wasm (asm decls). * gcc.c-torture/execute/ieee/bfloat16-builtin-issignaling-1.c: Mark skipped for wasm (no signaling nans). * gcc.c-torture/execute/ieee/builtin-issignaling-1.c: Likewise. * gcc.c-torture/execute/ieee/float128-builtin-issignaling-1.c: Likewise. * gcc.c-torture/execute/ieee/float128x-builtin-issignaling-1.c: Likewise. * gcc.c-torture/execute/ieee/float16-builtin-issignaling-1.c: Likewise. * gcc.c-torture/execute/ieee/float32-builtin-issignaling-1.c: Likewise. * gcc.c-torture/execute/ieee/float32x-builtin-issignaling-1.c: Likewise. * gcc.c-torture/execute/ieee/float64-builtin-issignaling-1.c: Likewise. * gcc.c-torture/execute/ieee/float64x-builtin-issignaling-1.c: Likewise. * gcc.c-torture/execute/pr67037-1.c: Fork from pr67037.c. * gcc.c-torture/execute/pr67037.c: Mark skipped for wasm (unprotoyped call). * gcc.dg/builtin-apply5.c: Likewise. * gcc.dg/20060410.c: Mark skipped for wasm (output format). * gcc.dg/charset/function.c: Likewise. * gcc.dg/ipa/symver1.c: Likewise. * gcc.dg/pr28755.c: Likewise. * gcc.dg/attr-weakref-1.c: Mark skipped for wasm (weakrefs). * gcc.dg/builtin-prefetch-1.c: Mark skipped for wasm (no prefetch). * gcc.dg/builtins-config.h: Mark wasm as not supporting the full C99 runtime. * gcc.dg/c23-stdint-1.c: Likewise. * gcc.dg/c99-stdint-1.c: Likewise. * gcc.dg/c99-stdint-2.c: Likewise. * gcc.dg/c99-stdint-7.c: Likewise. * gcc.dg/c99-stdint-8.c: Likewise. * gcc.dg/format/pr78304.c: Likewise. * gcc.dg/stdint-width-1.c: Likewise. * gcc.dg/stdint-width-2.c: Likewise. * gcc.dg/pch/valid-1.c: Mark skipped for wasm (debug info). * gcc.dg/cpp/escape-3.i: Likewise. * gcc.dg/pr115066.c: Likewise. * gcc.dg/tls/thr-cse-1.c: Mark skipped for wasm (threads). * gcc.misc-tests/options.exp: Mark skipped for wasm (WABT commandline). * lib/file-format.exp: Introduce wasm object file format. * lib/scanasm.exp: Likewise. * lib/target-supports.exp: Disable unsupported functionality. --- gcc/testsuite/c-c++-common/analyzer/errno-1.c | 2 + .../c-c++-common/analyzer/isatty-1.c | 1 + .../gcc.c-torture/compile/20000804-1.c | 1 + gcc/testsuite/gcc.c-torture/compile/pr55921.c | 1 + .../gcc.c-torture/compile/pr60655-1.c | 2 +- .../gcc.c-torture/execute/20030222-1.c | 2 +- .../execute/builtins/20010124-1.x | 2 +- .../ieee/bfloat16-builtin-issignaling-1.c | 1 + .../execute/ieee/builtin-issignaling-1.c | 1 + .../ieee/float128-builtin-issignaling-1.c | 1 + .../ieee/float128x-builtin-issignaling-1.c | 1 + .../ieee/float16-builtin-issignaling-1.c | 1 + .../ieee/float32-builtin-issignaling-1.c | 1 + .../ieee/float32x-builtin-issignaling-1.c | 1 + .../ieee/float64-builtin-issignaling-1.c | 1 + .../ieee/float64x-builtin-issignaling-1.c | 1 + .../gcc.c-torture/execute/pr67037-1.c | 56 +++++++++++++++++++ gcc/testsuite/gcc.c-torture/execute/pr67037.c | 4 +- gcc/testsuite/gcc.dg/20060410.c | 2 +- .../analyzer/fd-access-mode-target-headers.c | 1 + .../gcc.dg/analyzer/fd-mktemp-family.c | 1 + gcc/testsuite/gcc.dg/analyzer/mkdtemp-1.c | 1 + gcc/testsuite/gcc.dg/analyzer/mkostemp-1.c | 1 + gcc/testsuite/gcc.dg/analyzer/mkostemps-1.c | 1 + gcc/testsuite/gcc.dg/analyzer/mkstemp-1.c | 1 + gcc/testsuite/gcc.dg/analyzer/mkstemps-1.c | 1 + gcc/testsuite/gcc.dg/analyzer/mktemp-1.c | 1 + gcc/testsuite/gcc.dg/array-quals-1.c | 1 + gcc/testsuite/gcc.dg/attr-weakref-1.c | 3 + gcc/testsuite/gcc.dg/builtin-alloc-size.c | 1 + gcc/testsuite/gcc.dg/builtin-apply5.c | 1 + gcc/testsuite/gcc.dg/builtin-prefetch-1.c | 3 +- gcc/testsuite/gcc.dg/builtins-config.h | 2 + gcc/testsuite/gcc.dg/builtins-nonnull.c | 1 + gcc/testsuite/gcc.dg/c23-stdint-1.c | 1 + gcc/testsuite/gcc.dg/c99-stdint-1.c | 1 + gcc/testsuite/gcc.dg/c99-stdint-2.c | 1 + gcc/testsuite/gcc.dg/c99-stdint-7.c | 3 + gcc/testsuite/gcc.dg/c99-stdint-8.c | 1 + gcc/testsuite/gcc.dg/charset/function.c | 2 +- gcc/testsuite/gcc.dg/cpp/escape-3.i | 1 + gcc/testsuite/gcc.dg/format/pr78304.c | 1 + gcc/testsuite/gcc.dg/ipa/symver1.c | 2 +- gcc/testsuite/gcc.dg/lower-subreg-1.c | 2 +- gcc/testsuite/gcc.dg/pch/valid-1.c | 1 + gcc/testsuite/gcc.dg/pr115066.c | 2 +- gcc/testsuite/gcc.dg/pr28755.c | 2 +- gcc/testsuite/gcc.dg/pr49551.c | 2 +- gcc/testsuite/gcc.dg/profile-info-section.c | 1 + gcc/testsuite/gcc.dg/stdint-width-1.c | 1 + gcc/testsuite/gcc.dg/stdint-width-2.c | 1 + gcc/testsuite/gcc.dg/tls/thr-cse-1.c | 2 +- gcc/testsuite/gcc.misc-tests/gcov-23.c | 1 + gcc/testsuite/gcc.misc-tests/gcov.exp | 4 ++ gcc/testsuite/gcc.misc-tests/options.exp | 9 ++- gcc/testsuite/lib/file-format.exp | 8 ++- gcc/testsuite/lib/scanasm.exp | 2 + gcc/testsuite/lib/target-supports.exp | 39 ++++++++++--- 58 files changed, 166 insertions(+), 26 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/execute/pr67037-1.c diff --git a/gcc/testsuite/c-c++-common/analyzer/errno-1.c b/gcc/testsuite/c-c++-common/analyzer/errno-1.c index 6b9d28c1079..39fa4aa58cd 100644 --- a/gcc/testsuite/c-c++-common/analyzer/errno-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/errno-1.c @@ -1,3 +1,5 @@ +/* { dg-skip-if "wasi-libc doesn't work well with analyzer" { wasm*-*-* } } */ + #include #include "analyzer-decls.h" diff --git a/gcc/testsuite/c-c++-common/analyzer/isatty-1.c b/gcc/testsuite/c-c++-common/analyzer/isatty-1.c index c5d376da498..af4ba4721d6 100644 --- a/gcc/testsuite/c-c++-common/analyzer/isatty-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/isatty-1.c @@ -1,5 +1,6 @@ /* { dg-skip-if "" { powerpc*-*-aix* } } */ /* { dg-skip-if "" { "avr-*-*" } } */ +/* { dg-skip-if "" { "wasm*-*-*" } } */ #include #include "../../gcc.dg/analyzer/analyzer-decls.h" diff --git a/gcc/testsuite/gcc.c-torture/compile/20000804-1.c b/gcc/testsuite/gcc.c-torture/compile/20000804-1.c index c6f6497b7a7..dbc2e8d3a21 100644 --- a/gcc/testsuite/gcc.c-torture/compile/20000804-1.c +++ b/gcc/testsuite/gcc.c-torture/compile/20000804-1.c @@ -7,6 +7,7 @@ /* { dg-xfail-if "Inconsistent constraint on asm" { csky-*-* } { "-O0" } { "" } } */ /* { dg-xfail-if "Inconsistent constraint on asm" { bpf-*-* } { "-O0" } { "" } } */ /* { dg-xfail-if "" { h8300-*-* } } */ +/* { dg-skip-if "" { wasm*-*-* } } */ /* { dg-require-stack-size "99*4+16" } */ /* { dg-additional-options "-std=gnu89" } */ diff --git a/gcc/testsuite/gcc.c-torture/compile/pr55921.c b/gcc/testsuite/gcc.c-torture/compile/pr55921.c index cf9084e33f0..1c14284067e 100644 --- a/gcc/testsuite/gcc.c-torture/compile/pr55921.c +++ b/gcc/testsuite/gcc.c-torture/compile/pr55921.c @@ -1,6 +1,7 @@ /* PR tree-optimization/55921 */ /* { dg-skip-if "Not enough registers" { "pdp11-*-*" } } */ /* { dg-skip-if "exceeds eBPF stack limit" { bpf-*-* } } */ +/* { dg-skip-if "" { wasm*-*-* } } */ typedef union { diff --git a/gcc/testsuite/gcc.c-torture/compile/pr60655-1.c b/gcc/testsuite/gcc.c-torture/compile/pr60655-1.c index 6911e0d278e..1b0d53c8c2d 100644 --- a/gcc/testsuite/gcc.c-torture/compile/pr60655-1.c +++ b/gcc/testsuite/gcc.c-torture/compile/pr60655-1.c @@ -1,4 +1,4 @@ -/* { dg-options "-fdata-sections" { target { { ! { { hppa*-*-hpux* } && { ! lp64 } } } && { ! "nvptx-*-* pdp11-*-*" } } } } */ +/* { dg-options "-fdata-sections" { target { { ! { { hppa*-*-hpux* } && { ! lp64 } } } && { ! "nvptx-*-* pdp11-*-* wasm*-*-*" } } } } */ typedef unsigned char unit; typedef unit *unitptr; diff --git a/gcc/testsuite/gcc.c-torture/execute/20030222-1.c b/gcc/testsuite/gcc.c-torture/execute/20030222-1.c index d619b8159b4..c8a73d4de3c 100644 --- a/gcc/testsuite/gcc.c-torture/execute/20030222-1.c +++ b/gcc/testsuite/gcc.c-torture/execute/20030222-1.c @@ -3,7 +3,7 @@ succeeded at all. We use volatile to make sure the long long is actually truncated to int, in case a single register is wide enough for a long long. */ -/* { dg-skip-if "asm requires register allocation" { nvptx-*-* } } */ +/* { dg-skip-if "asm requires register allocation" { nvptx-*-* wasm*-*-* } } */ #include void abort (void); diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/20010124-1.x b/gcc/testsuite/gcc.c-torture/execute/builtins/20010124-1.x index c38970d40c0..864eef6b779 100644 --- a/gcc/testsuite/gcc.c-torture/execute/builtins/20010124-1.x +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/20010124-1.x @@ -1,6 +1,6 @@ load_lib target-supports.exp -if [istarget "nvptx-*-*"] { +if { [istarget "nvptx-*-*"] || [istarget "wasm*-*-*"] } { # This test uses memcpy for block move in the same file as it # defines it. The two decls are not the same, by design, and we # end up emitting a definition of memcpy, along with a .extern diff --git a/gcc/testsuite/gcc.c-torture/execute/ieee/bfloat16-builtin-issignaling-1.c b/gcc/testsuite/gcc.c-torture/execute/ieee/bfloat16-builtin-issignaling-1.c index 0e428db792b..f5f06008bf5 100644 --- a/gcc/testsuite/gcc.c-torture/execute/ieee/bfloat16-builtin-issignaling-1.c +++ b/gcc/testsuite/gcc.c-torture/execute/ieee/bfloat16-builtin-issignaling-1.c @@ -5,6 +5,7 @@ /* { dg-add-options ieee } */ /* { dg-require-effective-target bfloat16_runtime } */ /* { dg-additional-options "-fsignaling-nans" } */ +/* { dg-skip-if "WASM does not have signaling NaNs" { wasm*-*-* } } */ /* Workaround for PR57484 on ia32: */ /* { dg-additional-options "-msse2 -mfpmath=sse" { target { ia32 && sse2_runtime } } } */ diff --git a/gcc/testsuite/gcc.c-torture/execute/ieee/builtin-issignaling-1.c b/gcc/testsuite/gcc.c-torture/execute/ieee/builtin-issignaling-1.c index 60125b2b656..4e47ed2e1e7 100644 --- a/gcc/testsuite/gcc.c-torture/execute/ieee/builtin-issignaling-1.c +++ b/gcc/testsuite/gcc.c-torture/execute/ieee/builtin-issignaling-1.c @@ -1,6 +1,7 @@ /* { dg-do run } */ /* { dg-add-options ieee } */ /* { dg-additional-options "-fsignaling-nans" } */ +/* { dg-skip-if "WASM does not have signaling NaNs" { wasm*-*-* } } */ /* Workaround for PR57484 on ia32: */ /* { dg-additional-options "-msse2 -mfpmath=sse" { target { ia32 && sse2_runtime } } } */ diff --git a/gcc/testsuite/gcc.c-torture/execute/ieee/float128-builtin-issignaling-1.c b/gcc/testsuite/gcc.c-torture/execute/ieee/float128-builtin-issignaling-1.c index 3299ffd5666..acd9677297d 100644 --- a/gcc/testsuite/gcc.c-torture/execute/ieee/float128-builtin-issignaling-1.c +++ b/gcc/testsuite/gcc.c-torture/execute/ieee/float128-builtin-issignaling-1.c @@ -5,6 +5,7 @@ /* { dg-add-options ieee } */ /* { dg-require-effective-target float128_runtime } */ /* { dg-additional-options "-fsignaling-nans" } */ +/* { dg-skip-if "WASM does not have signaling NaNs" { wasm*-*-* } } */ /* Workaround for PR57484 on ia32: */ /* { dg-additional-options "-msse2 -mfpmath=sse" { target { ia32 && sse2_runtime } } } */ diff --git a/gcc/testsuite/gcc.c-torture/execute/ieee/float128x-builtin-issignaling-1.c b/gcc/testsuite/gcc.c-torture/execute/ieee/float128x-builtin-issignaling-1.c index af0b25af8a5..ca765f34ff5 100644 --- a/gcc/testsuite/gcc.c-torture/execute/ieee/float128x-builtin-issignaling-1.c +++ b/gcc/testsuite/gcc.c-torture/execute/ieee/float128x-builtin-issignaling-1.c @@ -5,6 +5,7 @@ /* { dg-add-options ieee } */ /* { dg-require-effective-target float128x_runtime } */ /* { dg-additional-options "-fsignaling-nans" } */ +/* { dg-skip-if "WASM does not have signaling NaNs" { wasm*-*-* } } */ /* Workaround for PR57484 on ia32: */ /* { dg-additional-options "-msse2 -mfpmath=sse" { target { ia32 && sse2_runtime } } } */ diff --git a/gcc/testsuite/gcc.c-torture/execute/ieee/float16-builtin-issignaling-1.c b/gcc/testsuite/gcc.c-torture/execute/ieee/float16-builtin-issignaling-1.c index a0747e4240b..0dbe2c976fc 100644 --- a/gcc/testsuite/gcc.c-torture/execute/ieee/float16-builtin-issignaling-1.c +++ b/gcc/testsuite/gcc.c-torture/execute/ieee/float16-builtin-issignaling-1.c @@ -5,6 +5,7 @@ /* { dg-add-options ieee } */ /* { dg-require-effective-target float16_runtime } */ /* { dg-additional-options "-fsignaling-nans" } */ +/* { dg-skip-if "WASM does not have signaling NaNs" { wasm*-*-* } } */ /* Workaround for PR57484 on ia32: */ /* { dg-additional-options "-msse2 -mfpmath=sse" { target { ia32 && sse2_runtime } } } */ diff --git a/gcc/testsuite/gcc.c-torture/execute/ieee/float32-builtin-issignaling-1.c b/gcc/testsuite/gcc.c-torture/execute/ieee/float32-builtin-issignaling-1.c index 38e56c2c00c..9e0d9b33c9b 100644 --- a/gcc/testsuite/gcc.c-torture/execute/ieee/float32-builtin-issignaling-1.c +++ b/gcc/testsuite/gcc.c-torture/execute/ieee/float32-builtin-issignaling-1.c @@ -5,6 +5,7 @@ /* { dg-add-options ieee } */ /* { dg-require-effective-target float32_runtime } */ /* { dg-additional-options "-fsignaling-nans" } */ +/* { dg-skip-if "WASM does not have signaling NaNs" { wasm*-*-* } } */ /* Workaround for PR57484 on ia32: */ /* { dg-additional-options "-msse2 -mfpmath=sse" { target { ia32 && sse2_runtime } } } */ diff --git a/gcc/testsuite/gcc.c-torture/execute/ieee/float32x-builtin-issignaling-1.c b/gcc/testsuite/gcc.c-torture/execute/ieee/float32x-builtin-issignaling-1.c index 88eefdbc1d6..ecd8a596306 100644 --- a/gcc/testsuite/gcc.c-torture/execute/ieee/float32x-builtin-issignaling-1.c +++ b/gcc/testsuite/gcc.c-torture/execute/ieee/float32x-builtin-issignaling-1.c @@ -5,6 +5,7 @@ /* { dg-add-options ieee } */ /* { dg-require-effective-target float32x_runtime } */ /* { dg-additional-options "-fsignaling-nans" } */ +/* { dg-skip-if "WASM does not have signaling NaNs" { wasm*-*-* } } */ /* Workaround for PR57484 on ia32: */ /* { dg-additional-options "-msse2 -mfpmath=sse" { target { ia32 && sse2_runtime } } } */ diff --git a/gcc/testsuite/gcc.c-torture/execute/ieee/float64-builtin-issignaling-1.c b/gcc/testsuite/gcc.c-torture/execute/ieee/float64-builtin-issignaling-1.c index 07d755b37be..ec13f17fd51 100644 --- a/gcc/testsuite/gcc.c-torture/execute/ieee/float64-builtin-issignaling-1.c +++ b/gcc/testsuite/gcc.c-torture/execute/ieee/float64-builtin-issignaling-1.c @@ -5,6 +5,7 @@ /* { dg-add-options ieee } */ /* { dg-require-effective-target float64_runtime } */ /* { dg-additional-options "-fsignaling-nans" } */ +/* { dg-skip-if "WASM does not have signaling NaNs" { wasm*-*-* } } */ /* Workaround for PR57484 on ia32: */ /* { dg-additional-options "-msse2 -mfpmath=sse" { target { ia32 && sse2_runtime } } } */ diff --git a/gcc/testsuite/gcc.c-torture/execute/ieee/float64x-builtin-issignaling-1.c b/gcc/testsuite/gcc.c-torture/execute/ieee/float64x-builtin-issignaling-1.c index fe6420aaa95..7665afc3c5b 100644 --- a/gcc/testsuite/gcc.c-torture/execute/ieee/float64x-builtin-issignaling-1.c +++ b/gcc/testsuite/gcc.c-torture/execute/ieee/float64x-builtin-issignaling-1.c @@ -5,6 +5,7 @@ /* { dg-add-options ieee } */ /* { dg-require-effective-target float64x_runtime } */ /* { dg-additional-options "-fsignaling-nans" } */ +/* { dg-skip-if "WASM does not have signaling NaNs" { wasm*-*-* } } */ /* Workaround for PR57484 on ia32: */ /* { dg-additional-options "-msse2 -mfpmath=sse" { target { ia32 && sse2_runtime } } } */ diff --git a/gcc/testsuite/gcc.c-torture/execute/pr67037-1.c b/gcc/testsuite/gcc.c-torture/execute/pr67037-1.c new file mode 100644 index 00000000000..5e506972202 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr67037-1.c @@ -0,0 +1,56 @@ +/* { dg-additional-options "-std=gnu17" } */ + +long __attribute__((noipa)) +sink1(void) +{ + return 0; +} +long __attribute__((noipa)) +sink2(void*) +{ + return 0; +} + + +static inline void lstrcpynW( short *d, const short *s, int n ) +{ + unsigned int count = n; + + while ((count > 1) && *s) + { + count--; + *d++ = *s++; + } + if (count) *d = 0; +} + +int __attribute__((noinline,noclone)) +badfunc(int u0, int u1, int u2, int u3, + short *fsname, unsigned int fsname_len) +{ + static const short ntfsW[] = {'N','T','F','S',0}; + char superblock[2048+3300]; + int ret = 0; + short *p; + + if (sink1()) + return 0; + p = (void *)sink1(); + if (p != 0) + goto done; + + sink2(superblock); + + lstrcpynW(fsname, ntfsW, fsname_len); + + ret = 1; +done: + return ret; +} + + +int main() +{ + short buf[6]; + return !badfunc(0, 0, 0, 0, buf, 6); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/pr67037.c b/gcc/testsuite/gcc.c-torture/execute/pr67037.c index da626e8da8c..4ba9cbdc667 100644 --- a/gcc/testsuite/gcc.c-torture/execute/pr67037.c +++ b/gcc/testsuite/gcc.c-torture/execute/pr67037.c @@ -1,5 +1,7 @@ /* { dg-additional-options "-std=gnu17" } */ - +/* { dg-skip-if "" { wasm*-*-* } } */ +/* wasm doesn't play well with unprototyped fns when called with mismatching + number of args */ long (*extfunc)(); static inline void lstrcpynW( short *d, const short *s, int n ) diff --git a/gcc/testsuite/gcc.dg/20060410.c b/gcc/testsuite/gcc.dg/20060410.c index b4d00cb991d..233aec72ef9 100644 --- a/gcc/testsuite/gcc.dg/20060410.c +++ b/gcc/testsuite/gcc.dg/20060410.c @@ -13,4 +13,4 @@ int bar (void) return ((struct foo *)0x1234)->i; } -/* { dg-final { scan-assembler "foo" { xfail nvptx-*-* } } } */ +/* { dg-final { scan-assembler "foo" { xfail nvptx-*-* wasm*-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-access-mode-target-headers.c b/gcc/testsuite/gcc.dg/analyzer/fd-access-mode-target-headers.c index 1386ac2de1e..0f2eb5267df 100644 --- a/gcc/testsuite/gcc.dg/analyzer/fd-access-mode-target-headers.c +++ b/gcc/testsuite/gcc.dg/analyzer/fd-access-mode-target-headers.c @@ -1,5 +1,6 @@ /* { dg-skip-if "" { { powerpc*-*-aix* avr-*-* *-*-vxworks* } || newlib } } */ /* { dg-skip-if "PR analyzer/107750" { *-*-solaris2* } } */ +/* { dg-skip-if "wasi-libc doesn't work well with analyzer" { wasm*-*-* } } */ #include #include diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-mktemp-family.c b/gcc/testsuite/gcc.dg/analyzer/fd-mktemp-family.c index db690256c05..5a0784cb9f3 100644 --- a/gcc/testsuite/gcc.dg/analyzer/fd-mktemp-family.c +++ b/gcc/testsuite/gcc.dg/analyzer/fd-mktemp-family.c @@ -1,5 +1,6 @@ /* Tests for fd leak and errno handling of mktemp-family functions. */ /* { dg-additional-options "-Wno-analyzer-null-argument" } */ +/* { dg-skip-if "wasi-libc doesn't work well with analyzer" { wasm*-*-* } } */ #include #include diff --git a/gcc/testsuite/gcc.dg/analyzer/mkdtemp-1.c b/gcc/testsuite/gcc.dg/analyzer/mkdtemp-1.c index da77ce78651..48a012c8d83 100644 --- a/gcc/testsuite/gcc.dg/analyzer/mkdtemp-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/mkdtemp-1.c @@ -1,4 +1,5 @@ /* { dg-additional-options "-Wno-analyzer-null-argument" } */ +/* { dg-skip-if "wasi-libc doesn't work well with analyzer" { wasm*-*-* } } */ #include #include diff --git a/gcc/testsuite/gcc.dg/analyzer/mkostemp-1.c b/gcc/testsuite/gcc.dg/analyzer/mkostemp-1.c index 55135ffd947..8dade236acb 100644 --- a/gcc/testsuite/gcc.dg/analyzer/mkostemp-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/mkostemp-1.c @@ -1,5 +1,6 @@ /* { dg-additional-options "-Wno-analyzer-null-argument" } */ /* { dg-prune-output "leak of file descriptor" } */ +/* { dg-skip-if "wasi-libc doesn't work well with analyzer" { wasm*-*-* } } */ #include #include diff --git a/gcc/testsuite/gcc.dg/analyzer/mkostemps-1.c b/gcc/testsuite/gcc.dg/analyzer/mkostemps-1.c index 013906092d5..c3b045ad3ad 100644 --- a/gcc/testsuite/gcc.dg/analyzer/mkostemps-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/mkostemps-1.c @@ -1,5 +1,6 @@ /* { dg-additional-options "-Wno-analyzer-null-argument" } */ /* { dg-prune-output "leak of file descriptor" } */ +/* { dg-skip-if "wasi-libc doesn't work well with analyzer" { wasm*-*-* } } */ #include #include diff --git a/gcc/testsuite/gcc.dg/analyzer/mkstemp-1.c b/gcc/testsuite/gcc.dg/analyzer/mkstemp-1.c index e7a7a724abf..f88103f9f76 100644 --- a/gcc/testsuite/gcc.dg/analyzer/mkstemp-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/mkstemp-1.c @@ -1,5 +1,6 @@ /* { dg-additional-options "-Wno-analyzer-null-argument" } */ /* { dg-prune-output "leak of file descriptor" } */ +/* { dg-skip-if "wasi-libc doesn't work well with analyzer" { wasm*-*-* } } */ #include #include diff --git a/gcc/testsuite/gcc.dg/analyzer/mkstemps-1.c b/gcc/testsuite/gcc.dg/analyzer/mkstemps-1.c index 75fcb9dbb08..a927cf05bb1 100644 --- a/gcc/testsuite/gcc.dg/analyzer/mkstemps-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/mkstemps-1.c @@ -1,5 +1,6 @@ /* { dg-additional-options "-Wno-analyzer-null-argument" } */ /* { dg-prune-output "leak of file descriptor" } */ +/* { dg-skip-if "wasi-libc doesn't work well with analyzer" { wasm*-*-* } } */ #include #include diff --git a/gcc/testsuite/gcc.dg/analyzer/mktemp-1.c b/gcc/testsuite/gcc.dg/analyzer/mktemp-1.c index 0f4b448a6aa..141a5c9cced 100644 --- a/gcc/testsuite/gcc.dg/analyzer/mktemp-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/mktemp-1.c @@ -1,4 +1,5 @@ /* { dg-additional-options "-Wno-analyzer-null-argument" } */ +/* { dg-skip-if "wasi-libc doesn't work well with analyzer" { wasm*-*-* } } */ /* TODO: mktemp is deprecated per MSC24-C (https://wiki.sei.cmu.edu/confluence/x/hNYxBQ). diff --git a/gcc/testsuite/gcc.dg/array-quals-1.c b/gcc/testsuite/gcc.dg/array-quals-1.c index e379f6121b7..eb238fee136 100644 --- a/gcc/testsuite/gcc.dg/array-quals-1.c +++ b/gcc/testsuite/gcc.dg/array-quals-1.c @@ -5,6 +5,7 @@ /* { dg-do compile } */ /* { dg-options "-Wno-discarded-array-qualifiers" } */ /* { dg-additional-options "-fno-pie" { target pie } } */ +/* { dg-skip-if "No sections on wasm" { wasm*-*-* } } */ /* The MMIX port always switches to the .data section at the end of a file. */ /* { dg-final { scan-assembler-not "\\.data(?!\\.rel\\.ro)" { xfail powerpc*-*-aix* mmix-*-* x86_64-*-mingw* } } } */ /* { dg-final { scan-assembler-symbol-section {^_?a$} {^\.(const|rodata|srodata|sdata)|\[RO\]} } } */ diff --git a/gcc/testsuite/gcc.dg/attr-weakref-1.c b/gcc/testsuite/gcc.dg/attr-weakref-1.c index 1d25d9c2d41..abf77474ae2 100644 --- a/gcc/testsuite/gcc.dg/attr-weakref-1.c +++ b/gcc/testsuite/gcc.dg/attr-weakref-1.c @@ -8,6 +8,9 @@ // { dg-skip-if "" { "hppa*-*-hpux*" "*-*-aix*" "nvptx-*-*" } } // { dg-skip-if PR119369 { amdgcn-*-* } } +// WebAssembly does support undefined weak symbols, just not weakrefs +/* { dg-skip-if "" { wasm*-*-* } } */ + // For kernel modules and static RTPs, the loader treats undefined weak // symbols in the same way as undefined strong symbols. The test // therefore fails to load, so skip it. diff --git a/gcc/testsuite/gcc.dg/builtin-alloc-size.c b/gcc/testsuite/gcc.dg/builtin-alloc-size.c index bc1bd5bf4e8..b39ba339e15 100644 --- a/gcc/testsuite/gcc.dg/builtin-alloc-size.c +++ b/gcc/testsuite/gcc.dg/builtin-alloc-size.c @@ -3,6 +3,7 @@ attribute alloc_size that __builtin_object_size can make use of (or are treated as if they were for that purpose).. { dg-do compile } + { dg-skip-if "wasm uses wasi-libc" { wasm*-*-* } } { dg-additional-options "-O2 -fdump-tree-optimized" } */ void sink (void*); diff --git a/gcc/testsuite/gcc.dg/builtin-apply5.c b/gcc/testsuite/gcc.dg/builtin-apply5.c index 16892f76a8a..b02267bfce5 100644 --- a/gcc/testsuite/gcc.dg/builtin-apply5.c +++ b/gcc/testsuite/gcc.dg/builtin-apply5.c @@ -1,6 +1,7 @@ /* { dg-options "-O2 -Wmissing-noreturn -fgnu89-inline" } */ /* { dg-additional-options "-mno-mmx" { target { { i?86-*-* x86_64-*-* } && ia32 } } } */ /* { dg-do compile } */ +/* { dg-skip-if "Unprototyped calls not supported" { wasm*-*-* } } */ extern void abort (void); diff --git a/gcc/testsuite/gcc.dg/builtin-prefetch-1.c b/gcc/testsuite/gcc.dg/builtin-prefetch-1.c index a24c5f7ebc6..c924a627bf2 100644 --- a/gcc/testsuite/gcc.dg/builtin-prefetch-1.c +++ b/gcc/testsuite/gcc.dg/builtin-prefetch-1.c @@ -3,7 +3,8 @@ Prefetch using some invalid rw and locality values. These must be compile-time constants. */ -/* { dg-do run } */ +/* { dg-do run } + { dg-skip-if "wasm does not support prefetch" { wasm*-*-* } } */ extern void exit (int); diff --git a/gcc/testsuite/gcc.dg/builtins-config.h b/gcc/testsuite/gcc.dg/builtins-config.h index 5e27c1deb33..b262ce33a9d 100644 --- a/gcc/testsuite/gcc.dg/builtins-config.h +++ b/gcc/testsuite/gcc.dg/builtins-config.h @@ -12,6 +12,8 @@ #if defined(__hppa) && defined(__hpux) /* PA HP-UX doesn't have the entire C99 runtime. */ +#elif defined(__wasm32__) +/* WebAssembly doesn't have the entire C99 runtime. */ #elif defined(__INTERIX) /* Interix6 doesn't have the entire C99 runtime. */ #elif defined(__AVR__) diff --git a/gcc/testsuite/gcc.dg/builtins-nonnull.c b/gcc/testsuite/gcc.dg/builtins-nonnull.c index d59579d78c8..cbc2b297199 100644 --- a/gcc/testsuite/gcc.dg/builtins-nonnull.c +++ b/gcc/testsuite/gcc.dg/builtins-nonnull.c @@ -1,6 +1,7 @@ /* PR c/17308 - nonnull attribute not as useful as it could be PR c/78673 - sprintf missing attribute nonnull on destination argument { dg-do "compile" } + { dg-skip-if "wasm uses wasi-libc" { wasm*-*-* } } { dg-additional-options "-O2 -Wnonnull -ftrack-macro-expansion=0 -std=c99" } */ #define va_list __builtin_va_list diff --git a/gcc/testsuite/gcc.dg/c23-stdint-1.c b/gcc/testsuite/gcc.dg/c23-stdint-1.c index 9a984cfb4d7..c7f2473bace 100644 --- a/gcc/testsuite/gcc.dg/c23-stdint-1.c +++ b/gcc/testsuite/gcc.dg/c23-stdint-1.c @@ -1,6 +1,7 @@ /* Test __STDC_VERSION_STDINT_H__ in C23. */ /* { dg-do preprocess } */ /* { dg-options "-std=c23 -pedantic-errors -ffreestanding" } */ +/* { dg-skip-if "wasi-libc doesn't support c23" { wasm*-*-* } } */ #include diff --git a/gcc/testsuite/gcc.dg/c99-stdint-1.c b/gcc/testsuite/gcc.dg/c99-stdint-1.c index f5c2cda77c9..2b44b82746b 100644 --- a/gcc/testsuite/gcc.dg/c99-stdint-1.c +++ b/gcc/testsuite/gcc.dg/c99-stdint-1.c @@ -11,6 +11,7 @@ /* { dg-options "-std=iso9899:1999 -pedantic-errors -fhosted" } */ /* { dg-require-effective-target ptr32plus } */ /* { dg-additional-options "-DSIGNAL_SUPPRESS" { target { ! signal } } } */ +/* { dg-skip-if "wasi-libc doesn't support int width" { wasm*-*-* } } */ #include #include diff --git a/gcc/testsuite/gcc.dg/c99-stdint-2.c b/gcc/testsuite/gcc.dg/c99-stdint-2.c index 08d9f6023d9..2c83aba18ae 100644 --- a/gcc/testsuite/gcc.dg/c99-stdint-2.c +++ b/gcc/testsuite/gcc.dg/c99-stdint-2.c @@ -4,6 +4,7 @@ /* { dg-options "-std=iso9899:1999 -pedantic-errors -ffreestanding" } */ /* { dg-require-effective-target ptr32plus } */ /* { dg-additional-options "-DSIGNAL_SUPPRESS" { target { ! signal } } } */ +/* { dg-skip-if "wasi-libc doesn't support int width" { wasm*-*-* } } */ /* The test is that there are no diagnostics, so just include the hosted version. */ diff --git a/gcc/testsuite/gcc.dg/c99-stdint-7.c b/gcc/testsuite/gcc.dg/c99-stdint-7.c index 777e895b506..83b5e57e675 100644 --- a/gcc/testsuite/gcc.dg/c99-stdint-7.c +++ b/gcc/testsuite/gcc.dg/c99-stdint-7.c @@ -3,6 +3,7 @@ conditions. */ /* { dg-do compile } */ /* { dg-options "-std=iso9899:1999 -fhosted" } */ +/* { dg-additional-options "-DSIGNAL_SUPPRESS" { target { ! signal } } } */ #include @@ -191,12 +192,14 @@ #error "PTRDIFF_MAX not usable in #if or wrong value" #endif +#ifndef SIGNAL_SUPPRESS #if SIG_ATOMIC_MIN != __SIG_ATOMIC_MIN__ #error "SIG_ATOMIC_MIN not usable in #if or wrong value" #endif #if SIG_ATOMIC_MAX != __SIG_ATOMIC_MAX__ #error "SIG_ATOMIC_MAX not usable in #if or wrong value" #endif +#endif #if SIZE_MAX != __SIZE_MAX__ #error "SIZE_MAX not usable in #if or wrong value" diff --git a/gcc/testsuite/gcc.dg/c99-stdint-8.c b/gcc/testsuite/gcc.dg/c99-stdint-8.c index c64b3feb4f6..9daba2375fa 100644 --- a/gcc/testsuite/gcc.dg/c99-stdint-8.c +++ b/gcc/testsuite/gcc.dg/c99-stdint-8.c @@ -3,6 +3,7 @@ conditions. Freestanding version. */ /* { dg-do compile } */ /* { dg-options "-std=iso9899:1999 -ffreestanding" } */ +/* { dg-additional-options "-DSIGNAL_SUPPRESS" { target { ! signal } } } */ /* The test is that there are no diagnostics, so just include the hosted version. */ diff --git a/gcc/testsuite/gcc.dg/charset/function.c b/gcc/testsuite/gcc.dg/charset/function.c index 5aba6511bd0..a589fa064f5 100644 --- a/gcc/testsuite/gcc.dg/charset/function.c +++ b/gcc/testsuite/gcc.dg/charset/function.c @@ -1,6 +1,6 @@ /* { dg-do compile } { dg-require-iconv "IBM1047" } - { dg-final { scan-assembler-not "\"foobar\"" } } */ + { dg-final { scan-assembler-not "\"foobar\"" { xfail wasm*-*-* } } } */ const char *str; diff --git a/gcc/testsuite/gcc.dg/cpp/escape-3.i b/gcc/testsuite/gcc.dg/cpp/escape-3.i index cb4758190f7..0659942c372 100644 --- a/gcc/testsuite/gcc.dg/cpp/escape-3.i +++ b/gcc/testsuite/gcc.dg/cpp/escape-3.i @@ -6,6 +6,7 @@ /* { dg-do compile } */ /* { dg-options "-g1" } */ +/* { dg-skip-if "wasm doesn't support -g" { wasm*-*-* } } */ int foo (int a, int b) { diff --git a/gcc/testsuite/gcc.dg/format/pr78304.c b/gcc/testsuite/gcc.dg/format/pr78304.c index f6ad80793c7..dc278d5fe39 100644 --- a/gcc/testsuite/gcc.dg/format/pr78304.c +++ b/gcc/testsuite/gcc.dg/format/pr78304.c @@ -1,4 +1,5 @@ /* { dg-do compile { target inttypes_types } } */ +/* { dg-skip-if "wasi-libc does not support PRIuN" { wasm*-*-* } } */ /* { dg-options "-O2 -Wall -Wextra" } */ #include diff --git a/gcc/testsuite/gcc.dg/ipa/symver1.c b/gcc/testsuite/gcc.dg/ipa/symver1.c index d120ed5d76b..6c1a84a0a16 100644 --- a/gcc/testsuite/gcc.dg/ipa/symver1.c +++ b/gcc/testsuite/gcc.dg/ipa/symver1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-skip-if "only works for ELF targets" { *-*-darwin* *-*-aix* } } */ +/* { dg-skip-if "only works for ELF targets" { *-*-darwin* *-*-aix* wasm*-*-* } } */ __attribute__ ((__symver__ ("foo@VER_2"))) __attribute__ ((__symver__ ("foo@VER_3"))) diff --git a/gcc/testsuite/gcc.dg/lower-subreg-1.c b/gcc/testsuite/gcc.dg/lower-subreg-1.c index c62db2c466c..749c85269cb 100644 --- a/gcc/testsuite/gcc.dg/lower-subreg-1.c +++ b/gcc/testsuite/gcc.dg/lower-subreg-1.c @@ -1,4 +1,4 @@ -/* { dg-do compile { target { ! { mips64 || { aarch64*-*-* arm*-*-* i?86-*-* ia64-*-* pru-*-* sparc*-*-* x86_64-*-* } } } } } */ +/* { dg-do compile { target { ! { mips64 || { aarch64*-*-* arm*-*-* i?86-*-* ia64-*-* pru-*-* sparc*-*-* x86_64-*-* wasm*-*-* } } } } } */ /* { dg-options "-O -fdump-rtl-subreg1" } */ /* { dg-require-effective-target ilp32 } */ diff --git a/gcc/testsuite/gcc.dg/pch/valid-1.c b/gcc/testsuite/gcc.dg/pch/valid-1.c index b950d0d4c64..1704317ed69 100644 --- a/gcc/testsuite/gcc.dg/pch/valid-1.c +++ b/gcc/testsuite/gcc.dg/pch/valid-1.c @@ -1,4 +1,5 @@ /* { dg-options "-I. -Winvalid-pch -g" } */ +/* { dg-skip-if "wasm doesn't support -g" { wasm*-*-* } } */ #include "valid-1.h"/* { dg-warning "created with .none. debug info, but used with" } */ /* { dg-error "No such file" "no such file" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/gcc.dg/pr115066.c b/gcc/testsuite/gcc.dg/pr115066.c index d79233f2e79..79f4780cd2e 100644 --- a/gcc/testsuite/gcc.dg/pr115066.c +++ b/gcc/testsuite/gcc.dg/pr115066.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-skip-if "split DWARF unsupported" { hppa*-*-hpux* powerpc*-ibm-aix* *-*-darwin* } } */ +/* { dg-skip-if "split DWARF unsupported" { hppa*-*-hpux* powerpc*-ibm-aix* *-*-darwin* wasm*-*-* } } */ /* { dg-options "-gsplit-dwarf -g3 -dA -gdwarf-4 -gno-strict-dwarf" } */ /* { dg-final { scan-assembler-times {\.section\t"?\.debug_macro} 1 } } */ /* { dg-final { scan-assembler-not {\.byte\t0x5\t[^\n\r]* Define macro strp} } } */ diff --git a/gcc/testsuite/gcc.dg/pr28755.c b/gcc/testsuite/gcc.dg/pr28755.c index 50b56fb8907..5e76ea40d62 100644 --- a/gcc/testsuite/gcc.dg/pr28755.c +++ b/gcc/testsuite/gcc.dg/pr28755.c @@ -3,7 +3,7 @@ /* { dg-require-effective-target ptr32plus } */ /* { dg-options "-Os" } */ /* { dg-final { scan-assembler-times "2112543726\|7deadbee" 2 } } */ -/* { dg-skip-if "integer output is different here" { nvptx-*-* } } */ +/* { dg-skip-if "integer output is different here" { nvptx-*-* wasm*-*-* } } */ struct S { diff --git a/gcc/testsuite/gcc.dg/pr49551.c b/gcc/testsuite/gcc.dg/pr49551.c index dda0667f3e6..0b99475fe47 100644 --- a/gcc/testsuite/gcc.dg/pr49551.c +++ b/gcc/testsuite/gcc.dg/pr49551.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-O -fdata-sections" } */ -/* { dg-skip-if "-fdata-sections not supported" { hppa*-*-hpux* nvptx-*-* } } */ +/* { dg-skip-if "-fdata-sections not supported" { hppa*-*-hpux* nvptx-*-* wasm*-*-* } } */ int x = 1; int x; diff --git a/gcc/testsuite/gcc.dg/profile-info-section.c b/gcc/testsuite/gcc.dg/profile-info-section.c index 8f31f3b2c07..baf8a5f3de7 100644 --- a/gcc/testsuite/gcc.dg/profile-info-section.c +++ b/gcc/testsuite/gcc.dg/profile-info-section.c @@ -1,6 +1,7 @@ /* { dg-do compile } */ /* { dg-skip-if "profile-info-section" { powerpc-ibm-aix* } } */ /* { dg-options "-fprofile-arcs -fprofile-info-section -fdump-tree-optimized" } */ +/* { dg-require-effective-target named_sections } */ int foo() { diff --git a/gcc/testsuite/gcc.dg/stdint-width-1.c b/gcc/testsuite/gcc.dg/stdint-width-1.c index 3eba9f6cb15..8143a7b1604 100644 --- a/gcc/testsuite/gcc.dg/stdint-width-1.c +++ b/gcc/testsuite/gcc.dg/stdint-width-1.c @@ -2,6 +2,7 @@ /* { dg-do compile } */ /* { dg-options "-std=c11 -ffreestanding" } */ /* { dg-additional-options "-DSIGNAL_SUPPRESS" { target { ! signal } } } */ +/* { dg-skip-if "wasi-libc doesn't support int width" { wasm*-*-* } } */ #include #define __STDC_WANT_IEC_60559_BFP_EXT__ diff --git a/gcc/testsuite/gcc.dg/stdint-width-2.c b/gcc/testsuite/gcc.dg/stdint-width-2.c index a48333a3ec5..6233c76b55f 100644 --- a/gcc/testsuite/gcc.dg/stdint-width-2.c +++ b/gcc/testsuite/gcc.dg/stdint-width-2.c @@ -2,6 +2,7 @@ /* { dg-do compile } */ /* { dg-options "-std=c23 -ffreestanding" } */ /* { dg-additional-options "-DSIGNAL_SUPPRESS" { target { ! signal } } } */ +/* { dg-skip-if "wasi-libc doesn't support int width" { wasm*-*-* } } */ #include #include diff --git a/gcc/testsuite/gcc.dg/tls/thr-cse-1.c b/gcc/testsuite/gcc.dg/tls/thr-cse-1.c index 7145671eb95..38f03c3a4a4 100644 --- a/gcc/testsuite/gcc.dg/tls/thr-cse-1.c +++ b/gcc/testsuite/gcc.dg/tls/thr-cse-1.c @@ -19,7 +19,7 @@ int foo (int b, int c, int d) return a; } -/* { dg-final { scan-assembler-not "emutls_get_address.*emutls_get_address.*" { target { ! { "*-wrs-vxworks" "*-*-darwin8" "hppa*-*-hpux*" "i?86-*-mingw*" "x86_64-*-mingw*" visium-*-* nvptx-*-* } } } } } */ +/* { dg-final { scan-assembler-not "emutls_get_address.*emutls_get_address.*" { target { ! { "*-wrs-vxworks" "*-*-darwin8" "hppa*-*-hpux*" "i?86-*-mingw*" "x86_64-*-mingw*" visium-*-* nvptx-*-* wasm*-*-* } } } } } */ /* { dg-final { scan-assembler-not "call\tL___emutls_get_address.stub.*call\tL___emutls_get_address.stub.*" { target "*-*-darwin8" } } } */ /* { dg-final { scan-assembler-not "(b,l|bl) __emutls_get_address.*(b,l|bl) __emutls_get_address.*" { target "hppa*-*-hpux*" } } } */ /* { dg-final { scan-assembler-not "tls_lookup.*tls_lookup.*" { target *-wrs-vxworks } } } */ diff --git a/gcc/testsuite/gcc.misc-tests/gcov-23.c b/gcc/testsuite/gcc.misc-tests/gcov-23.c index 72ba0aa1389..d32ec99f51e 100644 --- a/gcc/testsuite/gcc.misc-tests/gcov-23.c +++ b/gcc/testsuite/gcc.misc-tests/gcov-23.c @@ -1,5 +1,6 @@ /* { dg-options "-fcondition-coverage -ftest-coverage -O2" } */ /* { dg-do compile } */ +/* { dg-skip-if "wasi-libc doesn't implement longjmp" { wasm*-*-* } } */ #include #include diff --git a/gcc/testsuite/gcc.misc-tests/gcov.exp b/gcc/testsuite/gcc.misc-tests/gcov.exp index 0e31804b37c..e2a6a93ef01 100644 --- a/gcc/testsuite/gcc.misc-tests/gcov.exp +++ b/gcc/testsuite/gcc.misc-tests/gcov.exp @@ -39,6 +39,10 @@ if ![info exists GCOV_UNDER_TEST] { # Initialize harness. dg-init +if [istarget wasm*-*-*] then { + return 0; +} + # Delete old .gcda files. set files [glob -nocomplain gcov*.gcda] if { $files != "" } { diff --git a/gcc/testsuite/gcc.misc-tests/options.exp b/gcc/testsuite/gcc.misc-tests/options.exp index 0a634f7939f..8dd2d726f37 100644 --- a/gcc/testsuite/gcc.misc-tests/options.exp +++ b/gcc/testsuite/gcc.misc-tests/options.exp @@ -59,9 +59,12 @@ proc check_for_all_options {language gcc_options compiler_pattern as_pattern ld_ set as_options [list "additional_flags=-print-prog-name=as"] set as_prog [lindex [gcc_target_compile "" "" "none" $as_options] 0] if {![regexp -line -- " ${as_prog}(\\.exe)? .*$as_pattern" $gcc_output]} { - - fail "$test (assembler options)" - return + # wasm does not use a standard assembler, its options are very different + # from gas and the like + if { ![istarget "wasm*-*-*"] } { + fail "$test (assembler options)" + return + } } # Match /collect2, /ld, or *-ld. if {![regexp -- "(/collect2|\[-/\]ld)(\\.exe)? .*$ld_pattern" $gcc_output]} { diff --git a/gcc/testsuite/lib/file-format.exp b/gcc/testsuite/lib/file-format.exp index b36812a1fa4..5b4194d4161 100644 --- a/gcc/testsuite/lib/file-format.exp +++ b/gcc/testsuite/lib/file-format.exp @@ -28,6 +28,9 @@ proc gcc_target_object_format { } { if [info exists gcc_target_object_format_saved] { verbose "gcc_target_object_format returning saved $gcc_target_object_format_saved" 2 + } elseif { [istarget wasm*-*-*] } { + # WebAssembly has its own assembly and objerct file format. + set gcc_target_object_format_saved wasm } elseif { [istarget *-*-darwin*] } { # Darwin doesn't necessarily have objdump, so hand-code it. set gcc_target_object_format_saved mach-o @@ -83,7 +86,10 @@ proc gcc_target_object_format { } { } som { set gcc_target_object_format_saved som - } + } + wasm { + set gcc_target_object_format_saved wasm + } default { verbose "Unknown file format: $objformat" 3 set gcc_target_object_format_saved unknown diff --git a/gcc/testsuite/lib/scanasm.exp b/gcc/testsuite/lib/scanasm.exp index abfdd6a3a14..26dcfae2349 100644 --- a/gcc/testsuite/lib/scanasm.exp +++ b/gcc/testsuite/lib/scanasm.exp @@ -148,6 +148,7 @@ proc hidden-scan-for { symbol } { coff { return "$symbol\[,\d\]*hidden" } elf { return "hidden\[ \t_\]*$symbol" } mach-o { return "private_extern\[ \t_\]*_?$symbol" } + wasm { return "(@sym(.import.data)? \\$$symbol|\\$$symbol \\\(@sym) (|weak |local )hidden" } default { return "" } } @@ -159,6 +160,7 @@ proc weak-scan-for { symbol } { switch $objformat { default { return "weak\[^ \t\]*\[ \t\]_?$symbol" } + wasm { return "(@sym(.import.data)? \\$$symbol|\\$$symbol \\\(@sym) weak" } } } diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index 373a61f4d57..de612b0d67b 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -351,6 +351,7 @@ proc check_weak_available { } { a.out { return 1 } mach-o { return 1 } som { return 1 } + wasm { return 1 } unknown { return -1 } default { return 0 } } @@ -496,6 +497,10 @@ proc check_visibility_available { what_kind } { # be determined. proc check_alias_available { } { + if { [istarget wasm*-*-*] } { + return 0; + } + global tool return [check_cached_effective_target alias_available { @@ -651,7 +656,8 @@ proc check_effective_target_trampolines { } { || [istarget nvptx-*-*] || [istarget ft32-*-*] || [istarget pru-*-*] - || [istarget bpf-*-*] } { + || [istarget bpf-*-*] + || [istarget wasm*-*-*] } { return 0; } return 1 @@ -723,6 +729,9 @@ proc dg-effective-target-value { effective_target } { # Return 1 if signal.h is supported. proc check_effective_target_signal { } { + if { [istarget wasm*-*-*] } { + return 0 + } if [target_info exists gcc,signal_suppress] { return 0 } @@ -993,7 +1002,7 @@ proc add_options_for_check_function_bodies { flags } { # Return 1 if indirect jumps are supported, 0 otherwise. proc check_effective_target_indirect_jumps {} { - if { [istarget nvptx-*-*] || [istarget bpf-*-*] } { + if { [istarget nvptx-*-*] || [istarget bpf-*-*] || [istarget wasm*-*-*] } { return 0 } return 1 @@ -1002,7 +1011,7 @@ proc check_effective_target_indirect_jumps {} { # Return 1 if nonlocal goto is supported, 0 otherwise. proc check_effective_target_nonlocal_goto {} { - if { [istarget nvptx-*-*] || [istarget bpf-*-*] } { + if { [istarget nvptx-*-*] || [istarget bpf-*-*] || [istarget wasm*-*-*] } { return 0 } return 1 @@ -1020,7 +1029,8 @@ proc check_effective_target_global_constructor {} { # Return 1 if taking label values is supported, 0 otherwise. proc check_effective_target_label_values {} { - if { [istarget nvptx-*-*] || [target_info exists gcc,no_label_values] } { + if { [istarget nvptx-*-*] || [istarget wasm*-*-*] + || [target_info exists gcc,no_label_values] } { return 0 } @@ -1047,7 +1057,7 @@ proc check_effective_target_return_address {} { return 0 } # No notion of return address in eBPF. - if { [istarget bpf-*-*] } { + if { [istarget bpf-*-*] || [istarget wasm*-*-*] } { return 0 } # It could be supported on amdgcn, but isn't yet. @@ -1062,7 +1072,7 @@ proc check_effective_target_return_address {} { # with K&R C function declarations. proc check_effective_target_untyped_assembly {} { - if { [istarget nvptx-*-*] } { + if { [istarget wasm*-*-*] || [istarget nvptx-*-*] } { return 0 } return 1 @@ -1277,6 +1287,9 @@ proc check_effective_target_fgnu_tm {} { # Return 1 if the target supports mmap, 0 otherwise. proc check_effective_target_mmap {} { + if [istarget wasm*-*-*] { + return 0; + } return [check_function_available "mmap"] } @@ -4919,6 +4932,9 @@ proc check_effective_target_vect_intdouble_cvt { } { #Return 1 if we're supporting __int128 for target, 0 otherwise. proc check_effective_target_int128 { } { + if [istarget wasm*-*-*] { + return 0; + } return [check_no_compiler_messages int128 object { int dummy[ #ifndef __SIZEOF_INT128__ @@ -12226,7 +12242,8 @@ proc check_effective_target_lto { } { return 0 } if { [istarget nvptx-*-*] - || [istarget amdgcn-*-*] } { + || [istarget amdgcn-*-*] + || [istarget wasm*-*-*] } { return 0; } return [check_no_compiler_messages lto object { @@ -13035,6 +13052,7 @@ proc check_effective_target_fenv_exceptions_long_double {} { proc check_effective_target_exceptions {} { if { [istarget amdgcn*-*-*] || [istarget bpf-*-*] + || [istarget wasm*-*-*] || [istarget nvptx-*-*] } { return 0 } @@ -14050,7 +14068,7 @@ foreach N {df} { # Return 1 if this target uses an LLVM assembler and/or linker proc check_effective_target_llvm_binutils { } { return [check_cached_effective_target llvm_binutils { - expr { [istarget amdgcn*-*-*] + expr { [istarget amdgcn*-*-*] || [istarget wasm*-*-*] || [check_effective_target_offload_gcn] }}] } @@ -14126,7 +14144,7 @@ proc check_effective_target_large_initializer { } { # in the assembly. proc check_effective_target_non_strict_prototype { } { - if { [istarget nvptx*-*-*] } { + if { [istarget wasm*-*-*] || [istarget nvptx*-*-*] } { return 0 } @@ -14328,6 +14346,9 @@ proc check_effective_target_lra { } { # Return 1 if 'asm goto' with outputs is supported, 0 otherwise. proc check_effective_target_asm_goto_with_outputs { } { + if { [istarget wasm*-*-*] } { + return 0 + } if { [istarget nvptx-*-*] } { return 1 }